1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-01-24 06:20:05 +08:00
SpaceVim/lua/spacevim/plugin/tabline.lua

612 lines
16 KiB
Lua
Raw Normal View History

2022-09-25 19:12:46 +08:00
--=============================================================================
-- tabline.lua --- tabline plugin implemented in lua
2023-03-26 13:50:22 +08:00
-- Copyright (c) 2016-2023 Wang Shidong & Contributors
2022-09-25 19:12:46 +08:00
-- Author: Wang Shidong < wsdjeg@outlook.com >
-- URL: https://spacevim.org
-- License: GPLv3
--=============================================================================
local M = {}
2024-04-21 22:57:47 +08:00
-- https://github.com/ryanoasis/powerline-extra-symbols
local separators = {
arrow = { '', '' },
curve = { '', '' },
slant = { '', '' },
brace = { '', '' },
fire = { '', '' },
['nil'] = { '', '' },
}
local i_separators = {
arrow = { '', '' },
curve = { '', '' },
slant = { '', '' },
bar = { '|', '|' },
['nil'] = { '', '' },
}
2022-09-25 19:12:46 +08:00
2024-04-21 22:57:47 +08:00
local isep
local right_sep
local left_sep
2022-09-25 19:12:46 +08:00
2024-04-21 22:57:47 +08:00
local highlight = require('spacevim.api.vim.highlight')
local file = require('spacevim.api.file')
local messletters = require('spacevim.api.messletters')
local WIN = require('spacevim.api.vim.window')
2024-04-21 22:57:47 +08:00
local shown_items = {}
local right_hide_bufs = {}
local visiable_bufs = {}
local left_hide_bufs = {}
local function check_len(bufs)
local len = 0
for _, v in ipairs(bufs) do
local name = vim.fn.bufname(v)
name = vim.fn.fnamemodify(name, ':t')
len = len + #name + 6
if len > vim.o.columns - 25 then
return true
2022-09-25 19:12:46 +08:00
end
2024-04-21 22:57:47 +08:00
end
return false
end
local function reverse_table(t)
local tmp = {}
for i = 1, #t do
local key = #t + 1 - i
tmp[i] = t[key]
end
return tmp
2022-09-25 19:12:46 +08:00
end
2024-04-21 22:57:47 +08:00
local function build_item(bufnr, n)
local name = vim.fn.bufname(bufnr)
local icon = ''
local tablineat = '%' .. n .. '@v:lua.___spacevim_tabline.jump@'
2024-04-21 22:57:47 +08:00
if name == '' then
name = 'No Name'
else
name = vim.fn.fnamemodify(name, ':t')
icon = file.fticon(name)
end
local item_hilight
if vim.api.nvim_buf_get_option(bufnr, 'modified') then
item_hilight = '%#SpaceVim_tabline_m# '
elseif bufnr == vim.api.nvim_get_current_buf() then
item_hilight = '%#SpaceVim_tabline_a# '
else
item_hilight = '%#SpaceVim_tabline_b# '
end
return {
str = item_hilight
.. tablineat
.. messletters.bubble_num(n, 1)
.. ' '
.. name
.. ' '
.. icon
.. ' ',
bufnr = bufnr,
len = #name + 4,
pin = false,
}
end
local function build_tab_item(tabid)
local bufnr = vim.api.nvim_win_get_buf(vim.api.nvim_tabpage_get_win(tabid))
local name = vim.fn.bufname(bufnr)
local icon = ''
local nr = vim.api.nvim_tabpage_get_number(tabid)
local tablineat = '%' .. nr .. '@SpaceVim#layers#core#tabline#jump@'
if name == '' then
name = 'No Name'
else
name = vim.fn.fnamemodify(name, ':t')
icon = file.fticon(name)
end
2022-09-25 19:12:46 +08:00
2024-04-21 22:57:47 +08:00
local item_hilight
2022-09-25 19:12:46 +08:00
2024-04-21 22:57:47 +08:00
if vim.api.nvim_buf_get_option(bufnr, 'modified') then
item_hilight = '%#SpaceVim_tabline_m# '
elseif bufnr == vim.api.nvim_get_current_buf() then
item_hilight = '%#SpaceVim_tabline_a# '
else
item_hilight = '%#SpaceVim_tabline_b# '
end
return {
str = item_hilight
.. tablineat
.. messletters.bubble_num(nr, 1)
.. ' '
.. name
.. ' '
.. icon
.. ' ',
bufnr = bufnr,
len = #name + 4,
pin = false,
}
end
local function tabline_sep(a, b)
local hi_a
local hi_b
if not a then
hi_a = 'SpaceVim_tabline_b'
elseif vim.api.nvim_buf_get_option(a.bufnr, 'modified') then
2024-04-21 22:57:47 +08:00
hi_a = 'SpaceVim_tabline_m'
elseif a.bufnr == vim.api.nvim_get_current_buf() then
hi_a = 'SpaceVim_tabline_a'
else
hi_a = 'SpaceVim_tabline_b'
end
if not b then
hi_b = 'SpaceVim_tabline_b'
elseif vim.api.nvim_buf_get_option(b.bufnr, 'modified') then
hi_b = 'SpaceVim_tabline_m'
elseif b.bufnr == vim.api.nvim_get_current_buf() then
hi_b = 'SpaceVim_tabline_a'
else
hi_b = 'SpaceVim_tabline_b'
end
if hi_a == hi_b then
return isep
end
return '%#' .. hi_a .. '_' .. hi_b .. '#' .. right_sep
end
local function index(list, item)
local n = 0
for _, v in ipairs(list) do
if v == item then
return n
end
n = n + 1
end
return -1
end
local function get_show_items()
if vim.fn.tabpagenr('$') > 1 then
shown_items = {}
for _, i in ipairs(vim.api.nvim_list_tabpages()) do
table.insert(shown_items, build_tab_item(i))
end
return shown_items
else
shown_items = {}
left_hide_bufs = vim.tbl_filter(function(val)
return vim.api.nvim_buf_is_valid(val) and vim.api.nvim_buf_get_option(val, 'buflisted')
end, left_hide_bufs)
right_hide_bufs = vim.tbl_filter(function(val)
return vim.api.nvim_buf_is_valid(val) and vim.api.nvim_buf_get_option(val, 'buflisted')
end, right_hide_bufs)
local origin_ct = #visiable_bufs
visiable_bufs = vim.tbl_filter(function(val)
return vim.api.nvim_buf_is_valid(val) and vim.api.nvim_buf_get_option(val, 'buflisted')
end, visiable_bufs)
if #visiable_bufs ~= origin_ct then
local matchlen = false
if #right_hide_bufs > 0 and not matchlen then
while not matchlen and #right_hide_bufs > 0 do
table.insert(visiable_bufs, table.remove(right_hide_bufs))
if check_len(visiable_bufs) then
matchlen = true
table.insert(right_hide_bufs, 1, table.remove(visiable_bufs, #visiable_bufs))
end
end
end
if #left_hide_bufs > 0 and not matchlen then
while not matchlen and #left_hide_bufs > 0 do
table.insert(visiable_bufs, 1, table.remove(left_hide_bufs, #left_hide_bufs))
if check_len(visiable_bufs) then
matchlen = true
table.insert(left_hide_bufs, table.remove(visiable_bufs, 1))
end
end
end
end
local n = 1
for _, bufnr in ipairs(visiable_bufs) do
table.insert(shown_items, build_item(bufnr, n))
n = n + 1
end
return shown_items
end
end
function M.add(bufnr) end
function M.move_to_previous()
local ntp = vim.fn.tabpagenr('$')
if ntp > 1 then
local ctpn = vim.fn.tabpagenr()
local idx = ctpn - 2
if idx == -1 then
idx = ntp
end
vim.cmd('tabmove ' .. idx)
else
local bufnr = vim.api.nvim_get_current_buf()
2024-04-21 22:57:47 +08:00
local idx = index(visiable_bufs, bufnr)
2024-04-21 22:57:47 +08:00
if idx > 0 then -- second item or others
visiable_bufs[idx + 1] = visiable_bufs[idx]
visiable_bufs[idx] = bufnr
elseif idx == 0 and #left_hide_bufs > 0 then
table.insert(visiable_bufs, 2, table.remove(left_hide_bufs, #left_hide_bufs))
while check_len(visiable_bufs) and #visiable_bufs > 1 do
table.insert(right_hide_bufs, 1, table.remove(visiable_bufs, #visiable_bufs))
end
2024-04-21 22:57:47 +08:00
end
end
vim.cmd('redrawtabline')
end
function M.move_to_next()
local ntp = vim.fn.tabpagenr('$')
if ntp > 1 then
local ctpn = vim.fn.tabpagenr()
local idx = ctpn + 1
if idx > ntp then
idx = 0
end
vim.cmd('tabmove ' .. idx)
else
local bufnr = vim.api.nvim_get_current_buf()
2024-04-21 22:57:47 +08:00
local idx = index(visiable_bufs, bufnr)
2024-04-21 22:57:47 +08:00
if idx > -1 and idx < #visiable_bufs - 1 then -- second item or others
visiable_bufs[idx + 1] = visiable_bufs[idx + 2]
visiable_bufs[idx + 2] = bufnr
elseif idx == #visiable_bufs - 1 and #right_hide_bufs > 0 then
table.insert(visiable_bufs, #visiable_bufs - 1, table.remove(right_hide_bufs, 1))
while check_len(visiable_bufs) and #visiable_bufs > 1 do
table.insert(left_hide_bufs, table.remove(visiable_bufs, 1))
end
2024-04-21 22:57:47 +08:00
end
end
vim.cmd('redrawtabline')
end
function M.close_current_buffer()
local bufnr = vim.api.nvim_get_current_buf()
local idx = index(visiable_bufs, bufnr)
local f = ''
if vim.api.nvim_buf_get_option(bufnr, 'modified') then
end
if idx > 0 then
vim.cmd('b' .. visiable_bufs[idx])
vim.cmd('bd ' .. bufnr)
end
end
function M.enable()
local seps = separators[vim.g.spacevim_statusline_separator] or separators.arrow
local iseps = i_separators[vim.g.spacevim_statusline_iseparator] or i_separators.arrow
isep = iseps[1]
right_sep = seps[1]
left_sep = seps[2]
2024-07-05 23:11:59 +08:00
for bufnr = 1, vim.fn.bufnr('$') do
if
vim.api.nvim_buf_is_valid(bufnr) and vim.api.nvim_buf_get_option(bufnr, 'buflisted')
then
table.insert(visiable_bufs, bufnr)
end
end
2024-04-21 22:57:47 +08:00
local tabline_augroup = vim.api.nvim_create_augroup('spacevim_tabline', { clear = true })
vim.api.nvim_create_autocmd({ 'BufNewFile', 'BufReadPost', 'BufAdd' }, {
2024-04-21 22:57:47 +08:00
callback = vim.schedule_wrap(function(event)
if
vim.api.nvim_buf_is_valid(event.buf)
and index(right_hide_bufs, event.buf) == -1
and index(visiable_bufs, event.buf) == -1
and index(left_hide_bufs, event.buf) == -1
then
table.insert(right_hide_bufs, event.buf)
end
end),
group = tabline_augroup,
})
vim.api.nvim_create_autocmd({
'BufEnter',
}, {
callback = vim.schedule_wrap(function(event)
if
vim.api.nvim_buf_is_valid(event.buf) and vim.api.nvim_buf_get_option(event.buf, 'buflisted')
then
if index(visiable_bufs, event.buf) == -1 then
if index(left_hide_bufs, event.buf) > -1 then
local all_bufs = {}
for _, v in ipairs(left_hide_bufs) do
table.insert(all_bufs, v)
end
for _, v in ipairs(visiable_bufs) do
table.insert(all_bufs, v)
end
for _, v in ipairs(right_hide_bufs) do
table.insert(all_bufs, v)
end
left_hide_bufs = {}
visiable_bufs = {}
right_hide_bufs = {}
local find_current_buf = false
local matchlen = false
for _, v in ipairs(all_bufs) do
if v == event.buf then
find_current_buf = true
end
if not find_current_buf then
table.insert(left_hide_bufs, v)
elseif find_current_buf and not matchlen then
table.insert(visiable_bufs, v)
if check_len(visiable_bufs) then
matchlen = true
if #visiable_bufs > 1 then
table.insert(right_hide_bufs, table.remove(visiable_bufs, #visiable_bufs))
end
end
else
table.insert(right_hide_bufs, v)
end
end
elseif index(right_hide_bufs, event.buf) > -1 then
local all_bufs = {}
for _, v in ipairs(left_hide_bufs) do
table.insert(all_bufs, v)
2022-09-25 19:12:46 +08:00
end
2024-04-21 22:57:47 +08:00
for _, v in ipairs(visiable_bufs) do
table.insert(all_bufs, v)
2022-09-25 19:12:46 +08:00
end
2024-04-21 22:57:47 +08:00
for _, v in ipairs(right_hide_bufs) do
table.insert(all_bufs, v)
end
left_hide_bufs = {}
visiable_bufs = {}
right_hide_bufs = {}
local find_current_buf = false
local matchlen = false
all_bufs = reverse_table(all_bufs)
for _, v in ipairs(all_bufs) do
if v == event.buf then
find_current_buf = true
end
if not find_current_buf then
table.insert(right_hide_bufs, 1, v)
elseif find_current_buf and not matchlen then
table.insert(visiable_bufs, 1, v)
if check_len(visiable_bufs) then
matchlen = true
if #visiable_bufs > 1 then
table.insert(left_hide_bufs, table.remove(visiable_bufs, 1))
end
end
else
table.insert(left_hide_bufs, 1, v)
end
2022-09-25 19:12:46 +08:00
end
2024-04-21 22:57:47 +08:00
end
2022-09-25 19:12:46 +08:00
end
2024-04-21 22:57:47 +08:00
end
end),
group = tabline_augroup,
})
vim.api.nvim_create_autocmd({
'BufWinEnter',
'BufWinLeave',
'BufWritePost',
'TabEnter',
'VimResized',
'WinEnter',
'WinLeave',
}, {
callback = vim.schedule_wrap(function(event)
if vim.api.nvim_buf_is_valid(event.buf) then
vim.cmd('redrawtabline')
end
end),
group = tabline_augroup,
})
end
function M.get()
local tablinestr = ''
shown_items = get_show_items()
local preview_item
if #left_hide_bufs > 0 and vim.fn.tabpagenr('$') == 1 then
tablinestr = '%#SpaceVim_tabline_b# << '
.. #left_hide_bufs
.. ' '
.. tabline_sep(preview_item, shown_items[1])
2024-04-21 22:57:47 +08:00
end
for _, item in ipairs(shown_items) do
if preview_item then
-- 如果存在上一个buf则增加分隔符
tablinestr = tablinestr .. tabline_sep(preview_item, item)
end
tablinestr = tablinestr .. item.str
preview_item = item
end
if preview_item then
-- 如果存在上一个buf则增加分隔符
tablinestr = tablinestr .. tabline_sep(preview_item, nil)
if #right_hide_bufs > 0 and vim.fn.tabpagenr('$') == 1 then
tablinestr = tablinestr .. '%#SpaceVim_tabline_b# ' .. #right_hide_bufs .. ' >> '
end
tablinestr = tablinestr
.. '%#SpaceVim_tabline_b#%=%#SpaceVim_tabline_a_SpaceVim_tabline_b# '
.. left_sep
if vim.fn.tabpagenr('$') > 1 then
tablinestr = tablinestr .. '%#SpaceVim_tabline_a# Tabs '
else
tablinestr = tablinestr .. '%#SpaceVim_tabline_a# Buffers '
end
end
return tablinestr
end
function M.def_colors()
local name = vim.g.colors_name or 'gruvbox'
local t
if #vim.g.spacevim_custom_color_palette > 0 then
t = vim.g.spacevim_custom_color_palette
else
local ok = pcall(function()
t = vim.fn['SpaceVim#mapping#guide#theme#' .. name .. '#palette']()
end)
if not ok then
t = vim.fn['SpaceVim#mapping#guide#theme#gruvbox#palette']()
2022-09-25 19:12:46 +08:00
end
2024-04-21 22:57:47 +08:00
end
vim.api.nvim_set_hl(0, 'SpaceVim_tabline_a', {
fg = t[1][1],
bg = t[1][2],
ctermfg = t[1][4],
ctermbg = t[1][3],
})
vim.api.nvim_set_hl(0, 'SpaceVim_tabline_b', {
fg = t[2][1],
bg = t[2][2],
ctermfg = t[2][4],
ctermbg = t[2][3],
})
vim.api.nvim_set_hl(0, 'SpaceVim_tabline_m', {
fg = t[5][1],
bg = t[5][2],
ctermfg = t[5][3],
ctermbg = t[5][4],
})
vim.api.nvim_set_hl(0, 'SpaceVim_tabline_m_i', {
fg = t[5][2],
bg = t[2][2],
ctermfg = t[5][4],
ctermbg = t[2][3],
})
highlight.hi_separator('SpaceVim_tabline_a', 'SpaceVim_tabline_b')
highlight.hi_separator('SpaceVim_tabline_m', 'SpaceVim_tabline_b')
highlight.hi_separator('SpaceVim_tabline_m', 'SpaceVim_tabline_a')
2022-09-25 19:12:46 +08:00
end
local function is_best_win(winid)
local bufnr = vim.api.nvim_win_get_buf(winid)
local ft = vim.bo[bufnr].filetype
if ft == 'defx' or ft == 'nerdtree' or ft == 'tagbar' then
return false
end
return true
end
local function open_in_best_win(bufnr)
if is_best_win(vim.api.nvim_get_current_win()) then
vim.api.nvim_set_current_buf(bufnr)
return
end
for winnr = 1, vim.fn.winnr('$') do
local winid = vim.fn.win_getid(winnr)
if is_best_win(winid) and not WIN.is_float(winid) then
vim.api.nvim_set_current_win(winid)
vim.api.nvim_set_current_buf(bufnr)
end
end
end
2024-04-21 22:57:47 +08:00
function M.jump(id)
if id == 'next' then
if vim.fn.tabpagenr('$') > 1 then
vim.cmd('tabnext')
else
local bufnr = vim.api.nvim_get_current_buf()
local idx = index(visiable_bufs, bufnr)
if idx > -1 and idx < #visiable_bufs - 1 then
vim.cmd('b' .. visiable_bufs[idx + 2])
elseif idx > -1 and idx == #visiable_bufs - 1 then
if #right_hide_bufs > 0 then
vim.cmd('b' .. right_hide_bufs[1])
elseif #left_hide_bufs > 0 then
vim.cmd('b' .. left_hide_bufs[1])
else
vim.cmd('b' .. visiable_bufs[1])
end
2024-04-21 22:57:47 +08:00
end
end
elseif id == 'prev' then
if vim.fn.tabpagenr('$') > 1 then
vim.cmd('tabprevious')
else
local bufnr = vim.api.nvim_get_current_buf()
local idx = index(visiable_bufs, bufnr)
if idx > 0 then
vim.cmd('b' .. visiable_bufs[idx])
elseif idx == 0 and idx < #visiable_bufs - 1 then
if #left_hide_bufs > 0 then
vim.cmd('b' .. left_hide_bufs[#left_hide_bufs])
elseif #right_hide_bufs > 0 then
vim.cmd('b' .. right_hide_bufs[#right_hide_bufs])
else
vim.cmd('b' .. visiable_bufs[#visiable_bufs])
end
2024-04-21 22:57:47 +08:00
end
end
elseif #shown_items >= id then
if vim.fn.tabpagenr('$') > 1 then
vim.cmd('tabnext' .. id)
else
open_in_best_win(shown_items[id].bufnr)
2024-04-21 22:57:47 +08:00
end
end
end
2022-09-25 19:12:46 +08:00
_G.___spacevim_tabline = { jump = M.jump }
2022-09-25 19:12:46 +08:00
return M