summaryrefslogtreecommitdiff
path: root/test/panes.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-28 01:01:35 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:14 -0300
commit9d2e07e997de155c7dbb894a79e5c11839eab39e (patch)
tree45d09fbe224693b2b9426213e59e56d5b1f35224 /test/panes.zig
parent425d9beb9c977df364ed83743cb2efdef9429478 (diff)
downloadpardes-9d2e07e997de155c7dbb894a79e5c11839eab39e.tar.gz
pardes-9d2e07e997de155c7dbb894a79e5c11839eab39e.zip
Scroll a tag taller than its rows to keep its caret in view
A tag shows at most eight rows, so a longer one (a 9P write of many lines, or `o` in the tag) put its caret on a line that was never drawn. Pane, column and workspace tags now keep a first line on screen that follows the caret while they have the keyboard, and the pointer and the pane text count their rows from it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'test/panes.zig')
-rw-r--r--test/panes.zig60
1 files changed, 60 insertions, 0 deletions
diff --git a/test/panes.zig b/test/panes.zig
index 954e431b..9b800430 100644
--- a/test/panes.zig
+++ b/test/panes.zig
@@ -228,6 +228,66 @@ test "a tag with a newline in it is as tall as its lines, and each line is typed
}
}
+test "a tag with more lines than rows scrolls to keep its caret in view" {
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 80, .rows = 30 });
+ defer p.deinit();
+ const pane = try p.setTestFile("body\n");
+ p.presentation.enabled = false;
+ var many: std.ArrayList(u8) = .empty;
+ defer many.deinit(std.testing.allocator);
+ for (1..21) |n| try many.print(std.testing.allocator, "\nL{d}", .{n});
+ try pane.appendTag(many.items);
+ p.update(.tick);
+ try std.testing.expectEqual(@as(u16, pardes.MAX_TAG_ROWS), pane.tag_rows);
+ var frame = std.heap.ArenaAllocator.init(std.testing.allocator);
+ defer frame.deinit();
+ const r = p.rects[0];
+ const x = r.x + pardes.TAG_TEXT_INSET;
+ // To the last line: the tag scrolls so it is the bottom row, caret on it.
+ p.update(.{ .key = .{ .cp = ':' } });
+ p.update(.{ .key = .{ .cp = 'g' } });
+ p.update(.{ .key = .{ .cp = 'e' } });
+ try std.testing.expectEqual(@as(i32, 20), pane.tag.cur_row);
+ const bottom = try p.render(frame.allocator());
+ const tag_y = p.tagTop(pane, r);
+ const last_row = tag_y + pardes.MAX_TAG_ROWS - 1;
+ try std.testing.expectEqual(last_row, bottom.cursor.?.y);
+ try std.testing.expectEqualStrings("L", bottom.at(x, last_row).grapheme());
+ try std.testing.expectEqualStrings("2", bottom.at(x + 1, last_row).grapheme());
+ try std.testing.expectEqualStrings("0", bottom.at(x + 2, last_row).grapheme());
+ // what the pointer sees is what is shown: its first row is line 13
+ const text = try pardes.edit.paneText(p, pane);
+ try std.testing.expectEqualStrings("L13", modal.lineSlice(text, 0));
+ ClickCursorTests.click(p, .left, x + 1, tag_y + 1);
+ try std.testing.expectEqual(@as(i32, 14), pane.tag.cur_row);
+ try std.testing.expectEqual(@as(i32, 1), pane.tag.cur_col);
+ // Back to the first line brings the prefix back into view.
+ p.update(.{ .key = .{ .cp = Key.escape } });
+ p.update(.{ .key = .{ .cp = 'g' } });
+ p.update(.{ .key = .{ .cp = 'g' } });
+ const top = try p.render(frame.allocator());
+ try std.testing.expectEqual(@as(u16, 0), pane.tag_top);
+ try std.testing.expectEqual(tag_y, top.cursor.?.y);
+ try std.testing.expectEqualStrings("/", top.at(x, tag_y).grapheme());
+
+ // A column tag does the same in its rows.
+ many.clearRetainingCapacity();
+ try many.appendSlice(std.testing.allocator, "New");
+ for (1..21) |n| try many.print(std.testing.allocator, "\nC{d}", .{n});
+ p.col_tags[0].own = try p.gpa.dupe(u8, many.items);
+ p.update(.tick);
+ const rows = p.columnBarHeight();
+ try std.testing.expectEqual(@as(u16, pardes.MAX_TAG_ROWS), rows);
+ pardes.tagline.enterHeader(p, 0);
+ p.update(.{ .key = .{ .cp = 'g' } });
+ p.update(.{ .key = .{ .cp = 'e' } });
+ const header = try p.render(frame.allocator());
+ const header_row = p.topBarHeight() + rows - 1;
+ try std.testing.expectEqual(header_row, header.cursor.?.y);
+ try std.testing.expectEqualStrings("C", header.at(p.col_x[0] + pardes.TAG_TEXT_INSET, header_row).grapheme());
+ try std.testing.expectEqualStrings("2", header.at(p.col_x[0] + pardes.TAG_TEXT_INSET + 1, header_row).grapheme());
+}
+
const TagNavigationTests = struct {
fn key(p: *Pardes, cp: u21) void {
p.update(.{ .key = .{ .cp = cp } });