summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-15 18:59:33 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:14 -0300
commitb7914a0bd59334f618b62e0b98271211bbec46b9 (patch)
tree53af62ce0ae022e580e35aadbd952e1656dcfa30 /test
parent3f4f26e0e40d06427e72f72e760d01adcdc0326c (diff)
downloadpardes-b7914a0bd59334f618b62e0b98271211bbec46b9.tar.gz
pardes-b7914a0bd59334f618b62e0b98271211bbec46b9.zip
Clear previous selections before resolving Look destinations
Diffstat (limited to 'test')
-rw-r--r--test/panes.zig110
-rw-r--r--test/pdf.zig26
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);