diff --git a/lua/git/diff.lua b/lua/git/diff.lua index d84152f..81b3b13 100644 --- a/lua/git/diff.lua +++ b/lua/git/diff.lua @@ -157,13 +157,17 @@ local function uri_split(opts, cur_buf, cur_revspec) local cur_writable = cur.stage == 0 if opts.revspec ~= "" and opts.revspec:find(":", 1, true) then - if not repo.object_exists(worktree, opts.revspec) then + local content = util.exec( + { "git", "cat-file", "-p", opts.revspec }, + { cwd = worktree, silent = true } + ) + if not content then util.warning("invalid revspec: %s", opts.revspec) return end place_pair( cur_buf, - object.buf_for(worktree, opts.revspec), + object.buf_for(worktree, opts.revspec, content), cur_writable, opts.vertical ) @@ -192,13 +196,17 @@ local function uri_split(opts, cur_buf, cur_revspec) else other_revspec = ":0:" .. cur.path end - if not repo.object_exists(worktree, other_revspec) then + local content = util.exec( + { "git", "cat-file", "-p", other_revspec }, + { cwd = worktree, silent = true } + ) + if not content then util.warning("invalid revspec: %s", other_revspec) return end place_pair( cur_buf, - object.buf_for(worktree, other_revspec), + object.buf_for(worktree, other_revspec, content), cur.stage ~= nil, opts.vertical ) @@ -248,13 +256,16 @@ function M.split(opts) else revspec = opts.revspec .. ":" .. rel end - if not repo.object_exists(worktree, revspec) then + local content = util.exec( + { "git", "cat-file", "-p", revspec }, + { cwd = worktree, silent = true } + ) + if not content then util.warning("invalid revspec: %s", revspec) return end - local buf = vim.fn.bufadd("git://" .. revspec) - vim.b[buf].git_worktree = worktree - + local object = require("git.object") + local buf = object.buf_for(worktree, revspec, content) local other_writable = util.parse_revspec(revspec).stage == 0 place_pair(buf, cur_buf, other_writable, opts.vertical) end diff --git a/lua/git/object.lua b/lua/git/object.lua index 8dd751a..80643f4 100644 --- a/lua/git/object.lua +++ b/lua/git/object.lua @@ -135,16 +135,29 @@ local function attach_index_writer(buf, worktree, path) }) end +---Pre-fetched content keyed by bufnr. Set by `buf_for(_, _, content)` +---and consumed by the next `read_uri` dispatch on that buffer. Lets +---callers fold validation + content fetch + buffer load into one +---`cat-file` call instead of preflighting separately. +---@type table +local pending_content = {} + ---Return a buffer holding the content addressed by a git revspec. The ---URI is `git://` and BufReadCmd routes through `M.read_uri`, ----which loads via `git cat-file -p`. +---which loads via `git cat-file -p`. If `content` is given, primes a +---cache so the BufReadCmd handler reuses it instead of running another +---`cat-file -p`. ---@param worktree string ---@param revspec string any revspec git understands (e.g. `HEAD:foo`, `:foo`, `:1:foo`, ``, `:foo`) +---@param content string? ---@return integer -function M.buf_for(worktree, revspec) +function M.buf_for(worktree, revspec, content) local name = "git://" .. revspec local buf = vim.fn.bufadd(name) vim.b[buf].git_worktree = worktree + if content then + pending_content[buf] = content + end vim.fn.bufload(buf) return buf end @@ -172,10 +185,14 @@ function M.read_uri(buf) vim.bo[buf].swapfile = false vim.bo[buf].bufhidden = "wipe" - local stdout = util.exec( - { "git", "cat-file", "-p", revspec }, - { cwd = worktree } - ) + local stdout = pending_content[buf] + pending_content[buf] = nil + if stdout == nil then + stdout = util.exec( + { "git", "cat-file", "-p", revspec }, + { cwd = worktree } + ) + end if stdout then vim.api.nvim_buf_set_lines(buf, 0, -1, false, util.split_lines(stdout)) end diff --git a/lua/git/repo.lua b/lua/git/repo.lua index 91d3794..e975b50 100644 --- a/lua/git/repo.lua +++ b/lua/git/repo.lua @@ -343,18 +343,4 @@ function M.rev_parse(worktree, ref, short) return trimmed ~= "" and trimmed or nil end ----Verify a revspec resolves to an existing git object. `cat-file -e` is ----git's cheapest existence check, and unlike `rev-parse --verify` it ----also accepts the `:` form that BufReadCmd revspec URIs ----use. ----@param worktree string ----@param revspec string ----@return boolean -function M.object_exists(worktree, revspec) - return util.exec( - { "git", "cat-file", "-e", revspec }, - { cwd = worktree, silent = true } - ) ~= nil -end - return M