237 lines
7.4 KiB
Lua
237 lines
7.4 KiB
Lua
local h = require("test.git.helpers")
|
|
local t = require("test")
|
|
|
|
---Replicate the user's global cursor-restore autocmd. Scoped to a
|
|
---named augroup + cleanup so it doesn't leak between tests.
|
|
local function install_cursor_restore_autocmd()
|
|
local group =
|
|
vim.api.nvim_create_augroup("test.cursor_restore", { clear = true })
|
|
vim.api.nvim_create_autocmd("BufReadPost", {
|
|
group = group,
|
|
pattern = "*",
|
|
command = 'silent! normal! g`"zv',
|
|
})
|
|
t.defer(function()
|
|
pcall(vim.api.nvim_del_augroup_by_name, "test.cursor_restore")
|
|
end)
|
|
end
|
|
|
|
---@param sidebar_buf integer
|
|
---@param needle string
|
|
---@return integer?
|
|
local function find_line(sidebar_buf, needle)
|
|
for i, l in ipairs(vim.api.nvim_buf_get_lines(sidebar_buf, 0, -1, false)) do
|
|
if l:match(needle) then
|
|
return i
|
|
end
|
|
end
|
|
end
|
|
|
|
---Find the gitstatus sidebar window in the current tabpage.
|
|
---@return integer? sidebar_buf
|
|
---@return integer? sidebar_win
|
|
local function find_sidebar()
|
|
for _, w in ipairs(vim.api.nvim_tabpage_list_wins(0)) do
|
|
local b = vim.api.nvim_win_get_buf(w)
|
|
if vim.bo[b].filetype == "gitstatus" then
|
|
return b, w
|
|
end
|
|
end
|
|
end
|
|
|
|
---Find a diff window in the given tabpage (or current). "left" / "right"
|
|
---is determined by column position: the layout is [sidebar | left | right],
|
|
---so the leftmost &diff window is the left pane and the rightmost is the
|
|
---right pane.
|
|
---@param role "left"|"right"
|
|
---@param tab integer?
|
|
---@return integer?
|
|
local function find_diff_win(role, tab)
|
|
local diffs = {}
|
|
for _, w in ipairs(vim.api.nvim_tabpage_list_wins(tab or 0)) do
|
|
if vim.wo[w].diff then
|
|
table.insert(diffs, w)
|
|
end
|
|
end
|
|
table.sort(diffs, function(a, b)
|
|
return vim.api.nvim_win_get_position(a)[2]
|
|
< vim.api.nvim_win_get_position(b)[2]
|
|
end)
|
|
if role == "left" then
|
|
return diffs[1]
|
|
end
|
|
return diffs[#diffs]
|
|
end
|
|
|
|
---@param file_path string
|
|
---@param committed_content string
|
|
---@param worktree_content string
|
|
---@return integer sidebar_win
|
|
---@return integer entry_line
|
|
local function setup_sidebar_with_unstaged_file(
|
|
file_path,
|
|
committed_content,
|
|
worktree_content
|
|
)
|
|
local repo = h.make_repo({ [file_path] = committed_content })
|
|
t.write(repo, file_path, worktree_content)
|
|
vim.cmd("cd " .. repo)
|
|
|
|
require("git.status_view").open({ placement = "sidebar" })
|
|
local sidebar_buf, sidebar_win = find_sidebar()
|
|
assert(sidebar_buf, "sidebar buffer should exist")
|
|
assert(sidebar_win, "sidebar window should exist")
|
|
|
|
local r = assert(
|
|
require("git.core.repo").find(vim.fn.getcwd()),
|
|
"repo should resolve for the test worktree"
|
|
)
|
|
r:refresh()
|
|
t.wait_for(function()
|
|
return r.status and #r.status:rows("unstaged") > 0
|
|
end, "git status to report unstaged changes")
|
|
|
|
local entry_line = assert(
|
|
find_line(sidebar_buf, vim.pesc(file_path) .. "$"),
|
|
file_path .. " should appear in sidebar"
|
|
)
|
|
return sidebar_win, entry_line
|
|
end
|
|
|
|
t.test("stage with diff open: sidebar cursor stays put", function()
|
|
install_cursor_restore_autocmd()
|
|
local sidebar_win, line = setup_sidebar_with_unstaged_file(
|
|
"zsh/rc",
|
|
"ZSH=true\n",
|
|
"ZSH=true\nmodified\n"
|
|
)
|
|
|
|
vim.api.nvim_set_current_win(sidebar_win)
|
|
vim.api.nvim_win_set_cursor(sidebar_win, { line, 0 })
|
|
|
|
t.press("<Tab>")
|
|
t.wait_for(function()
|
|
return find_diff_win("left") ~= nil
|
|
end, "diff windows to appear")
|
|
|
|
local r = assert(require("git.core.repo").find(vim.fn.getcwd()))
|
|
vim.api.nvim_set_current_win(sidebar_win)
|
|
t.press("s")
|
|
t.wait_for(function()
|
|
return #r.status:rows("staged") > 0
|
|
end, "stage to propagate to repo state")
|
|
|
|
t.eq(
|
|
vim.api.nvim_win_get_cursor(sidebar_win),
|
|
{ line, 0 },
|
|
"sidebar cursor should remain at the entry's original line"
|
|
)
|
|
end)
|
|
|
|
t.test(
|
|
"stage with diff open: diff foldmethod is preserved on refresh",
|
|
function()
|
|
local sidebar_win, line = setup_sidebar_with_unstaged_file(
|
|
"zsh/rc",
|
|
"# vim: set ft=zsh nowrap:\nZSH=true\n",
|
|
"# vim: set ft=zsh nowrap:\nZSH=true\nmodified\n"
|
|
)
|
|
|
|
vim.api.nvim_set_current_win(sidebar_win)
|
|
vim.api.nvim_win_set_cursor(sidebar_win, { line, 0 })
|
|
|
|
t.press("<Tab>")
|
|
t.wait_for(function()
|
|
return find_diff_win("left") ~= nil
|
|
end, "diff windows to appear")
|
|
local left_win = assert(find_diff_win("left"))
|
|
t.eq(
|
|
vim.wo[left_win].foldmethod,
|
|
"diff",
|
|
"left diff foldmethod should be 'diff' after Tab"
|
|
)
|
|
|
|
local r = assert(require("git.core.repo").find(vim.fn.getcwd()))
|
|
vim.api.nvim_set_current_win(sidebar_win)
|
|
t.press("s")
|
|
t.wait_for(function()
|
|
return #r.status:rows("staged") > 0
|
|
end, "stage to propagate to repo state")
|
|
|
|
t.eq(
|
|
vim.wo[left_win].foldmethod,
|
|
"diff",
|
|
"left diff foldmethod should still be 'diff' after stage refresh"
|
|
)
|
|
end
|
|
)
|
|
|
|
t.test(
|
|
"<Tab> in a second tabpage opens the diff inside that tabpage",
|
|
function()
|
|
local sidebar_win, line =
|
|
setup_sidebar_with_unstaged_file("foo.txt", "v1\n", "v2\n")
|
|
local tab1 = vim.api.nvim_get_current_tabpage()
|
|
|
|
vim.api.nvim_set_current_win(sidebar_win)
|
|
vim.api.nvim_win_set_cursor(sidebar_win, { line, 0 })
|
|
t.press("<Tab>")
|
|
t.wait_for(function()
|
|
return find_diff_win("left", tab1) ~= nil
|
|
end, "diff windows in tab1 to appear")
|
|
|
|
vim.cmd("tabnew")
|
|
require("git.status_view").open({ placement = "sidebar" })
|
|
local tab2 = vim.api.nvim_get_current_tabpage()
|
|
t.truthy(tab2 ~= tab1, "tabnew should produce a distinct tabpage")
|
|
|
|
local _, sidebar_win2 = find_sidebar()
|
|
assert(sidebar_win2, "sidebar window should exist in tab2")
|
|
vim.api.nvim_set_current_win(sidebar_win2)
|
|
vim.api.nvim_win_set_cursor(sidebar_win2, { line, 0 })
|
|
|
|
t.press("<Tab>")
|
|
t.wait_for(function()
|
|
return find_diff_win("left", tab2) ~= nil
|
|
end, "diff windows in tab2 to appear")
|
|
|
|
t.truthy(
|
|
find_diff_win("right", tab2),
|
|
"right diff window should be in tab2"
|
|
)
|
|
end
|
|
)
|
|
|
|
t.test("refresh on stage updates the index URI buffer's content", function()
|
|
local sidebar_win, line =
|
|
setup_sidebar_with_unstaged_file("foo.txt", "v1\n", "v2\n")
|
|
|
|
vim.api.nvim_set_current_win(sidebar_win)
|
|
vim.api.nvim_win_set_cursor(sidebar_win, { line, 0 })
|
|
t.press("<Tab>")
|
|
t.wait_for(function()
|
|
return find_diff_win("left") ~= nil
|
|
end, "diff windows to appear")
|
|
|
|
local left_win = assert(find_diff_win("left"))
|
|
local index_buf = vim.api.nvim_win_get_buf(left_win)
|
|
t.eq(
|
|
vim.api.nvim_buf_get_lines(index_buf, 0, -1, false),
|
|
{ "v1" },
|
|
"index pane should initially show committed content"
|
|
)
|
|
|
|
vim.api.nvim_set_current_win(sidebar_win)
|
|
t.press("s")
|
|
t.wait_for(function()
|
|
local first = vim.api.nvim_buf_get_lines(index_buf, 0, -1, false)[1]
|
|
return first == "v2"
|
|
end, "index pane to refresh to staged content")
|
|
|
|
t.eq(
|
|
vim.api.nvim_buf_get_lines(index_buf, 0, -1, false),
|
|
{ "v2" },
|
|
"index pane should reflect staged content after refresh"
|
|
)
|
|
end)
|