Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Request]: Reexposing groups and statuses like is_pinned. #736

Closed
cenk1cenk2 opened this issue Apr 21, 2023 · 14 comments · May be fixed by #741
Closed

[Feature Request]: Reexposing groups and statuses like is_pinned. #736

cenk1cenk2 opened this issue Apr 21, 2023 · 14 comments · May be fixed by #741
Labels
enhancement New feature or request

Comments

@cenk1cenk2
Copy link

What?

Hello @akinsho,

Thank you for maintaining this plugin for such a long time.

With the latest changes, "bufferline.groups" no longer expose the groups for manipulation/look-up except for testing. If it is not much of a hassle can these be reexported?

I might be missing the other way to implement this but thank you so much for your time either way.

Why?

I know this is the internal API of the plugin but I have been heavily using it to implement functionality like closing all buffers but current except for the pinned ones, maybe that would be the case for others too.

These use cases like closing all but current were discussed in an issue before and you have indicated that this is easily implementable. Still, with the API no longer exposing them, it is impossible to do so anymore.

@cenk1cenk2 cenk1cenk2 added the enhancement New feature or request label Apr 21, 2023
@akinsho
Copy link
Owner

akinsho commented Apr 21, 2023

Hi @cenk1cenk2,

That's a really unfortunate feature/behaviour of lua that I can't hide private implementation details. I would have/strongly advise against using the internal APIs like this. Unfortunately it ties my hands way too much to have to worry about breaking users configs if they are using things I haven't explicitly exposed.

I think as a general rule to maintain my sanity if a module isn't documented as exposed it should be treated as private and I will tweak those things as needed. So I don't want to revert this since one of the reasons I changed this was because I didn't want these things exposed by accident so people wouldn't use them. Going forward I will actively actually try to hide anything that I can since I really don't want the internals of this plugin exposed by accident.

That being said I'm open to providing public APIs for achieving some common/valuable features.
In this case I'm not sure precisely what feature/API exactly is missing. You shouldn't be manually manipulating groups I think this is a huge problem internally (as I've described).

Maybe you can list out what functionality you are trying to achieve then I can think of if it's easy/possible etc.

It's important not to focus on the internal API but on the functionality you want since ultimately a lot of the internals can and will change over time definitely.

@cenk1cenk2
Copy link
Author

Hey @akinsho,

Thank you for your time and detailed answer. I do 100% agree on keeping private things private as you said and fully support the changes.

In my case, I do only need to know if a certain buffer with a number is in a certain group. I suppose that can be a useful feature if anybody has implemented a functionality like me closing everything unless they are pinned.

I suppose this has been discussed many times before like #580, #309, therefore, might be worthy of the public API.

@akinsho
Copy link
Owner

akinsho commented Apr 21, 2023

@cenk1cenk2 there is already a command called BufferlineGroupClose which you can use to close any group, would this problem be solved by being able to specify multiple groups?

The reason I closed those other issues is that users have been trying to nudge this plugin into doing buffer management but I've explained many times that the object of this plugin is UI it's not a tool designed for buffer management

@akinsho
Copy link
Owner

akinsho commented Apr 21, 2023

I guess you could add to group close with an except=pinned a flag that could be used to invert the behaviour

@cenk1cenk2
Copy link
Author

To be honest, the only thing that can solve my use case is to have a function that can check whether the buffer is certain group. I have missed the commands like BufferlineGroupClose at the time I have implemented this, so thanks for the heads up since I now know I can implement some of the functions I have without doing any trickery.

But with that said I sincerly thank you for taking your time and very grateful for all the answers as well as if you do not see it fit to have this on the public API, I still totaly understand that since it can be a very specific use-case that does not comply with having a clean way to manage buffers.

@akinsho
Copy link
Owner

akinsho commented Apr 24, 2023

So I think I still misunderstand the use case because it sounds like you just want to be able to close all buffer not inside of a group e.g. close all unpinned buffers. This should be easy enough by changing the GroupClose command to do something like GroupClose except=pinned this would basically allow any buffer in that group to say open and close all the rest.

It seems like this would solve your issue? why do you think you'd still need a function to manually check the groups?

@cenk1cenk2
Copy link
Author

cenk1cenk2 commented Apr 24, 2023

Sorry for a bit beating around the bush and wasting your time without a proper use case.

The addition of except=pinned would be a great addition in my eyes, which will also allow me to clean up some code.

So for an example use-case of the one that has been mentioned in the prior issues which are "close all buffers but current", where it can be supported with my hacky version of the code found here.

  • So let us imagine we have multiple buffers and some of them are pinned.
    image
  • Whenever the command for "close all buffers but current" is issued, the expected result is to keep the pinned tabs as well as the current tab.
    image
  • So the basic solution is to loop through all the buffers managed by the plugin getting the valid buffers through require("bufferline.utils").get_valid_buffers() and looping over them. While looping it would skip if the buffer is in a certain group like pinned which only the plugin knows and if the current buffer number matches what is focused on the window.

OFC, this can be got around by pinning the actual buffer first then, closing all except pinned, then unpinning the buffer with current structure.

Another use case that I can throw in the mix is something like "smart quit", where it would prompt y/n if the buffer is pinned or modified, and this can be found as code here.

  • In this case, it is more basic, where you try to close a buffer and it checks whether the buffer is in a certain group in this case pinned, and prompts you if this is the actual thing you want to do.

Thank you again for your time on this issue and sorry for not being as straightforward with the use case.

@kasthor
Copy link

kasthor commented Apr 24, 2023

Hey, just hopping in

I was actually working on a similar thing, problem is that i navigate code and start opening multiple buffers and it gets out of control, so I was thinking about how to close my buffers in a keystroke

I was thinking to propose a "close_by" API call which will just provide a filter function ( similar to the sort_by ) and then close if true or false, this would allow extensibility to anyone who needs it, but i'm afraid it will be rejected for falling on the "buffer management" realm

problem i've found is that my UI doesn't refresh if I close the buffer manually

also, a sugestion, instead of using is_pinned you can check the group name, my approach to an external close_by looks like this:

local function buffers_close_by(func)
  local elements = bufferline.get_elements().elements

  for index in ipairs(elements) do
    bufferline.exec(index, function(buf)
      if func(buf) then
        close_buffer(buf)
      end
    end)
  end
end

@cenk1cenk2
Copy link
Author

cenk1cenk2 commented Apr 24, 2023

Yeah I now realize that I use the archaic version of the API to try to achieve what I am doing. Thanks for the heads up @kasthor.

@akinsho
Copy link
Owner

akinsho commented Apr 24, 2023

So a lot of these use cases fall into the buffer management plugin space which I often find there are already enough solutions for in other plugins or natively.

Some examples of good plugins that solve buffer management well already are:

For example close all but current gets mentioned a lot but neovim already has a pretty simple solution for a basic version of this which is

	vim.keymap.set('n', '<leader>on', [[<cmd>w <bar> %bd <bar> e#<CR>]], { desc = 'close all other buffers' })

The complex combination of close all that aren't pinned except the current one I think is outside the realm of general enough to add to the plugin this seems like something quite specific to a workflow and not generally applicable.

In general to clarify the only buffer "management" commands in this plugin only exist because they operate through or on something that only this plugin is aware of/created e.g. groups, this is the requirement for it being added to this plugin, it solves a problem that only this plugin can solve (which is often because it's a paradigm created by this plugin).

Anyway the TLDR is, some sort of except=<group-name> seems like a good addition to me, any more specific use cases on top of that seem like they stray into basically taking on the extra work of buffer management.

@akinsho
Copy link
Owner

akinsho commented Apr 24, 2023

@kasthor your snippet/desired functionality can be achieved entirely without bufferline existing or being involved e.g.

for _, id in ipairs(vim.api.nvim_list_bufs()) do
  if vim.api.nvim_buf_is_valid(id) then
    -- you can do whatever you want based on 
    -- vim.bo
    local modified = vim.bo[id].modified
    local buftype = vim.bo[id].buftype
    local filetype = vim.bo[id].filetype
    local name = vim.api.nvim_buf_get_name(id)
    if predicate_i_want then
      vim.api.nvim_buf_delete(id, { force = true})
    end
  end
end

@Gremious
Copy link

Gremious commented Jun 22, 2023

With the future addition of the except= argument, I'd like to kindly ask for an example - how would a "close all but current or pinned" function look like?

I am also one of the people who would really like to be able to do this, I often want to close all my tabs except the one I'm currently editing, and without losing all the important pinned ones.

@bruce3x
Copy link

bruce3x commented Aug 16, 2023

@Gremious
I am using this function to close other buffers without pinned.

function()
  local bufferline = require("bufferline")
  local commands = require("bufferline.commands")
  local current = vim.api.nvim_get_current_buf()
  vim.schedule(function()
    for _, e in ipairs(bufferline.get_elements().elements) do
      local is_current = e.id == current
      local is_pinned = bufferline.groups._is_pinned(e)
      if not is_current and not is_pinned then
        commands.unpin_and_close(e.id)
      end
    end
  end)
end

@cenk1cenk2
Copy link
Author

Thank you for your time on this, I would just close this to reduce clutter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants