diff options
Diffstat (limited to 'test/panes.zig')
| -rw-r--r-- | test/panes.zig | 162 |
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; |
