fix(git/status_view): scope dispatch to current tabpage + test cleanup
This commit is contained in:
+2
-3
@@ -2,7 +2,7 @@
|
|||||||
"$schema": "https://raw.githubusercontent.com/EmmyLuaLs/emmylua-analyzer-rust/refs/heads/main/crates/emmylua_code_analysis/resources/schema.json",
|
"$schema": "https://raw.githubusercontent.com/EmmyLuaLs/emmylua-analyzer-rust/refs/heads/main/crates/emmylua_code_analysis/resources/schema.json",
|
||||||
"runtime": {
|
"runtime": {
|
||||||
"version": "LuaJIT",
|
"version": "LuaJIT",
|
||||||
"requirePattern": ["lua/?.lua", "lua/?/init.lua"]
|
"requirePattern": ["?.lua", "?/init.lua", "lua/?.lua", "lua/?/init.lua"]
|
||||||
},
|
},
|
||||||
"diagnostics": {
|
"diagnostics": {
|
||||||
"disable": ["unnecessary-if", "preferred-local-alias", "redefined-local"]
|
"disable": ["unnecessary-if", "preferred-local-alias", "redefined-local"]
|
||||||
@@ -23,8 +23,7 @@
|
|||||||
"~/.local/share/nvim/site/pack/core/opt/nvim-tree.lua",
|
"~/.local/share/nvim/site/pack/core/opt/nvim-tree.lua",
|
||||||
"~/.local/share/nvim/site/pack/core/opt/oil.nvim",
|
"~/.local/share/nvim/site/pack/core/opt/oil.nvim",
|
||||||
"~/.local/share/nvim/site/pack/core/opt/outline.nvim",
|
"~/.local/share/nvim/site/pack/core/opt/outline.nvim",
|
||||||
"~/.local/share/nvim/site/pack/core/opt/blink.cmp",
|
"~/.local/share/nvim/site/pack/core/opt/blink.cmp"
|
||||||
"./test"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-12
@@ -62,14 +62,23 @@ local function find_view()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param win integer?
|
||||||
|
---@return boolean
|
||||||
|
local function valid_in_current_tab(win)
|
||||||
|
if not win or not vim.api.nvim_win_is_valid(win) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return vim.api.nvim_win_get_tabpage(win)
|
||||||
|
== vim.api.nvim_get_current_tabpage()
|
||||||
|
end
|
||||||
|
|
||||||
---@param s ow.Git.StatusView.State
|
---@param s ow.Git.StatusView.State
|
||||||
---@return integer?
|
---@return integer?
|
||||||
local function win_for(s)
|
local function win_for(s)
|
||||||
local win = s.win
|
if valid_in_current_tab(s.win) then
|
||||||
if win and vim.api.nvim_win_is_valid(win) then
|
return s.win
|
||||||
return win
|
|
||||||
end
|
end
|
||||||
win = find_view()
|
local win = find_view()
|
||||||
s.win = win
|
s.win = win
|
||||||
return win
|
return win
|
||||||
end
|
end
|
||||||
@@ -267,14 +276,10 @@ end
|
|||||||
---@return integer? left
|
---@return integer? left
|
||||||
---@return integer? right
|
---@return integer? right
|
||||||
local function adopt_diff_wins(s, status_win)
|
local function adopt_diff_wins(s, status_win)
|
||||||
local left = s.diff_left_win
|
local left = valid_in_current_tab(s.diff_left_win) and s.diff_left_win
|
||||||
local right = s.diff_right_win
|
or nil
|
||||||
if left and not vim.api.nvim_win_is_valid(left) then
|
local right = valid_in_current_tab(s.diff_right_win) and s.diff_right_win
|
||||||
left = nil
|
or nil
|
||||||
end
|
|
||||||
if right and not vim.api.nvim_win_is_valid(right) then
|
|
||||||
right = nil
|
|
||||||
end
|
|
||||||
if left and right then
|
if left and right then
|
||||||
return left, right
|
return left, right
|
||||||
end
|
end
|
||||||
|
|||||||
+62
-52
@@ -1,15 +1,13 @@
|
|||||||
local t = require("test")
|
|
||||||
local helpers = require("test.git.helpers")
|
|
||||||
local cmd = require("git.cmd")
|
local cmd = require("git.cmd")
|
||||||
|
local h = require("test.git.helpers")
|
||||||
|
local t = require("test")
|
||||||
|
|
||||||
require("git").init()
|
require("git").init()
|
||||||
|
|
||||||
local git = helpers.git
|
|
||||||
|
|
||||||
---@param files table<string, string>?
|
---@param files table<string, string>?
|
||||||
---@return string dir
|
---@return string dir
|
||||||
local function make_repo(files)
|
local function make_repo(files)
|
||||||
return helpers.make_repo(files, { cd = true })
|
return h.make_repo(files, { cd = true })
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param actual string[]
|
---@param actual string[]
|
||||||
@@ -49,12 +47,9 @@ t.test("parse_args handles escaped quote inside double quotes", function()
|
|||||||
t.eq(cmd.parse_args([["a\"b" c]]), { 'a"b', "c" })
|
t.eq(cmd.parse_args([["a\"b" c]]), { 'a"b', "c" })
|
||||||
end)
|
end)
|
||||||
|
|
||||||
t.test(
|
t.test("parse_args treats backslash literally inside single quotes", function()
|
||||||
"parse_args treats backslash literally inside single quotes",
|
|
||||||
function()
|
|
||||||
t.eq(cmd.parse_args([['a\b' c]]), { "a\\b", "c" })
|
t.eq(cmd.parse_args([['a\b' c]]), { "a\\b", "c" })
|
||||||
end
|
end)
|
||||||
)
|
|
||||||
|
|
||||||
t.test("parse_args concatenates adjacent quoted segments", function()
|
t.test("parse_args concatenates adjacent quoted segments", function()
|
||||||
t.eq(cmd.parse_args([[foo"bar"baz]]), { "foobarbaz" })
|
t.eq(cmd.parse_args([[foo"bar"baz]]), { "foobarbaz" })
|
||||||
@@ -162,19 +157,19 @@ end)
|
|||||||
|
|
||||||
t.test("complete branch returns plain refs (no pseudo, no stash)", function()
|
t.test("complete branch returns plain refs (no pseudo, no stash)", function()
|
||||||
local dir = make_repo({ a = "x" })
|
local dir = make_repo({ a = "x" })
|
||||||
git(dir, "branch", "feature")
|
h.git(dir, "branch", "feature")
|
||||||
git(dir, "tag", "v1")
|
h.git(dir, "tag", "v1")
|
||||||
t.write(dir, "a", "modified")
|
t.write(dir, "a", "modified")
|
||||||
git(dir, "stash")
|
h.git(dir, "stash")
|
||||||
local matches = cmd.complete("", "G branch ", 9)
|
local matches = cmd.complete("", "G branch ", 9)
|
||||||
eq_sorted(matches, { "feature", "main", "v1" })
|
eq_sorted(matches, { "feature", "main", "v1" })
|
||||||
end)
|
end)
|
||||||
|
|
||||||
t.test("complete merge returns refs + pseudo + stash", function()
|
t.test("complete merge returns refs + pseudo + stash", function()
|
||||||
local dir = make_repo({ a = "x" })
|
local dir = make_repo({ a = "x" })
|
||||||
git(dir, "branch", "feature")
|
h.git(dir, "branch", "feature")
|
||||||
t.write(dir, "a", "y")
|
t.write(dir, "a", "y")
|
||||||
git(dir, "stash")
|
h.git(dir, "stash")
|
||||||
local matches = cmd.complete("", "G merge ", 8)
|
local matches = cmd.complete("", "G merge ", 8)
|
||||||
eq_sorted(
|
eq_sorted(
|
||||||
matches,
|
matches,
|
||||||
@@ -184,15 +179,15 @@ end)
|
|||||||
|
|
||||||
t.test("complete push first positional returns remotes", function()
|
t.test("complete push first positional returns remotes", function()
|
||||||
local dir = make_repo({ a = "x" })
|
local dir = make_repo({ a = "x" })
|
||||||
git(dir, "remote", "add", "origin", "/tmp/nope")
|
h.git(dir, "remote", "add", "origin", "/tmp/nope")
|
||||||
git(dir, "remote", "add", "upstream", "/tmp/nope")
|
h.git(dir, "remote", "add", "upstream", "/tmp/nope")
|
||||||
local matches = cmd.complete("", "G push ", 7)
|
local matches = cmd.complete("", "G push ", 7)
|
||||||
eq_sorted(matches, { "origin", "upstream" })
|
eq_sorted(matches, { "origin", "upstream" })
|
||||||
end)
|
end)
|
||||||
|
|
||||||
t.test("complete push second positional returns refs", function()
|
t.test("complete push second positional returns refs", function()
|
||||||
local dir = make_repo({ a = "x" })
|
local dir = make_repo({ a = "x" })
|
||||||
git(dir, "branch", "feature")
|
h.git(dir, "branch", "feature")
|
||||||
local matches = cmd.complete("", "G push origin ", 14)
|
local matches = cmd.complete("", "G push origin ", 14)
|
||||||
eq_sorted(matches, { "HEAD", "feature", "main" })
|
eq_sorted(matches, { "HEAD", "feature", "main" })
|
||||||
end)
|
end)
|
||||||
@@ -203,9 +198,9 @@ t.test("complete add returns only unstaged/untracked paths", function()
|
|||||||
t.write(dir, "newfile", "new")
|
t.write(dir, "newfile", "new")
|
||||||
local r = assert(require("git.repo").resolve(dir))
|
local r = assert(require("git.repo").resolve(dir))
|
||||||
r:refresh()
|
r:refresh()
|
||||||
vim.wait(500, function()
|
t.wait_for(function()
|
||||||
return r.status and #vim.tbl_keys(r.status.entries) > 0
|
return r.status and #vim.tbl_keys(r.status.entries) > 0
|
||||||
end)
|
end, "git status to report entries", 500)
|
||||||
local matches = cmd.complete("", "G add ", 6)
|
local matches = cmd.complete("", "G add ", 6)
|
||||||
eq_sorted(matches, { "newfile", "tracked" })
|
eq_sorted(matches, { "newfile", "tracked" })
|
||||||
end)
|
end)
|
||||||
@@ -218,19 +213,19 @@ t.test("complete after `--` returns tracked paths only", function()
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
t.test("complete stash returns subsubcommands", function()
|
t.test("complete stash returns subsubcommands", function()
|
||||||
local dir = make_repo({ a = "x" })
|
make_repo({ a = "x" })
|
||||||
local matches = cmd.complete("p", "G stash p", 9)
|
local matches = cmd.complete("p", "G stash p", 9)
|
||||||
eq_sorted(matches, { "pop", "push" })
|
eq_sorted(matches, { "pop", "push" })
|
||||||
end)
|
end)
|
||||||
|
|
||||||
t.test("complete show with <rev>:<path> returns tree paths", function()
|
t.test("complete show with <rev>:<path> returns tree paths", function()
|
||||||
local dir = make_repo({ a = "x", ["sub/b"] = "y" })
|
make_repo({ a = "x", ["sub/b"] = "y" })
|
||||||
local matches = cmd.complete("HEAD:", "G show HEAD:", 12)
|
local matches = cmd.complete("HEAD:", "G show HEAD:", 12)
|
||||||
eq_sorted(matches, { "HEAD:a", "HEAD:sub/" })
|
eq_sorted(matches, { "HEAD:a", "HEAD:sub/" })
|
||||||
end)
|
end)
|
||||||
|
|
||||||
t.test("complete unknown subcommand falls back to tracked paths", function()
|
t.test("complete unknown subcommand falls back to tracked paths", function()
|
||||||
local dir = make_repo({ a = "x", b = "y" })
|
make_repo({ a = "x", b = "y" })
|
||||||
local matches = cmd.complete("", "G nonexistent ", 14)
|
local matches = cmd.complete("", "G nonexistent ", 14)
|
||||||
eq_sorted(matches, { "a", "b" })
|
eq_sorted(matches, { "a", "b" })
|
||||||
end)
|
end)
|
||||||
@@ -250,14 +245,35 @@ end
|
|||||||
---@param buf_name_pattern string
|
---@param buf_name_pattern string
|
||||||
---@param timeout integer?
|
---@param timeout integer?
|
||||||
local function wait_buf_populated(buf_name_pattern, timeout)
|
local function wait_buf_populated(buf_name_pattern, timeout)
|
||||||
vim.wait(timeout or 1000, function()
|
t.wait_for(function()
|
||||||
for _, b in ipairs(vim.api.nvim_list_bufs()) do
|
for _, b in ipairs(vim.api.nvim_list_bufs()) do
|
||||||
if vim.api.nvim_buf_get_name(b):match(buf_name_pattern) then
|
if vim.api.nvim_buf_get_name(b):match(buf_name_pattern) then
|
||||||
return #vim.api.nvim_buf_get_lines(b, 0, -1, false) > 1
|
return #vim.api.nvim_buf_get_lines(b, 0, -1, false) > 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
end)
|
end, "buffer matching " .. buf_name_pattern .. " to populate", timeout)
|
||||||
|
end
|
||||||
|
|
||||||
|
---Wait for a buffer matching `buf_name_pattern` to contain a line whose
|
||||||
|
---content equals `line`. Useful for asserting that re-running a :G
|
||||||
|
---command repopulated the buffer with new output.
|
||||||
|
---@param buf_name_pattern string
|
||||||
|
---@param line string
|
||||||
|
---@param timeout integer?
|
||||||
|
local function wait_buf_has_line(buf_name_pattern, line, timeout)
|
||||||
|
t.wait_for(function()
|
||||||
|
for _, b in ipairs(vim.api.nvim_list_bufs()) do
|
||||||
|
if vim.api.nvim_buf_get_name(b):match(buf_name_pattern) then
|
||||||
|
for _, l in ipairs(vim.api.nvim_buf_get_lines(b, 0, -1, false)) do
|
||||||
|
if l == line then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end, "buffer " .. buf_name_pattern .. " to contain " .. line, timeout)
|
||||||
end
|
end
|
||||||
|
|
||||||
t.test("run :G diff reuses the same buffer across invocations", function()
|
t.test("run :G diff reuses the same buffer across invocations", function()
|
||||||
@@ -265,17 +281,17 @@ t.test("run :G diff reuses the same buffer across invocations", function()
|
|||||||
t.write(dir, "a", "v2\n")
|
t.write(dir, "a", "v2\n")
|
||||||
|
|
||||||
cmd.run({ "diff" })
|
cmd.run({ "diff" })
|
||||||
wait_buf_populated("%[Git diff%]")
|
wait_buf_has_line("%[Git diff%]", "+v2")
|
||||||
local first_count = count_bufs_named("%[Git diff%]")
|
t.eq(count_bufs_named("%[Git diff%]"), 1)
|
||||||
t.eq(first_count, 1)
|
|
||||||
|
|
||||||
t.write(dir, "a", "v3\n")
|
t.write(dir, "a", "v3\n")
|
||||||
cmd.run({ "diff" })
|
cmd.run({ "diff" })
|
||||||
vim.wait(300)
|
wait_buf_has_line("%[Git diff%]", "+v3")
|
||||||
t.eq(count_bufs_named("%[Git diff%]"), 1, "second :G diff should reuse")
|
t.eq(count_bufs_named("%[Git diff%]"), 1, "second :G diff should reuse")
|
||||||
|
|
||||||
|
t.write(dir, "a", "v4\n")
|
||||||
cmd.run({ "diff" })
|
cmd.run({ "diff" })
|
||||||
vim.wait(300)
|
wait_buf_has_line("%[Git diff%]", "+v4")
|
||||||
t.eq(count_bufs_named("%[Git diff%]"), 1, "third :G diff should reuse")
|
t.eq(count_bufs_named("%[Git diff%]"), 1, "third :G diff should reuse")
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@@ -293,13 +309,14 @@ end
|
|||||||
t.test(":G show <CR> on + line opens the blob URI", function()
|
t.test(":G show <CR> on + line opens the blob URI", function()
|
||||||
local dir = make_repo({ a = "first\n" })
|
local dir = make_repo({ a = "first\n" })
|
||||||
t.write(dir, "a", "second\n")
|
t.write(dir, "a", "second\n")
|
||||||
git(dir, "add", "a")
|
h.git(dir, "add", "a")
|
||||||
git(dir, "commit", "-q", "-m", "second")
|
h.git(dir, "commit", "-q", "-m", "second")
|
||||||
local r = assert(require("git.repo").resolve(dir))
|
assert(require("git.repo").resolve(dir))
|
||||||
local blob = vim.trim(git(dir, "rev-parse", "HEAD:a").stdout)
|
local blob = h.git(dir, "rev-parse", "HEAD:a").stdout
|
||||||
|
|
||||||
cmd.run({ "show", "HEAD" })
|
cmd.run({ "show", "HEAD" })
|
||||||
wait_buf_populated("%[Git show HEAD%]")
|
wait_buf_populated("%[Git show HEAD%]")
|
||||||
|
---@type integer?
|
||||||
local diff_buf
|
local diff_buf
|
||||||
for _, b in ipairs(vim.api.nvim_list_bufs()) do
|
for _, b in ipairs(vim.api.nvim_list_bufs()) do
|
||||||
if vim.api.nvim_buf_get_name(b):match("%[Git show HEAD%]") then
|
if vim.api.nvim_buf_get_name(b):match("%[Git show HEAD%]") then
|
||||||
@@ -319,30 +336,23 @@ end)
|
|||||||
t.test("<leader>gl log buffer refills after jumping back", function()
|
t.test("<leader>gl log buffer refills after jumping back", function()
|
||||||
local dir = make_repo({ a = "v1\n" })
|
local dir = make_repo({ a = "v1\n" })
|
||||||
t.write(dir, "a", "v2\n")
|
t.write(dir, "a", "v2\n")
|
||||||
helpers.git(dir, "add", "a")
|
h.git(dir, "add", "a")
|
||||||
helpers.git(dir, "commit", "-q", "-m", "second")
|
h.git(dir, "commit", "-q", "-m", "second")
|
||||||
|
|
||||||
require("git.log_view").open({ max_count = 1000 })
|
require("git.log_view").open({ max_count = 1000 })
|
||||||
wait_buf_populated("^gitlog://")
|
wait_buf_populated("^gitlog://")
|
||||||
local log_buf = vim.api.nvim_get_current_buf()
|
local log_buf = vim.api.nvim_get_current_buf()
|
||||||
local log_win = vim.api.nvim_get_current_win()
|
local log_win = vim.api.nvim_get_current_win()
|
||||||
t.truthy(
|
t.truthy(vim.api.nvim_buf_get_name(log_buf):match("^gitlog://"))
|
||||||
vim.api.nvim_buf_get_name(log_buf):match("^gitlog://")
|
local initial_lines = #vim.api.nvim_buf_get_lines(log_buf, 0, -1, false)
|
||||||
)
|
|
||||||
local initial_lines =
|
|
||||||
#vim.api.nvim_buf_get_lines(log_buf, 0, -1, false)
|
|
||||||
t.truthy(initial_lines >= 2)
|
t.truthy(initial_lines >= 2)
|
||||||
|
|
||||||
-- Step into a commit, then <C-o> back to the log.
|
-- Step into a commit, then <C-o> back to the log.
|
||||||
vim.api.nvim_win_set_cursor(log_win, { 1, 0 })
|
vim.api.nvim_win_set_cursor(log_win, { 1, 0 })
|
||||||
local cr =
|
t.press("<CR>")
|
||||||
vim.api.nvim_replace_termcodes("<CR>", true, false, true)
|
|
||||||
vim.api.nvim_feedkeys(cr, "x", false)
|
|
||||||
t.truthy(vim.api.nvim_buf_get_name(0):match("^git://"))
|
t.truthy(vim.api.nvim_buf_get_name(0):match("^git://"))
|
||||||
|
|
||||||
local co =
|
t.press("<C-o>")
|
||||||
vim.api.nvim_replace_termcodes("<C-o>", true, false, true)
|
|
||||||
vim.api.nvim_feedkeys(co, "x", false)
|
|
||||||
t.eq(vim.api.nvim_get_current_buf(), log_buf)
|
t.eq(vim.api.nvim_get_current_buf(), log_buf)
|
||||||
t.eq(
|
t.eq(
|
||||||
#vim.api.nvim_buf_get_lines(log_buf, 0, -1, false),
|
#vim.api.nvim_buf_get_lines(log_buf, 0, -1, false),
|
||||||
@@ -354,8 +364,8 @@ end)
|
|||||||
t.test("<CR> still dispatches after navigating away and back", function()
|
t.test("<CR> still dispatches after navigating away and back", function()
|
||||||
local dir = make_repo({ a = "v1\n" })
|
local dir = make_repo({ a = "v1\n" })
|
||||||
t.write(dir, "a", "v2\n")
|
t.write(dir, "a", "v2\n")
|
||||||
helpers.git(dir, "add", "a")
|
h.git(dir, "add", "a")
|
||||||
helpers.git(dir, "commit", "-q", "-m", "second")
|
h.git(dir, "commit", "-q", "-m", "second")
|
||||||
|
|
||||||
-- Open the HEAD commit object buffer. Its cat-file output includes a
|
-- Open the HEAD commit object buffer. Its cat-file output includes a
|
||||||
-- "parent <sha>" line we can navigate from.
|
-- "parent <sha>" line we can navigate from.
|
||||||
@@ -376,8 +386,7 @@ t.test("<CR> still dispatches after navigating away and back", function()
|
|||||||
-- <C-o> back to first_obj_buf. With bufhidden=delete, vim re-reads the
|
-- <C-o> back to first_obj_buf. With bufhidden=delete, vim re-reads the
|
||||||
-- URI, which previously raced with BufDelete-driven unbind and left
|
-- URI, which previously raced with BufDelete-driven unbind and left
|
||||||
-- state cleared, so open_under_cursor returned false.
|
-- state cleared, so open_under_cursor returned false.
|
||||||
local co = vim.api.nvim_replace_termcodes("<C-o>", true, false, true)
|
t.press("<C-o>")
|
||||||
vim.api.nvim_feedkeys(co, "x", false)
|
|
||||||
t.eq(vim.api.nvim_get_current_buf(), first_obj_buf)
|
t.eq(vim.api.nvim_get_current_buf(), first_obj_buf)
|
||||||
local tree_lnum = assert(find_line(first_obj_buf, "tree "))
|
local tree_lnum = assert(find_line(first_obj_buf, "tree "))
|
||||||
vim.api.nvim_win_set_cursor(first_obj_win, { tree_lnum, 0 })
|
vim.api.nvim_win_set_cursor(first_obj_win, { tree_lnum, 0 })
|
||||||
@@ -390,10 +399,11 @@ end)
|
|||||||
t.test(":G diff <CR> on + line falls back to worktree file", function()
|
t.test(":G diff <CR> on + line falls back to worktree file", function()
|
||||||
local dir = make_repo({ a = "v1\n" })
|
local dir = make_repo({ a = "v1\n" })
|
||||||
t.write(dir, "a", "v2\n")
|
t.write(dir, "a", "v2\n")
|
||||||
local r = assert(require("git.repo").resolve(dir))
|
assert(require("git.repo").resolve(dir))
|
||||||
|
|
||||||
cmd.run({ "diff" })
|
cmd.run({ "diff" })
|
||||||
wait_buf_populated("%[Git diff%]")
|
wait_buf_populated("%[Git diff%]")
|
||||||
|
---@type integer?
|
||||||
local diff_buf
|
local diff_buf
|
||||||
for _, b in ipairs(vim.api.nvim_list_bufs()) do
|
for _, b in ipairs(vim.api.nvim_list_bufs()) do
|
||||||
if vim.api.nvim_buf_get_name(b):match("%[Git diff%]") then
|
if vim.api.nvim_buf_get_name(b):match("%[Git diff%]") then
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ local t = require("test")
|
|||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
|
---@class test.git.SystemCompleted : vim.SystemCompleted
|
||||||
|
---@field stdout string
|
||||||
|
|
||||||
---@param dir string
|
---@param dir string
|
||||||
---@vararg string
|
---@return test.git.SystemCompleted
|
||||||
---@return vim.SystemCompleted
|
|
||||||
function M.git(dir, ...)
|
function M.git(dir, ...)
|
||||||
local r = vim.system({ "git", ... }, { cwd = dir, text = true }):wait()
|
local r = vim.system({ "git", ... }, { cwd = dir, text = true }):wait()
|
||||||
if r.code ~= 0 then
|
if r.code ~= 0 then
|
||||||
@@ -17,6 +19,11 @@ function M.git(dir, ...)
|
|||||||
2
|
2
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
if r.stdout then
|
||||||
|
r.stdout = vim.trim(r.stdout)
|
||||||
|
else
|
||||||
|
r.stdout = ""
|
||||||
|
end
|
||||||
return r
|
return r
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
+32
-34
@@ -1,24 +1,22 @@
|
|||||||
|
---@diagnostic disable: access-invisible
|
||||||
|
local h = require("test.git.helpers")
|
||||||
local t = require("test")
|
local t = require("test")
|
||||||
local helpers = require("test.git.helpers")
|
|
||||||
|
|
||||||
require("git").init()
|
require("git").init()
|
||||||
|
|
||||||
local git = helpers.git
|
|
||||||
local make_repo = helpers.make_repo
|
|
||||||
|
|
||||||
---@param r ow.Git.Repo
|
---@param r ow.Git.Repo
|
||||||
---@param key string
|
---@param key string
|
||||||
---@param timeout integer?
|
---@param timeout integer?
|
||||||
local function wait_cleared(r, key, timeout)
|
local function wait_cleared(r, key, timeout)
|
||||||
vim.wait(timeout or 2000, function()
|
t.wait_for(function()
|
||||||
return r._cache[key] == nil
|
return r._cache[key] == nil
|
||||||
end)
|
end, key .. " cache to clear", timeout or 2000)
|
||||||
end
|
end
|
||||||
|
|
||||||
t.test("list_refs returns heads, tags, remotes (no HEAD)", function()
|
t.test("list_refs returns heads, tags, remotes (no HEAD)", function()
|
||||||
local dir = make_repo({ a = "x" })
|
local dir = h.make_repo({ a = "x" })
|
||||||
git(dir, "branch", "feature")
|
h.git(dir, "branch", "feature")
|
||||||
git(dir, "tag", "v1")
|
h.git(dir, "tag", "v1")
|
||||||
local r = assert(require("git.repo").resolve(dir))
|
local r = assert(require("git.repo").resolve(dir))
|
||||||
local refs = r:list_refs()
|
local refs = r:list_refs()
|
||||||
table.sort(refs)
|
table.sort(refs)
|
||||||
@@ -26,13 +24,13 @@ t.test("list_refs returns heads, tags, remotes (no HEAD)", function()
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
t.test("list_pseudo_refs always includes HEAD", function()
|
t.test("list_pseudo_refs always includes HEAD", function()
|
||||||
local dir = make_repo({ a = "x" })
|
local dir = h.make_repo({ a = "x" })
|
||||||
local r = assert(require("git.repo").resolve(dir))
|
local r = assert(require("git.repo").resolve(dir))
|
||||||
t.eq(r:list_pseudo_refs(), { "HEAD" })
|
t.eq(r:list_pseudo_refs(), { "HEAD" })
|
||||||
end)
|
end)
|
||||||
|
|
||||||
t.test("list_pseudo_refs picks up MERGE_HEAD when present", function()
|
t.test("list_pseudo_refs picks up MERGE_HEAD when present", function()
|
||||||
local dir = make_repo({ a = "x" })
|
local dir = h.make_repo({ a = "x" })
|
||||||
local r = assert(require("git.repo").resolve(dir))
|
local r = assert(require("git.repo").resolve(dir))
|
||||||
t.write(dir .. "/.git", "MERGE_HEAD", "deadbeef\n")
|
t.write(dir .. "/.git", "MERGE_HEAD", "deadbeef\n")
|
||||||
-- Bypass cache (file appeared after first scan).
|
-- Bypass cache (file appeared after first scan).
|
||||||
@@ -43,15 +41,15 @@ t.test("list_pseudo_refs picks up MERGE_HEAD when present", function()
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
t.test("list_stash_refs is empty when no stash", function()
|
t.test("list_stash_refs is empty when no stash", function()
|
||||||
local dir = make_repo({ a = "x" })
|
local dir = h.make_repo({ a = "x" })
|
||||||
local r = assert(require("git.repo").resolve(dir))
|
local r = assert(require("git.repo").resolve(dir))
|
||||||
t.eq(r:list_stash_refs(), {})
|
t.eq(r:list_stash_refs(), {})
|
||||||
end)
|
end)
|
||||||
|
|
||||||
t.test("list_stash_refs lists stash + entries when stash exists", function()
|
t.test("list_stash_refs lists stash + entries when stash exists", function()
|
||||||
local dir = make_repo({ a = "x" })
|
local dir = h.make_repo({ a = "x" })
|
||||||
t.write(dir, "a", "modified")
|
t.write(dir, "a", "modified")
|
||||||
git(dir, "stash")
|
h.git(dir, "stash")
|
||||||
local r = assert(require("git.repo").resolve(dir))
|
local r = assert(require("git.repo").resolve(dir))
|
||||||
local refs = r:list_stash_refs()
|
local refs = r:list_stash_refs()
|
||||||
t.eq(#refs, 2)
|
t.eq(#refs, 2)
|
||||||
@@ -60,7 +58,7 @@ t.test("list_stash_refs lists stash + entries when stash exists", function()
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
t.test("get_cached memoizes by key", function()
|
t.test("get_cached memoizes by key", function()
|
||||||
local dir = make_repo({ a = "x" })
|
local dir = h.make_repo({ a = "x" })
|
||||||
local r = assert(require("git.repo").resolve(dir))
|
local r = assert(require("git.repo").resolve(dir))
|
||||||
local calls = 0
|
local calls = 0
|
||||||
local v1 = r:get_cached("k", function()
|
local v1 = r:get_cached("k", function()
|
||||||
@@ -76,23 +74,23 @@ t.test("get_cached memoizes by key", function()
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
t.test("cache clears after top-level .git change (commit)", function()
|
t.test("cache clears after top-level .git change (commit)", function()
|
||||||
local dir = make_repo({ a = "x" })
|
local dir = h.make_repo({ a = "x" })
|
||||||
local r = assert(require("git.repo").resolve(dir))
|
local r = assert(require("git.repo").resolve(dir))
|
||||||
local _ = r:list_refs()
|
local _ = r:list_refs()
|
||||||
t.truthy(r._cache.refs)
|
t.truthy(r._cache.refs)
|
||||||
t.write(dir, "b", "y")
|
t.write(dir, "b", "y")
|
||||||
git(dir, "add", "b")
|
h.git(dir, "add", "b")
|
||||||
git(dir, "commit", "-q", "-m", "two")
|
h.git(dir, "commit", "-q", "-m", "two")
|
||||||
wait_cleared(r, "refs")
|
wait_cleared(r, "refs")
|
||||||
t.falsy(r._cache.refs, "cache should be cleared after commit")
|
t.falsy(r._cache.refs, "cache should be cleared after commit")
|
||||||
end)
|
end)
|
||||||
|
|
||||||
t.test("cache clears after slash-branch creation (polyfill)", function()
|
t.test("cache clears after slash-branch creation (polyfill)", function()
|
||||||
local dir = make_repo({ a = "x" })
|
local dir = h.make_repo({ a = "x" })
|
||||||
local r = assert(require("git.repo").resolve(dir))
|
local r = assert(require("git.repo").resolve(dir))
|
||||||
local _ = r:list_refs()
|
local _ = r:list_refs()
|
||||||
t.truthy(r._cache.refs)
|
t.truthy(r._cache.refs)
|
||||||
git(dir, "branch", "feat/foo")
|
h.git(dir, "branch", "feat/foo")
|
||||||
wait_cleared(r, "refs")
|
wait_cleared(r, "refs")
|
||||||
t.falsy(r._cache.refs, "cache should clear via polyfilled subdir watcher")
|
t.falsy(r._cache.refs, "cache should clear via polyfilled subdir watcher")
|
||||||
local refs = r:list_refs()
|
local refs = r:list_refs()
|
||||||
@@ -101,10 +99,10 @@ t.test("cache clears after slash-branch creation (polyfill)", function()
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
t.test("cache clears after deeply nested slash branch", function()
|
t.test("cache clears after deeply nested slash branch", function()
|
||||||
local dir = make_repo({ a = "x" })
|
local dir = h.make_repo({ a = "x" })
|
||||||
local r = assert(require("git.repo").resolve(dir))
|
local r = assert(require("git.repo").resolve(dir))
|
||||||
local _ = r:list_refs()
|
local _ = r:list_refs()
|
||||||
git(dir, "branch", "deep/a/b/c")
|
h.git(dir, "branch", "deep/a/b/c")
|
||||||
wait_cleared(r, "refs")
|
wait_cleared(r, "refs")
|
||||||
local refs = r:list_refs()
|
local refs = r:list_refs()
|
||||||
table.sort(refs)
|
table.sort(refs)
|
||||||
@@ -112,9 +110,9 @@ t.test("cache clears after deeply nested slash branch", function()
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
t.test("resolve_sha returns ok + full sha for a known blob", function()
|
t.test("resolve_sha returns ok + full sha for a known blob", function()
|
||||||
local dir = make_repo({ a = "hello\n" })
|
local dir = h.make_repo({ a = "hello\n" })
|
||||||
local r = assert(require("git.repo").resolve(dir))
|
local r = assert(require("git.repo").resolve(dir))
|
||||||
local blob = vim.trim(git(dir, "rev-parse", "HEAD:a").stdout)
|
local blob = h.git(dir, "rev-parse", "HEAD:a").stdout
|
||||||
local short = blob:sub(1, 7)
|
local short = blob:sub(1, 7)
|
||||||
local full, status = r:resolve_sha(short)
|
local full, status = r:resolve_sha(short)
|
||||||
t.eq(status, "ok")
|
t.eq(status, "ok")
|
||||||
@@ -122,7 +120,7 @@ t.test("resolve_sha returns ok + full sha for a known blob", function()
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
t.test("resolve_sha returns missing for an unknown prefix", function()
|
t.test("resolve_sha returns missing for an unknown prefix", function()
|
||||||
local dir = make_repo({ a = "x" })
|
local dir = h.make_repo({ a = "x" })
|
||||||
local r = assert(require("git.repo").resolve(dir))
|
local r = assert(require("git.repo").resolve(dir))
|
||||||
local full, status = r:resolve_sha("0000deadbeef")
|
local full, status = r:resolve_sha("0000deadbeef")
|
||||||
t.eq(full, nil)
|
t.eq(full, nil)
|
||||||
@@ -130,29 +128,29 @@ t.test("resolve_sha returns missing for an unknown prefix", function()
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
t.test("resolve_sha caches by prefix", function()
|
t.test("resolve_sha caches by prefix", function()
|
||||||
local dir = make_repo({ a = "x" })
|
local dir = h.make_repo({ a = "x" })
|
||||||
local r = assert(require("git.repo").resolve(dir))
|
local r = assert(require("git.repo").resolve(dir))
|
||||||
local blob = vim.trim(git(dir, "rev-parse", "HEAD:a").stdout)
|
local blob = h.git(dir, "rev-parse", "HEAD:a").stdout
|
||||||
local short = blob:sub(1, 7)
|
local short = blob:sub(1, 7)
|
||||||
local _, _ = r:resolve_sha(short)
|
local _, _ = r:resolve_sha(short)
|
||||||
t.truthy(r._cache["resolve:" .. short], "result should be cached")
|
t.truthy(r._cache["resolve:" .. short], "result should be cached")
|
||||||
end)
|
end)
|
||||||
|
|
||||||
t.test("watcher cleans up after a slash-branch dir is removed", function()
|
t.test("watcher cleans up after a slash-branch dir is removed", function()
|
||||||
local dir = make_repo({ a = "x" })
|
local dir = h.make_repo({ a = "x" })
|
||||||
local r = assert(require("git.repo").resolve(dir))
|
local r = assert(require("git.repo").resolve(dir))
|
||||||
git(dir, "branch", "feat/foo")
|
h.git(dir, "branch", "feat/foo")
|
||||||
-- Wait for the dynamic watcher on .git/refs/heads/feat to be added.
|
-- Wait for the dynamic watcher on .git/refs/heads/feat to be added.
|
||||||
local feat_path = dir .. "/.git/refs/heads/feat"
|
local feat_path = dir .. "/.git/refs/heads/feat"
|
||||||
vim.wait(2000, function()
|
t.wait_for(function()
|
||||||
return r._watchers[feat_path] ~= nil
|
return r._watchers[feat_path] ~= nil
|
||||||
end)
|
end, "watcher to be installed on feat/ subdir", 2000)
|
||||||
t.truthy(r._watchers[feat_path], "feat/ subdir should be watched")
|
t.truthy(r._watchers[feat_path], "feat/ subdir should be watched")
|
||||||
-- Remove the branch; the feat/ directory becomes empty and is
|
-- Remove the branch; the feat/ directory becomes empty and is
|
||||||
-- pruned by git, triggering the deleted-self event.
|
-- pruned by git, triggering the deleted-self event.
|
||||||
git(dir, "branch", "-D", "feat/foo")
|
h.git(dir, "branch", "-D", "feat/foo")
|
||||||
vim.wait(2000, function()
|
t.wait_for(function()
|
||||||
return r._watchers[feat_path] == nil
|
return r._watchers[feat_path] == nil
|
||||||
end)
|
end, "watcher on feat/ subdir to close", 2000)
|
||||||
t.falsy(r._watchers[feat_path], "watcher should self-close")
|
t.falsy(r._watchers[feat_path], "watcher should self-close")
|
||||||
end)
|
end)
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
|
local h = require("test.git.helpers")
|
||||||
local t = require("test")
|
local t = require("test")
|
||||||
local helpers = require("test.git.helpers")
|
|
||||||
|
|
||||||
require("git").init()
|
require("git").init()
|
||||||
|
|
||||||
local git = helpers.git
|
|
||||||
local make_repo = helpers.make_repo
|
|
||||||
|
|
||||||
---Replicate the user's global cursor-restore autocmd. Scoped to a
|
---Replicate the user's global cursor-restore autocmd. Scoped to a
|
||||||
---named augroup + cleanup so it doesn't leak between tests.
|
---named augroup + cleanup so it doesn't leak between tests.
|
||||||
local function install_cursor_restore_autocmd()
|
local function install_cursor_restore_autocmd()
|
||||||
@@ -32,26 +29,24 @@ local function find_line(sidebar_buf, needle)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
---@return integer? sidebar_buf, integer? sidebar_win
|
---Find the gitstatus sidebar window in the current tabpage.
|
||||||
|
---@return integer? sidebar_buf
|
||||||
|
---@return integer? sidebar_win
|
||||||
local function find_sidebar()
|
local function find_sidebar()
|
||||||
local buf, win
|
for _, w in ipairs(vim.api.nvim_tabpage_list_wins(0)) do
|
||||||
for _, b in ipairs(vim.api.nvim_list_bufs()) do
|
local b = vim.api.nvim_win_get_buf(w)
|
||||||
if vim.bo[b].filetype == "gitstatus" then
|
if vim.bo[b].filetype == "gitstatus" then
|
||||||
buf = b
|
return b, w
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
for _, w in ipairs(vim.api.nvim_list_wins()) do
|
|
||||||
if vim.api.nvim_win_get_buf(w) == buf then
|
|
||||||
win = w
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return buf, win
|
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param role string
|
---Find a diff-role window in the given tabpage (or current).
|
||||||
|
---@param role "left"|"right"
|
||||||
|
---@param tab integer?
|
||||||
---@return integer?
|
---@return integer?
|
||||||
local function find_diff_win(role)
|
local function find_diff_win(role, tab)
|
||||||
for _, w in ipairs(vim.api.nvim_list_wins()) do
|
for _, w in ipairs(vim.api.nvim_tabpage_list_wins(tab or 0)) do
|
||||||
if vim.w[w].git_diff_role == role then
|
if vim.w[w].git_diff_role == role then
|
||||||
return w
|
return w
|
||||||
end
|
end
|
||||||
@@ -68,7 +63,7 @@ local function setup_sidebar_with_unstaged_file(
|
|||||||
committed_content,
|
committed_content,
|
||||||
worktree_content
|
worktree_content
|
||||||
)
|
)
|
||||||
local repo = make_repo({ [file_path] = committed_content })
|
local repo = h.make_repo({ [file_path] = committed_content })
|
||||||
t.write(repo, file_path, worktree_content)
|
t.write(repo, file_path, worktree_content)
|
||||||
vim.cmd("cd " .. repo)
|
vim.cmd("cd " .. repo)
|
||||||
|
|
||||||
@@ -82,9 +77,9 @@ local function setup_sidebar_with_unstaged_file(
|
|||||||
"repo should resolve for the test worktree"
|
"repo should resolve for the test worktree"
|
||||||
)
|
)
|
||||||
r:refresh()
|
r:refresh()
|
||||||
vim.wait(1000, function()
|
t.wait_for(function()
|
||||||
return r.status and #r.status:by_kind("unstaged") > 0
|
return r.status and #r.status:by_kind("unstaged") > 0
|
||||||
end)
|
end, "git status to report unstaged changes")
|
||||||
|
|
||||||
local entry_line = assert(
|
local entry_line = assert(
|
||||||
find_line(sidebar_buf, vim.pesc(file_path) .. "$"),
|
find_line(sidebar_buf, vim.pesc(file_path) .. "$"),
|
||||||
@@ -93,17 +88,6 @@ local function setup_sidebar_with_unstaged_file(
|
|||||||
return sidebar_win, entry_line
|
return sidebar_win, entry_line
|
||||||
end
|
end
|
||||||
|
|
||||||
local function press(keys)
|
|
||||||
local rhs = vim.api.nvim_replace_termcodes(keys, true, false, true)
|
|
||||||
vim.api.nvim_feedkeys(rhs, "x", false)
|
|
||||||
end
|
|
||||||
|
|
||||||
---@param cond fun(): boolean
|
|
||||||
---@param msg string
|
|
||||||
local function wait_for(cond, msg)
|
|
||||||
t.truthy(vim.wait(1000, cond), "timed out waiting for: " .. msg)
|
|
||||||
end
|
|
||||||
|
|
||||||
t.test("stage with diff open: sidebar cursor stays put", function()
|
t.test("stage with diff open: sidebar cursor stays put", function()
|
||||||
install_cursor_restore_autocmd()
|
install_cursor_restore_autocmd()
|
||||||
local sidebar_win, line = setup_sidebar_with_unstaged_file(
|
local sidebar_win, line = setup_sidebar_with_unstaged_file(
|
||||||
@@ -115,15 +99,15 @@ t.test("stage with diff open: sidebar cursor stays put", function()
|
|||||||
vim.api.nvim_set_current_win(sidebar_win)
|
vim.api.nvim_set_current_win(sidebar_win)
|
||||||
vim.api.nvim_win_set_cursor(sidebar_win, { line, 0 })
|
vim.api.nvim_win_set_cursor(sidebar_win, { line, 0 })
|
||||||
|
|
||||||
press("<Tab>")
|
t.press("<Tab>")
|
||||||
wait_for(function()
|
t.wait_for(function()
|
||||||
return find_diff_win("left") ~= nil
|
return find_diff_win("left") ~= nil
|
||||||
end, "diff windows to appear")
|
end, "diff windows to appear")
|
||||||
|
|
||||||
local r = assert(require("git.repo").find(vim.fn.getcwd()))
|
local r = assert(require("git.repo").find(vim.fn.getcwd()))
|
||||||
vim.api.nvim_set_current_win(sidebar_win)
|
vim.api.nvim_set_current_win(sidebar_win)
|
||||||
press("s")
|
t.press("s")
|
||||||
wait_for(function()
|
t.wait_for(function()
|
||||||
return #r.status:by_kind("staged") > 0
|
return #r.status:by_kind("staged") > 0
|
||||||
end, "stage to propagate to repo state")
|
end, "stage to propagate to repo state")
|
||||||
|
|
||||||
@@ -146,8 +130,8 @@ t.test(
|
|||||||
vim.api.nvim_set_current_win(sidebar_win)
|
vim.api.nvim_set_current_win(sidebar_win)
|
||||||
vim.api.nvim_win_set_cursor(sidebar_win, { line, 0 })
|
vim.api.nvim_win_set_cursor(sidebar_win, { line, 0 })
|
||||||
|
|
||||||
press("<Tab>")
|
t.press("<Tab>")
|
||||||
wait_for(function()
|
t.wait_for(function()
|
||||||
return find_diff_win("left") ~= nil
|
return find_diff_win("left") ~= nil
|
||||||
end, "diff windows to appear")
|
end, "diff windows to appear")
|
||||||
local left_win = assert(find_diff_win("left"))
|
local left_win = assert(find_diff_win("left"))
|
||||||
@@ -159,8 +143,8 @@ t.test(
|
|||||||
|
|
||||||
local r = assert(require("git.repo").find(vim.fn.getcwd()))
|
local r = assert(require("git.repo").find(vim.fn.getcwd()))
|
||||||
vim.api.nvim_set_current_win(sidebar_win)
|
vim.api.nvim_set_current_win(sidebar_win)
|
||||||
press("s")
|
t.press("s")
|
||||||
wait_for(function()
|
t.wait_for(function()
|
||||||
return #r.status:by_kind("staged") > 0
|
return #r.status:by_kind("staged") > 0
|
||||||
end, "stage to propagate to repo state")
|
end, "stage to propagate to repo state")
|
||||||
|
|
||||||
@@ -172,14 +156,51 @@ t.test(
|
|||||||
end
|
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()
|
||||||
|
|
||||||
|
-- First show diff in tab1, so state.diff_*_win point at tab1.
|
||||||
|
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()
|
t.test("refresh on stage updates the index URI buffer's content", function()
|
||||||
local sidebar_win, line =
|
local sidebar_win, line =
|
||||||
setup_sidebar_with_unstaged_file("foo.txt", "v1\n", "v2\n")
|
setup_sidebar_with_unstaged_file("foo.txt", "v1\n", "v2\n")
|
||||||
|
|
||||||
vim.api.nvim_set_current_win(sidebar_win)
|
vim.api.nvim_set_current_win(sidebar_win)
|
||||||
vim.api.nvim_win_set_cursor(sidebar_win, { line, 0 })
|
vim.api.nvim_win_set_cursor(sidebar_win, { line, 0 })
|
||||||
press("<Tab>")
|
t.press("<Tab>")
|
||||||
wait_for(function()
|
t.wait_for(function()
|
||||||
return find_diff_win("left") ~= nil
|
return find_diff_win("left") ~= nil
|
||||||
end, "diff windows to appear")
|
end, "diff windows to appear")
|
||||||
|
|
||||||
@@ -192,8 +213,8 @@ t.test("refresh on stage updates the index URI buffer's content", function()
|
|||||||
)
|
)
|
||||||
|
|
||||||
vim.api.nvim_set_current_win(sidebar_win)
|
vim.api.nvim_set_current_win(sidebar_win)
|
||||||
press("s")
|
t.press("s")
|
||||||
wait_for(function()
|
t.wait_for(function()
|
||||||
local first = vim.api.nvim_buf_get_lines(index_buf, 0, -1, false)[1]
|
local first = vim.api.nvim_buf_get_lines(index_buf, 0, -1, false)[1]
|
||||||
return first == "v2"
|
return first == "v2"
|
||||||
end, "index pane to refresh to staged content")
|
end, "index pane to refresh to staged content")
|
||||||
|
|||||||
+19
-2
@@ -138,10 +138,27 @@ end
|
|||||||
---@param content string
|
---@param content string
|
||||||
function M.write(dir, path, content)
|
function M.write(dir, path, content)
|
||||||
local full = vim.fs.joinpath(dir, path)
|
local full = vim.fs.joinpath(dir, path)
|
||||||
vim.fn.mkdir(vim.fs.dirname(full), "p")
|
local parent = vim.fs.dirname(full)
|
||||||
local f = assert(io.open(full --[[@as string]], "w"))
|
vim.fn.mkdir(parent, "p")
|
||||||
|
local f, err = io.open(full, "w")
|
||||||
|
if not f then
|
||||||
|
error(err or "io.open failed: " .. full)
|
||||||
|
end
|
||||||
f:write(content)
|
f:write(content)
|
||||||
f:close()
|
f:close()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param keys string
|
||||||
|
function M.press(keys)
|
||||||
|
local rhs = vim.api.nvim_replace_termcodes(keys, true, false, true)
|
||||||
|
vim.api.nvim_feedkeys(rhs, "x", false)
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param cond fun(): boolean
|
||||||
|
---@param msg string
|
||||||
|
---@param timeout integer?
|
||||||
|
function M.wait_for(cond, msg, timeout)
|
||||||
|
M.truthy(vim.wait(timeout or 1000, cond), "timed out waiting for: " .. msg)
|
||||||
|
end
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|||||||
+11
-5
@@ -1,4 +1,7 @@
|
|||||||
local cfg = vim.fn.stdpath("config")
|
local cfg = vim.fn.stdpath("config")
|
||||||
|
if type(cfg) == "table" then
|
||||||
|
cfg = assert(cfg[1])
|
||||||
|
end
|
||||||
package.path = package.path
|
package.path = package.path
|
||||||
.. (";" .. cfg .. "/lua/?.lua")
|
.. (";" .. cfg .. "/lua/?.lua")
|
||||||
.. (";" .. cfg .. "/lua/?/init.lua")
|
.. (";" .. cfg .. "/lua/?/init.lua")
|
||||||
@@ -14,6 +17,8 @@ end
|
|||||||
|
|
||||||
local t = require("test")
|
local t = require("test")
|
||||||
|
|
||||||
|
---@param target string
|
||||||
|
---@return string[]?
|
||||||
local function gather(target)
|
local function gather(target)
|
||||||
local abs = vim.fn.fnamemodify(target, ":p")
|
local abs = vim.fn.fnamemodify(target, ":p")
|
||||||
if vim.fn.isdirectory(abs) == 1 then
|
if vim.fn.isdirectory(abs) == 1 then
|
||||||
@@ -24,9 +29,8 @@ local function gather(target)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local args = arg or {}
|
local targets = (arg and #arg > 0) and arg or { cfg .. "/test" }
|
||||||
local targets = #args > 0 and args or { cfg .. "/test" }
|
---@type string[]
|
||||||
|
|
||||||
local files = {}
|
local files = {}
|
||||||
local resolve_failed = false
|
local resolve_failed = false
|
||||||
for _, target in ipairs(targets) do
|
for _, target in ipairs(targets) do
|
||||||
@@ -44,8 +48,10 @@ table.sort(files)
|
|||||||
|
|
||||||
local total_passed, total_failed = 0, 0
|
local total_passed, total_failed = 0, 0
|
||||||
for _, f in ipairs(files) do
|
for _, f in ipairs(files) do
|
||||||
f = f --[[@as string]]
|
local label = f
|
||||||
local label = f:sub(1, #cfg + 1) == cfg .. "/" and f:sub(#cfg + 2) or f
|
if f:sub(1, #cfg + 1) == cfg .. "/" then
|
||||||
|
label = f:sub(#cfg + 2)
|
||||||
|
end
|
||||||
t.start_file(label)
|
t.start_file(label)
|
||||||
local ok, err = pcall(dofile, f)
|
local ok, err = pcall(dofile, f)
|
||||||
if not ok then
|
if not ok then
|
||||||
|
|||||||
Reference in New Issue
Block a user