romgrk / barbar.nvim

The neovim tabline plugin.
2.23k stars 83 forks source link

feat: specify `icons` per buffer activity/state #386

Closed Iron-E closed 1 year ago

Iron-E commented 1 year ago

This PR allows customization of the bufferline.icons setting per activity / state, like so:

require'bufferline'.setup {
  icons = {
    -- Configure the base icons on the bufferline.
    buffer_index = false,
    buffer_number = false,
    close = '',
    diagnostics = {…}, -- moved here from the `diagnostics` option
    filetype = {
      -- Sets the icon's highlight group.
      -- If false, will use nvim-web-devicons colors
      custom_colors = false,

      -- Requires `nvim-web-devicons` if `true`
      enabled = true,
    },
    inactive = {separator = {left = '▎'}},
    separator = {left = '▎'},

    -- Configure the icons on the bufferline when modified or pinned.
    -- Supports all the base icon options.
    modified = {button = '●'},
    pinned = {button = '車'},

    -- Configure the icons on the bufferline based on the visibility of a buffer.
    -- Supports all the base icon options, plus `modified` and `pinned`.
    alternate = {filetype = {enabled = false}},
    current = {buffer_index = true},
    inactive = {button = '×'},
    visible = {modified = {buffer_number = false}},
  },
}

When multiple options match (e.g. icons.separator, icons.modified.separator, and icons.alternate.separator), precedence works as follows:

  1. icons.(alternate|current|inactive|visible).(modified|pinned).foo, if the buffer is modified or pinned
  2. icons.(modified|pinned).foo, if the buffer is modified or pinned
  3. icons.(alternate|current|inactive|visible).foo
  4. icons.foo

Users who specify their icons/icon_separator_active/etc options the old way are prompted with a deprecation notice, but no action is necessary. The old options are automatically translated to the new format, and this will continue until a theoretical v2.0.0 releases.


This seemed like the best compromise between letting a user provide a function (my initial proposal) and adhering to the simplicity of user configuration (romgrk's preference).


Closes #46. Closes #243. Closes #379.

otavioschwanck commented 1 year ago

Extremely WIP.

This PR allows customization of the bufferline.icons setting per activity / state, like so:

--- @class bufferline.options.icons.buffer
--- @field buffer_number? boolean iff `true`, show the `bufnr` for the associated buffer.
--- @field buffer_index? boolean iff `true`, show the index of the associated buffer with respect to the ordering of the buffers in the tabline.
--- @field file_icon? boolean iff `true`, show the `devicons` for the associated buffer's `filetype`.

--- @class bufferline.options.icons.state: bufferline.options.icons.buffer
--- @field modified? bufferline.options.icons.buffer the icons used for an modified buffer
--- @field pinned? bufferline.options.icons.buffer the icons used for a pinned buffer

--- @class bufferline.options.icons
--- @field alternate? bufferline.options.icons.state the icons used for an alternate buffer
--- @field current? bufferline.options.icons.state the icons for the current buffer
--- @field default? bufferline.options.icons.state the icons used when no other filter matches
--- @field inactive? bufferline.options.icons.state the icons for inactive buffers
--- @field visible? bufferline.options.icons.state the icons for visible buffers

When multiple definitions match, they most specific definition applies on top of its defaults. For example:

require'bufferline'.setup {
  icons = {
    default = {buffer_number = true, pinned = {buffer_index = true}},
    visible = {file_icon = true, modified = {file_icon = false}},
  },
}
  • A visible buffer will show its file icon.
  • A visible, pinned buffer will show its file icon and buffer index.
  • A visible, modified buffer will show no icons (since visible.modified.file_icon overrides visible.file_icon).
  • A visible, modified, and pinned buffer will show only the buffer index.
  • A non-visible, pinned buffer will show its buffer index and buffer number.
  • A non-visible, non-pinned buffer will show its buffer number.

There is automatic translation done for users who specify their options in the "old" way, i.e.:

--- @alias bufferline.options.icons.preset boolean|"both"|"buffer_number_with_icon"|"buffer_numbers"|"numbers"

--- @type {[bufferline.options.icons.preset]: bufferline.options.icons}
local PRESETS = {
  [false] = {},
  [true] = {default = {file_icon = true}},
  both = {default = {buffer_index = true, file_icon = true}},
  buffer_number_with_icon = {default = {buffer_number = true, file_icon = true}},
  buffer_numbers = {default = {buffer_number = true}},
  numbers = {default = {buffer_index = true}},
}

This seemed like the best compromise between letting a user provide a function (my initial proposal) and adhering to the simplicity of user configuration (romgrk's preference).

Closes #379.

Very nice, a nice think to have maybe is the pinned tabs be always visible (for a next task)

Iron-E commented 1 year ago

@otavioschwanck feel free to try this PR now, I've been using it for about a day and haven't gotten any errors (but that usually means they're hiding, so an extra tester would be helpful!). I believe your desired configuration would be:

require'bufferline'.setup {
  icons = {
    pinned = {
      buffer_index = true,
    },
  },
}

Feel free to make another issue for keeping pinned tabs visible.

otavioschwanck commented 1 year ago

Some issues:

If we set the deprecated options, barbar throw an error and close itself.

i think the close = 'icon' is a strange option.

i had to do that:

        icons = {
          pinned = { buffer_index = true, close = '󰐃' },
        },

Maybe something like: left, icon or button, idk,

Iron-E commented 1 year ago

Thank you for testing it out!

If we set the deprecated options, barbar throw an error and close itself.

It shouldn't be doing that; did that happen to you? The deprecation notice shouldn't make barbar disable by itself, so it could be a separate issue. If you have an error message or stacktrace that would be helpful.

i think the close = '<icon>' is a strange option.

That's fair, and I'm certainly open to renaming the options. button is a good suggestion.

i had to do that:

Yeah, if you had icon_pinned set you'd have to set icons.pinned.close. Hopefully the deprecation notice told you that (but if not, please let me know!)

otavioschwanck commented 1 year ago

Thank you for testing it out!

If we set the deprecated options, barbar throw an error and close itself.

It shouldn't be doing that; did that happen to you? The deprecation notice shouldn't make barbar disable by itself, so it could be a separate issue. If you have an error message or stacktrace that would be helpful.

i think the close = '<icon>' is a strange option.

That's fair, and I'm certainly open to renaming the options. button is a good suggestion.

i had to do that:

Yeah, if you had icon_pinned set you'd have to set icons.pinned.close. Hopefully the deprecation notice told you that (but if not, please let me know!)

Just use my config:

      require('bufferline').setup({
        diagnostics = {
          [vim.diagnostic.severity.ERROR] = { enabled = false },
          [vim.diagnostic.severity.WARN] = { enabled = false },
          [vim.diagnostic.severity.INFO] = { enabled = false },
          [vim.diagnostic.severity.HINT] = { enabled = false },
        },
        icon_pinned = '󰐃',
        exclude_ft = {'netrw'},
        focus_on_close = 'left',
        closable = false,
        icon_separator_active = '',
        icon_separator_inactive = '',
        minimum_padding = 1,
        maximum_padding = 1
      })

Trying to pin, throws:

Barbar detected an error while running. Barbar disabled itself :/ Include this in your report: ...cal/share/nvim/lazy/barbar.nvim/lua/bufferline/state.lua:244: bad argument #1 to 'setfallbacktable' (table expected, got string)
stack traceback:
^I[C]: in function 'setfallbacktable'
^I...cal/share/nvim/lazy/barbar.nvim/lua/bufferline/state.lua:244: in function 'icons'
^I...al/share/nvim/lazy/barbar.nvim/lua/bufferline/layout.lua:59: in function 'calculate_buffer_width'
^I...al/share/nvim/lazy/barbar.nvim/lua/bufferline/layout.lua:95: in function 'calculate_buffers_width'
^I...al/share/nvim/lazy/barbar.nvim/lua/bufferline/layout.lua:109: in function 'calculate'
^I...al/share/nvim/lazy/barbar.nvim/lua/bufferline/render.lua:758: in function <...al/share/nvim/lazy/barbar.nvim/lua/bufferline/render.lua:730>
^I[C]: in function 'xpcall'
^I...al/share/nvim/lazy/barbar.nvim/lua/bufferline/render.lua:962: in function 'update'
^I...local/share/nvim/lazy/barbar.nvim/lua/bufferline/api.lua:463: in function 'toggle_pin'
^I...io/.local/share/nvim/lazy/barbar.nvim/lua/bufferline.lua:112: in function <...io/.local/share/nvim/lazy/barbar.nvim/lua/bufferline.lua:112>
Iron-E commented 1 year ago

Alright, I found the issue thanks to your report. I double checked all the deprecated options so they should be functional despite being deprecated.

Note: I renamed close to button.

Iron-E commented 1 year ago

@mawkler can you also try this when you get a chance? I've been using it for a few days now and haven't had issues. It would be good to have more experience reports, even if you're not actually using the new features, just to make sure there isn't anything I missed. If you don't have time, that's alright!

mawkler commented 1 year ago

@Iron-E Sure!

I managed to get an error immediately lol. Is this enough information?:

Barbar detected an error while running. Barbar disabled itself :/ Include this in your report: ...al/share/nvim/lazy/barbar.nvim/lua/bufferline/layout.lua:79: Expected lua string
stack traceback:
    [C]: in function 'strwidth'
    ...al/share/nvim/lazy/barbar.nvim/lua/bufferline/layout.lua:79: in function 'calculate_buffer_width'
    ...al/share/nvim/lazy/barbar.nvim/lua/bufferline/layout.lua:94: in function 'calculate_buffers_width'
    ...al/share/nvim/lazy/barbar.nvim/lua/bufferline/layout.lua:108: in function 'calculate'
    ...al/share/nvim/lazy/barbar.nvim/lua/bufferline/render.lua:514: in function <...al/share/nvim/lazy/barbar.nvim/lua/bufferline/render.lua:489>
    [C]: in function 'xpcall'
    ...al/share/nvim/lazy/barbar.nvim/lua/bufferline/render.lua:728: in function 'update'
    ...al/share/nvim/lazy/barbar.nvim/lua/bufferline/events.lua:134: in function <...al/share/nvim/lazy/barbar.nvim/lua/bufferline/events.lua:134>
    [C]: at 0x55c43f254c47
    [C]: in function 'pcall'
    ...e/nvim/lazy/telescope.nvim/lua/telescope/actions/set.lua:168: in function 'run_replace_or_original'
    ...re/nvim/lazy/telescope.nvim/lua/telescope/actions/mt.lua:65: in function 'run_replace_or_original'
    ...re/nvim/lazy/telescope.nvim/lua/telescope/actions/mt.lua:65: in function 'run_replace_or_original'
    ...re/nvim/lazy/telescope.nvim/lua/telescope/actions/mt.lua:65: in function <...re/nvim/lazy/telescope.nvim/lua/telescope/actions/mt.lua:54>
    .../melker/.config/nvim/lua/configs/telescope-multiopen.lua:25: in function 'multiopen'
    .../melker/.config/nvim/lua/configs/telescope-multiopen.lua:40: in function 'run_replace_or_original'
    ...re/nvim/lazy/telescope.nvim/lua/telescope/actions/mt.lua:65: in function 'callback'
    .../melker/.config/nvim/lua/configs/telescope-multiopen.lua:48: in function <.../melker/.config/nvim/lua/configs/telescope-multiopen.lua:47>
Iron-E commented 1 year ago

I managed to get an error immediately

😳

Is this enough information?

Yeah, I can work with that

mawkler commented 1 year ago

Here's the config I'm using. If I remove the icons table I don't get the error.

vim.g.bufferline = {
  no_name_title = '[No Name]',
  insert_at_end = true,
  exclude_name = { '[dap-repl]' },
  exclude_ft = { 'qf' },
  maximum_length = 60,
  hide = {
    extensions = true,
  },
  icons = {
    button = false,
  },
}
Iron-E commented 1 year ago

Ah. It expects button to be a string, so the config in that case would be icons = {button = ''}.

I can either update the deprecation text, or just make button = false a valid setting. Do you have a preference?

mawkler commented 1 year ago

I see! I think button = false makes sense and is similar to closable = false which is what I had to migrate from.

Iron-E commented 1 year ago

I see! I think button = false makes sense and is similar to closable = false which is what I had to migrate from.

Alright, button = false should now be a valid option. Let me know if you run into any more problems!

mawkler commented 1 year ago

Thank you! I'll keep daily driving feat/379 and let you know if I encounter any more issues!

Iron-E commented 1 year ago

Thanks for sacrificing some time out of your busy schedule! I appreciate it. This is a lot of code; I wanted to get your OK on the high-level concepts even if you didn't have time to go line-by-line.

I'll test it one more time before merging.