356 lines
12 KiB
Lua
356 lines
12 KiB
Lua
local helpers = require("helpers")
|
|
local scratch = require("scratch_comments")
|
|
local views = require("scratch_comments.model.views")
|
|
local store = require("scratch_comments.model.store")
|
|
local expect = MiniTest.expect
|
|
|
|
local function only()
|
|
return views.anchored()[1]
|
|
end
|
|
|
|
before_each(function()
|
|
helpers.reset()
|
|
end)
|
|
|
|
describe("a line comment", function()
|
|
before_each(function()
|
|
helpers.buffer("anchoring.md", { "one", "two", "the quick brown fox", "four", "five" })
|
|
vim.cmd("3Comment")
|
|
helpers.write("on the fox")
|
|
end)
|
|
|
|
it("follows its text when lines are inserted above", function()
|
|
vim.api.nvim_buf_set_lines(0, 0, 0, false, { "new a", "new b", "new c" })
|
|
expect.equality(only().start_line, 6)
|
|
expect.equality(only().end_line, 6)
|
|
expect.equality(scratch.render():match("%- (line %d+)"), "line 6")
|
|
end)
|
|
|
|
it("follows its text when lines above are deleted", function()
|
|
vim.api.nvim_buf_set_lines(0, 0, 2, false, {})
|
|
expect.equality(only().start_line, 1)
|
|
end)
|
|
|
|
it("reads its snippet live", function()
|
|
vim.api.nvim_buf_set_text(0, 2, 4, 2, 9, { "slow" })
|
|
expect.equality(only().snippet, "the slow brown fox")
|
|
end)
|
|
|
|
it("stays anchored when part of the line is edited", function()
|
|
vim.api.nvim_win_set_cursor(0, { 3, 4 })
|
|
vim.cmd("normal! ciwslow")
|
|
expect.equality(#views.anchored(), 1)
|
|
end)
|
|
|
|
it("stays anchored when the whole line is rewritten", function()
|
|
vim.api.nvim_win_set_cursor(0, { 3, 0 })
|
|
vim.cmd("normal! ccthe slow fox")
|
|
expect.equality(#views.orphans(), 0)
|
|
end)
|
|
end)
|
|
|
|
describe("a range comment", function()
|
|
before_each(function()
|
|
helpers.buffer("anchoring.md", { "a", "b", "c", "d", "e" })
|
|
vim.cmd("2,4Comment")
|
|
helpers.write("on b through d")
|
|
end)
|
|
|
|
it("covers its lines", function()
|
|
expect.equality(only().start_line, 2)
|
|
expect.equality(only().end_line, 4)
|
|
end)
|
|
|
|
it("grows when lines are inserted inside it", function()
|
|
vim.api.nvim_buf_set_lines(0, 2, 2, false, { "inside" })
|
|
expect.equality(only().start_line, 2)
|
|
expect.equality(only().end_line, 5)
|
|
end)
|
|
|
|
it("shrinks when its last line is deleted, without taking in the next line", function()
|
|
vim.api.nvim_buf_set_lines(0, 3, 4, false, {})
|
|
expect.equality(only().end_line, 3)
|
|
expect.equality(only().snippet, "b\nc")
|
|
end)
|
|
|
|
it("stays anchored when one of its lines is rewritten", function()
|
|
vim.api.nvim_win_set_cursor(0, { 3, 0 })
|
|
vim.cmd("normal! ccrewritten")
|
|
expect.equality(#views.orphans(), 0)
|
|
end)
|
|
|
|
it("shrinks when a middle line is deleted", function()
|
|
vim.cmd("3d")
|
|
expect.equality(#views.orphans(), 0)
|
|
expect.equality(only().end_line, 3)
|
|
end)
|
|
end)
|
|
|
|
describe("an orphan", function()
|
|
before_each(function()
|
|
helpers.buffer("anchoring.md", { "one", "two", "the quick fox", "four", "five" })
|
|
vim.cmd("3Comment")
|
|
helpers.write("on the fox")
|
|
helpers.undo_break()
|
|
vim.cmd("3d")
|
|
helpers.text_changed()
|
|
end)
|
|
|
|
it("is what a comment becomes when its lines are deleted", function()
|
|
expect.equality(#views.anchored(), 0)
|
|
expect.equality(#views.orphans(), 1)
|
|
end)
|
|
|
|
it("has no sign", function()
|
|
local namespace = vim.api.nvim_get_namespaces().scratch_comments_signs
|
|
expect.equality(#vim.api.nvim_buf_get_extmarks(0, namespace, 0, -1, {}), 0)
|
|
end)
|
|
|
|
it("is exported in its own section, with its text", function()
|
|
local markdown = scratch.render()
|
|
expect.no_equality(markdown:find("## Orphaned", 1, true), nil)
|
|
expect.no_equality(markdown:find("on the fox", 1, true), nil)
|
|
end)
|
|
|
|
it("is in the list, marked", function()
|
|
vim.cmd("CommentList")
|
|
local entries = vim.fn.getqflist()
|
|
expect.equality(#entries, 1)
|
|
expect.no_equality(entries[1].text:find("[orphaned]", 1, true), nil)
|
|
vim.cmd("cclose")
|
|
end)
|
|
|
|
it("is anchored again by undo", function()
|
|
helpers.undo_break()
|
|
vim.cmd("silent undo")
|
|
expect.equality(#views.orphans(), 0)
|
|
expect.equality(only().start_line, 3)
|
|
end)
|
|
|
|
it("can be deleted from the comment list", function()
|
|
vim.cmd.CommentList()
|
|
vim.cmd.CommentDelete()
|
|
expect.equality(#views.orphans(), 0)
|
|
end)
|
|
end)
|
|
|
|
describe("a file's comments", function()
|
|
before_each(function()
|
|
vim.cmd.edit("tests/fixtures/lifecycle.txt")
|
|
vim.cmd("Comment")
|
|
helpers.write("on the first line")
|
|
end)
|
|
|
|
it("survive :e!", function()
|
|
vim.cmd("edit!")
|
|
expect.equality(#views.anchored(), 1)
|
|
end)
|
|
|
|
it("survive :bd and reattach when reopened", function()
|
|
vim.cmd("bdelete")
|
|
expect.equality(#store.all(), 1)
|
|
expect.equality(store.all()[1].state, "parked")
|
|
expect.equality(views.anchored()[1].comment, "on the first line")
|
|
vim.cmd.edit("tests/fixtures/lifecycle.txt")
|
|
vim.wait(0)
|
|
expect.equality(store.all()[1].state, nil)
|
|
expect.equality(views.anchored()[1].start_line, 1)
|
|
end)
|
|
|
|
it("retains a comment through :bunload and :bwipeout", function()
|
|
local source = vim.api.nvim_get_current_buf()
|
|
vim.cmd.enew()
|
|
vim.cmd("bunload tests/fixtures/lifecycle.txt")
|
|
expect.equality(store.all()[1].state, "parked")
|
|
local ns = vim.api.nvim_get_namespaces().scratch_comments
|
|
expect.equality(#vim.api.nvim_buf_get_extmarks(source, ns, 0, -1, {}), 0)
|
|
expect.equality(#views.anchored(), 1)
|
|
vim.cmd("bwipeout! tests/fixtures/lifecycle.txt")
|
|
expect.equality(#store.all(), 1)
|
|
expect.equality(store.all()[1].state, "parked")
|
|
end)
|
|
|
|
it("keeps a wiped diff-style buffer until the same URI returns", function()
|
|
local url = "codediff:////tmp/repo///HEAD/review.lua"
|
|
vim.cmd.enew()
|
|
vim.api.nvim_buf_set_name(0, url)
|
|
vim.api.nvim_buf_set_lines(0, 0, -1, false, { "one", "two" })
|
|
vim.bo.bufhidden = "wipe"
|
|
vim.cmd("2Comment")
|
|
helpers.write("virtual note")
|
|
local old = vim.api.nvim_get_current_buf()
|
|
vim.cmd("enew!")
|
|
expect.equality(vim.api.nvim_buf_is_valid(old), false)
|
|
expect.equality(store.all()[#store.all()].state, "parked")
|
|
vim.api.nvim_buf_set_name(0, url)
|
|
vim.api.nvim_buf_set_lines(0, 0, -1, false, { "one", "two" })
|
|
vim.api.nvim_exec_autocmds("BufEnter", { buffer = 0 })
|
|
vim.wait(0)
|
|
expect.equality(store.all()[#store.all()].state, nil)
|
|
expect.equality(helpers.sign_at(2), "│")
|
|
expect.equality(store.all()[#store.all()].comment, "virtual note")
|
|
expect.equality(#views.anchored(), 2)
|
|
end)
|
|
|
|
it("makes a reattached URI comment an orphan when its line is deleted", function()
|
|
local url = "review-test:///edited-after-attach.lua"
|
|
vim.cmd.enew()
|
|
vim.api.nvim_buf_set_name(0, url)
|
|
vim.api.nvim_buf_set_lines(0, 0, -1, false, { "one", "two" })
|
|
vim.bo.bufhidden = "wipe"
|
|
vim.cmd("2Comment")
|
|
helpers.write("on two")
|
|
vim.cmd("enew!")
|
|
vim.api.nvim_buf_set_name(0, url)
|
|
vim.api.nvim_buf_set_lines(0, 0, -1, false, { "one", "two" })
|
|
vim.api.nvim_exec_autocmds("BufEnter", { buffer = 0 })
|
|
vim.wait(0)
|
|
expect.equality(store.all()[#store.all()].state, nil)
|
|
local source_win = vim.api.nvim_get_current_win()
|
|
vim.cmd.CommentList()
|
|
vim.api.nvim_win_call(source_win, function()
|
|
vim.api.nvim_buf_set_lines(0, 1, 2, false, {})
|
|
end)
|
|
vim.wait(0)
|
|
expect.equality(#views.orphans(), 1)
|
|
local items = vim.fn.getqflist()
|
|
expect.equality(items[#items].text, "[orphaned] on two")
|
|
end)
|
|
|
|
it("uses the latest live URI range after a provider replaces its lines", function()
|
|
local url = "review-test:///live-range.lua"
|
|
vim.cmd.enew()
|
|
vim.api.nvim_buf_set_name(0, url)
|
|
vim.api.nvim_buf_set_lines(0, 0, -1, false, { "one", "two" })
|
|
vim.bo.bufhidden = "wipe"
|
|
vim.cmd("2Comment")
|
|
helpers.write("on two")
|
|
vim.cmd("enew!")
|
|
vim.api.nvim_buf_set_name(0, url)
|
|
vim.api.nvim_buf_set_lines(0, 0, -1, false, { "one", "two" })
|
|
vim.api.nvim_exec_autocmds("BufEnter", { buffer = 0 })
|
|
vim.wait(0)
|
|
local comment = store.all()[#store.all()]
|
|
expect.equality(comment.state, nil)
|
|
vim.api.nvim_buf_set_text(0, 1, 1, 1, 2, { "E" })
|
|
vim.wait(0)
|
|
expect.equality(comment.snippet, "tEo")
|
|
vim.api.nvim_buf_set_lines(0, 0, 0, false, { "leading" })
|
|
vim.wait(0)
|
|
expect.equality(comment.last_location.start_line, 3)
|
|
vim.api.nvim_buf_set_lines(0, 0, -1, false, { "leading", "one", "tEo" })
|
|
vim.wait(0)
|
|
expect.equality(comment.state, nil)
|
|
expect.equality(views.in_buffer(vim.api.nvim_get_current_buf())[1].start_line, 3)
|
|
end)
|
|
|
|
it("keeps a URI anchor through batched movement and provider replacement", function()
|
|
local url = "review-test:///batched.lua"
|
|
vim.cmd.enew()
|
|
vim.api.nvim_buf_set_name(0, url)
|
|
vim.api.nvim_buf_set_lines(0, 0, -1, false, { "one", "two" })
|
|
vim.bo.bufhidden = "wipe"
|
|
vim.cmd("2Comment")
|
|
helpers.write("on two")
|
|
vim.cmd("enew!")
|
|
vim.api.nvim_buf_set_name(0, url)
|
|
vim.api.nvim_buf_set_lines(0, 0, -1, false, { "one", "two" })
|
|
vim.api.nvim_exec_autocmds("BufEnter", { buffer = 0 })
|
|
vim.wait(0)
|
|
local comment = store.all()[#store.all()]
|
|
vim.api.nvim_buf_set_lines(0, 0, 0, false, { "first" })
|
|
vim.wait(0)
|
|
vim.api.nvim_buf_set_lines(0, 0, 0, false, { "second" })
|
|
vim.api.nvim_buf_set_lines(0, 0, -1, false, { "second", "first", "one", "two" })
|
|
vim.wait(0)
|
|
expect.equality(comment.state, nil)
|
|
expect.equality(comment.last_location.start_line, 4)
|
|
expect.equality(views.in_buffer(vim.api.nvim_get_current_buf())[1].start_line, 4)
|
|
end)
|
|
|
|
it("parks a moved range at its current location and reattaches there", function()
|
|
local url = "review-test:///moved.lua"
|
|
vim.cmd.enew()
|
|
vim.api.nvim_buf_set_name(0, url)
|
|
vim.api.nvim_buf_set_lines(0, 0, -1, false, { "one", "two" })
|
|
vim.bo.bufhidden = "wipe"
|
|
vim.cmd("2Comment")
|
|
helpers.write("on two")
|
|
vim.api.nvim_buf_set_lines(0, 0, 0, false, { "leading" })
|
|
local id = store.all()[#store.all()].id
|
|
expect.equality(
|
|
vim.iter(views.anchored()):find(function(view)
|
|
return view.id == id
|
|
end).start_line,
|
|
3
|
|
)
|
|
vim.cmd("enew!")
|
|
local comment = store.all()[#store.all()]
|
|
expect.equality(comment.state, "parked")
|
|
expect.equality(comment.last_location.start_line, 3)
|
|
expect.equality(comment.snippet, "two")
|
|
vim.api.nvim_buf_set_name(0, url)
|
|
vim.api.nvim_buf_set_lines(0, 0, -1, false, { "leading", "one", "two" })
|
|
vim.api.nvim_exec_autocmds("BufEnter", { buffer = 0 })
|
|
vim.wait(0)
|
|
expect.equality(comment.state, nil)
|
|
expect.equality(views.in_buffer(vim.api.nvim_get_current_buf())[1].start_line, 3)
|
|
end)
|
|
|
|
it("waits for a delayed URI read before reattaching", function()
|
|
local url = "review-test:///later.lua"
|
|
local pending
|
|
vim.api.nvim_create_autocmd("BufReadCmd", {
|
|
pattern = "review-test:///*",
|
|
once = true,
|
|
callback = function(args)
|
|
pending = args.buf
|
|
end,
|
|
})
|
|
vim.cmd.enew()
|
|
vim.api.nvim_buf_set_name(0, url)
|
|
vim.api.nvim_buf_set_lines(0, 0, -1, false, { "one", "two" })
|
|
vim.bo.bufhidden = "wipe"
|
|
vim.cmd("2Comment")
|
|
helpers.write("delayed")
|
|
vim.cmd("enew!")
|
|
expect.equality(store.all()[#store.all()].state, "parked")
|
|
vim.cmd.edit(url)
|
|
vim.wait(0)
|
|
expect.equality(store.all()[#store.all()].state, "parked")
|
|
expect.equality(pending, vim.api.nvim_get_current_buf())
|
|
vim.api.nvim_buf_set_lines(pending, 0, -1, false, { "one" })
|
|
vim.wait(0)
|
|
expect.equality(store.all()[#store.all()].state, "parked")
|
|
vim.api.nvim_buf_set_lines(pending, 1, -1, false, { "two" })
|
|
vim.wait(0)
|
|
expect.equality(store.all()[#store.all()].state, nil)
|
|
expect.equality(views.in_buffer(pending)[1].start_line, 2)
|
|
-- A provider may replace an already-matching partial result again.
|
|
vim.api.nvim_buf_set_lines(pending, 1, 2, false, { "two" })
|
|
vim.wait(0)
|
|
expect.equality(store.all()[#store.all()].state, nil)
|
|
expect.equality(views.in_buffer(pending)[1].start_line, 2)
|
|
end)
|
|
|
|
it("marks a changed saved range inactive after reopening", function()
|
|
vim.cmd("bdelete")
|
|
vim.cmd.edit("tests/fixtures/lifecycle.txt")
|
|
vim.api.nvim_buf_set_lines(0, 0, 1, false, { "different" })
|
|
vim.wait(0)
|
|
expect.equality(#views.orphans(), 1)
|
|
expect.equality(#views.anchored(), 0)
|
|
vim.cmd.CommentList()
|
|
vim.cmd.CommentDelete()
|
|
expect.equality(#store.all(), 0)
|
|
end)
|
|
|
|
it("retains an orphan when its buffer is wiped", function()
|
|
vim.cmd("1d")
|
|
helpers.text_changed()
|
|
expect.equality(#views.orphans(), 1)
|
|
vim.cmd("bwipeout!")
|
|
expect.equality(#views.orphans(), 1)
|
|
end)
|
|
end)
|