How to setup tabline separators like in lightline
Closed this issue · 3 comments
Hi, I am migrating from lightline and trying to figure out to add these types of separators:
I tried using surround
, but it seems to be more well-suited for surrounding characters like (
)
. I would like to use the single-character separators for the bufferline.
Do you have any recommendations on how it might be implemented with heirline?
so, it is possible, but requires a bit of effort to pull it off nicely.. here it goes:
-- initialise the handle for the buflist. This will be an array of bufnumbers.
-- define a couple of utility functions to check if the component is at the end of the buflist,
-- of if it is right before the active buffer
local bufcache = {}
local function is_last(bufnr)
return bufcache[#bufcache] == bufnr
end
local function is_before_active(bufnr)
for i, b in ipairs(bufcache) do
if b == bufnr then
return vim.api.nvim_get_current_buf() == bufcache[i + 1]
end
end
end
local TablineBufferBlock = {
{
condition = function(self)
return self.is_active
end,
hl = { bg = "white" },
{
provider = " ", -- right full chevron (green on white)
hl = { fg = "green", bg = "white" },
},
{ TablinePicker, TablineFileNameBlock, TablineCloseButton },
{
provider = " ", -- right full chevron (white on green/none)
hl = function(self)
if is_last(self.bufnr) then
return { fg = "white", bg = "none" }
else
return { fg = "white", bg = "green" }
end
end,
},
},
{
condition = function(self)
return not self.is_active
end,
hl = { bg = "green" },
{ TablinePicker, TablineFileNameBlock, TablineCloseButton },
{
init = function(self)
self.provider = "" -- reset the provider to an empty string
if is_last(self.bufnr) then
self.provider = " " -- full right chevron (green on none)
self.hl = { fg = "green", bg = "none" }
elseif not is_before_active(self.bufnr) then
self.provider = " " -- thin right chevron (white on green)
self.hl = { fg = "white", bg = "green" }
end
end,
},
},
}
local BufferLine = utils.make_buflist(
TablineBufferBlock,
{ provider = " ", hl = { fg = "gray" } },
{ provider = " ", hl = { fg = "gray" } },
nil,
bufcache
)
The difficulty here lies in the fact that both separators and their highlights depend on the current buffer and their relative/absolute position in the buflist. This is much easier to do in the statusline/winbar where fields are usually static
HTH
Thank you for the excellent answer. One minor tweak I made was to add a condition so that it only adds a chevron before the current buffer if that buffer is not the first one in the list.
Another question I have, is it possible to support this but for tabpages also like in Lightline? In Lightline there is a configuration that shows the filename of the current buffer of the current window per tabpage.
I tried this so far:
local TabpageFileFlags = {
{
condition = function(self)
return vim.api.nvim_buf_get_option(self.bufnr, "modified")
end,
provider = "+ ",
},
{
condition = function(self)
return not vim.api.nvim_buf_get_option(self.bufnr, "modifiable")
or vim.api.nvim_buf_get_option(self.bufnr, "readonly")
end,
provider = function(self)
if vim.api.nvim_buf_get_option(self.bufnr, "buftype") == "terminal" then
return " "
else
return ""
end
end,
hl = { fg = "orange" },
},
}
local TabpageName = {
provider = function(self)
return vim.fn.fnamemodify(vim.api.nvim_buf_get_name(self.bufnr), ":t")
end
}
local function is_last_tab(tabnr)
local tabpages = vim.api.nvim_list_tabpages()
return tabpages[#tabpages] == tabnr
end
local function is_before_active_tab(tabnr)
local tabpages = vim.api.nvim_list_tabpages()
for i, t in ipairs(tabpages) do
if t == tabnr then
return vim.api.nvim_get_current_buf() == tabpages[i + 1]
end
end
end
local Tabpage = {
init = function(self)
local winnr = vim.api.nvim_tabpage_get_win(self.tabnr)
self.bufnr = vim.api.nvim_win_get_buf(winnr)
end,
{
condition = function(self)
return self.is_active
end,
hl = { bg = "white" },
{
provider = " ", -- right full chevron (green on white)
hl = { fg = "green", bg = "white" },
},
{ TabpageName, TabpageFileFlags },
{
provider = " ", -- right full chevron (white on green/none)
hl = function(self)
if is_last_tab(self.tabnr) then
return { fg = "white", bg = "none" }
else
return { fg = "white", bg = "green" }
end
end,
},
},
{
condition = function(self)
return not self.is_active
end,
hl = { bg = "green" },
{ TabpageName, TabpageFileFlags },
{
init = function(self)
self.provider = "" -- reset the provider to an empty string
if is_last_tab(self.bufnr) then
self.provider = " " -- full right chevron (green on none)
self.hl = { fg = "green", bg = "none" }
elseif not is_before_active_tab(self.bufnr) then
self.provider = " " -- thin right chevron (white on green)
self.hl = { fg = "white", bg = "green" }
end
end,
},
},
}
local Tabline = require("heirline.utils").make_tablist(Tabpage)
A problem I run into is that once I start closing tabs the self.tabnr
becomes invalid. Once that happens any calls to calculate the winnr and bufnr throws an exception. Do you have any ideas or recommendations?
you should use but_func
argument to make_buflist
for this. You can pass a function that returns bufnrs of the current tab. Be aware that there is a difference between tab number and tab id (as for winnr and winid).