summaryrefslogtreecommitdiff
path: root/test/panes.zig
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/panes.zig
parent3f4f26e0e40d06427e72f72e760d01adcdc0326c (diff)
downloadpardes-b7914a0bd59334f618b62e0b98271211bbec46b9.tar.gz
pardes-b7914a0bd59334f618b62e0b98271211bbec46b9.zip
Clear previous selections before resolving Look destinations
Diffstat (limited to 'test/panes.zig')
-rw-r--r--test/panes.zig110
1 files changed, 110 insertions, 0 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;
+}