fix(git): resolve sidebar and diff-split rendering bugs
This commit is contained in:
+45
-35
@@ -34,6 +34,7 @@ local SIDEBAR_WIDTH = 50
|
||||
---@field worktree string
|
||||
---@field lines table<integer, ow.Git.SidebarEntry>
|
||||
---@field sidebar_win integer?
|
||||
---@field invocation_win integer? window focused when the sidebar opened. The first diff repurposes it as the right pane
|
||||
---@field diff_left_win integer?
|
||||
---@field diff_right_win integer?
|
||||
---@field user_aucmd integer?
|
||||
@@ -575,39 +576,30 @@ local function reset_diff_win(win)
|
||||
end)
|
||||
end
|
||||
|
||||
---@param sidebar_win integer
|
||||
---Validate the window the user was in when the sidebar opened. The first
|
||||
---diff repurposes it as the right pane, regardless of whether it holds an
|
||||
---empty buffer or a real file. Returns nil if the user closed it, moved
|
||||
---to another tabpage, or it's somehow the sidebar itself.
|
||||
---@param s ow.Git.SidebarState
|
||||
---@return integer?
|
||||
local function find_default_main_win(sidebar_win)
|
||||
local non_sidebar = {}
|
||||
for _, win in ipairs(vim.api.nvim_tabpage_list_wins(0)) do
|
||||
if win ~= sidebar_win then
|
||||
table.insert(non_sidebar, win)
|
||||
end
|
||||
end
|
||||
if #non_sidebar ~= 1 then
|
||||
local function invocation_win_for(s)
|
||||
local win = s.invocation_win
|
||||
if not win or not vim.api.nvim_win_is_valid(win) then
|
||||
return nil
|
||||
end
|
||||
local buf = vim.api.nvim_win_get_buf(non_sidebar[1])
|
||||
if
|
||||
vim.api.nvim_buf_get_name(buf) == ""
|
||||
and vim.bo[buf].buftype == ""
|
||||
and not vim.bo[buf].modified
|
||||
and vim.api.nvim_buf_line_count(buf) == 1
|
||||
and vim.api.nvim_buf_get_lines(buf, 0, 1, false)[1] == ""
|
||||
then
|
||||
return non_sidebar[1]
|
||||
if win == s.sidebar_win then
|
||||
return nil
|
||||
end
|
||||
if
|
||||
vim.api.nvim_win_get_tabpage(win)
|
||||
~= vim.api.nvim_get_current_tabpage()
|
||||
then
|
||||
return nil
|
||||
end
|
||||
return win
|
||||
end
|
||||
|
||||
---@param win integer
|
||||
---@param enabled boolean
|
||||
local function set_diff(win, enabled)
|
||||
vim.wo[win].diff = enabled
|
||||
if enabled then
|
||||
vim.wo[win].foldenable = true
|
||||
vim.wo[win].foldlevel = 0
|
||||
end
|
||||
end
|
||||
local set_diff = diff.set_diff
|
||||
|
||||
---@param s ow.Git.SidebarState
|
||||
---@param sidebar_win integer
|
||||
@@ -696,18 +688,19 @@ local function show_diff(s, entry, focus_left)
|
||||
left_win = vsplit_at(right_win, "left")
|
||||
reset_diff_win(left_win)
|
||||
elseif not (left_win or right_win) then
|
||||
local default_main = find_default_main_win(sidebar_win)
|
||||
if default_main then
|
||||
right_win = default_main
|
||||
local target = invocation_win_for(s)
|
||||
if target then
|
||||
right_win = target
|
||||
reset_diff_win(right_win)
|
||||
left_win = vsplit_at(right_win, "left")
|
||||
reset_diff_win(left_win)
|
||||
else
|
||||
-- No reusable default-empty window. Open the diff pair by
|
||||
-- splitting from the sidebar. winfixwidth keeps the sidebar at 50
|
||||
-- when there are other windows to absorb the split; if the
|
||||
-- sidebar is the only window in the tab, the split has to take
|
||||
-- from the sidebar itself, so restore the width explicitly.
|
||||
-- Invocation window is gone (closed or in another tabpage).
|
||||
-- Open the diff pair by splitting from the sidebar. winfixwidth
|
||||
-- keeps the sidebar at 50 when there are other windows to
|
||||
-- absorb the split; if the sidebar is the only window in the
|
||||
-- tab, the split has to take from the sidebar itself, so
|
||||
-- restore the width explicitly.
|
||||
right_win = vsplit_at(sidebar_win, "right")
|
||||
reset_diff_win(right_win)
|
||||
left_win = vsplit_at(right_win, "left")
|
||||
@@ -725,6 +718,13 @@ 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.
|
||||
set_diff(left_win, false)
|
||||
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
|
||||
@@ -732,6 +732,15 @@ local function show_diff(s, entry, focus_left)
|
||||
diff.set_buf_name_and_filetype(side.buf, side.name)
|
||||
end
|
||||
end
|
||||
-- Synthetic index/HEAD buffers never run BufRead, so modeline-only
|
||||
-- filetypes aren't detected. Copy from the side that did resolve.
|
||||
local left_ft = vim.bo[pair.left.buf].filetype
|
||||
local right_ft = vim.bo[pair.right.buf].filetype
|
||||
if left_ft == "" and right_ft ~= "" then
|
||||
vim.bo[pair.left.buf].filetype = right_ft
|
||||
elseif right_ft == "" and left_ft ~= "" then
|
||||
vim.bo[pair.right.buf].filetype = left_ft
|
||||
end
|
||||
set_diff(left_win, true)
|
||||
set_diff(right_win, true)
|
||||
s.last_shown_key = key
|
||||
@@ -897,6 +906,7 @@ local function open(worktree)
|
||||
worktree = worktree,
|
||||
lines = {},
|
||||
sidebar_win = win,
|
||||
invocation_win = previous_win,
|
||||
}
|
||||
|
||||
local function k(lhs, rhs, desc)
|
||||
|
||||
Reference in New Issue
Block a user