diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-15 18:59:33 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:14 -0300 |
| commit | b7914a0bd59334f618b62e0b98271211bbec46b9 (patch) | |
| tree | 53af62ce0ae022e580e35aadbd952e1656dcfa30 /test | |
| parent | 3f4f26e0e40d06427e72f72e760d01adcdc0326c (diff) | |
| download | pardes-b7914a0bd59334f618b62e0b98271211bbec46b9.tar.gz pardes-b7914a0bd59334f618b62e0b98271211bbec46b9.zip | |
Clear previous selections before resolving Look destinations
Diffstat (limited to 'test')
| -rw-r--r-- | test/panes.zig | 110 | ||||
| -rw-r--r-- | test/pdf.zig | 26 |
2 files changed, 127 insertions, 9 deletions
diff --git a/test/panes.zig b/test/panes.zig index 28af8141..cb2e8169 100644 --- a/test/panes.zig +++ b/test/panes.zig @@ -4256,3 +4256,113 @@ test "terminal overlays preserve trailing blank styles without coloring inserted try std.testing.expectEqual(colors[2], extended.at(x, y + 4).style.bg); try std.testing.expect(p.shell_rows.pane == null); } + +const LookResetTests = struct { + fn seed(pane: *Pane, operand: []const u8) !void { + pane.cur_row = 0; + pane.cur_col = 3; + pane.vsel = .{ .active = true, .explicit = true, .row = 0, .col = 0 }; + pane.msel = .{ .active = true, .r0 = 0, .r1 = 1 }; + pane.sels[0] = .{ .row = 1, .col = 2, .arow = 0, .acol = 1 }; + pane.nsel = 1; + pane.select = true; + pane.normal.count = 5; + pane.append_at = .{ .row = 0, .col = 3 }; + pane.sticky_col = 7; + for (0..pane.sel.len) |slot| { + pane.clearPointerSelection(slot); + pane.sel[slot] = .{ .state = .done, .source_id = slot + 1, .r0 = 1, .r1 = 1, .c0 = 0, .c1 = 3 }; + const rows = try pane.gpa.alloc(Pane.PointerRow, 1); + rows[0] = .{ .row = 0, .lo = 0, .hi = 4 }; + pane.pointer_selections[slot] = .{ + .gesture = pane.sel[slot], + .rows = rows, + .raw_text = try pane.gpa.dupe(u8, operand), + }; + } + } + + fn cleared(pane: *const Pane) !void { + try std.testing.expect(!pane.msel.active); + try std.testing.expectEqual(@as(u8, 0), pane.nsel); + try std.testing.expect(!pane.select); + try std.testing.expectEqual(modal.Normal.State{}, pane.normal); + try std.testing.expect(pane.append_at == null); + try std.testing.expectEqual(@as(i32, -1), pane.sticky_col); + for (pane.sel) |selection| try std.testing.expectEqual(.none, selection.state); + for (pane.pointer_selections) |selection| try std.testing.expect(selection == null); + } + + fn selected(pane: *const Pane) []const u8 { + if (!pane.vsel.active or pane.cur_row != pane.vsel.row) return ""; + const line = modal.lineSlice(pane.file.?.content, @intCast(pane.cur_row)); + const lo: usize = @intCast(@min(pane.cur_col, pane.vsel.col)); + const hi: usize = @intCast(@max(pane.cur_col, pane.vsel.col)); + return line[lo..modal.nextGrapheme(line, hi)]; + } + + test "Look replaces old selection for same-pane addresses ranges and text fallback" { + const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 80, .rows = 24 }); + defer p.deinit(); + const pane = try p.setTestFile("alpha\nbravo\ncharlie\nneedle\n"); + try seed(pane, "/test.txt:3:2"); + // This operand is released by Look's selection cleanup. + p.lookAt(0, pane.pointer_selections[0].?.raw_text.?); + try cleared(pane); + try std.testing.expectEqual(@as(usize, 0), p.active); + try std.testing.expectEqual(@as(i32, 2), pane.cur_row); + try std.testing.expectEqual(@as(i32, 1), pane.cur_col); + try std.testing.expect(!pane.vsel.active); + + try seed(pane, "/test.txt:2:2-4"); + p.lookAt(0, pane.pointer_selections[0].?.raw_text.?); + try cleared(pane); + try std.testing.expectEqual(@as(i32, 1), pane.cur_row); + try std.testing.expectEqualStrings("rav", selected(pane)); + + p.gpa.free(pane.file.?.path); + pane.file.?.path = try p.gpa.dupe(u8, "/tmp/look-selection-source.txt"); + try seed(pane, "needle"); + p.lookAt(0, pane.pointer_selections[0].?.raw_text.?); + try cleared(pane); + try std.testing.expectEqual(@as(i32, 3), pane.cur_row); + try std.testing.expectEqualStrings("needle", selected(pane)); + } + + test "Look clears both source and existing destination selections before focus" { + const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 100, .rows = 30 }); + defer p.deinit(); + const source = try p.setTestFile("source\nlines\n"); + const id = p.freeSlot().?; + const destination = try p.newDocPane(id); + destination.file = .{ + .path = try p.gpa.dupe(u8, "/look-destination.txt"), + .content = try p.gpa.dupe(u8, "alpha\nbravo\ncharlie\n"), + .history = try panes.File.History.create(p.gpa), + }; + layout.insert(p, 0, 1, id); + layout.compute(p); + for ([_]bool{ false, true }) |range| { + p.active = 0; + try seed(source, if (range) "/look-destination.txt:2:2-4" else "/look-destination.txt:3:2"); + try seed(destination, "previous destination"); + p.lookAt(0, source.pointer_selections[0].?.raw_text.?); + try std.testing.expectEqual(id, p.active); + try cleared(source); + try cleared(destination); + try std.testing.expect(!source.vsel.active); + if (range) { + try std.testing.expectEqual(@as(i32, 1), destination.cur_row); + try std.testing.expectEqualStrings("rav", selected(destination)); + } else { + try std.testing.expectEqual(@as(i32, 2), destination.cur_row); + try std.testing.expectEqual(@as(i32, 1), destination.cur_col); + try std.testing.expect(!destination.vsel.active); + } + } + } +}; + +test { + _ = LookResetTests; +} diff --git a/test/pdf.zig b/test/pdf.zig index 113ed8b9..7a05447e 100644 --- a/test/pdf.zig +++ b/test/pdf.zig @@ -120,8 +120,12 @@ const PdfLinkTests = struct { defer frame.deinit(); _ = try p.render(frame.allocator()); while (p.nextEffect()) |_| {} - click(p, try textCell(p, "target.txt")); + const target_cell = try textCell(p, "target.txt"); + try std.testing.expect(panes.Pdf.beginSelection(p, p.panes[0].?, target_cell.col, target_cell.row)); + try std.testing.expect(p.panes[0].?.pdf.?.selection != null); + click(p, target_cell); try expectOpened(p, null); + try std.testing.expect(p.panes[0].?.pdf.?.selection == null); const choices = for (p.panes, 0..) |slot, id| { if (id == 0) continue; if (slot) |pane| if (pane.file) |file| if (file.output != null) break pane; @@ -146,7 +150,7 @@ const PdfLinkTests = struct { for (0..(config.look_preview_delay_frames orelse 0)) |_| p.update(.tick); } - test "PDF links hover clears on leave page and reload while right drag selects text" { + test "PDF links hover clears on leave page and reload while right drag chooses Look text" { if (!pdf_enabled or platform == .web) return; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); @@ -181,10 +185,13 @@ const PdfLinkTests = struct { const label = try textCell(p, "label"); p.update(.{ .mouse = .{ .button = config.look_button, .kind = .press, .col = label.col, .row = label.row } }); p.update(.{ .mouse = .{ .button = config.look_button, .kind = .drag, .col = label.col + 3, .row = label.row } }); - p.update(.{ .mouse = .{ .button = config.look_button, .kind = .release, .col = label.col + 3, .row = label.row } }); - try expectOpened(p, null); try std.testing.expect(pane.pdf.?.selection != null); try std.testing.expect(pane.pdf.?.selection_text.len > 0); + p.update(.{ .mouse = .{ .button = config.look_button, .kind = .release, .col = label.col + 3, .row = label.row } }); + try expectOpened(p, null); + try std.testing.expect(pane.pdf.?.selection == null); + try std.testing.expect(pane.pdf.?.selection_text.len == 0); + try std.testing.expect(pane.pdf.?.search_query.len > 0); } }; @@ -1844,8 +1851,8 @@ test "PDF native mouse selection, Look, and highlights share page geometry" { } // A native right-click resolves the same MuPDF-snapped word and feeds it - // to Look. Search highlights precede selection highlights so the live - // selection remains visually authoritative where they overlap. + // to Look. Resolving it clears the previous selection, leaving the new + // search highlights without carrying an old selection into the result. p.update(.{ .mouse = .{ .button = config.look_button, .kind = .press, .col = word_col, .row = selected_row } }); p.update(.{ .mouse = .{ .button = config.look_button, .kind = .release, .col = word_col, .row = selected_row } }); try std.testing.expect(std.ascii.indexOfIgnoreCase(pv.search_query, "Pardes") != null); @@ -1855,9 +1862,9 @@ test "PDF native mouse selection, Look, and highlights share page geometry" { p.scratch.allocator(), panes.Pdf.highlightInput(p, 0, pane), )).forPage(pv.page); - try std.testing.expect(highlights.len > 1); - try std.testing.expectEqual(pdf_impl.HighlightKind.search, highlights[0].kind); - try std.testing.expectEqual(pdf_impl.HighlightKind.selection, highlights[highlights.len - 1].kind); + try std.testing.expect(highlights.len > 0); + for (highlights) |highlight| try std.testing.expectEqual(pdf_impl.HighlightKind.search, highlight.kind); + try std.testing.expect(pv.selection == null and pv.selection_text.len == 0); const revision_before_reveal = raster.revision; const max_document_scroll = @as(f64, @floatFromInt( pv.document_height -| panes.Pdf.paneViewport(p, pane).?.pixel_h, @@ -1928,6 +1935,7 @@ test "PDF native mouse selection, Look, and highlights share page geometry" { // Unsupported text-selection actions are consumed by the PDF adapter: // they neither invent a range over placeholder cells nor disturb the // native MuPDF selection. The select-button's no-drag click still clears. + try std.testing.expect(panes.Pdf.beginSelection(p, pane, word_col, selected_row)); p.update(.{ .key = .{ .cp = 'v' } }); try std.testing.expect(pv.selection != null); try std.testing.expect(!pane.vsel.active); |
