perf: async cache initialization and remove deepcopy
Problem: first completion request blocked the UI with a synchronous vim.system():wait() call, and every subsequent key completion unnecessarily deep-copied the entire cache. Solution: use vim.system with an async callback to initialize the cache without blocking. Queue pending completion requests during loading and serve them once parsing finishes. Return cached keys directly instead of deep-copying.
This commit is contained in:
parent
dfbae31684
commit
8bb6a81d1f
2 changed files with 55 additions and 25 deletions
|
|
@ -5,6 +5,9 @@ local M = {}
|
||||||
local keys_cache = nil
|
local keys_cache = nil
|
||||||
---@type table<string, string[]>?
|
---@type table<string, string[]>?
|
||||||
local enums_cache = nil
|
local enums_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 })
|
||||||
|
|
@ -15,14 +18,14 @@ function M.enabled()
|
||||||
return vim.bo.filetype == 'ghostty'
|
return vim.bo.filetype == 'ghostty'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param stdout string
|
||||||
---@return blink.cmp.CompletionItem[]
|
---@return blink.cmp.CompletionItem[]
|
||||||
local function parse_keys()
|
local function parse_keys(stdout)
|
||||||
local Kind = require('blink.cmp.types').CompletionItemKind
|
local Kind = require('blink.cmp.types').CompletionItemKind
|
||||||
local result = vim.system({ 'ghostty', '+show-config', '--docs' }):wait()
|
|
||||||
local items = {}
|
local items = {}
|
||||||
local doc_lines = {}
|
local doc_lines = {}
|
||||||
|
|
||||||
for line in ((result.stdout or '') .. '\n'):gmatch('(.-)\n') do
|
for line in (stdout .. '\n'):gmatch('(.-)\n') do
|
||||||
if line:match('^#') then
|
if line:match('^#') then
|
||||||
local stripped = line:gsub('^# ?', '')
|
local stripped = line:gsub('^# ?', '')
|
||||||
doc_lines[#doc_lines + 1] = stripped
|
doc_lines[#doc_lines + 1] = stripped
|
||||||
|
|
@ -79,13 +82,7 @@ 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 keys_cache then
|
|
||||||
keys_cache = parse_keys()
|
|
||||||
enums_cache = parse_enums()
|
|
||||||
end
|
|
||||||
|
|
||||||
local line = ctx.line
|
local line = ctx.line
|
||||||
local col = ctx.cursor[2]
|
local col = ctx.cursor[2]
|
||||||
local eq_pos = line:find('=')
|
local eq_pos = line:find('=')
|
||||||
|
|
@ -108,16 +105,42 @@ function M:get_completions(ctx, callback)
|
||||||
is_incomplete_backward = false,
|
is_incomplete_backward = false,
|
||||||
items = items,
|
items = items,
|
||||||
})
|
})
|
||||||
return function() end
|
return
|
||||||
end
|
end
|
||||||
callback({ items = {} })
|
callback({ items = {} })
|
||||||
else
|
else
|
||||||
callback({
|
callback({
|
||||||
is_incomplete_forward = false,
|
is_incomplete_forward = false,
|
||||||
is_incomplete_backward = false,
|
is_incomplete_backward = false,
|
||||||
items = vim.deepcopy(keys_cache),
|
items = keys_cache,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param ctx blink.cmp.Context
|
||||||
|
---@param callback fun(response: blink.cmp.CompletionResponse)
|
||||||
|
---@return fun()
|
||||||
|
function M:get_completions(ctx, callback)
|
||||||
|
if keys_cache then
|
||||||
|
respond(ctx, callback)
|
||||||
|
return function() end
|
||||||
|
end
|
||||||
|
|
||||||
|
pending[#pending + 1] = { ctx = ctx, callback = callback }
|
||||||
|
if not loading then
|
||||||
|
loading = true
|
||||||
|
vim.system({ 'ghostty', '+show-config', '--docs' }, {}, function(result)
|
||||||
|
vim.schedule(function()
|
||||||
|
keys_cache = parse_keys(result.stdout or '')
|
||||||
|
enums_cache = parse_enums()
|
||||||
|
loading = false
|
||||||
|
for _, p in ipairs(pending) do
|
||||||
|
respond(p.ctx, p.callback)
|
||||||
|
end
|
||||||
|
pending = {}
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end
|
||||||
return function() end
|
return function() end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,24 +19,31 @@ local BASH_COMPLETION = 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)
|
||||||
if cmd[1] == 'ghostty' then
|
if cmd[1] == 'ghostty' then
|
||||||
return {
|
local result = { stdout = CONFIG_DOCS, code = 0 }
|
||||||
wait = function()
|
if on_exit then
|
||||||
return { stdout = CONFIG_DOCS, code = 0 }
|
on_exit(result)
|
||||||
end,
|
return {}
|
||||||
}
|
end
|
||||||
|
return { wait = function() return result end }
|
||||||
end
|
end
|
||||||
return {
|
local result = { stdout = '', code = 1 }
|
||||||
wait = function()
|
if on_exit then
|
||||||
return { stdout = '', code = 1 }
|
on_exit(result)
|
||||||
end,
|
return {}
|
||||||
}
|
end
|
||||||
|
return { wait = function() return result end }
|
||||||
|
end
|
||||||
|
vim.schedule = function(fn)
|
||||||
|
fn()
|
||||||
end
|
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