Skip to content

FEATURE: Show source selector tabs in the tabline #1368

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

Closed
1 task done
pwnalone opened this issue Feb 29, 2024 · 16 comments
Closed
1 task done

FEATURE: Show source selector tabs in the tabline #1368

pwnalone opened this issue Feb 29, 2024 · 16 comments
Labels
documentation Improvements or additions to documentation enhancement New feature or request how-to idea

Comments

@pwnalone
Copy link

Did you check the docs?

  • I have read all the docs.

Is your feature request related to a problem? Please describe.

Neotree currently provides the ability to show the source selector tabs in the status line or winbar, but it would be nice if it were possible to show them in the tabline. I use bufferline.nvim and I would prefer that the source selector tabs from Neotree were at the same level as my other buffer tabs (i.e. where the red box is in the screenshot, below).

image

This idea was previous proposed here in the discussion under #425, but it was never implemented.

Describe the solution you'd like.

I'm new to Lua so I'm not sure how this would best be implemented, or if it would even be possible to implement here versus in another plugin like bufferline. The three scenarios that I am able to envision are:

  1. This feature is implemented here.
  2. This feature is implemented in other plugins (e.g. bufferline).
  3. This feature is implemented as an extension that can be used from other plugins like bufferline.

For example, in bufferline's configuration, you can reserve space for a sidebar (e.g. file explorer) so that the buffer tabs do not display over the sidebar. Additionally, you can configure the text that will be displayed above this sidebar.

return {
  'akinsho/bufferline.nvim',
  version = '*',
  dependencies = { 'nvim-tree/nvim-web-devicons' },
  event = { 'VimEnter' },
  init = function()
    vim.opt.termguicolors = true
  end,
  opts = {
    options = {
      offsets = {
        {
          filetype = 'neo-tree',
          text = '<The source selector tabs could go here>',
          text_align = 'center',
          highlight = 'Directory',
        },
      },
    },
  },
}

It seems that the above text key can be a function, and any string that gets returned will be displayed in the tabline above the sidebar. This may provide an easy way to implement this feature, or it may already be possible using some of Neotree's internal functions.

Describe alternatives you've considered.

The alternative that I have considered is to just use the status line or winbar, but my preference, of course, would be to use the tabline. I understand that this feature may not be the preference of most, but I just thought I would create this issue to express my own interest in it, and to see if others would be interested as well.

Additional Context

No response

@pwnalone pwnalone added the enhancement New feature or request label Feb 29, 2024
@pysan3
Copy link
Collaborator

pysan3 commented Feb 29, 2024

I definitely love the idea, but long story short, it is very difficult.

The content of the selector can be calculated with require("neo-tree.ui.selector").get().

This is used like this as you can see here.

M.set_source_selector = function(state)
if state.enable_source_selector == false then
return
end
local sel_config = utils.resolve_config_option(require("neo-tree").config, "source_selector", {})
if sel_config and sel_config.winbar then
vim.wo[state.winid].winbar = "%{%v:lua.require'neo-tree.ui.selector'.get()%}"
end
if sel_config and sel_config.statusline then
vim.wo[state.winid].statusline = "%{%v:lua.require'neo-tree.ui.selector'.get()%}"
end
end

If you run this in neovim (:lua require("neo-tree.ui.selector").get()<CR>), you'll see that the string already contains highlighting and other stuffs.
However, iirc those tabline plugins are too clever that they calculate the text-width of the text() function and try to adjust the length and so on.

If the plugin had such field as raw where it showed exactly what was passed, it would work, but it is a very difficult task to make separate plugins cooperate. (you know like there are gazillion tabline plugins lol)

For example, tabline needs one extra space to compensate the WinSeparator compared to winbar, but on which side (left or right)? Should that be handled on neo-tree side? or in the bufferline plugin?

IMO this is the reason why it is too difficult to officially support this functionality, but if you have any ideas how it can be implemented I'd love to hear your opinion! Don't get me wrong, I like the idea but I just can't come up with a reliable way to achieve this.


If you have the time and knowledge, all of the building blocks are in this single file and it is relatively well documented.

I'm the main author of this code (with a lot of help of others ofc!) so ask me if you have any questions.

@pysan3
Copy link
Collaborator

pysan3 commented Feb 29, 2024

Hmm lovely...

image

diff --git a/lua/bufferline/offset.lua b/lua/bufferline/offset.lua
index 0315107..42aa3fb 100644
--- a/lua/bufferline/offset.lua
+++ b/lua/bufferline/offset.lua
@@ -28,7 +28,7 @@ local supported_win_types = {
 ---@param is_left boolean?
 ---@return string
 local function get_section_text(size, highlight, offset, is_left)
-  local text = offset.text
+  local text = offset.raw or offset.text
 
   if type(text) == "function" then text = text() end
   text = text or padding:rep(size - 2)
@@ -36,7 +36,9 @@ local function get_section_text(size, highlight, offset, is_left)
   local text_size, left, right = api.nvim_strwidth(text), 0, 0
   local alignment = offset.text_align or "center"
 
-  if text_size + 2 >= size then
+  if offset.raw then
+    -- skip (left = 0, right = 0)
+  elseif text_size + 2 >= size then
     text, left, right = utils.truncate_name(text, size - 2), 1, 1
   else
     local remainder = size - text_size

But I'm not motivated enough to send them a PR.

You can do whatever you want with my code. Maybe if you send them this link, they might be kind enough to add the functionality.

Uploaded the code just in case: https://github.com/pysan3/bufferline.nvim/tree/bufferline-offset-raw-text

@pwnalone
Copy link
Author

Thanks for the quick reply and for the solution! I checked out your fork and it is exactly what I was looking for, but when testing it out in preparation for making a PR, I did notice one issue that would probably prevent it from being accepted into bufferline.

When you open neotree and then shift focus away from it without closing the sidebar, the source selector tabs disappear and the buffer tabs are no longer offset properly.

image

I have a feeling that this might be a simple fix, so I will take a look and see if I can get it working with my limited Lua knowledge.

@pysan3
Copy link
Collaborator

pysan3 commented Feb 29, 2024

Yikes... You are right, and there's no good way to fix it actually.

.get() assumes that the nvim_api_current_win() is a neo-tree window.

So you need some specific implementation to cache the result, and keep displaying it when you're out of neo-tree, or you can add an event_handler for neo-tree to udpate this global variable on "neo_tree_buffer_enter". Nah it's getting more and more complex lol.

_G.__cached_neo_tree_selector = nil
_G.__get_neo_tree_selector = function()
  local str = require("neo-tree.ui.selector").get()
  if str then
    _G.__cached_neo_tree_selector = str
  end
  return _G.__cached_neo_tree_selector
end

-- setup({
  opts = {
    options = {
      offsets = {
        {
          filetype = "neo-tree",
          raw = " %{%v:lua._G.__get_neo_tree_selector()%} ",
          highlight = { sep = { link = "WinSeparator" } },
          separator = "",
        },
      },

@pysan3
Copy link
Collaborator

pysan3 commented Feb 29, 2024

OK final working solution, which is very hacky. I do not maintain this code and I don't know when it'll break.

cc @pwnalone

-- neo-tree
-- require("neo-tree").setup({
    event_handlers = {
      {
        event = "after_render",
        handler = function(state)
          if state.current_position == "left" or state.current_position == "right" then
            vim.api.nvim_win_call(state.winid, function()
              local str = require("neo-tree.ui.selector").get()
              if str then
                _G.__cached_neo_tree_selector = str
              end
            end)
          end
        end,
      },
    }
-- end

-- bufferline
_G.__cached_neo_tree_selector = nil
_G.__get_selector = function()
  return _G.__cached_neo_tree_selector
end

-- require("bufferline.nvim").setup({
    options = {
      offsets = {
        {
          filetype = "neo-tree",
          raw = " %{%v:lua.__get_selector()%} ",
          highlight = { sep = { link = "WinSeparator" } },
          separator = "",
        },
      },
-- end

@pwnalone
Copy link
Author

@pysan3

Thank you so much for looking into this and coming up with a working solution!

Do you think this would be something that I could convince the maintainers of bufferline to include in their code base? Or is it too specific to neotree and wouldn't provide any benefit for other file explorers like nvim-tree?

@pysan3
Copy link
Collaborator

pysan3 commented Mar 2, 2024

The change needed for bufferline is the raw parameter which is not limited to trees but should open more possibilities to any plugin.

I don't think nvim tree has any winbar functionality (in my old memory) so they won't benefit from this?

My concerns are...

  • Shall we add it to the docs or keep it like an undocumented secret feature.
  • Shall we also add this raw keyword to not only offsets (sidebars) but also to normal buffers?
  • Shall we also allow raw() like text can take functions as well?
    • Which will make implementation a bit more complicated and will be too much for an undocumented feature imo
    • My snippet will benefit from this as now I must make a dumb wrapper to fetch the value.

@pysan3
Copy link
Collaborator

pysan3 commented Mar 3, 2024

@pwnalone As there's nothing to be done in neo-tree, can we close this issue?

@cseickel Do you think this snippet is worth being added to the wiki? #1368 (comment)

@pysan3 pysan3 added documentation Improvements or additions to documentation idea how-to labels Mar 3, 2024
@cseickel
Copy link
Contributor

cseickel commented Mar 3, 2024

@cseickel Do you think this snippet is worth being added to the wiki?

The answer to that question is always yes.

@pysan3
Copy link
Collaborator

pysan3 commented Mar 3, 2024

Could you do it for me as I don't know how to interact with the wiki...

@cseickel
Copy link
Contributor

cseickel commented Mar 3, 2024

Could you do it for me as I don't know how to interact with the wiki...

Sorry,the point of the wiki is for community self help and sharing, I'm not going to get in the business of adding other people's stuff for them. I think you are more than capable of finding the edit button.

@pysan3
Copy link
Collaborator

pysan3 commented Mar 9, 2024

@pwnalone Did you make a PR/FR upstream?

Anyways please close this issue if my solution is working / you are satisfied.

@pwnalone
Copy link
Author

Hi, @pysan3, sorry for the late reply; I had an urgent matter to attend to. I have not had a chance to make a PR yet, but I will close this issue in the meantime, since there is nothing left that needs to be done on neo-tree's side of things.

Thank you again for your help in this and for providing a working solution!

@pysan3
Copy link
Collaborator

pysan3 commented Mar 11, 2024

Thanks for your reply @pwnalone .

Please ping me when you make the regarding PR/FR.

@so-rose
Copy link

so-rose commented Mar 17, 2024

Hi @pwnalone, just wanted to chime in and say thanks for the patch / fork! Works like a charm.

@pwnalone
Copy link
Author

@so-rose Thanks, but @pysan3 is the one who made the patch/fork. I just created the feature request, which was actually first proposed by @cseickel in #425, so I can't really take any of the credit.

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

No branches or pull requests

4 participants