refactor(git): URI scheme is now a git revspec, loaded via cat-file -p
This commit is contained in:
+2
-6
@@ -74,7 +74,7 @@ end
|
||||
---@param path string
|
||||
local function show_file_in_split(worktree, user_ref, path)
|
||||
local label = repo.rev_parse(worktree, user_ref, true) or user_ref
|
||||
local uri = "git://" .. label .. "//" .. path
|
||||
local uri = "git://" .. label .. ":" .. path
|
||||
local buf = vim.fn.bufadd(uri)
|
||||
vim.b[buf].git_worktree = worktree
|
||||
vim.cmd("split " .. vim.fn.fnameescape(uri))
|
||||
@@ -119,11 +119,7 @@ local function run_in_split(worktree, args, conf)
|
||||
vim.b[buf].git_parent_ref =
|
||||
repo.rev_parse(worktree, user_ref .. "^", true)
|
||||
end
|
||||
pcall(
|
||||
vim.api.nvim_buf_set_name,
|
||||
buf,
|
||||
"git://" .. (sha or user_ref) .. "//"
|
||||
)
|
||||
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
|
||||
|
||||
+26
-27
@@ -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)
|
||||
|
||||
+1
-1
@@ -63,7 +63,7 @@ function M.setup()
|
||||
end
|
||||
vim.filetype.add({
|
||||
pattern = {
|
||||
["git://.-//(.+)"] = function(_, bufnr, inner)
|
||||
["git://.*:([^:]+)$"] = function(_, bufnr, inner)
|
||||
return vim.filetype.match({ filename = inner, buf = bufnr })
|
||||
end,
|
||||
},
|
||||
|
||||
+10
-6
@@ -87,11 +87,14 @@ end
|
||||
---@param ref string the commit ref the blob represents (e.g. `<sha>` or `<sha>^`)
|
||||
---@return integer
|
||||
local function blob_buf(worktree, blob, path, ref)
|
||||
local name = "git://" .. ref .. "//" .. path
|
||||
local revspec = ref .. ":" .. path
|
||||
if is_zero(blob) then
|
||||
return diff.empty_buf({ name = name, bufhidden = "hide" })
|
||||
return diff.empty_buf({
|
||||
name = "git://" .. revspec,
|
||||
bufhidden = "hide",
|
||||
})
|
||||
end
|
||||
return diff.git_show_buf(worktree, ref, path)
|
||||
return diff.git_show_buf(worktree, revspec)
|
||||
end
|
||||
|
||||
---@param worktree string
|
||||
@@ -142,7 +145,7 @@ end
|
||||
function M.open_commit(worktree, ref, opts)
|
||||
local split = opts and opts.split
|
||||
local sha = repo.rev_parse(worktree, ref, true) or ref
|
||||
local name = "git://" .. sha .. "//"
|
||||
local name = "git://" .. sha
|
||||
local existing = vim.fn.bufnr(name)
|
||||
if existing ~= -1 and vim.api.nvim_buf_is_loaded(existing) then
|
||||
if split == false then
|
||||
@@ -218,7 +221,7 @@ function M.open_object(worktree, ref, opts)
|
||||
|
||||
local split = opts and opts.split
|
||||
local sha = repo.rev_parse(worktree, ref, true) or ref
|
||||
local name = "git://" .. sha .. "//"
|
||||
local name = "git://" .. sha
|
||||
local existing = vim.fn.bufnr(name)
|
||||
if existing ~= -1 and vim.api.nvim_buf_is_loaded(existing) then
|
||||
if split == false then
|
||||
@@ -279,7 +282,8 @@ function M.open_under_cursor()
|
||||
line:match("^%d+ (%w+) (%x+)\t(.+)$")
|
||||
if entry_sha then
|
||||
if entry_type == "blob" then
|
||||
local buf = diff.git_show_buf(ctx.worktree, ctx.ref, entry_name)
|
||||
local buf =
|
||||
diff.git_show_buf(ctx.worktree, ctx.ref .. ":" .. entry_name)
|
||||
vim.cmd.normal({ "m'", bang = true })
|
||||
vim.api.nvim_set_current_buf(buf)
|
||||
else
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ local M = {}
|
||||
function M.show(worktree, ref, opts)
|
||||
local split = opts and opts.split
|
||||
local sha = repo.rev_parse(worktree, ref, true) or ref
|
||||
local name = "git://" .. sha .. "//"
|
||||
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)
|
||||
|
||||
+15
-15
@@ -484,15 +484,19 @@ end
|
||||
---@return ow.Git.DiffSide
|
||||
local function head_pane(worktree, path)
|
||||
return {
|
||||
buf = diff.git_show_buf(worktree, "HEAD", path),
|
||||
name = "git://HEAD//" .. path,
|
||||
buf = diff.git_show_buf(worktree, "HEAD:" .. path),
|
||||
name = "git://HEAD:" .. path,
|
||||
}
|
||||
end
|
||||
|
||||
---@param worktree string
|
||||
---@param path string
|
||||
---@return ow.Git.DiffSide
|
||||
local function head_empty_pane(path)
|
||||
return { buf = diff.empty_buf(), name = "git://HEAD//" .. path }
|
||||
local function absent_pane(worktree, path)
|
||||
return {
|
||||
buf = diff.empty_buf(),
|
||||
name = "[absent] " .. vim.fs.joinpath(worktree, path),
|
||||
}
|
||||
end
|
||||
|
||||
---@param worktree string
|
||||
@@ -505,12 +509,6 @@ local function worktree_pane(worktree, path)
|
||||
}
|
||||
end
|
||||
|
||||
---@param path string
|
||||
---@return ow.Git.DiffSide
|
||||
local function worktree_empty_pane(path)
|
||||
return { buf = diff.empty_buf(), name = "git://worktree//" .. path }
|
||||
end
|
||||
|
||||
---@param s ow.Git.SidebarState
|
||||
---@param entry ow.Git.FileEntry
|
||||
---@return ow.Git.DiffSide
|
||||
@@ -519,10 +517,12 @@ local function index_pane(s, entry)
|
||||
entry.section == "Untracked"
|
||||
or (entry.section == "Staged" and entry.x == "D")
|
||||
)
|
||||
if not in_index then
|
||||
return absent_pane(s.worktree, entry.path)
|
||||
end
|
||||
return {
|
||||
buf = in_index and diff.git_show_buf(s.worktree, "index", entry.path)
|
||||
or diff.empty_buf(),
|
||||
name = "git://index//" .. entry.path,
|
||||
buf = diff.git_show_buf(s.worktree, ":" .. entry.path),
|
||||
name = "git://:" .. entry.path,
|
||||
}
|
||||
end
|
||||
|
||||
@@ -534,7 +534,7 @@ local function other_pane(s, entry)
|
||||
local worktree = s.worktree
|
||||
if entry.section == "Staged" then
|
||||
if entry.x == "A" then
|
||||
return head_empty_pane(p)
|
||||
return absent_pane(worktree, p)
|
||||
end
|
||||
if entry.x == "D" then
|
||||
return head_pane(worktree, p)
|
||||
@@ -544,7 +544,7 @@ local function other_pane(s, entry)
|
||||
end
|
||||
if entry.section == "Unstaged" then
|
||||
if entry.y == "D" then
|
||||
return worktree_empty_pane(p)
|
||||
return absent_pane(worktree, p)
|
||||
end
|
||||
return worktree_pane(worktree, p)
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user