fix: pre-release cleanup for v0.2.0 (#102)

## Problem

Three minor issues remain before the v0.2.0 release:

1. Git quotes filenames containing spaces, unicode, or special
characters
   in the fugitive status buffer. `parse_file_line` passed the quotes
   through verbatim, causing file-not-found errors on diff operations.

2. Navigation wrap-around in both conflict and merge modules was silent,
giving no indication when jumping past the last/first item back to the
   beginning/end.

3. `resolved_hunks` and `(resolved)` virtual text in the merge module
persisted across buffer re-reads, showing stale markers for hunks that
   were no longer resolved.

## Solution

1. Add an `unquote()` helper to fugitive.lua that strips surrounding
   quotes and unescapes `\\`, `\"`, `\n`, `\t`, and octal `\NNN`
   sequences. Applied to both return paths in `parse_file_line`.

2. Add `vim.notify` before the wrap-around jump in all four navigation
   functions (`goto_next`/`goto_prev` in conflict.lua and merge.lua).

3. Clear `resolved_hunks[bufnr]` and the merge namespace at the top of
   `setup_keymaps` so each buffer init starts fresh.

Closes #66
This commit is contained in:
Barrett Ruth 2026-02-09 15:08:36 -05:00 committed by GitHub
parent b5d28e9f2b
commit 35067151e4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 393 additions and 931 deletions

View file

@ -509,6 +509,44 @@ describe('merge', function()
helpers.delete_buffer(w_bufnr)
end)
it('goto_next notifies on wrap-around', function()
local working_path = '/tmp/diffs_test_wrap_notify.lua'
local w_bufnr = create_working_buffer({
'<<<<<<< HEAD',
'local x = 1',
'=======',
'local x = 2',
'>>>>>>> feature',
}, working_path)
local d_bufnr = create_diff_buffer({
'diff --git a/file.lua b/file.lua',
'--- a/file.lua',
'+++ b/file.lua',
'@@ -1,1 +1,1 @@',
'-local x = 1',
'+local x = 2',
}, working_path)
vim.api.nvim_set_current_buf(d_bufnr)
vim.api.nvim_win_set_cursor(0, { 6, 0 })
local notified = false
local orig_notify = vim.notify
vim.notify = function(msg)
if msg:match('wrapped to first hunk') then
notified = true
end
end
merge.goto_next(d_bufnr)
vim.notify = orig_notify
assert.is_true(notified)
helpers.delete_buffer(d_bufnr)
helpers.delete_buffer(w_bufnr)
end)
it('goto_prev jumps to previous conflict hunk', function()
local working_path = '/tmp/diffs_test_prev.lua'
local w_bufnr = create_working_buffer({
@ -577,6 +615,44 @@ describe('merge', function()
helpers.delete_buffer(w_bufnr)
end)
it('goto_prev notifies on wrap-around', function()
local working_path = '/tmp/diffs_test_prev_wrap_notify.lua'
local w_bufnr = create_working_buffer({
'<<<<<<< HEAD',
'local x = 1',
'=======',
'local x = 2',
'>>>>>>> feature',
}, working_path)
local d_bufnr = create_diff_buffer({
'diff --git a/file.lua b/file.lua',
'--- a/file.lua',
'+++ b/file.lua',
'@@ -1,1 +1,1 @@',
'-local x = 1',
'+local x = 2',
}, working_path)
vim.api.nvim_set_current_buf(d_bufnr)
vim.api.nvim_win_set_cursor(0, { 1, 0 })
local notified = false
local orig_notify = vim.notify
vim.notify = function(msg)
if msg:match('wrapped to last hunk') then
notified = true
end
end
merge.goto_prev(d_bufnr)
vim.notify = orig_notify
assert.is_true(notified)
helpers.delete_buffer(d_bufnr)
helpers.delete_buffer(w_bufnr)
end)
it('skips resolved hunks', function()
local working_path = '/tmp/diffs_test_skip_resolved.lua'
local w_bufnr = create_working_buffer({
@ -650,8 +726,19 @@ describe('merge', function()
helpers.delete_buffer(d_bufnr)
end)
end)
describe('setup_keymaps', function()
it('clears resolved state on re-init', function()
local working_path = '/tmp/diffs_test_reinit.lua'
local w_bufnr = create_working_buffer({
'<<<<<<< HEAD',
'local x = 1',
'=======',
'local x = 2',
'>>>>>>> feature',
}, working_path)
it('does not add hints when show_virtual_text is false', function()
local d_bufnr = create_diff_buffer({
'diff --git a/file.lua b/file.lua',
'--- a/file.lua',
@ -659,21 +746,37 @@ describe('merge', function()
'@@ -1,1 +1,1 @@',
'-local x = 1',
'+local x = 2',
})
}, working_path)
vim.api.nvim_set_current_buf(d_bufnr)
vim.api.nvim_win_set_cursor(0, { 5, 0 })
merge.setup_keymaps(d_bufnr, default_config({ show_virtual_text = false }))
local cfg = default_config()
merge.resolve_ours(d_bufnr, cfg)
assert.is_true(merge.is_resolved(d_bufnr, 1))
local extmarks =
vim.api.nvim_buf_get_extmarks(d_bufnr, merge.get_namespace(), 0, -1, { details = true })
local virt_text_count = 0
assert.is_true(#extmarks > 0)
merge.setup_keymaps(d_bufnr, cfg)
assert.is_false(merge.is_resolved(d_bufnr, 1))
extmarks =
vim.api.nvim_buf_get_extmarks(d_bufnr, merge.get_namespace(), 0, -1, { details = true })
local resolved_count = 0
for _, mark in ipairs(extmarks) do
if mark[4] and mark[4].virt_text then
virt_text_count = virt_text_count + 1
for _, chunk in ipairs(mark[4].virt_text) do
if chunk[1]:match('resolved') then
resolved_count = resolved_count + 1
end
end
end
end
assert.are.equal(0, virt_text_count)
assert.are.equal(0, resolved_count)
helpers.delete_buffer(d_bufnr)
helpers.delete_buffer(w_bufnr)
end)
end)
@ -694,18 +797,6 @@ describe('merge', function()
vim.api.nvim_buf_delete(buf, { force = true })
end)
it('parse_file_line returns status for modified files', function()
local fugitive = require('diffs.fugitive')
local buf = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_lines(buf, 0, -1, false, {
'Unstaged (1)',
'M file.lua',
})
local _, _, _, _, status = fugitive.get_file_at_line(buf, 2)
assert.are.equal('M', status)
vim.api.nvim_buf_delete(buf, { force = true })
end)
it('walkback from hunk line propagates status', function()
local fugitive = require('diffs.fugitive')
local buf = vim.api.nvim_create_buf(false, true)