Compare commits
2 commits
perf/async
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c0c59d1e57 | ||
|
|
7003996643 |
4 changed files with 123 additions and 41 deletions
|
|
@ -2,6 +2,12 @@
|
||||||
"runtime.version": "Lua 5.1",
|
"runtime.version": "Lua 5.1",
|
||||||
"runtime.path": ["lua/?.lua", "lua/?/init.lua"],
|
"runtime.path": ["lua/?.lua", "lua/?/init.lua"],
|
||||||
"diagnostics.globals": ["vim", "jit"],
|
"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.library": ["$VIMRUNTIME/lua", "${3rd}/luv/library"],
|
||||||
"workspace.checkThirdParty": false,
|
"workspace.checkThirdParty": false,
|
||||||
"completion.callSnippet": "Replace"
|
"completion.callSnippet": "Replace"
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,9 @@ local M = {}
|
||||||
|
|
||||||
---@type blink.cmp.CompletionItem[]?
|
---@type blink.cmp.CompletionItem[]?
|
||||||
local cache = nil
|
local cache = nil
|
||||||
|
local loading = false
|
||||||
|
---@type {ctx: blink.cmp.Context, callback: fun(response: blink.cmp.CompletionResponse)}[]
|
||||||
|
local pending = {}
|
||||||
|
|
||||||
function M.new()
|
function M.new()
|
||||||
return setmetatable({}, { __index = M })
|
return setmetatable({}, { __index = M })
|
||||||
|
|
@ -13,18 +16,17 @@ function M.enabled()
|
||||||
return vim.bo.filetype == 'tmux'
|
return vim.bo.filetype == 'tmux'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param man_stdout string
|
||||||
|
---@param names_stdout string
|
||||||
---@return table<string, string>
|
---@return table<string, string>
|
||||||
local function parse_descriptions()
|
local function parse_descriptions(man_stdout, names_stdout)
|
||||||
local result = vim.system({ 'bash', '-c', 'MANWIDTH=80 man -P cat tmux 2>/dev/null' }):wait()
|
|
||||||
local stdout = result.stdout or ''
|
|
||||||
local lines = {}
|
local lines = {}
|
||||||
for line in (stdout .. '\n'):gmatch('(.-)\n') do
|
for line in (man_stdout .. '\n'):gmatch('(.-)\n') do
|
||||||
lines[#lines + 1] = line
|
lines[#lines + 1] = line
|
||||||
end
|
end
|
||||||
|
|
||||||
local cmd_result = vim.system({ 'tmux', 'list-commands', '-F', '#{command_list_name}' }):wait()
|
|
||||||
local cmds = {}
|
local cmds = {}
|
||||||
for name in (cmd_result.stdout or ''):gmatch('[^\n]+') do
|
for name in names_stdout:gmatch('[^\n]+') do
|
||||||
cmds[name] = true
|
cmds[name] = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -45,7 +47,7 @@ local function parse_descriptions()
|
||||||
local j = def.line + 1
|
local j = def.line + 1
|
||||||
while j <= block_end do
|
while j <= block_end do
|
||||||
local l = lines[j]
|
local l = lines[j]
|
||||||
if l:match('^%s+%(alias:') then
|
if l:match('^%s+%(alias:') or vim.trim(l) == '' then
|
||||||
j = j + 1
|
j = j + 1
|
||||||
elseif l:match('^ ') then
|
elseif l:match('^ ') then
|
||||||
local stripped = vim.trim(l)
|
local stripped = vim.trim(l)
|
||||||
|
|
@ -54,8 +56,6 @@ local function parse_descriptions()
|
||||||
else
|
else
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
elseif vim.trim(l) == '' then
|
|
||||||
j = j + 1
|
|
||||||
else
|
else
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
|
|
@ -84,7 +84,7 @@ local function parse_descriptions()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local desc = table.concat(parts, '\n\n')
|
local desc = table.concat(parts, '\n\n')
|
||||||
desc = desc:gsub('\xe2\x80\x90 ', '')
|
desc = desc:gsub(string.char(0xe2, 0x80, 0x90) .. ' ', '')
|
||||||
desc = desc:gsub(' +', ' ')
|
desc = desc:gsub(' +', ' ')
|
||||||
if desc ~= '' then
|
if desc ~= '' then
|
||||||
descs[def.cmd] = desc
|
descs[def.cmd] = desc
|
||||||
|
|
@ -128,27 +128,66 @@ end
|
||||||
|
|
||||||
---@param ctx blink.cmp.Context
|
---@param ctx blink.cmp.Context
|
||||||
---@param callback fun(response: blink.cmp.CompletionResponse)
|
---@param callback fun(response: blink.cmp.CompletionResponse)
|
||||||
---@return fun()
|
local function respond(ctx, callback)
|
||||||
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])
|
local before = ctx.line:sub(1, ctx.cursor[2])
|
||||||
if before:match('^%s*[a-z-]*$') then
|
if before:match('^%s*[a-z-]*$') then
|
||||||
callback({
|
callback({
|
||||||
is_incomplete_forward = false,
|
is_incomplete_forward = false,
|
||||||
is_incomplete_backward = false,
|
is_incomplete_backward = false,
|
||||||
items = vim.deepcopy(cache),
|
items = cache,
|
||||||
})
|
})
|
||||||
else
|
else
|
||||||
callback({ items = {} })
|
callback({ items = {} })
|
||||||
end
|
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
|
return function() end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
36
lua/blink-cmp-tmux/health.lua
Normal file
36
lua/blink-cmp-tmux/health.lua
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
function M.check()
|
||||||
|
vim.health.start('blink-cmp-tmux')
|
||||||
|
|
||||||
|
local ok = pcall(require, 'blink.cmp')
|
||||||
|
if ok then
|
||||||
|
vim.health.ok('blink.cmp is installed')
|
||||||
|
else
|
||||||
|
vim.health.error('blink.cmp is not installed')
|
||||||
|
end
|
||||||
|
|
||||||
|
local bin = vim.fn.exepath('tmux')
|
||||||
|
if bin ~= '' then
|
||||||
|
vim.health.ok('tmux executable found: ' .. bin)
|
||||||
|
else
|
||||||
|
vim.health.error('tmux executable not found')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local result = vim.system({ 'tmux', 'list-commands' }):wait()
|
||||||
|
if result.code == 0 and result.stdout and result.stdout ~= '' then
|
||||||
|
vim.health.ok('tmux list-commands produces output')
|
||||||
|
else
|
||||||
|
vim.health.warn('tmux list-commands failed (completions will be unavailable)')
|
||||||
|
end
|
||||||
|
|
||||||
|
local man_bin = vim.fn.exepath('man')
|
||||||
|
if man_bin ~= '' then
|
||||||
|
vim.health.ok('man executable found: ' .. man_bin)
|
||||||
|
else
|
||||||
|
vim.health.warn('man executable not found (command descriptions will be unavailable)')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
||||||
|
|
@ -26,37 +26,38 @@ local MAN_PAGE = table.concat({
|
||||||
}, '\n')
|
}, '\n')
|
||||||
|
|
||||||
local function mock_system()
|
local function mock_system()
|
||||||
local original = vim.system
|
local original_system = vim.system
|
||||||
|
local original_schedule = vim.schedule
|
||||||
---@diagnostic disable-next-line: duplicate-set-field
|
---@diagnostic disable-next-line: duplicate-set-field
|
||||||
vim.system = function(cmd)
|
vim.system = function(cmd, _, on_exit)
|
||||||
|
local result
|
||||||
if cmd[1] == 'bash' then
|
if cmd[1] == 'bash' then
|
||||||
return {
|
result = { stdout = MAN_PAGE, code = 0 }
|
||||||
wait = function()
|
|
||||||
return { stdout = MAN_PAGE, code = 0 }
|
|
||||||
end,
|
|
||||||
}
|
|
||||||
elseif cmd[1] == 'tmux' and cmd[2] == 'list-commands' then
|
elseif cmd[1] == 'tmux' and cmd[2] == 'list-commands' then
|
||||||
if cmd[3] == '-F' then
|
if cmd[3] == '-F' then
|
||||||
return {
|
result = { stdout = TMUX_NAMES, code = 0 }
|
||||||
wait = function()
|
else
|
||||||
return { stdout = TMUX_NAMES, code = 0 }
|
result = { stdout = TMUX_COMMANDS, code = 0 }
|
||||||
end,
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
return {
|
else
|
||||||
wait = function()
|
result = { stdout = '', code = 1 }
|
||||||
return { stdout = TMUX_COMMANDS, code = 0 }
|
end
|
||||||
end,
|
if on_exit then
|
||||||
}
|
on_exit(result)
|
||||||
|
return {}
|
||||||
end
|
end
|
||||||
return {
|
return {
|
||||||
wait = function()
|
wait = function()
|
||||||
return { stdout = '', code = 1 }
|
return result
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
vim.schedule = function(fn)
|
||||||
|
fn()
|
||||||
|
end
|
||||||
return function()
|
return function()
|
||||||
vim.system = original
|
vim.system = original_system
|
||||||
|
vim.schedule = original_schedule
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue