refactor(git): unify diff/object dispatch, codify naming, add :Gdiffsplit

This commit is contained in:
2026-04-29 09:47:51 +02:00
parent 44f9503960
commit 5c5da7a854
10 changed files with 587 additions and 443 deletions
+22 -33
View File
@@ -1,5 +1,5 @@
local diff = require("git.diff")
local git = require("git")
local object = require("git.object")
local repo = require("git.repo")
local util = require("git.util")
@@ -433,7 +433,7 @@ local function refresh(bufnr, prefetched_stdout)
end
-- Any fs-event that triggered this refresh might have changed the
-- worktree under the diff buffers we last opened; invalidate the
-- cache so the next show_diff recomputes panes.
-- cache so the next view_entry recomputes panes.
s.last_shown_key = nil
local fp = fingerprint(branch, groups)
if fp == s.last_render_key then
@@ -484,18 +484,23 @@ end
---@return ow.Git.DiffSide
local function head_pane(worktree, path)
return {
buf = diff.git_show_buf(worktree, "HEAD:" .. path),
buf = object.buf_for(worktree, "HEAD:" .. path),
name = "git://HEAD:" .. path,
}
end
---@param worktree string
---@param path string
---@param kind "index"|"HEAD"|"worktree"
---@return ow.Git.DiffSide
local function absent_pane(worktree, path)
local function absent_pane(worktree, path, kind)
return {
buf = diff.empty_buf(),
name = "[absent] " .. vim.fs.joinpath(worktree, path),
name = string.format(
"[absent %s] %s",
kind,
vim.fs.joinpath(worktree, path)
),
}
end
@@ -503,10 +508,9 @@ end
---@param path string
---@return ow.Git.DiffSide
local function worktree_pane(worktree, path)
return {
buf = diff.load_file_buf(vim.fs.joinpath(worktree, path)),
name = nil,
}
local buf = vim.fn.bufadd(vim.fs.joinpath(worktree, path))
vim.fn.bufload(buf)
return { buf = buf, name = nil }
end
---@param s ow.Git.SidebarState
@@ -518,11 +522,11 @@ local function index_pane(s, entry)
or (entry.section == "Staged" and entry.x == "D")
)
if not in_index then
return absent_pane(s.worktree, entry.path)
return absent_pane(s.worktree, entry.path, "index")
end
return {
buf = diff.git_show_buf(s.worktree, ":" .. entry.path),
name = "git://:" .. entry.path,
buf = object.buf_for(s.worktree, ":0:" .. entry.path),
name = "git://:0:" .. entry.path,
}
end
@@ -534,7 +538,7 @@ local function other_pane(s, entry)
local worktree = s.worktree
if entry.section == "Staged" then
if entry.x == "A" then
return absent_pane(worktree, p)
return absent_pane(worktree, p, "HEAD")
end
if entry.x == "D" then
return head_pane(worktree, p)
@@ -544,7 +548,7 @@ local function other_pane(s, entry)
end
if entry.section == "Unstaged" then
if entry.y == "D" then
return absent_pane(worktree, p)
return absent_pane(worktree, p, "worktree")
end
return worktree_pane(worktree, p)
end
@@ -649,7 +653,7 @@ end
---@param s ow.Git.SidebarState
---@param entry ow.Git.SidebarEntry
---@param focus_left boolean
local function show_diff(s, entry, focus_left)
local function view_entry(s, entry, focus_left)
if not entry.path then
return
end
@@ -713,22 +717,7 @@ local function show_diff(s, entry, focus_left)
s.diff_left_win = left_win
s.diff_right_win = right_win
-- Toggle diff off around the buffer swap so Vim tears down the old
-- diff group and re-establishes a fresh one against the new pair.
-- nvim_win_set_buf swaps the buffer pointer without invalidating
-- cached diff state, and :diffupdate alone doesn't reliably force a
-- recompute when no buffer contents have actually changed.
diff.set_diff(left_win, false)
diff.set_diff(right_win, false)
vim.api.nvim_win_set_buf(left_win, pair.left.buf)
vim.api.nvim_win_set_buf(right_win, pair.right.buf)
for _, side in ipairs({ pair.left, pair.right }) do
if side.name then
diff.set_buf_name_and_filetype(side.buf, side.name)
end
end
diff.set_diff(left_win, true)
diff.set_diff(right_win, true)
diff.update_pair(left_win, right_win, pair)
s.last_shown_key = key
if focus_left then
@@ -744,7 +733,7 @@ local function preview_or_open(focus_left)
if not s or not entry then
return
end
show_diff(s, entry, focus_left)
view_entry(s, entry, focus_left)
end
local function action_stage()
@@ -876,7 +865,7 @@ local function open(worktree)
end
local previous_win = vim.api.nvim_get_current_win()
local bufnr, win = git.new_scratch({ split = "left", bufhidden = "wipe" })
local bufnr, win = util.new_scratch({ split = "left", bufhidden = "wipe" })
vim.bo[bufnr].filetype = "gitsidebar"
vim.wo[win].number = false