1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-01-24 03:00:06 +08:00
SpaceVim/lua/spacevim/plugin/tabline.lua
2024-07-07 14:42:40 +08:00

612 lines
16 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

--=============================================================================
-- tabline.lua --- tabline plugin implemented in lua
-- Copyright (c) 2016-2023 Wang Shidong & Contributors
-- Author: Wang Shidong < wsdjeg@outlook.com >
-- URL: https://spacevim.org
-- License: GPLv3
--=============================================================================
local M = {}
-- https://github.com/ryanoasis/powerline-extra-symbols
local separators = {
arrow = { '', '' },
curve = { '', '' },
slant = { '', '' },
brace = { '', '' },
fire = { '', '' },
['nil'] = { '', '' },
}
local i_separators = {
arrow = { '', '' },
curve = { '', '' },
slant = { '', '' },
bar = { '|', '|' },
['nil'] = { '', '' },
}
local isep
local right_sep
local left_sep
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')
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
end
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
end
local function build_item(bufnr, n)
local name = vim.fn.bufname(bufnr)
local icon = ''
local tablineat = '%' .. n .. '@v:lua.___spacevim_tabline.jump@'
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
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(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
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()
local idx = index(visiable_bufs, bufnr)
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
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()
local idx = index(visiable_bufs, bufnr)
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
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]
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
local tabline_augroup = vim.api.nvim_create_augroup('spacevim_tabline', { clear = true })
vim.api.nvim_create_autocmd({ 'BufNewFile', 'BufReadPost', 'BufAdd' }, {
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)
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
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
end
end
end
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])
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']()
end
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')
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
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
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
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)
end
end
end
_G.___spacevim_tabline = { jump = M.jump }
return M