1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-02-02 23:00:04 +08:00

perf(guide): improve key binding guide

This commit is contained in:
Eric Wong 2024-06-01 22:51:47 +08:00
parent d6a34e3aff
commit 24712351a1
2 changed files with 161 additions and 112 deletions

View File

@ -7,125 +7,144 @@
--============================================================================= --=============================================================================
local M = {} local M = {}
local system = require('spacevim.api').import('system')
function M.eval(l) function M.eval(l)
if vim.api ~= nil then if vim.api ~= nil then
return vim.api.nvim_eval(l) return vim.api.nvim_eval(l)
else
return vim.eval(l)
end
end
function M.islist(val)
if vim.islist then
return vim.islist(val)
---@diagnostic disable-next-line
elseif vim.tbl_islist then
---@diagnostic disable-next-line
return vim.tbl_islist(val)
else
if type(val) ~= 'table' then
return false
else else
return vim.eval(l) for k, _ in pairs(val) do
if type(k) ~= 'number' then
return false
end
end
return true
end end
end
end end
if vim.command ~= nil then if vim.command ~= nil then
function M.cmd(command) function M.cmd(command)
return vim.command(command) return vim.command(command)
end end
else else
function M.cmd(command) function M.cmd(command)
return vim.api.nvim_command(command) return vim.api.nvim_command(command)
end end
end end
-- there is no want to call viml function in old vim and neovim -- there is no want to call viml function in old vim and neovim
local function build_argv(...) local function build_argv(...)
local str = '' local str = ''
for index, value in ipairs(...) do for _, value in ipairs(...) do
if str ~= '' then if str ~= '' then
str = str .. ',' str = str .. ','
end
if type(value) == 'string' then
str = str .. '"' .. value .. '"'
elseif type(value) == 'number' then
str = str .. value
end
end end
return str if type(value) == 'string' then
str = str .. '"' .. value .. '"'
elseif type(value) == 'number' then
str = str .. value
end
end
return str
end end
function M.call(funcname, ...) function M.call(funcname, ...)
if vim.call ~= nil then if vim.call ~= nil then
return vim.call(funcname, ...) return vim.call(funcname, ...)
else
if vim.api ~= nil then
return vim.api.nvim_call_function(funcname, { ... })
else else
if vim.api ~= nil then -- call not call vim script function in lua
return vim.api.nvim_call_function(funcname, {...}) vim.command('let g:lua_rst = ' .. funcname .. '(' .. build_argv({ ... }) .. ')')
else return M.eval('g:lua_rst')
-- call not call vim script function in lua
vim.command('let g:lua_rst = ' .. funcname .. '(' .. build_argv({...}) .. ')')
return M.eval('g:lua_rst')
end
end end
end
end end
-- this is for Vim and old neovim -- this is for Vim and old neovim
M.fn = setmetatable({}, { M.fn = setmetatable({}, {
__index = function(t, key) __index = function(t, key)
local _fn local _fn
if vim.api ~= nil and vim.api[key] ~= nil then if vim.api ~= nil and vim.api[key] ~= nil then
_fn = function() _fn = function()
error(string.format("Tried to call API function with vim.fn: use vim.api.%s instead", key)) error(string.format('Tried to call API function with vim.fn: use vim.api.%s instead', key))
end end
else else
_fn = function(...) _fn = function(...)
return M.call(key, ...) return M.call(key, ...)
end end
end
t[key] = _fn
return _fn
end end
t[key] = _fn
return _fn
end,
}) })
-- This is for vim and old neovim to use vim.o -- This is for vim and old neovim to use vim.o
M.vim_options = setmetatable({}, { M.vim_options = setmetatable({}, {
__index = function(t, key) __index = function(t, key)
local _fn local _fn
if vim.api ~= nil then if vim.api ~= nil then
-- for neovim -- for neovim
return vim.api.nvim_get_option(key) return vim.api.nvim_get_option(key)
else else
-- for vim -- for vim
_fn = M.eval('&' .. key) _fn = M.eval('&' .. key)
end
t[key] = _fn
return _fn
end end
t[key] = _fn
return _fn
end,
}) })
function M.echo(msg) function M.echo(msg)
if vim.api ~= nil then if vim.api ~= nil then
vim.api.nvim_echo({{msg}}, false, {}) vim.api.nvim_echo({ { msg } }, false, {})
else else
vim.command('echo ' .. build_argv({msg})) vim.command('echo ' .. build_argv({ msg }))
end end
end end
local has_cache = {} local has_cache = {}
function M.has(feature) function M.has(feature)
if has_cache[feature] ~= nil then if has_cache[feature] ~= nil then
return has_cache[feature] return has_cache[feature]
else else
return M.eval('float2nr(has("' .. feature .. '"))') return M.eval('float2nr(has("' .. feature .. '"))')
end end
end end
if M.has('patch-7.4.279') then if M.has('patch-7.4.279') then
function M.globpath(dir, expr) function M.globpath(dir, expr)
return M.fn.globpath(dir, expr, 1, 1) return M.fn.globpath(dir, expr, 1, 1)
end end
else else
function M.globpath(dir, expr) function M.globpath(dir, expr)
return M.fn.split(fn.globpath(dir, expr), "\n") return M.fn.split(vim.fn.globpath(dir, expr), '\n')
end end
end end
function M.execute(cmd, silent) function M.execute(cmd, silent)
return M.fn.execute(cmd, silent) return M.fn.execute(cmd, silent)
end end
function M.win_screenpos(nr) function M.win_screenpos(nr)
return vim.fn.win_screenpos(nr) return vim.fn.win_screenpos(nr)
end end
return M return M

View File

@ -15,6 +15,7 @@ local cmp = require('spacevim.api').import('vim.compatible')
local buffer = require('spacevim.api').import('vim.buffer') local buffer = require('spacevim.api').import('vim.buffer')
local VIM = require('spacevim.api').import('vim') local VIM = require('spacevim.api').import('vim')
local SL = require('spacevim.api').import('vim.statusline') local SL = require('spacevim.api').import('vim.statusline')
local hl = require('spacevim.api.vim.highlight')
-- all local values should be listed here: -- all local values should be listed here:
@ -164,27 +165,27 @@ local function add_map_to_dict(map, level, dict)
local nlevel = level + 1 local nlevel = level + 1
if not dict[curkey] then if not dict[curkey] then
dict[curkey] = { name = vim.g.leaderGuide_default_group_name } dict[curkey] = { name = vim.g.leaderGuide_default_group_name }
elseif vim.tbl_islist(dict[curkey]) and vim.g.leaderGuide_flatten == 1 then elseif cmp.islist(dict[curkey]) and vim.g.leaderGuide_flatten == 1 then
local cmd = escape_mappings(map) local cmd = escape_mappings(map)
curkey = table.concat(map.lhs, '', level) curkey = table.concat(map.lhs, '', level)
nlevel = level nlevel = level
if not dict[curkey] then if not dict[curkey] then
dict[curkey] = { cmd, map.display } dict[curkey] = { cmd, map.display }
end end
elseif vim.tbl_islist(dict[curkey]) and vim.g.leaderGuide_flatten == 0 then elseif cmp.islist(dict[curkey]) and vim.g.leaderGuide_flatten == 0 then
curkey = curkey .. 'm' curkey = curkey .. 'm'
if not dict[curkey] then if not dict[curkey] then
dict[curkey] = { name = vim.g.leaderGuide_default_group_name } dict[curkey] = { name = vim.g.leaderGuide_default_group_name }
end end
end end
if not vim.tbl_islist(dict[curkey]) then if not cmp.islist(dict[curkey]) then
add_map_to_dict(map, nlevel, dict[curkey]) add_map_to_dict(map, nlevel, dict[curkey])
end end
else else
local cmd = escape_mappings(map) local cmd = escape_mappings(map)
if not dict[map.lhs[level]] then if not dict[map.lhs[level]] then
dict[map.lhs[level]] = { cmd, map.display } dict[map.lhs[level]] = { cmd, map.display }
elseif not vim.tbl_islist(dict[map.lhs[level]]) and vim.g.leaderGuide_flatten == 1 then elseif not cmp.islist(dict[map.lhs[level]]) and vim.g.leaderGuide_flatten == 1 then
local childmap = flattenmap(dict[map.lhs[level]], map.lhs[level]) local childmap = flattenmap(dict[map.lhs[level]], map.lhs[level])
for it, _ in pairs(childmap) do for it, _ in pairs(childmap) do
dict[it] = childmap[it] dict[it] = childmap[it]
@ -282,22 +283,44 @@ local function start_parser(key, dict)
end end
end end
---@param v string key board string
---@return string # displayed string of each item
local function get_displaystring(v)
local desc = ''
if lmap[v].name then
desc = lmap[v].name
else
desc = lmap[v][2] or ''
end
local offset = string.rep(' ', 8 - #v)
local displaystring
if vim.g.spacevim_leader_guide_theme == 'whichkey' then
displaystring = offset .. v .. ' -> ' .. desc
else
displaystring = offset .. '[' .. v .. '] ' .. desc
end
return displaystring
end
local function calc_layout() local function calc_layout()
local ret = {} local ret = {}
local smap = {}
local smap = vim.fn.filter(vim.fn.copy(lmap), 'v:key !=# "name"') for k, v in pairs(lmap) do
ret.n_items = vim.fn.len(smap) if v ~= 'name' then
local length = {} smap[k] = v
for k, v in pairs(smap) do
if v.name then
table.insert(length, vim.fn.strdisplaywidth('[' .. k .. ']' .. v.name))
else
table.insert(length, vim.fn.strdisplaywidth('[' .. k .. ']' .. v[2]))
end end
end end
local maxlength = vim.fn.max(length) + vim.g.leaderGuide_hspace
ret.n_items = vim.fn.len(smap)
local length = {}
log.debug('smap is:' .. vim.inspect(smap))
for k, _ in pairs(smap) do
table.insert(length, vim.fn.strdisplaywidth(get_displaystring(k)))
end
local maxlength = vim.fn.max(length) + vim.g.leaderGuide_hspace
log.debug('maxlength is:' .. maxlength)
if vim.g.leaderGuide_vertical == 1 then if vim.g.leaderGuide_vertical == 1 then
ret.n_rows = vim.fn.winheight(0) - 2 ret.n_rows = vim.fn.winheight(0) - 2
ret.n_cols = math.floor(ret.n_items / ret.n_rows) ret.n_cols = math.floor(ret.n_items / ret.n_rows)
@ -319,6 +342,7 @@ local function calc_layout()
end end
ret.win_dim = ret.n_rows ret.win_dim = ret.n_rows
end end
log.debug('layout is:' .. vim.inspect(ret))
return ret return ret
end end
@ -396,19 +420,7 @@ local function create_string(layout)
table.sort(smap, compare_key) table.sort(smap, compare_key)
for _, k in ipairs(smap) do for _, k in ipairs(smap) do
local desc = '' local displaystring = get_displaystring(k)
if lmap[k].name then
desc = lmap[k].name
else
desc = lmap[k][2] or ''
end
local offset = string.rep(' ', 8 - #k)
local displaystring
if vim.g.spacevim_leader_guide_theme == 'whichkey' then
displaystring = offset .. k .. ' -> ' .. desc
else
displaystring = offset .. '[' .. k .. '] ' .. desc
end
crow = rows[row] or {} crow = rows[row] or {}
if #crow == 0 then if #crow == 0 then
@ -416,10 +428,10 @@ local function create_string(layout)
end end
-- if the displaystring is too long -- if the displaystring is too long
if #displaystring > l.col_width then if #displaystring > l.col_width then
table.insert(crow, string.sub(displaystring, 1, l.col_width -5) .. '... ') table.insert(crow, string.sub(displaystring, 1, l.col_width - 5) .. '... ')
else else
table.insert(crow, displaystring) table.insert(crow, displaystring)
table.insert(crow, vim.fn['repeat'](' ', l.col_width - vim.fn.strdisplaywidth(displaystring))) table.insert(crow, string.rep(' ', l.col_width - vim.fn.strdisplaywidth(displaystring)))
end end
if vim.g.leaderGuide_sort_horizontal == 0 then if vim.g.leaderGuide_sort_horizontal == 0 then
if row > n_rows then if row > n_rows then
@ -455,8 +467,16 @@ local function create_string(layout)
return r return r
end end
local cursor_highlight_info
local function highlight_cursor() local function highlight_cursor()
vim.cmd('hi! def link SpaceVimGuideCursor Cursor') cursor_highlight_info = hl.group2dict('Cursor')
local hlinfo = {
name = 'SpaceVimGuideCursor',
guibg = cursor_highlight_info.guibg,
ctermbg = cursor_highlight_info.ctermbg,
}
hl.hi(hlinfo)
hl.hide_in_normal('Cursor')
if vis == 'gv' then if vis == 'gv' then
local _begin = vim.fn.getpos("'<") local _begin = vim.fn.getpos("'<")
local _end = vim.fn.getpos("'>") local _end = vim.fn.getpos("'>")
@ -480,6 +500,7 @@ local function highlight_cursor()
end end
local function remove_cursor_highlight() local function remove_cursor_highlight()
hl.hi(cursor_highlight_info)
pcall(vim.fn.matchdelete, cursor_hilight_id) pcall(vim.fn.matchdelete, cursor_hilight_id)
end end
@ -505,14 +526,23 @@ local function updateStatusline()
end end
local keys = prefix_key_inp local keys = prefix_key_inp
local separators = {
arrow = '',
curve = '',
slant = '',
brace = '',
fire = '',
['nil'] = '',
}
local sep = separators[vim.g.spacevim_statusline_separator] or separators.arrow
SL.open_float({ SL.open_float({
{ 'Guide: ', 'LeaderGuiderPrompt' }, { 'Guide: ', 'LeaderGuiderPrompt' },
{ '', 'LeaderGuiderSep1' }, { sep .. ' ', 'LeaderGuiderSep1' },
{ {
vim.fn['SpaceVim#mapping#leader#getName'](prefix_key) .. table.concat(keys, '') .. gname, vim.fn['SpaceVim#mapping#leader#getName'](prefix_key) .. table.concat(keys, '') .. gname,
'LeaderGuiderName', 'LeaderGuiderName',
}, },
{ '', 'LeaderGuiderSep2' }, { sep .. ' ', 'LeaderGuiderSep2' },
{ guide_help_msg(false), 'LeaderGuiderFill' }, { guide_help_msg(false), 'LeaderGuiderFill' },
{ string.rep(' ', 999), 'LeaderGuiderFill' }, { string.rep(' ', 999), 'LeaderGuiderFill' },
}) })
@ -563,11 +593,12 @@ local function winopen()
winfixwidth = true, winfixwidth = true,
winfixheight = true, winfixheight = true,
}) })
updateStatusline()
return winid, bufnr return winid, bufnr
end end
local function start_buffer() local function start_buffer()
winid, bufnr = winopen() if not vim.api.nvim_win_is_valid(winid) or not vim.api.nvim_buf_is_valid(bufnr) then
winid, bufnr = winopen()
end
local layout = calc_layout() local layout = calc_layout()
local text = create_string(layout) local text = create_string(layout)
if vim.g.leaderGuide_max_size then if vim.g.leaderGuide_max_size then
@ -583,12 +614,13 @@ local function start_buffer()
col = 0, col = 0,
}) })
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, text) vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, text)
updateStatusline()
cmp.fn.setbufvar(bufnr, '&modifiable', 0) cmp.fn.setbufvar(bufnr, '&modifiable', 0)
vim.cmd('redraw!') vim.cmd('redraw')
wait_for_input() wait_for_input()
end end
@ -603,11 +635,11 @@ local function winclose()
end end
local function handle_input(input) local function handle_input(input)
winclose() if not cmp.islist(input) then
if not vim.tbl_islist(input) then
lmap = input lmap = input
start_buffer() start_buffer()
else else
winclose()
prefix_key_inp = {} prefix_key_inp = {}
cmp.fn.feedkeys(vis .. reg .. count, 'ti') cmp.fn.feedkeys(vis .. reg .. count, 'ti')
@ -628,7 +660,6 @@ local function page_down()
end end
local function page_undo() local function page_undo()
winclose()
if #prefix_key_inp then if #prefix_key_inp then
table.remove(prefix_key_inp) table.remove(prefix_key_inp)
end end
@ -639,7 +670,6 @@ local function page_undo()
end end
local function page_up() local function page_up()
-- vim.api.nvim_feedkeys(Key.t('<C-c>'), 'n', false) -- vim.api.nvim_feedkeys(Key.t('<C-c>'), 'n', false)
vim.api.nvim_feedkeys(Key.t('<C-u>'), 'x', false) vim.api.nvim_feedkeys(Key.t('<C-u>'), 'x', false)
vim.cmd('redraw!') vim.cmd('redraw!')