diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-27 23:06:11 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:14 -0300 |
| commit | 95a3a1bb822e583988bfe0f312d0ef219b27a454 (patch) | |
| tree | 95306e8d3f36f8af05b3ea919f6cdef1e94a028b /test/panes.zig | |
| parent | c8f0c25a854b8e169db08a84d1fdcd915a70aaa0 (diff) | |
| download | pardes-95a3a1bb822e583988bfe0f312d0ef219b27a454.tar.gz pardes-95a3a1bb822e583988bfe0f312d0ef219b27a454.zip | |
Give a pane's body its own Text holding the cursor, selections, mode and undo
acme keeps what edits a text in its Text (dat.h:171-190) and the window
holds a body and a tag of that type. The cursor, the selections, the modal
state and the edit-buffer undo move off Pane into Text.zig, Pane holds
them as its body, and the edit and normal-mode operations take the Text
they edit. Nothing changes in behaviour; this is the step that lets the
tag become a second Text.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'test/panes.zig')
| -rw-r--r-- | test/panes.zig | 398 |
1 files changed, 199 insertions, 199 deletions
diff --git a/test/panes.zig b/test/panes.zig index 60dabb8a..4c969ab5 100644 --- a/test/panes.zig +++ b/test/panes.zig @@ -327,14 +327,14 @@ const TagNavigationTests = struct { key(p, 'i'); key(p, Key.end); const before = pane.tag_tail_len; - try std.testing.expect(pane.tag_edit and pane.mode == .insert); + try std.testing.expect(pane.tag_edit and pane.body.mode == .insert); for ("hjklHJKL") |letter| { const text = [_]u8{letter}; p.update(.{ .key = .{ .cp = letter, .text = &text } }); - try std.testing.expect(pane.tag_edit and pane.mode == .insert); + try std.testing.expect(pane.tag_edit and pane.body.mode == .insert); } try std.testing.expectEqualStrings("hjklHJKL", pane.tag_tail[before..pane.tag_tail_len]); - try std.testing.expect(pane.tag_edit and pane.mode == .insert and p.topbar_col == null); + try std.testing.expect(pane.tag_edit and pane.body.mode == .insert and p.topbar_col == null); try std.testing.expectEqual(@as(usize, 0), p.active); } } @@ -370,7 +370,7 @@ const BodyHitTests = struct { const expected = pane.wrapAt(row).line; p.update(.{ .mouse = mouse(layer, row, 2, .press) }); p.update(.{ .mouse = mouse(layer, row, 2, .release) }); - try std.testing.expectEqual(expected, pane.cur_row); + try std.testing.expectEqual(expected, pane.body.cur_row); try std.testing.expectEqual(top, pane.scroll()); } const last = pane.body_visible_rows - 1; @@ -383,11 +383,11 @@ const BodyHitTests = struct { try std.testing.expectEqualStrings("body\nbody", pardes.test_api.heldSelection(p, 0).?); p.update(.{ .mouse = mouse(layer, last, 10, .press) }); p.update(.{ .mouse = mouse(layer, last, 10, .release) }); - try std.testing.expectEqual(expected, pane.cur_row); + try std.testing.expectEqual(expected, pane.body.cur_row); var stale = mouse(layer, 0, 2, .press); stale.body_hit.?.serial +%= 1; p.update(.{ .mouse = stale }); - try std.testing.expectEqual(expected, pane.cur_row); + try std.testing.expectEqual(expected, pane.body.cur_row); p.update(.{ .key = .{ .cp = 'i' } }); p.update(.{ .key = .{ .cp = 'X', .text = "X" } }); try std.testing.expect(std.mem.indexOfScalar(u8, modal.lineSlice(pane.file.?.content, @intCast(expected)), 'X') != null); @@ -425,7 +425,7 @@ const LineNumberLookTests = struct { release.button = .right; p.update(.{ .mouse = press }); p.update(.{ .mouse = release }); - try std.testing.expectEqual(expected, pane.cur_row); + try std.testing.expectEqual(expected, pane.body.cur_row); } } }; @@ -496,9 +496,9 @@ const TreeContextTests = struct { try std.testing.expectEqual(@as(i32, 0), pane.scroll()); pardes.look.lookAt(p, 0, "/tree-context.zig:60"); try std.testing.expectEqual(@as(usize, 0), p.active); - try std.testing.expectEqual(@as(i32, 59), pane.cur_row); + try std.testing.expectEqual(@as(i32, 59), pane.body.cur_row); const surface = try p.render(frame.allocator()); - const visible = pane.wrapRow(pane.cur_row, pane.cur_col); + const visible = pane.wrapRow(pane.body.cur_row, pane.body.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); @@ -528,8 +528,8 @@ const TreeContextTests = struct { const x = rect.x + config.GUTTER + panes.File.gutterWidth(pane); const y = p.bodyTop(rect); 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, 0), pane.body.cur_row); + try std.testing.expectEqual(@as(i32, 6), pane.body.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); @@ -552,7 +552,7 @@ const TreeContextTests = struct { 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.expectEqual(@as(i32, 0), pane.wrapRow(0, pane.body.cur_col).row); try std.testing.expect(p.executeBuiltinLine(0, "TreeContext")); pane.scrollBy(7); _ = try p.render(frame.allocator()); @@ -581,8 +581,8 @@ const TreeContextTests = struct { } 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, 0), pane.body.cur_row); + try std.testing.expectEqual(@as(i32, 9), pane.body.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); @@ -617,8 +617,8 @@ const TreeContextTests = struct { }; 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); + try std.testing.expectEqual(@as(i32, 2), pane.body.cur_row); + try std.testing.expectEqual(@as(i32, @intCast(std.mem.indexOf(u8, body, "界").?)), pane.body.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); @@ -652,7 +652,7 @@ const TtySelectionTests = struct { try std.testing.expectEqualStrings("lph", p.yank orelse return error.MissingAutomaticTtyYank); p.update(.{ .key = .{ .cp = p.opts.tty_toggle, .ctrl = true } }); p.update(.{ .key = .{ .cp = 'l' } }); - try std.testing.expectEqual(@as(i32, 4), pane.cur_col); + try std.testing.expectEqual(@as(i32, 4), pane.body.cur_col); p.update(.{ .key = .{ .cp = 'y' } }); try std.testing.expectEqualStrings("a", p.yank.?); try noChildInput(p); @@ -664,7 +664,7 @@ const TtySelectionTests = struct { const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 40, .rows = 12 }); defer p.deinit(); const pane = p.panes[0].?; - pane.mode = .tty; + pane.body.mode = .tty; pane.tty_filter = false; p.presentation.enabled = false; while (p.nextEffect()) |_| {} @@ -680,7 +680,7 @@ const TtySelectionTests = struct { const y = p.bodyTop(rect); JumpSelectionTests.drag(p, x + @as(u16, if (prompt) 0 else 1), y, x + 3, y + @as(u16, if (prompt) 0 else 1)); const expected = if (prompt) "$ ab" else "lph\nrav"; - try std.testing.expectEqual(Pane.Mode.tty, pane.mode); + try std.testing.expectEqual(panes.Text.Mode.tty, pane.body.mode); try std.testing.expectEqualStrings(expected, pardes.test_api.heldSelection(p, 0).?); try std.testing.expectEqualStrings(expected, p.yank orelse return error.MissingAutomaticTtyYank); try noChildInput(p); @@ -689,7 +689,7 @@ const TtySelectionTests = struct { try noChildInput(p); try std.testing.expectEqualStrings(expected, p.fallback.clipboard.items); p.update(.{ .key = .{ .cp = p.opts.tty_toggle, .ctrl = true } }); - try std.testing.expectEqual(Pane.Mode.normal, pane.mode); + try std.testing.expectEqual(panes.Text.Mode.normal, pane.body.mode); const normal = try p.render(frame.allocator()); if (!prompt) { const selection_bg: pardes.Color = .{ .rgb = p.theme().sel_bg }; @@ -701,13 +701,13 @@ const TtySelectionTests = struct { try std.testing.expectEqualStrings(expected, p.yank.?); try noChildInput(p); p.update(.{ .key = .{ .cp = p.opts.tty_toggle, .ctrl = true } }); - try std.testing.expectEqual(Pane.Mode.tty, pane.mode); + try std.testing.expectEqual(panes.Text.Mode.tty, pane.body.mode); try noChildInput(p); _ = try p.render(frame.allocator()); try std.testing.expectEqualStrings(expected, pardes.test_api.heldSelection(p, 0).?); p.update(.{ .output = .{ .pane = 0, .bytes = "\x1b]133;C\x07" ++ "\r\nnew output" ** 30 } }); _ = try p.render(frame.allocator()); - try std.testing.expectEqual(Pane.Mode.tty, pane.mode); + try std.testing.expectEqual(panes.Text.Mode.tty, pane.body.mode); try std.testing.expectEqualStrings(expected, pardes.test_api.heldSelection(p, 0).?); try std.testing.expectEqualStrings(expected, p.yank.?); try noChildInput(p); @@ -723,7 +723,7 @@ const TtySelectionTests = struct { p.presentation.enabled = false; pardes.exec.spawnTty(p, 0); for (p.panes[0..2]) |slot| { - slot.?.mode = .tty; + slot.?.body.mode = .tty; slot.?.tty_filter = false; slot.?.greet = false; slot.?.vweight = 1; @@ -765,8 +765,8 @@ const TtySelectionTests = struct { }); defer p.gpa.free(expected); try std.testing.expectEqualStrings(expected, written.written()); - try std.testing.expectEqual(Pane.Mode.tty, p.panes[0].?.mode); - try std.testing.expectEqual(Pane.Mode.tty, p.panes[1].?.mode); + try std.testing.expectEqual(panes.Text.Mode.tty, p.panes[0].?.body.mode); + try std.testing.expectEqual(panes.Text.Mode.tty, p.panes[1].?.body.mode); try std.testing.expectEqualStrings("lph\nrav", pardes.test_api.heldSelection(p, 0).?); } } @@ -799,7 +799,7 @@ const TtySelectionTests = struct { const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 40, .rows = 12 }); defer p.deinit(); const pane = p.panes[0].?; - try std.testing.expectEqual(Pane.Mode.tty, pane.mode); + try std.testing.expectEqual(panes.Text.Mode.tty, pane.body.mode); if (bracketed) p.update(.{ .output = .{ .pane = 0, .bytes = "\x1b[?2004h" } }); try std.testing.expectEqual(bracketed, panes.Terminal.bracketedPaste(pane)); p.yank = try p.gpa.dupe(u8, "one\ntwo"); // what a `y` anywhere left behind @@ -867,13 +867,13 @@ const ClickCursorTests = struct { const x = rect.x + config.GUTTER + panes.File.gutterWidth(pane); const y = if (bottom_tag) rect.y else rect.y + pardes.BOX_H; click(p, .left, x + 15, y + case.click_row); - try std.testing.expectEqual(case.row, pane.cur_row); - try std.testing.expectEqual(case.col, pane.cur_col); + try std.testing.expectEqual(case.row, pane.body.cur_row); + try std.testing.expectEqual(case.col, pane.body.cur_col); const clicked = (try p.render(frame.allocator())).cursor orelse return error.MissingClickCursor; try std.testing.expectEqual(x + @as(u16, @intCast(case.col)), clicked.x); try std.testing.expectEqual(y + @as(u16, @intCast(case.row)), clicked.y); if (!already_insert) p.update(.{ .key = .{ .cp = 'i' } }); - try std.testing.expectEqual(Pane.Mode.insert, pane.mode); + try std.testing.expectEqual(panes.Text.Mode.insert, pane.body.mode); const insert = (try p.render(frame.allocator())).cursor orelse return error.MissingInsertCursor; try std.testing.expectEqual(clicked.x, insert.x); try std.testing.expectEqual(clicked.y, insert.y); @@ -906,12 +906,12 @@ const ClickCursorTests = struct { if (wrap) try std.testing.expect(glyph.y > p.rects[0].y + pardes.BOX_H); click(p, .left, glyph.x + 1, glyph.y); const byte = std.mem.indexOf(u8, source, "界").?; - try std.testing.expectEqual(@as(i32, @intCast(byte)), pane.cur_col); + try std.testing.expectEqual(@as(i32, @intCast(byte)), pane.body.cur_col); const clicked = (try p.render(frame.allocator())).cursor orelse return error.MissingClickCursor; try std.testing.expectEqual(glyph.x, clicked.x); try std.testing.expectEqual(glyph.y, clicked.y); if (!already_insert) p.update(.{ .key = .{ .cp = 'i' } }); - try std.testing.expectEqual(Pane.Mode.insert, pane.mode); + try std.testing.expectEqual(panes.Text.Mode.insert, pane.body.mode); const insert = (try p.render(frame.allocator())).cursor orelse return error.MissingInsertCursor; try std.testing.expectEqual(clicked.x, insert.x); try std.testing.expectEqual(clicked.y, insert.y); @@ -1016,10 +1016,10 @@ const JumpSelectionTests = struct { try std.testing.expectEqual(@as(usize, 0), p.jcur); try std.testing.expect(pane.file.?.scroll > 20); try LookResetTests.cleared(pane); - try std.testing.expect(!pane.vsel.active); + try std.testing.expect(!pane.body.vsel.active); try std.testing.expect(pardes.test_api.heldSelection(p, 0) == null); - try std.testing.expectEqual(@as(i32, 59), pane.cur_row); - try std.testing.expectEqual(@as(i32, 0), pane.cur_col); + try std.testing.expectEqual(@as(i32, 59), pane.body.cur_row); + try std.testing.expectEqual(@as(i32, 0), pane.body.cur_col); // A selection created after Back must also disappear on Forward. // Back announces itself, so the body sits under a notice band now. @@ -1032,10 +1032,10 @@ const JumpSelectionTests = struct { try std.testing.expectEqual(@as(usize, 1), p.jcur); try std.testing.expectEqual(@as(usize, 0), pane.file.?.scroll); try LookResetTests.cleared(pane); - try std.testing.expect(!pane.vsel.active); + try std.testing.expect(!pane.body.vsel.active); try std.testing.expect(pardes.test_api.heldSelection(p, 0) == null); - try std.testing.expectEqual(@as(i32, 0), pane.cur_row); - try std.testing.expectEqual(@as(i32, 0), pane.cur_col); + try std.testing.expectEqual(@as(i32, 0), pane.body.cur_row); + try std.testing.expectEqual(@as(i32, 0), pane.body.cur_col); } test "jump selection clears copied rectangles in both history directions" { @@ -1073,9 +1073,9 @@ const JumpSelectionTests = struct { try std.testing.expectEqual(@as(usize, 0), p.jcur); try LookResetTests.cleared(source); try LookResetTests.cleared(destination); - try std.testing.expect(!source.vsel.active and !destination.vsel.active); - try std.testing.expectEqual(@as(i32, 2), destination.cur_row); - try std.testing.expectEqual(@as(i32, 1), destination.cur_col); + try std.testing.expect(!source.body.vsel.active and !destination.body.vsel.active); + try std.testing.expectEqual(@as(i32, 2), destination.body.cur_row); + try std.testing.expectEqual(@as(i32, 1), destination.body.cur_col); try LookResetTests.seed(source, "new source held text"); try LookResetTests.seed(destination, "new destination held text"); @@ -1084,9 +1084,9 @@ const JumpSelectionTests = struct { try std.testing.expectEqual(@as(usize, 1), p.jcur); try LookResetTests.cleared(source); try LookResetTests.cleared(destination); - try std.testing.expect(!source.vsel.active and !destination.vsel.active); - try std.testing.expectEqual(@as(i32, 1), source.cur_row); - try std.testing.expectEqual(@as(i32, 0), source.cur_col); + try std.testing.expect(!source.body.vsel.active and !destination.body.vsel.active); + try std.testing.expectEqual(@as(i32, 1), source.body.cur_row); + try std.testing.expectEqual(@as(i32, 0), source.body.cur_col); } }; @@ -1395,7 +1395,7 @@ test "terminal overlay recoloring never materializes unrelated history" { const pane = p.panes[0].?; pane.tty_filter = false; for (0..1000) |_| p.update(.{ .output = .{ .pane = 0, .bytes = "\x1b[32mcaf\xc3\xa9 \xe7\x95\x8c\x1b[0m\r\n" } }); - pane.mode = .normal; + pane.body.mode = .normal; pane.ovl = .{ .row = 0, .rows = 1, .text = try p.gpa.dupe(u8, "edited history") }; var frame = std.heap.ArenaAllocator.init(testing.allocator); defer frame.deinit(); @@ -1422,7 +1422,7 @@ test "terminal output keeps following new rows after scrollback eviction" { defer p.deinit(); while (p.nextEffect()) |_| {} const pane = p.panes[0].?; - pane.mode = .tty; + pane.body.mode = .tty; pane.tty_filter = false; const pages = &pane.terminal.?.vt.screens.active.pages; pages.explicit_max_size = 64 * 1024; @@ -1431,7 +1431,7 @@ test "terminal output keeps following new rows after scrollback eviction" { var evictions: usize = 0; for (0..3) |phase| { if (phase > 0) { - pane.mode = .normal; + pane.body.mode = .normal; panes.Terminal.scrollGrid(pane, -30); try std.testing.expect(pages.scrollbar().offset < pages.scrollbar().total - pane.rows); panes.Terminal.enterTty(p, 0); @@ -1483,7 +1483,7 @@ test "terminal edit stays on its surviving row when old scrollback is evicted" { defer p.deinit(); while (p.nextEffect()) |_| {} const pane = p.panes[0].?; - pane.mode = .tty; + pane.body.mode = .tty; const pages = &pane.terminal.?.vt.screens.active.pages; pages.explicit_max_size = 64 * 1024; var next: usize = 0; @@ -1497,12 +1497,12 @@ test "terminal edit stays on its surviving row when old scrollback is evicted" { try std.testing.expect(next < 3000); var last_buf: [16]u8 = undefined; const last = try std.fmt.bufPrint(&last_buf, "row-{d:0>5}", .{next - 1}); - pane.mode = .normal; + pane.body.mode = .normal; const original_row: i32 = @intCast(pages.scrollbar().total - 2); pane.ovl = .{ .row = original_row, .rows = 1, .text = try gpa.dupe(u8, "my unsent edit") }; - pane.cur_row = original_row; - pane.cur_col = 3; - pane.cur_pinned = true; + pane.body.cur_row = original_row; + pane.body.cur_col = 3; + pane.body.cur_pinned = true; var removed: usize = 0; for (next..next + 3000) |n| { var buf: [32]u8 = undefined; @@ -1520,7 +1520,7 @@ test "terminal edit stays on its surviving row when old scrollback is evicted" { const row = original_row - @as(i32, @intCast(removed)); try std.testing.expectEqualStrings(last, modal.lineSlice(full, @intCast(row))); try std.testing.expectEqual(row, pane.ovl.?.row); - try std.testing.expectEqual(row, pane.cur_row); + try std.testing.expectEqual(row, pane.body.cur_row); try std.testing.expectEqualStrings("my unsent edit", pane.ovl.?.text); } @@ -1533,7 +1533,7 @@ test "terminal edits and undo survive partial history clearing and whole-screen defer p.deinit(); while (p.nextEffect()) |_| {} const pane = p.panes[0].?; - pane.mode = .tty; + pane.body.mode = .tty; if (action == .reset_alternate) p.update(.{ .output = .{ .pane = 0, .bytes = "\x1b[?1049h" } }); p.update(.{ .output = .{ .pane = 0, .bytes = "old row\r\n" ** 40 } }); @@ -1541,15 +1541,15 @@ test "terminal edits and undo survive partial history clearing and whole-screen pages.explicit_max_size = 64 * 1024; const row: i32 = @as(i32, @intCast(pages.total_rows - pane.rows)) + @as(i32, if (action == .partial_clear_history) -1 else 2); - pane.mode = .normal; + pane.body.mode = .normal; pane.ovl = .{ .row = row, .rows = if (action == .partial_clear_history) 3 else 2, .text = try gpa.dupe(u8, "edit one\nedit two") }; - pane.cur_row = row + 1; - pane.cur_col = 4; - pane.cur_pinned = true; - pane.vsel = .{ .active = true, .row = row, .col = 1 }; + pane.body.cur_row = row + 1; + pane.body.cur_col = 4; + pane.body.cur_pinned = true; + pane.body.vsel = .{ .active = true, .row = row, .col = 1 }; panes.Terminal.pushUndo(p, pane); - pane.ed_redo[0] = panes.Terminal.snap(p, pane) orelse return error.SnapshotFailed; - pane.ed_redo_len = 1; + pane.body.ed_redo[0] = panes.Terminal.snap(p, pane) orelse return error.SnapshotFailed; + pane.body.ed_redo_len = 1; if (action == .hidden_undo) { gpa.free(pane.ovl.?.text); pane.ovl = null; @@ -1566,10 +1566,10 @@ test "terminal edits and undo survive partial history clearing and whole-screen try std.testing.expectEqual(expected, edit.row); try std.testing.expectEqual(@as(i32, if (action == .clear_history or action == .partial_clear_history) 2 else 1), edit.rows); try std.testing.expectEqualStrings("edit one\nedit two", edit.text); - try std.testing.expectEqual(expected + 1, pane.cur_row); - try std.testing.expectEqual(expected, pane.vsel.row); + try std.testing.expectEqual(expected + 1, pane.body.cur_row); + try std.testing.expectEqual(expected, pane.body.vsel.row); } - for ([_]panes.Terminal.Snapshot{ pane.ed_undo[0], pane.ed_redo[0] }) |snapshot| { + for ([_]panes.Terminal.Snapshot{ pane.body.ed_undo[0], pane.body.ed_redo[0] }) |snapshot| { try std.testing.expectEqual(expected, snapshot.ovl.?.row); try std.testing.expectEqual(expected + 1, snapshot.cur_row); try std.testing.expectEqualStrings("edit one\nedit two", snapshot.ovl.?.text); @@ -1588,11 +1588,11 @@ test "terminal lower scroll regions do not move edits above them" { defer p.deinit(); while (p.nextEffect()) |_| {} const pane = p.panes[0].?; - pane.mode = .normal; + pane.body.mode = .normal; p.update(.{ .output = .{ .pane = 0, .bytes = "top\r\nsecond\r\nthird" } }); pane.ovl = .{ .row = 1, .rows = 1, .text = try gpa.dupe(u8, "unsent") }; - pane.cur_row = 1; - pane.cur_pinned = true; + pane.body.cur_row = 1; + pane.body.cur_pinned = true; panes.Terminal.pushUndo(p, pane); const total = panes.Terminal.scrollbar(pane).total; var setup: [64]u8 = undefined; @@ -1601,8 +1601,8 @@ test "terminal lower scroll regions do not move edits above them" { p.update(.{ .output = .{ .pane = 0, .bytes = "tail\r\n" ** 50 } }); try std.testing.expectEqual(total, panes.Terminal.scrollbar(pane).total); try std.testing.expectEqual(@as(i32, 1), pane.ovl.?.row); - try std.testing.expectEqual(@as(i32, 1), pane.cur_row); - try std.testing.expectEqual(@as(i32, 1), pane.ed_undo[0].ovl.?.row); + try std.testing.expectEqual(@as(i32, 1), pane.body.cur_row); + try std.testing.expectEqual(@as(i32, 1), pane.body.ed_undo[0].ovl.?.row); const full = try panes.Terminal.screenTextAlloc(pane, gpa); defer gpa.free(full); try std.testing.expect(std.mem.startsWith(u8, full, "top\nsecond\nthird\n")); @@ -1615,7 +1615,7 @@ test "terminal eviction and lower-region scrolling in one read preserve a surviv defer p.deinit(); while (p.nextEffect()) |_| {} const pane = p.panes[0].?; - pane.mode = .tty; + pane.body.mode = .tty; const pages = &pane.terminal.?.vt.screens.active.pages; pages.explicit_max_size = 64 * 1024; var next: usize = 0; @@ -1630,10 +1630,10 @@ test "terminal eviction and lower-region scrolling in one read preserve a surviv try std.testing.expect(next < 3000); const removed = pages.pages.first.?.rows(); const old_row: i32 = @intCast(removed + 2); - pane.mode = .normal; + pane.body.mode = .normal; pane.ovl = .{ .row = old_row, .rows = 1, .text = try gpa.dupe(u8, "kept edit") }; - pane.cur_row = old_row; - pane.cur_pinned = true; + pane.body.cur_row = old_row; + pane.body.cur_pinned = true; panes.Terminal.pushUndo(p, pane); const old_total = pages.total_rows; var buf: [128]u8 = undefined; @@ -1641,8 +1641,8 @@ test "terminal eviction and lower-region scrolling in one read preserve a surviv p.update(.{ .output = .{ .pane = 0, .bytes = bytes } }); try std.testing.expectEqual(old_total + 1 - removed, pages.total_rows); try std.testing.expectEqual(@as(i32, 2), pane.ovl.?.row); - try std.testing.expectEqual(@as(i32, 2), pane.cur_row); - try std.testing.expectEqual(@as(i32, 2), pane.ed_undo[0].ovl.?.row); + try std.testing.expectEqual(@as(i32, 2), pane.body.cur_row); + try std.testing.expectEqual(@as(i32, 2), pane.body.ed_undo[0].ovl.?.row); try std.testing.expectEqualStrings("kept edit", pane.ovl.?.text); } @@ -1667,9 +1667,9 @@ test "tag prompt entry and cancellation preserve exact text and cursor state" { pane.tag_init = true; pane.tag_sel = true; pane.tag_col = 1; - pane.cur_row = 1; - pane.cur_col = 2; - pane.cur_pinned = true; + pane.body.cur_row = 1; + pane.body.cur_col = 2; + pane.body.cur_pinned = true; if (case.key) |key| { p.update(.{ .key = key }); } else if (case.save) { @@ -1679,18 +1679,18 @@ test "tag prompt entry and cancellation preserve exact text and cursor state" { } try std.testing.expect(pane.tag_edit); try std.testing.expect(!pane.tag_sel); - try std.testing.expectEqual(.insert, pane.mode); - try std.testing.expectEqualDeep(modal.Normal.State{}, pane.normal); + try std.testing.expectEqual(.insert, pane.body.mode); + try std.testing.expectEqualDeep(modal.Normal.State{}, pane.body.normal); try std.testing.expectEqualStrings(tail, pane.tag_tail[0..tail.len]); try std.testing.expectEqualStrings(case.marker, pane.tag_tail[tail.len..pane.tag_tail_len]); try std.testing.expectEqual(pane.file.?.path.len + pane.tag_tail_len, pane.tag_col); p.update(.{ .key = .{ .cp = Key.escape } }); try std.testing.expect(pane.prompt == .none); try std.testing.expect(!pane.tag_edit); - try std.testing.expectEqual(.normal, pane.mode); + try std.testing.expectEqual(.normal, pane.body.mode); try std.testing.expectEqualStrings(tail, pane.tag_tail[0..pane.tag_tail_len]); - try std.testing.expectEqual(@as(i32, 1), pane.cur_row); - try std.testing.expectEqual(@as(i32, 2), pane.cur_col); + try std.testing.expectEqual(@as(i32, 1), pane.body.cur_row); + try std.testing.expectEqual(@as(i32, 2), pane.body.cur_col); try std.testing.expectEqualStrings("one\ntwo\n", pane.file.?.content); } } @@ -1713,7 +1713,7 @@ test "tag prompt capacity refusal leaves the existing tail and input state untou try std.testing.expect(pane.prompt == .none); try std.testing.expect(!pane.tag_edit); try std.testing.expect(pane.tag_sel); - try std.testing.expectEqual(.normal, pane.mode); + try std.testing.expectEqual(.normal, pane.body.mode); try std.testing.expectEqual(@as(u16, 17), pane.tag_col); try std.testing.expectEqual(pane.tag_tail.len - 1, pane.tag_tail_len); for (pane.tag_tail) |byte| try std.testing.expectEqual(@as(u8, 'x'), byte); @@ -1739,9 +1739,9 @@ test "tag prompt owns the pipe behavior through cancellation and submission" { const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true }); defer p.deinit(); const pane = try p.setTestFile("one\ntwo\n"); - pane.cur_row = 0; - pane.cur_col = 2; - pane.vsel = .{ .active = true, .row = 0, .col = 0, .explicit = true }; + pane.body.cur_row = 0; + pane.body.cur_col = 2; + pane.body.vsel = .{ .active = true, .row = 0, .col = 0, .explicit = true }; for (std.enums.values(modal.Normal.PipeBehavior)) |how| { p.startPrompt(pane, .{ .pipe = .append }); p.update(.{ .key = .{ .cp = Key.escape } }); @@ -1767,21 +1767,21 @@ test "tag prompt cancellation restores the selection before regex previews" { .{ .key = 'S', .pattern = " ", .secondary = 2 }, }; for (cases) |case| { - pane.cur_row = 0; - pane.cur_col = 10; - pane.cur_pinned = true; - pane.vsel = .{ .active = true, .row = 0, .col = 0, .explicit = true }; - pane.nsel = 0; + pane.body.cur_row = 0; + pane.body.cur_col = 10; + pane.body.cur_pinned = true; + pane.body.vsel = .{ .active = true, .row = 0, .col = 0, .explicit = true }; + pane.body.nsel = 0; p.update(.{ .key = .{ .cp = case.key } }); try std.testing.expect(pane.prompt == .search); p.update(.{ .key = .{ .cp = case.pattern[0], .text = case.pattern } }); - try std.testing.expectEqual(case.secondary, pane.nsel); + try std.testing.expectEqual(case.secondary, pane.body.nsel); p.update(.{ .key = .{ .cp = Key.escape } }); - try std.testing.expectEqual(@as(u8, 0), pane.nsel); + try std.testing.expectEqual(@as(u8, 0), pane.body.nsel); try std.testing.expectEqual(@as(u8, 0), pane.nsel_snap); - try std.testing.expectEqual(@as(i32, 10), pane.cur_col); - try std.testing.expectEqual(@as(i32, 0), pane.vsel.col); - try std.testing.expect(pane.vsel.active and pane.vsel.explicit); + try std.testing.expectEqual(@as(i32, 10), pane.body.cur_col); + try std.testing.expectEqual(@as(i32, 0), pane.body.vsel.col); + try std.testing.expect(pane.body.vsel.active and pane.body.vsel.explicit); try std.testing.expectEqualStrings("one two one", pane.file.?.content); } } @@ -1802,18 +1802,18 @@ test "tag prompt prefix allocation failure preserves an already seeded prompt" { pane.tag_sel = true; pane.tag_col = 14; pane.tag_anchor = 7; - pane.normal = .{ .count = 9, .prefix = .goto }; + pane.body.normal = .{ .count = 9, .prefix = .goto }; const previous_prompt = pane.prompt; - const previous_normal = pane.normal; + const previous_normal = pane.body.normal; _ = p.scratch.reset(.free_all); failing.fail_index = failing.alloc_index; p.startPrompt(pane, request); try std.testing.expect(failing.has_induced_failure); try std.testing.expectEqualDeep(previous_prompt, pane.prompt); - try std.testing.expectEqualDeep(previous_normal, pane.normal); + try std.testing.expectEqualDeep(previous_normal, pane.body.normal); try std.testing.expectEqualStrings(tail, pane.tag_tail[0..pane.tag_tail_len]); try std.testing.expect(pane.tag_edit and pane.tag_sel); - try std.testing.expectEqual(.normal, pane.mode); + try std.testing.expectEqual(.normal, pane.body.mode); try std.testing.expectEqual(@as(u16, 14), pane.tag_col); try std.testing.expectEqual(@as(u16, 7), pane.tag_anchor); } @@ -1867,7 +1867,7 @@ test "tag prompt successful seeded entry needs one scratch allocation" { const before = failing.alloc_index; p.startPrompt(pane, request); try std.testing.expectEqual(before + 1, failing.alloc_index); - try std.testing.expect(pane.tag_edit and pane.mode == .insert); + try std.testing.expect(pane.tag_edit and pane.body.mode == .insert); } } @@ -1892,20 +1892,20 @@ test "tag prompt failure may initialize only the default tail" { pane.tag_tail_len = 0; pane.tag_col = 17; pane.tag_sel = true; - pane.normal = .{ .count = 9, .prefix = .goto }; - const previous_normal = pane.normal; + pane.body.normal = .{ .count = 9, .prefix = .goto }; + const previous_normal = pane.body.normal; _ = p.scratch.reset(.free_all); failing.fail_index = failing.alloc_index + failure; p.startPrompt(pane, request); if (!failing.has_induced_failure) { - try std.testing.expect(pane.tag_edit and pane.mode == .insert); + try std.testing.expect(pane.tag_edit and pane.body.mode == .insert); succeeded = true; break; } try std.testing.expect(pane.prompt == .none); try std.testing.expect(!pane.tag_edit and pane.tag_sel); - try std.testing.expectEqual(.normal, pane.mode); - try std.testing.expectEqualDeep(previous_normal, pane.normal); + try std.testing.expectEqual(.normal, pane.body.mode); + try std.testing.expectEqualDeep(previous_normal, pane.body.normal); try std.testing.expectEqual(@as(u16, 17), pane.tag_col); if (pane.tag_init) { saw_seeded_failure = true; @@ -2390,10 +2390,10 @@ const OutputTests = struct { try std.testing.expectEqual(matches[1], pane.search_row.?); try std.testing.expect(pardes.test_api.searchStep(p, 0, -1)); try std.testing.expectEqual(matches[0], pane.search_row.?); - try std.testing.expectEqual(@as(i32, 3), pane.cur_row); + try std.testing.expectEqual(@as(i32, 3), pane.body.cur_row); try std.testing.expect(pardes.test_api.searchStep(p, 0, 1)); try std.testing.expectEqual(matches[1], pane.search_row.?); - try std.testing.expectEqual(@as(i32, 5), pane.cur_row); + try std.testing.expectEqual(@as(i32, 5), pane.body.cur_row); try std.testing.expect(pardes.test_api.searchStep(p, 0, 1)); try std.testing.expectEqual(matches[1], pane.search_row.?); @@ -2571,9 +2571,9 @@ const OutputTests = struct { const id = p.active; const help = p.panes[id].?; for ("gevkk") |key| p.update(.{ .key = .{ .cp = key } }); - try std.testing.expect(help.vsel.active); - try std.testing.expect(help.vsel.row > 5); - try std.testing.expect(help.cur_row != help.vsel.row); + try std.testing.expect(help.body.vsel.active); + try std.testing.expect(help.body.vsel.row > 5); + try std.testing.expect(help.body.cur_row != help.body.vsel.row); for (" h?") |key| p.update(.{ .key = .{ .cp = key } }); try std.testing.expectEqual(id, p.active); const content = help.file.?.content; @@ -2607,35 +2607,35 @@ const OutputTests = struct { const result = p.panes[id].?; p.active = id; for ("Cv3") |key| p.update(.{ .key = .{ .cp = key } }); - try std.testing.expect(result.nsel > 0); - try std.testing.expect(result.select); - try std.testing.expect(result.vsel.active); - try std.testing.expect(result.normal.count > 0); + try std.testing.expect(result.body.nsel > 0); + try std.testing.expect(result.body.select); + try std.testing.expect(result.body.vsel.active); + try std.testing.expect(result.body.normal.count > 0); result.file.?.scroll = 1; result.hscroll = 2; - const selected = result.vsel; - const selections = result.nsel; - const cursor_row = result.cur_row; - const cursor_col = result.cur_col; + const selected = result.body.vsel; + const selections = result.body.nsel; + const cursor_row = result.body.cur_row; + const cursor_col = result.body.cur_col; try fillResults(p, 0, "/", .{ .query = .hover }, "", try p.gpa.dupe(u8, content), null); - try std.testing.expectEqual(selected, result.vsel); - try std.testing.expectEqual(selections, result.nsel); - try std.testing.expectEqual(cursor_row, result.cur_row); - try std.testing.expectEqual(cursor_col, result.cur_col); + try std.testing.expectEqual(selected, result.body.vsel); + try std.testing.expectEqual(selections, result.body.nsel); + try std.testing.expectEqual(cursor_row, result.body.cur_row); + try std.testing.expectEqual(cursor_col, result.body.cur_col); try std.testing.expectEqual(@as(usize, 1), result.file.?.scroll); try std.testing.expectEqual(@as(i32, 2), result.hscroll); - try std.testing.expect(result.normal.count > 0); + try std.testing.expect(result.body.normal.count > 0); try fillResults(p, 0, "/", .{ .query = .hover }, "", try p.gpa.dupe(u8, "short\n"), null); try std.testing.expectEqualStrings("short\n", result.file.?.content); - try std.testing.expect(!result.vsel.active and !result.msel.active and !result.select); - try std.testing.expectEqual(@as(u8, 0), result.nsel); - try std.testing.expectEqual(@as(i32, 0), result.cur_row); - try std.testing.expectEqual(@as(i32, 0), result.cur_col); + try std.testing.expect(!result.body.vsel.active and !result.body.msel.active and !result.body.select); + try std.testing.expectEqual(@as(u8, 0), result.body.nsel); + try std.testing.expectEqual(@as(i32, 0), result.body.cur_row); + try std.testing.expectEqual(@as(i32, 0), result.body.cur_col); try std.testing.expectEqual(@as(usize, 0), result.file.?.scroll); try std.testing.expectEqual(@as(i32, 0), result.hscroll); - try std.testing.expectEqual(modal.Normal.State{}, result.normal); + try std.testing.expectEqual(modal.Normal.State{}, result.body.normal); } test "generated result replacement cancels an in-progress body selection" { @@ -2665,7 +2665,7 @@ const OutputTests = struct { try std.testing.expect(p.drag == .none); p.update(.{ .mouse = .{ .button = config.select_button, .kind = .release, .col = x + 2, .row = y + 1 } }); for (result.sel) |selection| try std.testing.expectEqual(.none, selection.state); - try std.testing.expect(!result.vsel.active and !result.msel.active); + try std.testing.expect(!result.body.vsel.active and !result.body.msel.active); } test "dump origins accept only builtins that actually own output panes" { @@ -2993,8 +2993,8 @@ const TerminalTests = struct { gpa.free(sn.style); }; - for ([_]pardes.Pane.Mode{ .tty, .normal }, 0..) |mode, i| { - pane.mode = mode; + for ([_]panes.Text.Mode{ .tty, .normal }, 0..) |mode, i| { + pane.body.mode = mode; p.shell_rows.stale = true; _ = frame.reset(.retain_capacity); const s = try p.render(frame.allocator()); @@ -3204,7 +3204,7 @@ const TerminalTests = struct { while (p.nextEffect()) |_| {} const pane = p.panes[0].?; pane.tty_filter = false; - pane.mode = .normal; + pane.body.mode = .normal; p.update(.{ .output = .{ .pane = 0, .bytes = "\x1b[31mAAA\x1b[0m\r\n\x1b[32mBBB\x1b[0m\r\n\x1b[34mCCC\x1b[0m" } }); @@ -3254,7 +3254,7 @@ const TerminalTests = struct { while (p.nextEffect()) |_| {} const pane = p.panes[0].?; pane.tty_filter = false; - pane.mode = .normal; + pane.body.mode = .normal; // A ONE-cell prompt carrying a combining mark — an NFD `e` — then `ABC` // typed at it. The cell walk that finds the prompt's end must step ONE @@ -3290,7 +3290,7 @@ const TerminalTests = struct { // Raw palette, so a leaked background reads back as `.index` — the theme // filter would repaint every blank cell and hide the evidence. pane.tty_filter = false; - pane.mode = .normal; + pane.body.mode = .normal; // Sixty rows, each a distinct background, so a leaked colour names the row // it leaked from. @@ -3346,7 +3346,7 @@ const TerminalTests = struct { while (p.nextEffect()) |_| {} const pane = p.panes[0].?; pane.tty_filter = false; - pane.mode = .normal; + pane.body.mode = .normal; p.update(.{ .output = .{ .pane = 0, .bytes = "\x1b[31mAAA\x1b[0m\r\n\x1b[32mBBB\x1b[0m\r\n\x1b[34mCCC\x1b[0m" } }); @@ -3383,7 +3383,7 @@ const TerminalTests = struct { while (p.nextEffect()) |_| {} const pane = p.panes[0].?; pane.tty_filter = false; - pane.mode = .normal; + pane.body.mode = .normal; p.update(.{ .output = .{ .pane = 0, .bytes = "\x1b[31mAAA\x1b[0m\r\n\x1b[32mBBB\x1b[0m\r\n\x1b[34mCCC\x1b[0m" } }); @@ -3459,7 +3459,7 @@ const TerminalTests = struct { while (p.nextEffect()) |_| {} const pane = p.panes[0].?; pane.tty_filter = filter; - pane.mode = .normal; + pane.body.mode = .normal; var buf: [256]u8 = undefined; const bytes = try std.fmt.bufPrint( @@ -3539,7 +3539,7 @@ const TerminalTests = struct { while (p.nextEffect()) |_| {} const pane = p.panes[0].?; pane.tty_filter = false; - pane.mode = .tty; + pane.body.mode = .tty; for (0..60) |i| { var buf: [40]u8 = undefined; @@ -3598,13 +3598,13 @@ const TerminalTests = struct { // ABSOLUTE assertions: both modes were wrong identically here, so a // tty/normal differential says nothing. for ([_]bool{ false, true }) |filter| { - for ([_]pardes.Pane.Mode{ .tty, .normal }) |mode| { + for ([_]panes.Text.Mode{ .tty, .normal }) |mode| { const p = try Pardes.init(testing.allocator, .{ .tty_only = true, .cols = 12, .rows = 8 }); defer p.deinit(); while (p.nextEffect()) |_| {} const pane = p.panes[0].?; pane.tty_filter = filter; - pane.mode = mode; + pane.body.mode = mode; p.update(.{ .output = .{ .pane = 0, .bytes = "\x1b[32m\u{754C}\x1b[41m\x1b[K\x1b[7G\x1b[44m\x1b[K\r\n" } }); var frame = std.heap.ArenaAllocator.init(testing.allocator); @@ -3634,13 +3634,13 @@ const TerminalTests = struct { // ghostty leaves a `spacer_head` in that last column, carrying the row's // background, and wraps the glyph to the next row. A head OWNS its column, // so skipping it the way a tail is skipped left the row's final column bare. - for ([_]pardes.Pane.Mode{ .tty, .normal }) |mode| { + for ([_]panes.Text.Mode{ .tty, .normal }) |mode| { const p = try Pardes.init(testing.allocator, .{ .startup_config = "Theme helix\n", .tty_only = true, .cols = 16, .rows = 8 }); defer p.deinit(); while (p.nextEffect()) |_| {} const pane = p.panes[0].?; pane.tty_filter = false; - pane.mode = mode; + pane.body.mode = mode; p.update(.{ .output = .{ .pane = 0, .bytes = "\x1b[41mzzzzzzzzzzzzz\u{754C}\x1b[0m\r\n" } }); var frame = std.heap.ArenaAllocator.init(testing.allocator); @@ -3667,7 +3667,7 @@ const TerminalTests = struct { while (p.nextEffect()) |_| {} const pane = p.panes[0].?; pane.tty_filter = false; - pane.mode = .tty; + pane.body.mode = .tty; for (0..40) |i| { var buf: [64]u8 = undefined; const bytes = std.fmt.bufPrint(&buf, "\x1b[38;5;{d}mline-{d:0>2}\x1b[0m\r\n", .{ 20 + i, i }) catch unreachable; @@ -3717,7 +3717,7 @@ const TerminalTests = struct { while (p.nextEffect()) |_| {} const pane = p.panes[0].?; pane.tty_filter = filter; - pane.mode = .normal; + pane.body.mode = .normal; var frame = std.heap.ArenaAllocator.init(testing.allocator); defer frame.deinit(); @@ -3749,7 +3749,7 @@ const TerminalTests = struct { while (p.nextEffect()) |_| {} const pane = p.panes[0].?; pane.tty_filter = false; - pane.mode = .normal; + pane.body.mode = .normal; for (0..6) |i| { var buf: [40]u8 = undefined; @@ -3791,7 +3791,7 @@ const TerminalTests = struct { while (p.nextEffect()) |_| {} const pane = p.panes[0].?; pane.tty_filter = false; - pane.mode = .normal; + pane.body.mode = .normal; p.update(.{ .output = .{ .pane = 0, .bytes = "\x1b[31m000\x1b[0m\r\n\x1b[32m111\x1b[0m\r\n\r\n\x1b[34m333\x1b[0m\r\n\x1b[35m444\x1b[0m" } }); @@ -3825,7 +3825,7 @@ const TerminalTests = struct { while (p.nextEffect()) |_| {} const pane = p.panes[0].?; pane.tty_filter = false; - pane.mode = .tty; + pane.body.mode = .tty; p.update(.{ .output = .{ .pane = 0, .bytes = "\x1b[31mAAA\x1b[0m\r\n\x1b[32mBBB\x1b[0m\r\n\x1b[34mCCC\x1b[0m" } }); @@ -3862,7 +3862,7 @@ const TerminalTests = struct { while (p.nextEffect()) |_| {} const pane = p.panes[0].?; pane.tty_filter = false; - pane.mode = .normal; + pane.body.mode = .normal; for (0..6) |i| { var buf: [64]u8 = undefined; const bytes = std.fmt.bufPrint(&buf, "\x1b[38;5;{d}mrow-{d}-abcdefgh\x1b[0m\r\n", .{ 30 + i, i }) catch unreachable; @@ -3912,7 +3912,7 @@ const TerminalTests = struct { while (p.nextEffect()) |_| {} const pane = p.panes[0].?; pane.tty_filter = false; - pane.mode = .normal; + pane.body.mode = .normal; for (0..26) |i| { var buf: [64]u8 = undefined; const bytes = std.fmt.bufPrint(&buf, "\x1b[38;5;{d}mrow-{d:0>2}-xyzzy\x1b[0m\r\n", .{ 20 + i, i }) catch unreachable; @@ -3971,7 +3971,7 @@ const TerminalTests = struct { // The raw palette, so a row's text names its exact colour instead of one // this test would have to re-derive from the theme. pane.tty_filter = false; - pane.mode = .normal; + pane.body.mode = .normal; for (0..26) |i| { var buf: [64]u8 = undefined; const bytes = std.fmt.bufPrint(&buf, "\x1b[38;5;{d}mrow-{d:0>2}-xyzzy\x1b[0m\r\n", .{ 20 + i, i }) catch unreachable; @@ -4059,7 +4059,7 @@ const TerminalTests = struct { while (p.nextEffect()) |_| {} const pane = p.panes[0].?; pane.tty_filter = false; - pane.mode = .normal; + pane.body.mode = .normal; for (0..26) |i| { var buf: [64]u8 = undefined; const bytes = std.fmt.bufPrint(&buf, "\x1b[38;5;{d}mrow-{d:0>2}-xyzzy\x1b[0m\r\n", .{ 20 + i, i }) catch unreachable; @@ -4130,9 +4130,9 @@ test "an empty counted paste leaves no count for the next motion" { const pane = try p.setTestFile("abcdefgh\n"); if (empty_register) p.yank = try p.gpa.dupe(u8, ""); for ("3p") |cp| p.update(.{ .key = .{ .cp = cp } }); - try std.testing.expectEqual(modal.Normal.State{}, pane.normal); + try std.testing.expectEqual(modal.Normal.State{}, pane.body.normal); p.update(.{ .key = .{ .cp = 'l' } }); - try std.testing.expectEqual(@as(i32, 1), pane.cur_col); + try std.testing.expectEqual(@as(i32, 1), pane.body.cur_col); try std.testing.expectEqualStrings("abcdefgh\n", pane.file.?.content); } } @@ -4156,7 +4156,7 @@ test "cancelled normal gestures leave no count or subprefix after mouse and focu defer frame.deinit(); _ = try p.render(frame.allocator()); for (keys) |cp| p.update(.{ .key = .{ .cp = cp } }); - try std.testing.expect(!std.meta.eql(modal.Normal.State{}, pane.normal)); + try std.testing.expect(!std.meta.eql(modal.Normal.State{}, pane.body.normal)); switch (gesture) { .body, .tag => { const rect = p.rects[0]; @@ -4185,10 +4185,10 @@ test "cancelled normal gestures leave no count or subprefix after mouse and focu try std.testing.expectEqual(@as(usize, 0), p.active); }, } - try std.testing.expectEqual(modal.Normal.State{}, pane.normal); - const col = pane.cur_col; + try std.testing.expectEqual(modal.Normal.State{}, pane.body.normal); + const col = pane.body.cur_col; p.update(.{ .key = .{ .cp = 'l' } }); - try std.testing.expectEqual(col + 1, pane.cur_col); + try std.testing.expectEqual(col + 1, pane.body.cur_col); try std.testing.expectEqualStrings("abcdefghij\n", pane.file.?.content); } } @@ -4199,16 +4199,16 @@ test "cancelled normal gestures leave no count or subprefix through raw tty mode const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 80, .rows = 12 }); defer p.deinit(); const pane = p.panes[0].?; - pane.mode = .normal; + pane.body.mode = .normal; p.update(.{ .output = .{ .pane = 0, .bytes = "abcdefghij\r\n" } }); for (keys) |cp| p.update(.{ .key = .{ .cp = cp } }); - try std.testing.expect(!std.meta.eql(modal.Normal.State{}, pane.normal)); + try std.testing.expect(!std.meta.eql(modal.Normal.State{}, pane.body.normal)); p.update(.{ .key = .{ .cp = p.opts.tty_toggle, .ctrl = true } }); - try std.testing.expectEqual(pardes.Pane.Mode.tty, pane.mode); - try std.testing.expectEqual(modal.Normal.State{}, pane.normal); + try std.testing.expectEqual(panes.Text.Mode.tty, pane.body.mode); + try std.testing.expectEqual(modal.Normal.State{}, pane.body.normal); p.update(.{ .key = .{ .cp = p.opts.tty_toggle, .ctrl = true } }); - try std.testing.expectEqual(pardes.Pane.Mode.normal, pane.mode); - try std.testing.expectEqual(modal.Normal.State{}, pane.normal); + try std.testing.expectEqual(panes.Text.Mode.normal, pane.body.mode); + try std.testing.expectEqual(modal.Normal.State{}, pane.body.normal); } } @@ -4333,8 +4333,8 @@ test "Zig keywords keep every rendered byte colored across line-number widths" { gpa.free(file.path); file.path = try gpa.dupe(u8, "/highlight.zig"); file.scroll = line - 1; - pane.cur_row = @intCast(line - 1); - pane.cur_col = @intCast(std.mem.indexOf(u8, sample, "fn").?); + pane.body.cur_row = @intCast(line - 1); + pane.body.cur_col = @intCast(std.mem.indexOf(u8, sample, "fn").?); pane.hscroll = view.horizontal; p.settings.colors = true; p.settings.wrap = view.wrap; @@ -4373,8 +4373,8 @@ test "Zig keywords keep every rendered byte colored across line-number widths" { const clicked = if_position.?; p.update(.{ .mouse = .{ .button = config.select_button, .kind = .press, .col = clicked.x, .row = clicked.y } }); p.update(.{ .mouse = .{ .button = config.select_button, .kind = .release, .col = clicked.x, .row = clicked.y } }); - try std.testing.expectEqual(@as(i32, @intCast(line - 1)), pane.cur_row); - try std.testing.expectEqual(@as(i32, @intCast(std.mem.indexOf(u8, sample, "if").?)), pane.cur_col); + try std.testing.expectEqual(@as(i32, @intCast(line - 1)), pane.body.cur_row); + try std.testing.expectEqual(@as(i32, @intCast(std.mem.indexOf(u8, sample, "if").?)), pane.body.cur_col); } } } @@ -4389,7 +4389,7 @@ test "terminal overlays preserve trailing blank styles without coloring inserted const pane = p.panes[0].?; pane.tty_filter = false; p.update(.{ .output = .{ .pane = 0, .bytes = "A\r\n\x1b[41m\x1b[2K\r\n\x1b[42m\x1b[2K\r\n\x1b[44m\x1b[2K\x1b[0m" } }); - pane.mode = .normal; + pane.body.mode = .normal; pane.ovl = .{ .row = 0, .rows = 3, .text = try gpa.dupe(u8, "A\n\n") }; var frame = std.heap.ArenaAllocator.init(gpa); defer frame.deinit(); @@ -4421,16 +4421,16 @@ test "terminal overlays preserve trailing blank styles without coloring inserted 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; + pane.body.cur_row = 0; + pane.body.cur_col = 3; + pane.body.vsel = .{ .active = true, .explicit = true, .row = 0, .col = 0 }; + pane.body.msel = .{ .active = true, .r0 = 0, .r1 = 1 }; + pane.body.sels[0] = .{ .row = 1, .col = 2, .arow = 0, .acol = 1 }; + pane.body.nsel = 1; + pane.body.select = true; + pane.body.normal.count = 5; + pane.body.append_at = .{ .row = 0, .col = 3 }; + pane.body.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 }; @@ -4445,21 +4445,21 @@ const LookResetTests = struct { } 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); + try std.testing.expect(!pane.body.msel.active); + try std.testing.expectEqual(@as(u8, 0), pane.body.nsel); + try std.testing.expect(!pane.body.select); + try std.testing.expectEqual(modal.Normal.State{}, pane.body.normal); + try std.testing.expect(pane.body.append_at == null); + try std.testing.expectEqual(@as(i32, -1), pane.body.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)); + if (!pane.body.vsel.active or pane.body.cur_row != pane.body.vsel.row) return ""; + const line = modal.lineSlice(pane.file.?.content, @intCast(pane.body.cur_row)); + const lo: usize = @intCast(@min(pane.body.cur_col, pane.body.vsel.col)); + const hi: usize = @intCast(@max(pane.body.cur_col, pane.body.vsel.col)); return line[lo..modal.nextGrapheme(line, hi)]; } @@ -4472,14 +4472,14 @@ const LookResetTests = struct { pardes.look.lookAt(p, 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 std.testing.expectEqual(@as(i32, 2), pane.body.cur_row); + try std.testing.expectEqual(@as(i32, 1), pane.body.cur_col); + try std.testing.expect(!pane.body.vsel.active); try seed(pane, "/test.txt:2:2-4"); pardes.look.lookAt(p, 0, pane.pointer_selections[0].?.raw_text.?); try cleared(pane); - try std.testing.expectEqual(@as(i32, 1), pane.cur_row); + try std.testing.expectEqual(@as(i32, 1), pane.body.cur_row); try std.testing.expectEqualStrings("rav", selected(pane)); p.gpa.free(pane.file.?.path); @@ -4487,7 +4487,7 @@ const LookResetTests = struct { try seed(pane, "needle"); pardes.look.lookAt(p, 0, pane.pointer_selections[0].?.raw_text.?); try cleared(pane); - try std.testing.expectEqual(@as(i32, 3), pane.cur_row); + try std.testing.expectEqual(@as(i32, 3), pane.body.cur_row); try std.testing.expectEqualStrings("needle", selected(pane)); } @@ -4512,14 +4512,14 @@ const LookResetTests = struct { try std.testing.expectEqual(id, p.active); try cleared(source); try cleared(destination); - try std.testing.expect(!source.vsel.active); + try std.testing.expect(!source.body.vsel.active); if (range) { - try std.testing.expectEqual(@as(i32, 1), destination.cur_row); + try std.testing.expectEqual(@as(i32, 1), destination.body.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); + try std.testing.expectEqual(@as(i32, 2), destination.body.cur_row); + try std.testing.expectEqual(@as(i32, 1), destination.body.cur_col); + try std.testing.expect(!destination.body.vsel.active); } } } |
