diff --git a/.luarc.json b/.luarc.json index 0c49a3b..b438cce 100644 --- a/.luarc.json +++ b/.luarc.json @@ -2,12 +2,6 @@ "runtime.version": "Lua 5.1", "runtime.path": ["lua/?.lua", "lua/?/init.lua"], "diagnostics.globals": ["vim", "jit"], - "diagnostics.disable": [ - "undefined-doc-name", - "undefined-doc-class", - "undefined-field", - "need-check-nil" - ], "workspace.library": ["$VIMRUNTIME/lua", "${3rd}/luv/library"], "workspace.checkThirdParty": false, "completion.callSnippet": "Replace" diff --git a/lua/blink-cmp-tmux.lua b/lua/blink-cmp-tmux.lua index 1653c06..5faf8f7 100644 --- a/lua/blink-cmp-tmux.lua +++ b/lua/blink-cmp-tmux.lua @@ -3,9 +3,6 @@ local M = {} ---@type blink.cmp.CompletionItem[]? local cache = nil -local loading = false ----@type {ctx: blink.cmp.Context, callback: fun(response: blink.cmp.CompletionResponse)}[] -local pending = {} function M.new() return setmetatable({}, { __index = M }) @@ -16,17 +13,18 @@ function M.enabled() return vim.bo.filetype == 'tmux' end ----@param man_stdout string ----@param names_stdout string ---@return table -local function parse_descriptions(man_stdout, names_stdout) +local function parse_descriptions() + local result = vim.system({ 'bash', '-c', 'MANWIDTH=80 man -P cat tmux 2>/dev/null' }):wait() + local stdout = result.stdout or '' local lines = {} - for line in (man_stdout .. '\n'):gmatch('(.-)\n') do + for line in (stdout .. '\n'):gmatch('(.-)\n') do lines[#lines + 1] = line end + local cmd_result = vim.system({ 'tmux', 'list-commands', '-F', '#{command_list_name}' }):wait() local cmds = {} - for name in names_stdout:gmatch('[^\n]+') do + for name in (cmd_result.stdout or ''):gmatch('[^\n]+') do cmds[name] = true end @@ -47,7 +45,7 @@ local function parse_descriptions(man_stdout, names_stdout) local j = def.line + 1 while j <= block_end do local l = lines[j] - if l:match('^%s+%(alias:') or vim.trim(l) == '' then + if l:match('^%s+%(alias:') then j = j + 1 elseif l:match('^ ') then local stripped = vim.trim(l) @@ -56,6 +54,8 @@ local function parse_descriptions(man_stdout, names_stdout) else break end + elseif vim.trim(l) == '' then + j = j + 1 else break end @@ -84,7 +84,7 @@ local function parse_descriptions(man_stdout, names_stdout) end end local desc = table.concat(parts, '\n\n') - desc = desc:gsub(string.char(0xe2, 0x80, 0x90) .. ' ', '') + desc = desc:gsub('\xe2\x80\x90 ', '') desc = desc:gsub(' +', ' ') if desc ~= '' then descs[def.cmd] = desc @@ -128,66 +128,27 @@ end ---@param ctx blink.cmp.Context ---@param callback fun(response: blink.cmp.CompletionResponse) -local function respond(ctx, callback) +---@return fun() +function M:get_completions(ctx, callback) + if not cache then + local ok, descs = pcall(parse_descriptions) + if not ok then + descs = {} + end + local result = vim.system({ 'tmux', 'list-commands' }):wait() + cache = parse(result.stdout or '', descs) + end + local before = ctx.line:sub(1, ctx.cursor[2]) if before:match('^%s*[a-z-]*$') then callback({ is_incomplete_forward = false, is_incomplete_backward = false, - items = cache, + items = vim.deepcopy(cache), }) else callback({ items = {} }) end -end - ----@param ctx blink.cmp.Context ----@param callback fun(response: blink.cmp.CompletionResponse) ----@return fun() -function M:get_completions(ctx, callback) - if cache then - respond(ctx, callback) - return function() end - end - - pending[#pending + 1] = { ctx = ctx, callback = callback } - if not loading then - loading = true - local man_out, names_out, cmds_out - local remaining = 3 - - local function on_all_done() - remaining = remaining - 1 - if remaining > 0 then - return - end - vim.schedule(function() - local ok, descs = pcall(parse_descriptions, man_out, names_out) - if not ok then - descs = {} - end - cache = parse(cmds_out, descs) - loading = false - for _, p in ipairs(pending) do - respond(p.ctx, p.callback) - end - pending = {} - end) - end - - vim.system({ 'bash', '-c', 'MANWIDTH=80 man -P cat tmux 2>/dev/null' }, {}, function(result) - man_out = result.stdout or '' - on_all_done() - end) - vim.system({ 'tmux', 'list-commands', '-F', '#{command_list_name}' }, {}, function(result) - names_out = result.stdout or '' - on_all_done() - end) - vim.system({ 'tmux', 'list-commands' }, {}, function(result) - cmds_out = result.stdout or '' - on_all_done() - end) - end return function() end end diff --git a/spec/tmux_spec.lua b/spec/tmux_spec.lua index da0c32e..3f47a97 100644 --- a/spec/tmux_spec.lua +++ b/spec/tmux_spec.lua @@ -26,38 +26,37 @@ local MAN_PAGE = table.concat({ }, '\n') local function mock_system() - local original_system = vim.system - local original_schedule = vim.schedule + local original = vim.system ---@diagnostic disable-next-line: duplicate-set-field - vim.system = function(cmd, _, on_exit) - local result + vim.system = function(cmd) if cmd[1] == 'bash' then - result = { stdout = MAN_PAGE, code = 0 } + return { + wait = function() + return { stdout = MAN_PAGE, code = 0 } + end, + } elseif cmd[1] == 'tmux' and cmd[2] == 'list-commands' then if cmd[3] == '-F' then - result = { stdout = TMUX_NAMES, code = 0 } - else - result = { stdout = TMUX_COMMANDS, code = 0 } + return { + wait = function() + return { stdout = TMUX_NAMES, code = 0 } + end, + } end - else - result = { stdout = '', code = 1 } - end - if on_exit then - on_exit(result) - return {} + return { + wait = function() + return { stdout = TMUX_COMMANDS, code = 0 } + end, + } end return { wait = function() - return result + return { stdout = '', code = 1 } end, } end - vim.schedule = function(fn) - fn() - end return function() - vim.system = original_system - vim.schedule = original_schedule + vim.system = original end end