From d2633ae9c25ff949938964cc58b2791299efefc3 Mon Sep 17 00:00:00 2001 From: Oscar Wallberg Date: Tue, 28 Apr 2026 08:03:05 +0200 Subject: [PATCH] perf(git): run rev-parse and git show sync --- lua/git/cmd.lua | 43 ++++++++------------- lua/git/repo.lua | 33 ++++++---------- lua/git/show.lua | 99 +++++++++++++++++++----------------------------- 3 files changed, 68 insertions(+), 107 deletions(-) diff --git a/lua/git/cmd.lua b/lua/git/cmd.lua index 656b76f..f19836d 100644 --- a/lua/git/cmd.lua +++ b/lua/git/cmd.lua @@ -74,13 +74,11 @@ end ---@param user_ref string ---@param path string local function show_file_in_split(worktree, user_ref, path) - repo.rev_parse(worktree, user_ref, true, function(sha) - local label = sha or user_ref - local uri = "git://" .. label .. "//" .. path - local buf = vim.fn.bufadd(uri) - vim.b[buf].git_worktree = worktree - vim.cmd("split " .. vim.fn.fnameescape(uri)) - end) + local label = repo.rev_parse(worktree, user_ref, true) or user_ref + local uri = "git://" .. label .. "//" .. path + local buf = vim.fn.bufadd(uri) + vim.b[buf].git_worktree = worktree + vim.cmd("split " .. vim.fn.fnameescape(uri)) end ---@param worktree string @@ -105,27 +103,18 @@ local function run_in_split(worktree, args, conf) vim.b[buf].git_worktree = worktree if conf.needs_ref then local user_ref = first_positional(args, 2) or "HEAD" - local function apply_name(label) - if not vim.api.nvim_buf_is_valid(buf) then - return - end - pcall(vim.api.nvim_buf_set_name, buf, "git://" .. label .. "//") - vim.bo[buf].filetype = conf.ft + local sha = repo.rev_parse(worktree, user_ref, true) + if sha then + vim.b[buf].git_ref = sha + vim.b[buf].git_parent_ref = + repo.rev_parse(worktree, user_ref .. "^", true) end - repo.rev_parse(worktree, user_ref, true, function(sha) - if not sha then - apply_name(user_ref) - return - end - repo.rev_parse(worktree, user_ref .. "^", true, function(parent) - if not vim.api.nvim_buf_is_valid(buf) then - return - end - vim.b[buf].git_ref = sha - vim.b[buf].git_parent_ref = parent - apply_name(sha) - end) - end) + pcall( + vim.api.nvim_buf_set_name, + buf, + "git://" .. (sha or user_ref) .. "//" + ) + vim.bo[buf].filetype = conf.ft else vim.bo[buf].filetype = conf.ft end diff --git a/lua/git/repo.lua b/lua/git/repo.lua index b2dca0c..659e53b 100644 --- a/lua/git/repo.lua +++ b/lua/git/repo.lua @@ -322,35 +322,26 @@ function M.head(path) return nil end ----Resolve a git revision to its object SHA. Calls `callback(sha?)` on the ----main loop with nil if the ref can't be parsed (root-commit's `^`, blob's ----`^`, malformed ref, etc.). When `short` is true, the result is abbreviated ----via `core.abbrev` (auto-extended by git to keep the prefix unique in the ----current repo). +---Resolve a git revision to its object SHA. Returns nil if the ref can't +---be parsed (root-commit's `^`, blob's `^`, malformed ref, etc.). When +---`short` is true, the result is abbreviated via `core.abbrev` +---(auto-extended by git to keep the prefix unique in the current repo). ---@param worktree string ---@param ref string ---@param short boolean ----@param callback fun(sha: string?) -function M.rev_parse(worktree, ref, short, callback) +---@return string? +function M.rev_parse(worktree, ref, short) local cmd = { "git", "rev-parse", "--verify", "--quiet" } if short then table.insert(cmd, "--short") end table.insert(cmd, ref) - vim.system( - cmd, - { cwd = worktree, text = true }, - vim.schedule_wrap(function(result) - local sha - if result.code == 0 then - local trimmed = vim.trim(result.stdout or "") - if trimmed ~= "" then - sha = trimmed - end - end - callback(sha) - end) - ) + local result = vim.system(cmd, { cwd = worktree, text = true }):wait() + if result.code ~= 0 then + return nil + end + local trimmed = vim.trim(result.stdout or "") + return trimmed ~= "" and trimmed or nil end return M diff --git a/lua/git/show.lua b/lua/git/show.lua index acf04fb..285bc5e 100644 --- a/lua/git/show.lua +++ b/lua/git/show.lua @@ -135,68 +135,49 @@ end ---@param opts ow.Git.OpenCommitOpts? function M.open_commit(worktree, ref, opts) local split = opts and opts.split - repo.rev_parse(worktree, ref, true, function(resolved) - local sha = resolved or ref - local name = "git://" .. sha .. "//" - -- Reuse a previously-opened buffer for the same commit; commit SHAs - -- are immutable so the content is stable. - local existing = vim.fn.bufnr(name) - if existing ~= -1 and vim.api.nvim_buf_is_loaded(existing) then - if split == false then - vim.cmd.normal({ "m'", bang = true }) - vim.api.nvim_set_current_buf(existing) - else - vim.api.nvim_open_win(existing, true, { - split = split or (vim.o.splitbelow and "below" or "above"), - }) - end - return + local sha = repo.rev_parse(worktree, ref, true) or ref + local name = "git://" .. sha .. "//" + -- Commit SHAs are immutable so a previously-opened buffer is still + -- valid. Reuse it instead of refetching. + local existing = vim.fn.bufnr(name) + if existing ~= -1 and vim.api.nvim_buf_is_loaded(existing) then + if split == false then + vim.cmd.normal({ "m'", bang = true }) + vim.api.nvim_set_current_buf(existing) + else + vim.api.nvim_open_win(existing, true, { + split = split or (vim.o.splitbelow and "below" or "above"), + }) end + return + end - local buf, win = git.new_scratch({ name = name, split = split }) - vim.b[buf].git_worktree = worktree - vim.b[buf].git_ref = sha + local result = vim.system( + { "git", "show", ref }, + { cwd = worktree, text = true } + ) + :wait() + if result.code ~= 0 then + log.error("git show %s failed: %s", ref, vim.trim(result.stderr or "")) + return + end - vim.system( - { "git", "show", ref }, - { cwd = worktree, text = true }, - vim.schedule_wrap(function(result) - if result.code ~= 0 then - log.error( - "git show %s failed: %s", - ref, - vim.trim(result.stderr or "") - ) - -- Drop the empty placeholder so a retry runs a fresh - -- fetch. With `split = false` the window falls back to - -- its alternate buffer (the gitlog); for a real split - -- we close the dedicated window to keep the layout tidy. - if split ~= false and vim.api.nvim_win_is_valid(win) then - pcall(vim.api.nvim_win_close, win, true) - end - if vim.api.nvim_buf_is_valid(buf) then - vim.api.nvim_buf_delete(buf, { force = true }) - end - return - end - if not vim.api.nvim_buf_is_valid(buf) then - return - end - local lines = util.split_lines(result.stdout or "") - repo.rev_parse(worktree, ref .. "^", true, function(parent) - if not vim.api.nvim_buf_is_valid(buf) then - return - end - vim.b[buf].git_parent_ref = parent - vim.bo[buf].modifiable = true - vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines) - vim.bo[buf].modifiable = false - vim.bo[buf].modified = false - vim.bo[buf].filetype = "git" - end) - end) - ) - end) + local parent = repo.rev_parse(worktree, ref .. "^", true) + local buf, _ = git.new_scratch({ name = name, split = split }) + vim.b[buf].git_worktree = worktree + vim.b[buf].git_ref = sha + vim.b[buf].git_parent_ref = parent + vim.bo[buf].modifiable = true + vim.api.nvim_buf_set_lines( + buf, + 0, + -1, + false, + util.split_lines(result.stdout or "") + ) + vim.bo[buf].modifiable = false + vim.bo[buf].modified = false + vim.bo[buf].filetype = "git" end ---@return boolean dispatched true if the cursor was on an actionable line