From 20dc6cc3c947efee2fe0b0fb921763218df586b3 Mon Sep 17 00:00:00 2001 From: Oscar Wallberg Date: Mon, 27 Apr 2026 13:27:22 +0200 Subject: [PATCH] perf(git): minor performance cleanups --- ftplugin/gitlog.lua | 6 +++++- lua/git/cmd.lua | 39 ++++++++++++++++++++++++++++----------- lua/git/diff.lua | 30 +++++++++++++----------------- lua/git/repo.lua | 6 +++++- 4 files changed, 51 insertions(+), 30 deletions(-) diff --git a/ftplugin/gitlog.lua b/ftplugin/gitlog.lua index 1ff2d52..fa89303 100644 --- a/ftplugin/gitlog.lua +++ b/ftplugin/gitlog.lua @@ -2,8 +2,12 @@ local cr = vim.api.nvim_replace_termcodes("", true, false, true) vim.keymap.set("n", "", function() local worktree = vim.b.git_worktree + -- Anchor past the leading graph chars (matches the leading sha column, + -- not any hex word that happens to appear later in the subject). local sha = worktree - and vim.api.nvim_get_current_line():match("(%x%x%x%x%x%x%x+)") + and vim.api + .nvim_get_current_line() + :match("^[*|/\\_ ]*(%x%x%x%x%x%x%x+)") if sha then require("git.show").open_commit(worktree, sha) else diff --git a/lua/git/cmd.lua b/lua/git/cmd.lua index d586ecb..2783ba9 100644 --- a/lua/git/cmd.lua +++ b/lua/git/cmd.lua @@ -18,16 +18,8 @@ local SPLIT_HANDLERS = { ---@type string[]? local cached_cmds ----@return string[] -local function git_cmds() - if cached_cmds then - return cached_cmds - end - local result = vim.system( - { "git", "--list-cmds=main,others,alias" }, - { text = true } - ) - :wait() +---@param result vim.SystemCompleted +local function populate_cached_cmds(result) cached_cmds = {} if result.code == 0 then for line in (result.stdout or ""):gmatch("[^\r\n]+") do @@ -37,7 +29,31 @@ local function git_cmds() end table.sort(cached_cmds) end - return cached_cmds +end + +---Prime `cached_cmds` asynchronously so the first `:G ` doesn't block. +local function prefetch_cmds() + vim.system( + { "git", "--list-cmds=main,others,alias" }, + { text = true }, + function(result) + vim.schedule(function() + populate_cached_cmds(result) + end) + end + ) +end + +---@return string[] +local function git_cmds() + if cached_cmds then + return cached_cmds + end + populate_cached_cmds( + vim.system({ "git", "--list-cmds=main,others,alias" }, { text = true }) + :wait() + ) + return cached_cmds or {} end ---@param content string @@ -204,6 +220,7 @@ local function complete(arg_lead, cmd_line, _) end function M.setup() + prefetch_cmds() vim.api.nvim_create_user_command("G", function(opts) M.run(opts.fargs) end, { diff --git a/lua/git/diff.lua b/lua/git/diff.lua index e85e03a..f6a97be 100644 --- a/lua/git/diff.lua +++ b/lua/git/diff.lua @@ -23,16 +23,20 @@ local function attach_index_writer(buf, worktree, path) return end local sha = vim.trim(hash.stdout or "") - local mode = "100644" - local ls = vim.system( - { "git", "ls-files", "-s", "--", path }, - { cwd = worktree, text = true } - ):wait() - if ls.code == 0 and ls.stdout then - local m = ls.stdout:match("^(%d+)") - if m then - mode = m + local mode = vim.b[buf].git_index_mode + if not mode then + mode = "100644" + local ls = vim.system( + { "git", "ls-files", "-s", "--", path }, + { cwd = worktree, text = true } + ):wait() + if ls.code == 0 and ls.stdout then + local m = ls.stdout:match("^(%d+)") + if m then + mode = m + end end + vim.b[buf].git_index_mode = mode end local upd = vim.system({ "git", @@ -116,14 +120,6 @@ end ---@param abs_path string ---@return integer function M.load_file_buf(abs_path) - for _, buf in ipairs(vim.api.nvim_list_bufs()) do - if - vim.api.nvim_buf_is_loaded(buf) - and vim.api.nvim_buf_get_name(buf) == abs_path - then - return buf - end - end local buf = vim.fn.bufadd(abs_path) vim.fn.bufload(buf) return buf diff --git a/lua/git/repo.lua b/lua/git/repo.lua index 5d52c3a..4d39f55 100644 --- a/lua/git/repo.lua +++ b/lua/git/repo.lua @@ -149,6 +149,7 @@ local function do_refresh(repo) format(code) end end + local dirty = false for buf in pairs(repo.buffers) do if not vim.api.nvim_buf_is_valid(buf) then repo.buffers[buf] = nil @@ -156,10 +157,13 @@ local function do_refresh(repo) local status = statuses[vim.api.nvim_buf_get_name(buf)] if vim.b[buf].git_status ~= status then vim.b[buf].git_status = status - vim.cmd.redrawstatus({ bang = true }) + dirty = true end end end + if dirty then + vim.cmd.redrawstatus({ bang = true }) + end vim.api.nvim_exec_autocmds("User", { pattern = "GitRefresh", data = { gitdir = repo.gitdir, worktree = repo.worktree },