diff --git a/lua/codediff/ui/view/compact.lua b/lua/codediff/ui/view/compact.lua index ce60c409..34e3c0c7 100644 --- a/lua/codediff/ui/view/compact.lua +++ b/lua/codediff/ui/view/compact.lua @@ -79,11 +79,6 @@ function M.compute_visible_lines(changes, side, line_count, context_lines) local range_start = range.start_line local range_end = range.end_line -- exclusive - -- For zero-width ranges (pure insertion/deletion), use start_line as anchor - if range_start == range_end then - range_end = range_start + 1 - end - local ctx_start = math.max(1, range_start - context_lines) local ctx_end = math.min(line_count, range_end - 1 + context_lines) for l = ctx_start, ctx_end do @@ -98,7 +93,17 @@ end -- closes folds — navigation keys like zj/zk/]z/[z are excluded since they -- don't change fold state). local FOLD_KEYS = { - "zo", "zO", "zc", "zC", "za", "zA", "zv", "zx", "zX", "zM", "zR", + "zo", + "zO", + "zc", + "zC", + "za", + "zA", + "zv", + "zx", + "zX", + "zM", + "zR", } --- Install buffer-local keymap wraps that propagate fold-open/close actions @@ -126,8 +131,7 @@ local function setup_fold_sync(session, tabpage) lifecycle.begin_keymap_scope(tabpage, "compact") for _, pane in ipairs(panes) do - if pane.win and vim.api.nvim_win_is_valid(pane.win) - and pane.buf and vim.api.nvim_buf_is_valid(pane.buf) then + if pane.win and vim.api.nvim_win_is_valid(pane.win) and pane.buf and vim.api.nvim_buf_is_valid(pane.buf) then for _, key in ipairs(FOLD_KEYS) do lifecycle.set_buf_keymap(tabpage, pane.buf, "n", key, function() local count = vim.v.count > 0 and tostring(vim.v.count) or "" @@ -153,8 +157,7 @@ local function setup_fold_sync(session, tabpage) _syncing = true local ok, err = pcall(function() for _, other in ipairs(panes) do - if other.win ~= pane.win - and other.win and vim.api.nvim_win_is_valid(other.win) then + if other.win ~= pane.win and other.win and vim.api.nvim_win_is_valid(other.win) then local target = M.compute_corresponding_lnum(changes, pane.side, other.side, src_lnum) target = math.max(1, math.min(target, vim.api.nvim_buf_line_count(other.buf))) -- Save & restore cursor so the partner pane doesn't visibly jump. diff --git a/tests/ui/view/compact_spec.lua b/tests/ui/view/compact_spec.lua index 91b8bbcd..9e1013bb 100644 --- a/tests/ui/view/compact_spec.lua +++ b/tests/ui/view/compact_spec.lua @@ -125,16 +125,16 @@ describe("compact mode (#344)", function() assert.is_nil(visible[11], "buffer only has 10 lines") end) - it("treats zero-width ranges (pure insertion/deletion) as a one-line anchor", function() - -- Zero-width range at line 5 — gets treated as the one-line slice [5,6). - -- With context=2: visible = max(1, 5-2)..min(N, 6-1+2) = 3..7. + it("shows context on both sides of zero-width ranges without an extra anchor line", function() + -- A zero-width range is a boundary between lines, not a changed line. + -- With context=2, show two real lines on either side: 3..6. local changes = { make_change(5, 5, 5, 8) } local visible = compact.compute_visible_lines(changes, "original", 100, 2) - for l = 3, 7 do + for l = 3, 6 do assert.is_true(visible[l], "line " .. l .. " should be visible") end assert.is_nil(visible[2]) - assert.is_nil(visible[8]) + assert.is_nil(visible[7]) end) it("merges overlapping hunks' visible ranges via set union", function() @@ -162,6 +162,8 @@ describe("compact mode (#344)", function() -- Original side: anchor at 5, ±2 context → 3..6. assert.is_true(orig_visible[5]) assert.is_true(orig_visible[3]) + assert.is_true(orig_visible[6]) + assert.is_nil(orig_visible[7]) assert.is_nil(orig_visible[10]) -- Modified side: hunk 10..12, ±2 context → 8..14. @@ -170,6 +172,20 @@ describe("compact mode (#344)", function() assert.is_nil(mod_visible[5]) end) + it("aligns the first folded line after a pure insertion", function() + local changes = { make_change(50, 50, 60, 61) } + local original = compact.compute_visible_lines(changes, "original", 100, 3) + local modified = compact.compute_visible_lines(changes, "modified", 110, 3) + + -- Context ends at 52/63, so the next folds begin at corresponding + -- unchanged lines 53/64. Before the fix, the original fold began at 54. + assert.is_true(original[52]) + assert.is_true(modified[63]) + assert.is_nil(original[53]) + assert.is_nil(modified[64]) + assert.equal(64, compact.compute_corresponding_lnum(changes, "original", "modified", 53)) + end) + it("supports zero context (only the hunk lines visible)", function() local changes = { make_change(10, 13, 10, 13) } local visible = compact.compute_visible_lines(changes, "original", 100, 0)