Skip to content

Commit

Permalink
feat: pinned buffers stay visible (#408)
Browse files Browse the repository at this point in the history
* ref(bbye): only use `list_reverse` if necessary

* ref: `utils.has` -> `vim.tbl_contains`

* perf(state): `pcall(function() foo(args) end)` → `pcall(foo, args)`

The former creates a new anonymous function every time we call the
function, whereas the latter calls an _existing_ function with the given
arguments. It is ~4× faster

* perf(state): `sort_pins_left` in place

This is a 5–10× improvement, depending on the current layout of the
bufferline.

* ref: clarify `Buffer.for_each_counted_enabled_diagnostic` params

* feat: pinned buffers only show file icon by default

* feat: pinned buffers stay visible

* ref: always use `is_pinned` when `buffer_data` is not in scope

* perf(render): resolve proper icons on `setup`

This is a >2× performance increase for `render.update`

* fix: `button = ''` causes strange layout

In some cases `button = ''` was interpreted as: "`''` is the `button` ",
not "there is no button", as such the layout was being adjusted as if it
was there.

* fix: buffer move animation
  • Loading branch information
Iron-E authored Apr 5, 2023
1 parent d4d0e06 commit 622089b
Show file tree
Hide file tree
Showing 11 changed files with 380 additions and 316 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,11 @@ map('n', '<Space>bw', '<Cmd>BufferOrderByWindowNumber<CR>', opts)
```lua
vim.g.barbar_auto_setup = false -- disable auto-setup
require'barbar'.setup { -- Set barbar's options
require'barbar'.setup {
-- WARN: do not copy everything below into your config!
-- It is just an example of what configuration options there are.
-- The defaults are suitable for most people.
-- Enable/disable animations
animation = true,
Expand Down Expand Up @@ -305,7 +309,7 @@ require'barbar'.setup { -- Set barbar's options
-- Configure the icons on the bufferline when modified or pinned.
-- Supports all the base icon options.
modified = {button = '●'},
pinned = {button = '車'},
pinned = {button = '車', filename = true, separator = {right = ''}},
-- Configure the icons on the bufferline based on the visibility of a buffer.
-- Supports all the base icon options, plus `modified` and `pinned`.
Expand Down
15 changes: 13 additions & 2 deletions doc/barbar.txt
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,11 @@ icons ~
}}}
<

*barbar-setup.icons.filename*
icons.filename ~
`boolean` (default: `true`)
If `true`, show the name of the file.

*barbar-setup.icons.filetype.custom_colors*
icons.filetype.custom_colors ~
`boolean` (default: `false`)
Expand Down Expand Up @@ -309,15 +314,21 @@ icons ~

*barbar-setup.icons.pinned*
icons.pinned ~
`table` (default: `{button = ''}`)
`table` (default: >
{
button = false,
filename = false,
separator = {right = ' '},
}
< )
The icons which should be used for a pinned buffer.
Supports all the base options (e.g. `buffer_index`, `filetype.enabled`,
etc)

Example: >
require'barbar'.setup {icons = {
modified = {separator = '⋄'},
pinned = {button = '車'},
pinned = {button = '車', filename = true},
}}
<

Expand Down
16 changes: 9 additions & 7 deletions lua/barbar/api.lua
Original file line number Diff line number Diff line change
Expand Up @@ -213,22 +213,23 @@ function api.goto_buffer_relative(steps)
set_current_buf(state.buffers[(idx + steps - 1) % #state.buffers + 1])
end

local move_animation = nil
local move_animation_data = nil
local move_animation = nil --- @type nil|barbar.animate.state
local move_animation_data = {
next_positions = nil, --- @type nil|integer[]
previous_positions = nil --- @type nil|integer[]
}

--- An incremental animation for `move_buffer_animated`.
--- @return nil
local function move_buffer_animated_tick(ratio, current_animation)
local data = move_animation_data

for _, current_number in ipairs(Layout.buffers) do
local current_data = state.get_buffer_data(current_number)

if current_animation.running == true then
current_data.position = animate.lerp(
ratio,
data.previous_positions[current_number],
data.next_positions[current_number]
(move_animation_data.previous_positions or {})[current_number],
(move_animation_data.next_positions or {})[current_number]
)
else
current_data.position = nil
Expand All @@ -240,7 +241,8 @@ local function move_buffer_animated_tick(ratio, current_animation)

if current_animation.running == false then
move_animation = nil
move_animation_data = nil
move_animation_data.next_positions = nil
move_animation_data.previous_positions = nil
end
end

Expand Down
15 changes: 11 additions & 4 deletions lua/barbar/bbye.lua
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,16 @@ local function get_focus_on_close(closing_number)

if #state_bufnrs < 1 then -- all of the buffers are excluded or unlisted
local open_bufnrs = list_bufs()
if focus_on_close == 'right' then
open_bufnrs = utils.list_reverse(open_bufnrs)

local start, end_, step
if focus_on_close == 'left' then
start, end_, step = 1, #open_bufnrs, 1
else
start, end_, step = #open_bufnrs, 1, -1
end

for _, nr in ipairs(open_bufnrs) do
for i = start, end_, step do
local nr = open_bufnrs[i]
if buf_get_option(nr, 'buflisted') then
return nr -- there was a listed buffer open, focus it.
end
Expand Down Expand Up @@ -194,7 +199,9 @@ function bbye.delete(action, force, buffer, mods)

-- For cases where adding buffers causes new windows to appear or hiding some
-- causes windows to disappear and thereby decrement, loop backwards.
for _, window_number in ipairs(utils.list_reverse(list_wins())) do
local wins = list_wins()
for i = #wins, 1, -1 do
local window_number = wins[i]
if win_get_buf(window_number) == buffer_number then
set_current_win(window_number)

Expand Down
27 changes: 21 additions & 6 deletions lua/barbar/buffer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -85,26 +85,41 @@ local buffer = {

--- For each severity in `diagnostics`: if it is enabled, and there are diagnostics associated with it in the `buffer_number` provided, call `f`.
--- @param buffer_number integer the buffer number to count diagnostics in
--- @param diagnostics barbar.config.options.icons.diagnostics the user configuration for diagnostics
--- @param f fun(count: integer, diagnostic: barbar.config.options.icons.diagnostics.severity, severity: integer) the function to run when diagnostics of a specific severity are enabled and present in the `buffer_number`
--- @param diagnostics barbar.config.options.icons.buffer.diagnostics the user configuration for diagnostics
--- @param f fun(count: integer, severity_idx: integer, option: barbar.config.options.icons.diagnostics.severity) the function to run when diagnostics of a specific severity are enabled and present in the `buffer_number`
--- @return nil
for_each_counted_enabled_diagnostic = function(buffer_number, diagnostics, f)
local count
for severity, severity_config in ipairs(diagnostics) do
if severity_config.enabled then
for severity_idx, severity_option in ipairs(diagnostics) do
if severity_option.enabled then
if count == nil then
count = count_diagnostics(buffer_number)
end

if count[severity] > 0 then
f(count[severity], severity_config, severity)
if count[severity_idx] > 0 then
f(count[severity_idx], severity_idx, severity_option)
end
end
end
end,

get_activity = get_activity,

--- @param activity barbar.buffer.activity.name
--- @param modified boolean
--- @param pinned boolean
--- @return barbar.config.options.icons.buffer
get_icons = function(activity, modified, pinned)
local icons_option = config.options.icons[activity:lower()]
if pinned then
icons_option = icons_option.pinned
elseif modified then
icons_option = icons_option.modified
end

return icons_option
end,

--- @param buffer_number integer
--- @param hide_extensions boolean? if `true`, exclude the extension of the file
--- @return string name
Expand Down
62 changes: 53 additions & 9 deletions lua/barbar/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ local DEPRECATE_PREFIX = '\nThe barbar.nvim option '
--- @field enabled boolean
--- @field icon string

--- @class barbar.config.options.icons.diagnostics
--- @class barbar.config.options.icons.buffer.diagnostics
--- @field [1] barbar.config.options.icons.diagnostics.severity
--- @field [2] barbar.config.options.icons.diagnostics.severity
--- @field [3] barbar.config.options.icons.diagnostics.severity
Expand All @@ -30,21 +30,22 @@ local DEFAULT_DIAGNOSTIC_ICONS = {
[vim.diagnostic.severity.WARN] = {enabled = false, icon = '⚠️ '},
}

--- @class barbar.config.options.icons.filetype
--- @class barbar.config.options.icons.buffer.filetype
--- @field custom_colors? boolean if present, this color will be used for ALL filetype icons
--- @field enabled? boolean iff `true`, show the `devicons` for the associated buffer's `filetype`.

--- @class barbar.config.options.icons.separator
--- @class barbar.config.options.icons.buffer.separator
--- @field left? string a buffer's left separator
--- @field right? string a buffer's right separator

--- @class barbar.config.options.icons.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 buffer_number? boolean iff `true`, show the `bufnr` for the associated buffer.
--- @field filename? boolean iff `true`, show the filename
--- @field button? false|string the button which is clicked to close / save a buffer, or indicate that it is pinned.
--- @field diagnostics? barbar.config.options.icons.diagnostics the diagnostic icons
--- @field filetype? barbar.config.options.icons.filetype filetype icon options
--- @field separator? barbar.config.options.icons.separator the left-hand separator between buffers in the tabline
--- @field diagnostics? barbar.config.options.icons.buffer.diagnostics the diagnostic icons
--- @field filetype? barbar.config.options.icons.buffer.filetype filetype icon options
--- @field separator? barbar.config.options.icons.buffer.separator the left-hand separator between buffers in the tabline

--- @class barbar.config.options.icons.state: barbar.config.options.icons.buffer
--- @field modified? barbar.config.options.icons.buffer the icons used for an modified buffer
Expand Down Expand Up @@ -198,7 +199,7 @@ function config.setup(options)
end
end

config.options = tbl_deep_extend('keep', options, {
local default_options = {
animation = true,
auto_hide = false,
clickable = true,
Expand All @@ -214,10 +215,11 @@ function config.setup(options)
buffer_number = false,
button = '',
diagnostics = {},
filename = true,
filetype = {enabled = true},
inactive = {separator = {left = '', right = ''}},
modified = {button = ''},
pinned = {button = ''},
pinned = {button = false, filename = false},
separator = {left = '', right = ''},
},
insert_at_end = false,
Expand All @@ -230,7 +232,16 @@ function config.setup(options)
semantic_letters = true,
sidebar_filetypes = {},
tabpages = true,
})
}

do
local pinned_icons = options.icons and options.icons.pinned
if pinned_icons == nil or pinned_icons.button == false or #pinned_icons.button < 1 then
default_options.icons.pinned.separator = {right = ' '}
end
end

config.options = tbl_deep_extend('keep', options, default_options)

-- NOTE: we do this because `vim.tbl_deep_extend` doesn't deep copy lists
for i, default_diagnostic_severity_icons in ipairs(DEFAULT_DIAGNOSTIC_ICONS) do
Expand All @@ -244,6 +255,39 @@ function config.setup(options)
diagnostic_severity_icons.icon = default_diagnostic_severity_icons.icon
end
end

local icons = config.options.icons

--- `config.options.icons` without the recursive structure
--- @type barbar.config.options.icons.buffer
local base_options = {
buffer_index = icons.buffer_index,
buffer_number = icons.buffer_number,
filename = icons.filename,
button = icons.button,
diagnostics = icons.diagnostics,
filetype = icons.filetype,
separator = icons.separator,
}

-- resolve all of the icons for the activities
for _, activity in ipairs {'alternate', 'current', 'inactive', 'visible'} do
local activity_options = tbl_deep_extend('keep', config.options.icons[activity] or {}, base_options)
config.options.icons[activity] = activity_options
config.options.icons[activity].modified = tbl_deep_extend(
'keep',
config.options.icons[activity].modified or {},
config.options.icons.modified or {},
activity_options
)

config.options.icons[activity].pinned = tbl_deep_extend(
'keep',
config.options.icons[activity].pinned or {},
config.options.icons.pinned or {},
activity_options
)
end
end

return config
2 changes: 1 addition & 1 deletion lua/barbar/events.lua
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ function events.enable()
end

-- escape quotes
table_insert(buffers, {name = name, pinned = state.get_buffer_data(bufnr).pinned})
table_insert(buffers, {name = name, pinned = state.is_pinned(bufnr)})
end

vim.g.Bufferline__session_restore = "lua require'barbar.state'.restore_buffers " ..
Expand Down
Loading

0 comments on commit 622089b

Please sign in to comment.