refactor(git): URI scheme is now a git revspec, loaded via cat-file -p

This commit is contained in:
2026-04-28 13:20:38 +02:00
parent a0c87b9b7b
commit 68f2ad1b52
6 changed files with 55 additions and 56 deletions
+26 -27
View File
@@ -57,32 +57,31 @@ local function attach_index_writer(buf, worktree, path)
})
end
---Return a buffer holding the content at `<ref>:<path>`. `ref` is
---"index", "HEAD", or a commit revspec.
---Return a buffer holding the content addressed by a git revspec. The
---URI is `git://<revspec>` and BufReadCmd loads via `git cat-file -p`.
---@param worktree string
---@param ref string
---@param path string
---@param revspec string any revspec git understands (e.g. `HEAD:foo`, `:foo`, `:1:foo`, `<sha>`, `<sha>:foo`)
---@return integer
function M.git_show_buf(worktree, ref, path)
local name = "git://" .. ref .. "//" .. path
function M.git_show_buf(worktree, revspec)
local name = "git://" .. revspec
local buf = vim.fn.bufadd(name)
vim.b[buf].git_worktree = worktree
vim.fn.bufload(buf)
return buf
end
---BufReadCmd handler for `git://<ref>//<path>` URIs. Worktree comes from
---`vim.b[buf].git_worktree` if set, else from cwd. Ref of "index" maps
---to `git show :<path>`; "worktree" leaves the buffer empty (placeholder
---for missing files); anything else is a revspec.
---BufReadCmd handler for `git://<revspec>` URIs. Loads content via
---`git cat-file -p <revspec>`. Worktree comes from `vim.b[buf]
---.git_worktree` if set, else from cwd. Index entries (revspec form
---`:<path>` for stage 0) are made writable via `attach_index_writer`,
---so `:w` updates the index. Other revspecs are read-only.
---@param buf integer
function M.read_uri(buf)
local name = vim.api.nvim_buf_get_name(buf)
local ref, path = name:match("^git://(.-)//(.*)$")
if not ref or path == "" then
local revspec = name:match("^git://(.+)$")
if not revspec then
return
end
---@cast path -nil
local worktree = vim.b[buf].git_worktree or select(2, repo.resolve_cwd())
if not worktree then
@@ -94,27 +93,26 @@ function M.read_uri(buf)
vim.bo[buf].swapfile = false
vim.bo[buf].bufhidden = "wipe"
if ref == "worktree" then
vim.bo[buf].buftype = "nofile"
vim.bo[buf].modifiable = false
vim.bo[buf].modified = false
vim.api.nvim_exec_autocmds("BufReadPost", { buffer = buf })
return
end
local revspec = ref == "index" and (":" .. path) or (ref .. ":" .. path)
local stdout = util.exec({ "git", "show", revspec }, { cwd = worktree })
local stdout = util.exec(
{ "git", "cat-file", "-p", revspec },
{ cwd = worktree }
)
if stdout then
vim.api.nvim_buf_set_lines(buf, 0, -1, false, util.split_lines(stdout))
end
if ref == "index" then
-- Stage-0 index entries (`:<path>` with no further `:`) are
-- editable; `:w` rewrites the index entry via `attach_index_writer`.
-- Anything else (HEAD:, <sha>:, :1:, :2:, :3:, bare object refs)
-- is read-only.
local index_path = revspec:match("^:([^:]+)$")
if index_path then
vim.bo[buf].buftype = "acwrite"
-- Re-running BufReadCmd (e.g. on `:edit`) would otherwise stack
-- another BufWriteCmd on the same buffer, so each `:w` runs
-- hash-object + update-index N times.
if not vim.b[buf].git_index_writer then
attach_index_writer(buf, worktree, path)
attach_index_writer(buf, worktree, index_path)
vim.b[buf].git_index_writer = true
end
else
@@ -221,8 +219,9 @@ function M.split(opts)
return
end
local label = opts.ref == "" and "index" or opts.ref
local uri = "git://" .. label .. "//" .. rel
-- Stage 0 (index) is `:<path>`; named refs are `<ref>:<path>`.
local revspec = opts.ref == "" and (":" .. rel) or (opts.ref .. ":" .. rel)
local uri = "git://" .. revspec
-- Stash the worktree on the buffer so the BufReadCmd handler doesn't
-- fall back to cwd resolution (wrong when cwd != worktree).
local buf = vim.fn.bufadd(uri)