perf: cache repo root and harden async paths (#100)
## Problem `get_repo_root()` shells out to `git rev-parse` on every call, causing 4-6 redundant subprocesses per `gdiff_file()` invocation. Three other minor issues: `highlight_vim_syntax()` leaks a scratch buffer if `nvim_buf_call` errors, `lib.ensure()` silently drops callbacks during download so hunks highlighted mid-download permanently miss intra-line highlights, and the debounce timer callback can operate on a deleted buffer. ## Solution Cache `get_repo_root()` results by parent directory — repo roots don't change within a session. Wrap `nvim_buf_call` and `nvim_buf_delete` in pcall so the scratch buffer is always cleaned up. Replace the early `callback(nil)` in `lib.ensure()` with a pending callback queue that fires once the download completes. Guard the debounce timer callback with `nvim_buf_is_valid`.
This commit is contained in:
parent
a2053a132b
commit
f5a090baae
4 changed files with 30 additions and 14 deletions
|
|
@ -1,13 +1,19 @@
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
|
local repo_root_cache = {}
|
||||||
|
|
||||||
---@param filepath string
|
---@param filepath string
|
||||||
---@return string?
|
---@return string?
|
||||||
function M.get_repo_root(filepath)
|
function M.get_repo_root(filepath)
|
||||||
local dir = vim.fn.fnamemodify(filepath, ':h')
|
local dir = vim.fn.fnamemodify(filepath, ':h')
|
||||||
|
if repo_root_cache[dir] ~= nil then
|
||||||
|
return repo_root_cache[dir]
|
||||||
|
end
|
||||||
local result = vim.fn.systemlist({ 'git', '-C', dir, 'rev-parse', '--show-toplevel' })
|
local result = vim.fn.systemlist({ 'git', '-C', dir, 'rev-parse', '--show-toplevel' })
|
||||||
if vim.v.shell_error ~= 0 then
|
if vim.v.shell_error ~= 0 then
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
repo_root_cache[dir] = result[1]
|
||||||
return result[1]
|
return result[1]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -238,7 +238,7 @@ local function highlight_vim_syntax(bufnr, ns, hunk, code_lines, covered_lines,
|
||||||
|
|
||||||
local spans = {}
|
local spans = {}
|
||||||
|
|
||||||
vim.api.nvim_buf_call(scratch, function()
|
pcall(vim.api.nvim_buf_call, scratch, function()
|
||||||
vim.cmd('setlocal syntax=' .. ft)
|
vim.cmd('setlocal syntax=' .. ft)
|
||||||
vim.cmd('redraw')
|
vim.cmd('redraw')
|
||||||
|
|
||||||
|
|
@ -256,7 +256,7 @@ local function highlight_vim_syntax(bufnr, ns, hunk, code_lines, covered_lines,
|
||||||
spans = M.coalesce_syntax_spans(query_fn, code_lines)
|
spans = M.coalesce_syntax_spans(query_fn, code_lines)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
vim.api.nvim_buf_delete(scratch, { force = true })
|
pcall(vim.api.nvim_buf_delete, scratch, { force = true })
|
||||||
|
|
||||||
local hunk_line_count = #hunk.lines
|
local hunk_line_count = #hunk.lines
|
||||||
local extmark_count = 0
|
local extmark_count = 0
|
||||||
|
|
|
||||||
|
|
@ -200,7 +200,9 @@ local function create_debounced_highlight(bufnr)
|
||||||
timer = nil
|
timer = nil
|
||||||
t:close()
|
t:close()
|
||||||
end
|
end
|
||||||
|
if vim.api.nvim_buf_is_valid(bufnr) then
|
||||||
highlight_buffer(bufnr)
|
highlight_buffer(bufnr)
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,9 @@ local cached_handle = nil
|
||||||
---@type boolean
|
---@type boolean
|
||||||
local download_in_progress = false
|
local download_in_progress = false
|
||||||
|
|
||||||
|
---@type fun(handle: table?)[]
|
||||||
|
local pending_callbacks = {}
|
||||||
|
|
||||||
---@return string
|
---@return string
|
||||||
local function get_os()
|
local function get_os()
|
||||||
local os_name = jit.os:lower()
|
local os_name = jit.os:lower()
|
||||||
|
|
@ -164,9 +167,10 @@ function M.ensure(callback)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
table.insert(pending_callbacks, callback)
|
||||||
|
|
||||||
if download_in_progress then
|
if download_in_progress then
|
||||||
dbg('download already in progress')
|
dbg('download already in progress, queued callback')
|
||||||
callback(nil)
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -192,21 +196,25 @@ function M.ensure(callback)
|
||||||
vim.system(cmd, {}, function(result)
|
vim.system(cmd, {}, function(result)
|
||||||
download_in_progress = false
|
download_in_progress = false
|
||||||
vim.schedule(function()
|
vim.schedule(function()
|
||||||
|
local handle = nil
|
||||||
if result.code ~= 0 then
|
if result.code ~= 0 then
|
||||||
vim.notify('[diffs] failed to download libvscode_diff', vim.log.levels.WARN)
|
vim.notify('[diffs] failed to download libvscode_diff', vim.log.levels.WARN)
|
||||||
dbg('curl failed: %s', result.stderr or '')
|
dbg('curl failed: %s', result.stderr or '')
|
||||||
callback(nil)
|
else
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local f = io.open(version_path(), 'w')
|
local f = io.open(version_path(), 'w')
|
||||||
if f then
|
if f then
|
||||||
f:write(EXPECTED_VERSION)
|
f:write(EXPECTED_VERSION)
|
||||||
f:close()
|
f:close()
|
||||||
end
|
end
|
||||||
|
|
||||||
vim.notify('[diffs] libvscode_diff downloaded', vim.log.levels.INFO)
|
vim.notify('[diffs] libvscode_diff downloaded', vim.log.levels.INFO)
|
||||||
callback(M.load())
|
handle = M.load()
|
||||||
|
end
|
||||||
|
|
||||||
|
local cbs = pending_callbacks
|
||||||
|
pending_callbacks = {}
|
||||||
|
for _, cb in ipairs(cbs) do
|
||||||
|
cb(handle)
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue