feat(git): add cat-file-based commit view for gitlog <CR>
This commit is contained in:
+1
-1
@@ -9,7 +9,7 @@ vim.keymap.set("n", "<CR>", function()
|
|||||||
.nvim_get_current_line()
|
.nvim_get_current_line()
|
||||||
:match("^[*|/\\_ ]*(%x%x%x%x%x%x%x+)")
|
:match("^[*|/\\_ ]*(%x%x%x%x%x%x%x+)")
|
||||||
if sha then
|
if sha then
|
||||||
require("git.show").open_commit(worktree, sha, { split = false })
|
require("git.show").open_commit_object(worktree, sha, { split = false })
|
||||||
else
|
else
|
||||||
-- "n" mode = no remap, so this doesn't recurse into our mapping.
|
-- "n" mode = no remap, so this doesn't recurse into our mapping.
|
||||||
vim.api.nvim_feedkeys(cr, "n", false)
|
vim.api.nvim_feedkeys(cr, "n", false)
|
||||||
|
|||||||
+76
-1
@@ -168,19 +168,94 @@ function M.open_commit(worktree, ref, opts)
|
|||||||
vim.bo[buf].filetype = "git"
|
vim.bo[buf].filetype = "git"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---Open a commit's body via `git cat-file -p` for the header (raw object
|
||||||
|
---form, flush-left message) plus `git diff-tree -p` for the patch. The
|
||||||
|
---`-m --first-parent` flags collapse merges and stashes into single
|
||||||
|
---`diff --git` blocks per file, so `M.open_at_cursor`'s `<CR>` parser
|
||||||
|
---can navigate them. (`git show` would emit `diff --cc` combined diffs
|
||||||
|
---in those cases, which the parser can't follow.) Used by the gitlog
|
||||||
|
---`<CR>` flow.
|
||||||
|
---@param worktree string
|
||||||
|
---@param ref string
|
||||||
|
---@param opts ow.Git.OpenCommitOpts?
|
||||||
|
function M.open_commit_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 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 header = util.exec(
|
||||||
|
{ "git", "cat-file", "-p", ref },
|
||||||
|
{ cwd = worktree }
|
||||||
|
)
|
||||||
|
if not header then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
-- `--root` lets initial commits show their full tree.
|
||||||
|
local patch = util.exec({
|
||||||
|
"git",
|
||||||
|
"diff-tree",
|
||||||
|
"-p",
|
||||||
|
"-m",
|
||||||
|
"--first-parent",
|
||||||
|
"--root",
|
||||||
|
"--no-commit-id",
|
||||||
|
ref,
|
||||||
|
}, { cwd = worktree })
|
||||||
|
if not patch then
|
||||||
|
return
|
||||||
|
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
|
||||||
|
-- Normalise to exactly one blank line between the message body and
|
||||||
|
-- the patch, regardless of trailing newlines on the header.
|
||||||
|
local content = (header:gsub("\n*$", "\n\n")) .. patch
|
||||||
|
vim.api.nvim_buf_set_lines(buf, 0, -1, false, util.split_lines(content))
|
||||||
|
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
|
---@return boolean dispatched true if the cursor was on an actionable line
|
||||||
function M.open_at_cursor()
|
function M.open_at_cursor()
|
||||||
local ctx = context()
|
local ctx = context()
|
||||||
if not ctx then
|
if not ctx then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local line = vim.api.nvim_get_current_line()
|
||||||
|
|
||||||
|
-- Cat-file header navigation. `parent <sha>` opens the referenced
|
||||||
|
-- commit. (`git show` doesn't emit a `parent` line, so this only
|
||||||
|
-- fires inside `M.open_commit_object` buffers.)
|
||||||
|
local parent_sha = line:match("^parent (%x+)$")
|
||||||
|
if parent_sha then
|
||||||
|
M.open_commit_object(ctx.worktree, parent_sha, { split = false })
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
local section = diff_section()
|
local section = diff_section()
|
||||||
if not section then
|
if not section then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
local parent = ctx.parent_ref or "0"
|
local parent = ctx.parent_ref or "0"
|
||||||
|
|
||||||
local line = vim.api.nvim_get_current_line()
|
|
||||||
if line:match("^diff %-%-git ") then
|
if line:match("^diff %-%-git ") then
|
||||||
show_diff(ctx, section)
|
show_diff(ctx, section)
|
||||||
return true
|
return true
|
||||||
|
|||||||
Reference in New Issue
Block a user