refactor(git): rebuild status_view diff layout per selection
This commit is contained in:
+42
-130
@@ -39,11 +39,7 @@ end
|
||||
---@field placement ow.Git.StatusView.Placement
|
||||
---@field lines table<integer, ow.Git.StatusView.Item>
|
||||
---@field win integer?
|
||||
---@field invocation_win integer?
|
||||
---@field diff_left_win integer?
|
||||
---@field diff_right_win integer?
|
||||
---@field unsubscribe fun()?
|
||||
---@field last_shown_key string?
|
||||
|
||||
---@type table<integer, ow.Git.StatusView.State>
|
||||
local state = {}
|
||||
@@ -165,7 +161,6 @@ local function refresh(bufnr)
|
||||
if not s or not vim.api.nvim_buf_is_valid(bufnr) then
|
||||
return
|
||||
end
|
||||
s.last_shown_key = nil
|
||||
render(bufnr, s.repo.status)
|
||||
end
|
||||
|
||||
@@ -264,62 +259,6 @@ local function reset_diff_win(win)
|
||||
end)
|
||||
end
|
||||
|
||||
---@param s ow.Git.StatusView.State
|
||||
---@return integer?
|
||||
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
|
||||
if win == s.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 s ow.Git.StatusView.State
|
||||
---@param status_win integer
|
||||
---@return integer? left
|
||||
---@return integer? right
|
||||
local function adopt_diff_wins(s, status_win)
|
||||
local left = valid_in_current_tab(s.diff_left_win) and s.diff_left_win
|
||||
or nil
|
||||
local right = valid_in_current_tab(s.diff_right_win) and s.diff_right_win
|
||||
or nil
|
||||
if left and right then
|
||||
return left, right
|
||||
end
|
||||
for _, win in ipairs(vim.api.nvim_tabpage_list_wins(0)) do
|
||||
if win ~= status_win then
|
||||
local role = vim.w[win].git_diff_role
|
||||
if role == "left" and not left then
|
||||
left = win
|
||||
elseif role == "right" and not right then
|
||||
right = win
|
||||
end
|
||||
end
|
||||
end
|
||||
return left, right
|
||||
end
|
||||
|
||||
---@param row ow.Git.Status.Row
|
||||
---@return string
|
||||
local function row_key(row)
|
||||
local entry = row.entry
|
||||
local orig
|
||||
if entry.kind == "changed" then
|
||||
---@cast entry ow.Git.Status.ChangedEntry
|
||||
orig = entry.orig
|
||||
end
|
||||
return row.section .. "|" .. entry.path .. "|" .. (orig or "")
|
||||
end
|
||||
|
||||
---@param target_win integer
|
||||
---@param dir "left"|"right"
|
||||
---@return integer
|
||||
@@ -333,23 +272,32 @@ local function vsplit_at(target_win, dir)
|
||||
return win
|
||||
end
|
||||
|
||||
---@param s ow.Git.StatusView.State
|
||||
---@param status_win integer
|
||||
---@param right_win integer?
|
||||
---@return integer
|
||||
local function ensure_right_win(s, status_win, right_win)
|
||||
if right_win then
|
||||
return right_win
|
||||
---@return integer?
|
||||
local function previous_target_win(status_win)
|
||||
local n = vim.fn.winnr("#")
|
||||
if n == 0 then
|
||||
return nil
|
||||
end
|
||||
local target = invocation_win_for(s)
|
||||
if target then
|
||||
right_win = target
|
||||
else
|
||||
right_win = vsplit_at(status_win, "right")
|
||||
vim.api.nvim_win_set_width(status_win, WINDOW_WIDTH)
|
||||
local win = vim.fn.win_getid(n)
|
||||
if win == 0 or win == status_win or not valid_in_current_tab(win) then
|
||||
return nil
|
||||
end
|
||||
local cfg = vim.api.nvim_win_get_config(win)
|
||||
if cfg.relative and cfg.relative ~= "" then
|
||||
return nil
|
||||
end
|
||||
return win
|
||||
end
|
||||
|
||||
---@param status_win integer
|
||||
---@param keep integer
|
||||
local function close_other_diff_wins(status_win, keep)
|
||||
for _, win in ipairs(vim.api.nvim_tabpage_list_wins(0)) do
|
||||
if win ~= status_win and win ~= keep and vim.wo[win].diff then
|
||||
pcall(vim.api.nvim_win_close, win, false)
|
||||
end
|
||||
end
|
||||
reset_diff_win(right_win)
|
||||
return right_win
|
||||
end
|
||||
|
||||
---@param s ow.Git.StatusView.State
|
||||
@@ -384,68 +332,35 @@ local function view_row(s, row, focus_left)
|
||||
return
|
||||
end
|
||||
|
||||
local key = row_key(row)
|
||||
local left_win, right_win = adopt_diff_wins(s, status_win)
|
||||
local want_pair = left and right
|
||||
|
||||
if s.last_shown_key == key then
|
||||
local intact = (want_pair and left_win and right_win)
|
||||
or (not want_pair and right_win and not left_win)
|
||||
if intact then
|
||||
local target = focus_left and (left_win or right_win) or status_win
|
||||
vim.api.nvim_set_current_win(target)
|
||||
return
|
||||
end
|
||||
local target = previous_target_win(status_win)
|
||||
if not target then
|
||||
target = vsplit_at(status_win, "right")
|
||||
end
|
||||
close_other_diff_wins(status_win, target)
|
||||
vim.api.nvim_win_set_width(status_win, WINDOW_WIDTH)
|
||||
reset_diff_win(target)
|
||||
diff.set_diff(target, false)
|
||||
|
||||
if not want_pair then
|
||||
if left_win and vim.api.nvim_win_is_valid(left_win) then
|
||||
pcall(vim.api.nvim_win_close, left_win, false)
|
||||
left_win = nil
|
||||
s.diff_left_win = nil
|
||||
end
|
||||
right_win = ensure_right_win(s, status_win, right_win)
|
||||
s.diff_right_win = right_win
|
||||
vim.w[right_win].git_diff_role = "right"
|
||||
local side = left or right
|
||||
if not (left and right) then
|
||||
local side = right or left
|
||||
---@cast side ow.Git.Diff.Side
|
||||
diff.set_diff(right_win, false)
|
||||
vim.api.nvim_win_set_buf(right_win, side.buf)
|
||||
vim.api.nvim_win_set_buf(target, side.buf)
|
||||
if side.name then
|
||||
util.set_buf_name(side.buf, side.name)
|
||||
end
|
||||
s.last_shown_key = key
|
||||
vim.api.nvim_set_current_win(focus_left and right_win or status_win)
|
||||
vim.api.nvim_set_current_win(focus_left and target or status_win)
|
||||
return
|
||||
end
|
||||
---@cast left ow.Git.Diff.Side
|
||||
---@cast right ow.Git.Diff.Side
|
||||
|
||||
if left_win and not right_win then
|
||||
right_win = vsplit_at(left_win, "right")
|
||||
reset_diff_win(right_win)
|
||||
elseif right_win and not left_win then
|
||||
left_win = vsplit_at(right_win, "left")
|
||||
reset_diff_win(left_win)
|
||||
elseif not (left_win or right_win) then
|
||||
right_win = ensure_right_win(s, status_win, nil)
|
||||
left_win = vsplit_at(right_win, "left")
|
||||
reset_diff_win(left_win)
|
||||
local combined = vim.api.nvim_win_get_width(left_win)
|
||||
+ vim.api.nvim_win_get_width(right_win)
|
||||
vim.api.nvim_win_set_width(left_win, math.floor(combined / 2))
|
||||
end
|
||||
---@cast left_win -nil
|
||||
---@cast right_win -nil
|
||||
|
||||
vim.w[left_win].git_diff_role = "left"
|
||||
vim.w[right_win].git_diff_role = "right"
|
||||
s.diff_left_win = left_win
|
||||
s.diff_right_win = right_win
|
||||
|
||||
diff.update_pair(left_win, right_win, { left = left, right = right })
|
||||
s.last_shown_key = key
|
||||
local left_win = vsplit_at(target, "left")
|
||||
reset_diff_win(left_win)
|
||||
local combined = vim.api.nvim_win_get_width(left_win)
|
||||
+ vim.api.nvim_win_get_width(target)
|
||||
vim.api.nvim_win_set_width(left_win, math.floor(combined / 2))
|
||||
|
||||
diff.update_pair(left_win, target, { left = left, right = right })
|
||||
vim.api.nvim_set_current_win(focus_left and left_win or status_win)
|
||||
end
|
||||
|
||||
@@ -640,14 +555,12 @@ end
|
||||
---@param r ow.Git.Repo
|
||||
---@param placement ow.Git.StatusView.Placement
|
||||
---@param win integer?
|
||||
---@param invocation_win integer?
|
||||
local function setup_buffer(bufnr, r, placement, win, invocation_win)
|
||||
local function setup_buffer(bufnr, r, placement, win)
|
||||
state[bufnr] = {
|
||||
repo = r,
|
||||
placement = placement,
|
||||
lines = {},
|
||||
win = win,
|
||||
invocation_win = invocation_win,
|
||||
}
|
||||
|
||||
local function k(lhs, rhs, desc)
|
||||
@@ -743,7 +656,6 @@ function M.open(opts)
|
||||
local s = state[buf]
|
||||
if s then
|
||||
s.win = win
|
||||
s.invocation_win = previous_win
|
||||
s.placement = placement
|
||||
end
|
||||
set_keymaps(buf, placement)
|
||||
@@ -805,7 +717,7 @@ function M.read_uri(buf)
|
||||
win = nil
|
||||
end
|
||||
if not state[buf] then
|
||||
setup_buffer(buf, r, "current", win, nil)
|
||||
setup_buffer(buf, r, "current", win)
|
||||
else
|
||||
state[buf].win = win
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user