Need help with nvim-bufferline.lua?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

akinsho
197 Stars 16 Forks The Unlicense 253 Commits 5 Opened issues

Description

A snazzy bufferline for Neovim

Services available

!
?

Need anything else?

Contributors list

# 21,940
OCaml
Neovim
neovim-...
rxjs
231 commits
# 316,617
Vim
Neovim
Lua
floatin...
3 commits
# 2,998
hugo
2d-game...
Game Ja...
vanilla...
2 commits
# 283,131
C#
unittes...
code-co...
.NET
2 commits
# 63,011
Vim
Neovim
Lua
vimrc
1 commit
# 34,825
Electro...
Neovim
React
reasonm...
1 commit
# 18,193
Neovim
Qt
singlet...
gdscrip...
1 commit
# 298,910
C++
chatroo...
videoch...
C
1 commit
# 711,855
JavaScr...
Shell
fantasy...
1 commit

nvim-bufferline.lua

A snazzy 💅 buffer line (with minimal tab integration) for Neovim built using lua.

Demo GIF

This plugin shamelessly attempts to emulate the aesthetics of GUI text editors/Doom Emacs. It was inspired by a screenshot of DOOM Emacs using centaur tabs. I don't intend to copy all of it's functionality though.

Features

  • Colours derived from colorscheme where possible.

  • Sort buffers by

    extension
    ,
    directory
    or pass in a custom compare function
  • Filter buffers using a custom function

Alternate option for tab styling

slanted tabs

NOTE: tested with

kitty
, results may vary depending on your terminal emulator of choice

see:

:h bufferline-styling

LSP error indicators

  • NOTE: This only works with neovim's native lsp.

LSP error

Option to show buffer numbers

bufferline with numbers

mode

both
with default number_style

both with default style

mode

both
with customized number_style
{"superscript", "subscript"}

both with customized style

Buffer pick functionality

bufferline pick

Make buffer names unique if there are duplicates

duplicate names

Close icons for closing individual buffers

close button

Re-order current buffer

re-order buffers

This order can be persisted between sessions (enabled by default).

Requirements

  • Neovim 0.5+ (nightly)
  • A patched font (see nerd fonts)

Installation

-- using packer.nvim
use {'akinsho/nvim-bufferline.lua', requires = 'kyazdani42/nvim-web-devicons'}
Plug 'kyazdani42/nvim-web-devicons' " Recommended (for coloured icons)
" Plug 'ryanoasis/vim-devicons' Icons without colours
Plug 'akinsho/nvim-bufferline.lua'

Why another buffer line plugin?

  1. I was looking for an excuse to play with lua and learn to create a plugin with it for Neovim and there was nothing else built in lua when I created this.
  2. I wanted to add some tweaks to my buffer line and didn't want to figure out a bunch of
    vimscript
    in some other plugin.

Caveats 🙏

  • This won't appeal to everyone's tastes. This plugin is opinionated about how the tabline looks, it's unlikely to please everyone, I don't want to try and support a bunch of different appearances.
  • I want to prevent this becoming a pain to maintain so I'll be conservative about what I add.
  • This plugin relies on some basic highlights being set by your colour scheme i.e.
    Normal
    ,
    String
    ,
    TabLineSel
    (
    WildMenu
    as fallback),
    Comment
    . It's unlikely to work with all colour schemes. You can either try manually overriding the colours or manually creating these highlight groups before loading this plugin.
  • If the contrast in your colour scheme isn't very high, think an all black colour scheme, some of the highlights of this plugin won't really work as intended since it depends on darkening things.

Usage

See the docs for details

:h nvim-bufferline.lua

You need to be using

termguicolors
for this plugin to work, as it reads the hex
gui
color values of various highlight groups.
set termguicolors
" In your init.{vim/lua}
lua require'bufferline'.setup{}

You can close buffers by clicking the close icon or by right clicking the tab anywhere

A few of this plugins commands can be mapped for ease of use.

" These commands will navigate through buffers in order regardless of which mode you are using
" e.g. if you change the order of buffers :bnext and :bprevious will not respect the custom ordering
nnoremap [b :BufferLineCycleNext
nnoremap b] :BufferLineCyclePrev

" These commands will move the current buffer backwards or forwards in the bufferline nnoremap :BufferLineMoveNext nnoremap :BufferLineMovePrev

" These commands will sort buffers by directory, language, or a custom criteria nnoremap be :BufferLineSortByExtension nnoremap bd :BufferLineSortByDirectory nnoremap :lua require'bufferline'.sort_buffers_by(function (buf_a, buf_b) return buf_a.id < buf_b.id end)

If you manually arrange your buffers using

:BufferLineMove{Prev|Next}
during an nvim session this can be persisted for the session. This is enabled by default but you need to ensure that your
sessionopts+=globals
otherwise the session file will not track global variables which is the mechanism used to store your sort order.

Configuration

require'bufferline'.setup{
  options = {
    view = "multiwindow" | "default",
    numbers = "none" | "ordinal" | "buffer_id" | "both",
    number_style = "superscript" | "" | { "none", "subscript" }, -- buffer_id at index 1, ordinal at index 2
    mappings = true | false,
    buffer_close_icon= '',
    modified_icon = '●',
    close_icon = '',
    left_trunc_marker = '',
    right_trunc_marker = '',
    max_name_length = 18,
    max_prefix_length = 15, -- prefix used when a buffer is deduplicated
    tab_size = 18,
    diagnostics = false | "nvim_lsp"
    diagnostics_indicator = function(count, level, diagnostics_dict)
      return "("..count..")"
    end
    -- NOTE: this will be called a lot so don't do any heavy processing here
    custom_filter = function(buf_number)
      -- filter out filetypes you don't want to see
      if vim.bo[buf_number].filetype ~= "" then
        return true
      end
      -- filter out by buffer name
      if vim.fn.bufname(buf_number) ~= "" then
        return true
      end
      -- filter out based on arbitrary rules
      -- e.g. filter out vim wiki buffer from tabline in your work repo
      if vim.fn.getcwd() == "" and vim.bo[buf_number].filetype ~= "wiki" then
        return true
      end
    end,
    show_buffer_close_icons = true | false,
    show_close_icon = true | false,
    show_tab_indicators = true | false,
    persist_buffer_sort = true, -- whether or not custom sorted buffers should persist
    -- can also be a table containing 2 custom separators
    -- [focused and unfocused]. eg: { '|', '|' }
    separator_style = "slant" | "thick" | "thin" | { 'any', 'any' },
    enforce_regular_tabs = false | true,
    always_show_bufferline = true | false,
    sort_by = 'extension' | 'relative_directory' | 'directory' | function(buffer_a, buffer_b)
      -- add custom logic
      return buffer_a.modified > buffer_b.modified
    end
  }
}

NOTE:

If using a plugin such as

vim-rooter
and you want to sort by path, prefer using
directory
rather than
relative_directory
. Relative directory works by ordering relative paths first, however if you move from project to project and vim switches its directory, the bufferline will re-order itself as a different set of buffers will now be relative.

LSP Error indicators

By setting

diagnostics = "nvim_lsp"
you will get an indicator in the bufferline for a given tab if it has any errors This will allow you to tell at a glance if a particular buffer has errors. Currently only the native neovim lsp is supported, mainly because it has the easiest API for fetching all errors for all buffers (with an attached lsp client).

In order to customise the appearance of the diagnostic count you can pass a custom function in your setup.

-- rest of config ...

--- count is an integer representing total count of errors --- level is a string "error" | "warning" --- diagnostics_dict is a dictionary from error level ("error", "warning" or "info")to number of errors for each level. --- this should return a string --- Don't get too fancy as this function will be executed a lot diagnostics_indicator = function(count, level, diagnostics_dict) local icon = level:match("error") and " " or " " return " " .. icon .. count end

custom indicator

diagnostics_indicator = function(_, _, diagnostics_dict)
  local s = " "
  for e, n in pairs(diagnostics_dict) do
    local sym = e == "error" and " "
      or (e == "warning" and " " or "" )
    s = s .. n .. sym
  end
  return s
end

diagnostics_indicator

The highlighting for the filename if there is an error can be changed by replacing the highlights for

error
,
error_visible
,
error_selected
,
warning
,
warning_visible
,
warning_selected
.

Regular tab sizes

Generally this plugin enforces a minimum tab size so that the buffer line appears consistent. Where a tab is smaller than the tab size it is padded. If it is larger than the tab size it is allowed to grow up to the max name length specified (+ the other indicators). If you set

enforce_regular_tabs = true
tabs will be prevented from extending beyond the tab size and all tabs will be the same length

Sort by
...

Bufferline allows you to sort the visible buffers by

extension
or
directory
:
" Using vim commands
:BufferLineSortByExtension
:BufferLineSortByDirectory
-- Or using lua functions
:lua require'bufferline'.sort_buffers_by('extension')`
:lua require'bufferline'.sort_buffers_by('directory')`

For more advanced usage you can provide a custom compare function which will receive two buffers to compare. You can see what fields are available to use using

sort_by = function(buffer_a, buffer_b)
  print(vim.inspect(buffer_a))
-- add custom logic
  return buffer_a.modified > buffer_b.modified
end

When using a sorted bufferline it's advisable that you use the

BufferLineCycleNext
and
BufferLineCyclePrev
commands since these will traverse the bufferline bufferlist in order whereas
bnext
and
bprev
will cycle buffers according to the buffer numbers given by vim.

Bufferline Pick functionality

Using the

BufferLinePick
command will allow for easy selection of a buffer in view. Trigger the command, using
:BufferLinePick
or better still map this to a key, e.g.
nnoremap  gb :BufferLinePick

then pick a buffer by typing the character for that specific buffer that appears

bufferline_pick

Multi-window mode

When this mode is active, for layouts of multiple windows in the tabpage, only the buffers that are displayed in those windows are listed in the tabline. That only applies to multi-window layouts, if there is only one window in the tabpage, all buffers are listed.

Mappings

If the

mappings
option is set to
true
.
1-9 mappings will
be created to navigate the first to the tenth buffer in the bufferline.
This is false by default. If you'd rather map these yourself, use:
nnoremap mymap :lua require"bufferline".go_to_buffer(num)

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.