summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/panes.zig162
1 files changed, 162 insertions, 0 deletions
diff --git a/test/panes.zig b/test/panes.zig
index 0577154f..073a9668 100644
--- a/test/panes.zig
+++ b/test/panes.zig
@@ -12,6 +12,167 @@ const image = pardes.image;
const syntax = pardes.syntax;
const filesystem = pardes.filesystem;
+const TreeContextTests = struct {
+ const source = "const Box = struct {\n" ++
+ " pub fn work(\n" ++
+ " value: usize,\n" ++
+ " ) void {\n" ++
+ " _ = value;\n" ++
+ " // one\n" ++
+ " // two\n" ++
+ " // three\n" ++
+ " // four\n" ++
+ " // five\n" ++
+ " // six\n" ++
+ " }\n" ++
+ "};\n";
+
+ fn setZigFile(p: *Pardes, content: []const u8) !*Pane {
+ const pane = try p.setTestFile(content);
+ p.gpa.free(pane.file.?.path);
+ pane.file.?.path = try p.gpa.dupe(u8, "/tree-context.zig");
+ p.presentation.enabled = false;
+ return pane;
+ }
+
+ test "TreeContext Look to an open file discards the old viewport extent" {
+ for ([_]bool{ false, true }) |context| {
+ if (context and !syntax.enabled) continue;
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 64, .rows = 18 });
+ defer p.deinit();
+ const pane = try setZigFile(p, "pub fn work() void {\n" ++ " // body\n" ** 100 ++ "}\n");
+ if (context) try std.testing.expect(p.executeBuiltinLine(0, "TreeContext"));
+ var frame = std.heap.ArenaAllocator.init(p.gpa);
+ defer frame.deinit();
+ _ = try p.render(frame.allocator());
+ try std.testing.expectEqual(@as(i32, 0), pane.scroll());
+ p.lookAt(0, "/tree-context.zig:60");
+ try std.testing.expectEqual(@as(usize, 0), p.active);
+ try std.testing.expectEqual(@as(i32, 59), pane.cur_row);
+ const surface = try p.render(frame.allocator());
+ const visible = pane.wrapRow(pane.cur_row, pane.cur_col);
+ try std.testing.expect(visible.row >= pane.context_rows);
+ try std.testing.expect(visible.row < pane.rows);
+ try std.testing.expectEqual(@as(i32, 59), pane.wrapAt(visible.row).line);
+ const cursor = surface.cursor orelse return error.MissingLookCursor;
+ const rect = p.rects[0];
+ const y = if (p.settings.tag_bottom) rect.y else rect.y + pardes.BOX_H;
+ try std.testing.expectEqual(y + @as(u16, @intCast(visible.row)), cursor.y);
+ }
+ }
+
+ test "TreeContext sticky declarations preserve the body while clicked and edited" {
+ if (!syntax.enabled) return error.SkipZigTest;
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 64, .rows = 18 });
+ defer p.deinit();
+ const pane = try setZigFile(p, source);
+ var frame = std.heap.ArenaAllocator.init(p.gpa);
+ defer frame.deinit();
+ pane.scrollBy(7);
+ _ = try p.render(frame.allocator());
+ try std.testing.expectEqual(@as(u16, 0), pane.context_rows);
+ try std.testing.expect(p.executeBuiltinLine(0, "TreeContext"));
+ _ = try p.render(frame.allocator());
+ try std.testing.expectEqual(@as(u16, 4), pane.context_rows);
+ for (0..4) |row| try std.testing.expectEqual(@as(i32, @intCast(row)), pane.wrapAt(@intCast(row)).line);
+ try std.testing.expectEqual(@as(i32, 7), pane.wrapAt(pane.context_rows).line);
+ const rect = p.rects[0];
+ const x = rect.x + config.GUTTER + panes.File.gutterWidth(pane);
+ const y = if (p.settings.tag_bottom) rect.y else rect.y + pardes.BOX_H;
+ ClickCursorTests.click(p, .left, x + 6, y);
+ try std.testing.expectEqual(@as(i32, 0), pane.cur_row);
+ try std.testing.expectEqual(@as(i32, 6), pane.cur_col);
+ try std.testing.expectEqual(@as(i32, 7), pane.scroll());
+ const cursor = (try p.render(frame.allocator())).cursor orelse return error.MissingContextCursor;
+ try std.testing.expectEqual(x + 6, cursor.x);
+ try std.testing.expectEqual(y, cursor.y);
+ p.update(.{ .key = .{ .cp = 'i' } });
+ p.update(.{ .key = .{ .cp = 'Z', .text = "Z" } });
+ try std.testing.expect(std.mem.startsWith(u8, pane.file.?.content, "const ZBox = struct {"));
+ try std.testing.expectEqual(@as(i32, 7), pane.scroll());
+ _ = try p.render(frame.allocator());
+ try std.testing.expectEqual(@as(u16, 4), pane.context_rows);
+ p.update(.{ .key = .{ .cp = Key.escape } });
+ var previous: u16 = pane.context_rows;
+ while (pane.scroll() > 0) {
+ pane.scrollBy(-1);
+ _ = try p.render(frame.allocator());
+ try std.testing.expect(pane.context_rows <= previous);
+ previous = pane.context_rows;
+ try std.testing.expectEqual(pane.scroll(), pane.wrapAt(pane.context_rows).line);
+ }
+ try std.testing.expectEqual(@as(u16, 0), pane.context_rows);
+ try std.testing.expectEqual(@as(i32, 0), pane.wrapRow(0, pane.cur_col).row);
+ try std.testing.expect(p.executeBuiltinLine(0, "TreeContext"));
+ pane.scrollBy(7);
+ _ = try p.render(frame.allocator());
+ try std.testing.expectEqual(@as(u16, 0), pane.context_rows);
+ }
+
+ test "TreeContext unwrapped headers map Unicode and survive source replacement" {
+ if (!syntax.enabled) return error.SkipZigTest;
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 48, .rows = 14 });
+ defer p.deinit();
+ const pane = try setZigFile(p, "pub fn @\"界name\"(\n\tvalue: usize,\n) void {\n" ++ " _ = value;\n" ** 12 ++ "}\n");
+ p.settings.wrap = false;
+ p.settings.colors = false;
+ try std.testing.expect(p.executeBuiltinLine(0, "TreeContext"));
+ pane.scrollBy(8);
+ pane.hscroll = 4;
+ var frame = std.heap.ArenaAllocator.init(p.gpa);
+ defer frame.deinit();
+ const surface = try p.render(frame.allocator());
+ try std.testing.expectEqual(@as(u16, 3), pane.context_rows);
+ const rect = p.rects[0];
+ const y = if (p.settings.tag_bottom) rect.y else rect.y + pardes.BOX_H;
+ var glyph_x: ?u16 = null;
+ for (0..surface.cols) |col| {
+ if (std.mem.eql(u8, surface.at(@intCast(col), y).grapheme(), "界")) glyph_x = @intCast(col);
+ }
+ const x = glyph_x orelse return error.MissingContextUnicode;
+ ClickCursorTests.click(p, .left, x + 1, y);
+ try std.testing.expectEqual(@as(i32, 0), pane.cur_row);
+ try std.testing.expectEqual(@as(i32, 9), pane.cur_col);
+ try std.testing.expectEqual(@as(i32, 8), pane.scroll());
+ const cursor = (try p.render(frame.allocator())).cursor orelse return error.MissingContextCursor;
+ try std.testing.expectEqual(x, cursor.x);
+ try std.testing.expectEqual(y, cursor.y);
+ panes.File.setContent(p, &pane.file.?, try p.gpa.dupe(u8, "// no enclosing declaration\n" ** 18));
+ _ = try p.render(frame.allocator());
+ try std.testing.expectEqual(@as(u16, 0), pane.context_rows);
+ try std.testing.expectEqual(pane.scroll(), pane.wrapAt(0).line);
+ }
+
+ test "TreeContext clipped headers leave wrapped body cursor coordinates intact" {
+ if (!syntax.enabled) return error.SkipZigTest;
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 24, .rows = 12 });
+ defer p.deinit();
+ const body = " // 012345678901234567890123456789界tail";
+ const pane = try setZigFile(p, "pub fn aLongDeclarationNameThatCannotFit() void {\n // before\n" ++ body ++ "\n}\n");
+ p.settings.wrap = true;
+ try std.testing.expect(p.executeBuiltinLine(0, "TreeContext"));
+ pane.scrollBy(2);
+ var frame = std.heap.ArenaAllocator.init(p.gpa);
+ defer frame.deinit();
+ const surface = try p.render(frame.allocator());
+ try std.testing.expectEqual(@as(u16, 1), pane.context_rows);
+ try std.testing.expectEqual(@as(i32, 2), pane.wrapAt(1).line);
+ try std.testing.expectEqual(@as(i32, 2), pane.wrapAt(2).line);
+ var target: ?struct { x: u16, y: u16 } = null;
+ for (0..surface.rows) |row| for (0..surface.cols) |col| {
+ if (std.mem.eql(u8, surface.at(@intCast(col), @intCast(row)).grapheme(), "界"))
+ target = .{ .x = @intCast(col), .y = @intCast(row) };
+ };
+ const glyph = target orelse return error.MissingWrappedContextBody;
+ ClickCursorTests.click(p, .left, glyph.x + 1, glyph.y);
+ try std.testing.expectEqual(@as(i32, 2), pane.cur_row);
+ try std.testing.expectEqual(@as(i32, @intCast(std.mem.indexOf(u8, body, "界").?)), pane.cur_col);
+ const cursor = (try p.render(frame.allocator())).cursor orelse return error.MissingContextBodyCursor;
+ try std.testing.expectEqual(glyph.x, cursor.x);
+ try std.testing.expectEqual(glyph.y, cursor.y);
+ }
+};
+
const TtySelectionTests = struct {
fn noChildInput(p: *Pardes) !void {
while (p.nextEffect()) |effect| {
@@ -2972,6 +3133,7 @@ const TerminalTests = struct {
};
test {
+ _ = TreeContextTests;
_ = TtySelectionTests;
_ = ClickCursorTests;
_ = JumpSelectionTests;