summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-27 23:06:11 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:14 -0300
commit95a3a1bb822e583988bfe0f312d0ef219b27a454 (patch)
tree95306e8d3f36f8af05b3ea919f6cdef1e94a028b /test
parentc8f0c25a854b8e169db08a84d1fdcd915a70aaa0 (diff)
downloadpardes-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')
-rw-r--r--test/fs_bench.zig4
-rw-r--r--test/hxdiff.zig34
-rw-r--r--test/mode.zig28
-rw-r--r--test/output.zig128
-rw-r--r--test/panes.zig398
-rw-r--r--test/pdf.zig42
-rw-r--r--test/perf.zig78
7 files changed, 356 insertions, 356 deletions
diff --git a/test/fs_bench.zig b/test/fs_bench.zig
index 00601ca3..a816ebbd 100644
--- a/test/fs_bench.zig
+++ b/test/fs_bench.zig
@@ -281,7 +281,7 @@ pub fn main(init: std.process.Init) !void {
var keys = try Session.init(&counting, 32 * 1024);
defer keys.deinit();
const pane = keys.core.panes[keys.file_id].?;
- pane.mode = .insert;
+ pane.body.mode = .insert;
const initial_bytes = pane.file.?.content.len;
key_body_bytes = initial_bytes;
if (scripted) {
@@ -295,7 +295,7 @@ pub fn main(init: std.process.Init) !void {
while (keys.core.nextEffect()) |_| {}
}
const elapsed = nowNs() - start;
- if (pane.file.?.content.len != initial_bytes + key_reps or pane.cur_col != key_reps or
+ if (pane.file.?.content.len != initial_bytes + key_reps or pane.body.cur_col != key_reps or
!std.mem.allEqual(u8, pane.file.?.content[0..key_reps], 'x')) return error.MissingKeystroke;
const events = &keys.core.panes[keys.file_id].?.fs.events;
if (scripted) for (0..key_reps) |i| {
diff --git a/test/hxdiff.zig b/test/hxdiff.zig
index e79a6bb6..627bbac3 100644
--- a/test/hxdiff.zig
+++ b/test/hxdiff.zig
@@ -397,9 +397,9 @@ fn runCase(arena: std.mem.Allocator, case: Case, pane_kind: []const u8) !Result
core.update(.{ .key = .{ .cp = core.opts.tty_toggle, .ctrl = true } });
pump(core);
if (core.panes[core.active]) |pane| {
- pane.cur_row = 0;
- pane.cur_col = 0;
- pane.cur_pinned = true;
+ pane.body.cur_row = 0;
+ pane.body.cur_col = 0;
+ pane.body.cur_pinned = true;
}
} else fatal("case {s}: unknown pane {s}", .{ case.name, pane_kind });
@@ -488,7 +488,7 @@ fn runCase(arena: std.mem.Allocator, case: Case, pane_kind: []const u8) !Result
// the cursor's empty row below the output (see Pardes.shellRows), so
// its line list is exactly a file content's — join it and you have the
// same bytes, trailing newline included, with nothing to patch up.
- const lines = try pardes.edit.paneCursorLines(core, pane);
+ const lines = try pardes.edit.paneCursorLines(core, &pane.body);
var text_len: usize = if (lines.len == 0) 0 else lines.len - 1;
for (lines) |ln| text_len = std.math.add(usize, text_len, ln.len) catch return error.OutOfMemory;
const joined = try arena.alloc(u8, text_len);
@@ -503,28 +503,28 @@ fn runCase(arena: std.mem.Allocator, case: Case, pane_kind: []const u8) !Result
}
text = joined;
}
- var anchor: Pos = .{ .row = pane.cur_row, .col = pane.cur_col };
- if (pane.vsel.active) {
- anchor = .{ .row = pane.vsel.row, .col = pane.vsel.col };
- } else if (pane.msel.active) {
+ var anchor: Pos = .{ .row = pane.body.cur_row, .col = pane.body.cur_col };
+ if (pane.body.vsel.active) {
+ anchor = .{ .row = pane.body.vsel.row, .col = pane.body.vsel.col };
+ } else if (pane.body.msel.active) {
// line selection: the far end (the r0/r1 not holding the cursor), col 0
- anchor = .{ .row = if (pane.cur_row == pane.msel.r1) pane.msel.r0 else pane.msel.r1, .col = 0 };
+ anchor = .{ .row = if (pane.body.cur_row == pane.body.msel.r1) pane.body.msel.r0 else pane.body.msel.r1, .col = 0 };
}
// mode "select" ONLY while v-extend is on (helix keeps x/%/mi selections
- // in normal mode); pane.mode itself never holds a select state
- const mode = if (pane.mode == .normal and pane.select) "select" else @tagName(pane.mode);
+ // in normal mode); pane.body.mode itself never holds a select state
+ const mode = if (pane.body.mode == .normal and pane.body.select) "select" else @tagName(pane.body.mode);
// multiple cursors: the primary (cur_row/cur_col + the anchor above) and
- // pane.sels, slotted together in document order. pane.sels is already
+ // pane.body.sels, slotted together in document order. pane.body.sels is already
// ordered, so the primary is the only one that needs placing.
var sels: ?[]const Sel = null;
var primary: ?usize = null;
- if (pane.nsel > 0) {
- const out = try arena.alloc(Sel, @as(usize, pane.nsel) + 1);
+ if (pane.body.nsel > 0) {
+ const out = try arena.alloc(Sel, @as(usize, pane.body.nsel) + 1);
var out_len: usize = 0;
- const prim: Sel = .{ .cursor = .{ .row = pane.cur_row, .col = pane.cur_col }, .anchor = anchor };
+ const prim: Sel = .{ .cursor = .{ .row = pane.body.cur_row, .col = pane.body.cur_col }, .anchor = anchor };
const pr_row = @min(prim.cursor.row, prim.anchor.row);
const pr_col = if (prim.cursor.row == prim.anchor.row) @min(prim.cursor.col, prim.anchor.col) else if (prim.cursor.row < prim.anchor.row) prim.cursor.col else prim.anchor.col;
- for (pane.sels[0..pane.nsel]) |s| {
+ for (pane.body.sels[0..pane.body.nsel]) |s| {
const s_row = @min(s.row, s.arow);
const s_col = if (s.row == s.arow) @min(s.col, s.acol) else if (s.row < s.arow) s.col else s.acol;
if (primary == null and (pr_row < s_row or (pr_row == s_row and pr_col <= s_col))) {
@@ -545,7 +545,7 @@ fn runCase(arena: std.mem.Allocator, case: Case, pane_kind: []const u8) !Result
.name = case.name,
.text = try arena.dupe(u8, text),
.mode = mode,
- .cursor = .{ .row = pane.cur_row, .col = pane.cur_col },
+ .cursor = .{ .row = pane.body.cur_row, .col = pane.body.cur_col },
.anchor = anchor,
.sels = sels,
.primary = primary,
diff --git a/test/mode.zig b/test/mode.zig
index cc36ac04..19d59699 100644
--- a/test/mode.zig
+++ b/test/mode.zig
@@ -3,9 +3,9 @@ const pardes = @import("pardes");
const panes = pardes.panes;
const Pardes = pardes.Pardes;
-fn mode(p: *Pardes, id: usize, expected: pardes.Pane.Mode) !void {
+fn mode(p: *Pardes, id: usize, expected: panes.Text.Mode) !void {
try std.testing.expect(p.executeBuiltinLine(id, "Mode"));
- try std.testing.expectEqual(expected, p.panes[id].?.mode);
+ try std.testing.expectEqual(expected, p.panes[id].?.body.mode);
try std.testing.expect(!p.panes[id].?.tag_edit);
}
@@ -33,14 +33,14 @@ test "Mode cycles terminal modes and keeps legacy toggle and custom tags" {
p.presentation.enabled = false;
while (p.nextEffect()) |_| {}
const pane = p.panes[0].?;
- try std.testing.expectEqual(pardes.Pane.Mode.tty, pane.mode);
+ try std.testing.expectEqual(panes.Text.Mode.tty, pane.body.mode);
try std.testing.expect(std.mem.indexOf(u8, try p.tagText(p.scratch.allocator(), pane), " Mode") != null);
try mode(p, 0, .normal);
try mode(p, 0, .insert);
try clickModeTag(p);
- try std.testing.expectEqual(pardes.Pane.Mode.insert, pane.tag_mode);
+ try std.testing.expectEqual(panes.Text.Mode.insert, pane.tag_mode);
p.update(.{ .key = .{ .cp = pardes.Key.tab } });
- try std.testing.expectEqual(pardes.Pane.Mode.tty, pane.mode);
+ try std.testing.expectEqual(panes.Text.Mode.tty, pane.body.mode);
try std.testing.expect(!pane.tag_edit);
while (p.nextEffect()) |effect| try std.testing.expect(effect != .write);
@@ -48,11 +48,11 @@ test "Mode cycles terminal modes and keeps legacy toggle and custom tags" {
try mode(p, 0, .normal);
try mode(p, 0, .insert);
try std.testing.expect(p.executeBuiltinLine(0, "Togglettymode"));
- try std.testing.expectEqual(pardes.Pane.Mode.tty, pane.mode);
+ try std.testing.expectEqual(panes.Text.Mode.tty, pane.body.mode);
p.update(.{ .key = .{ .cp = 'b', .ctrl = true } });
- try std.testing.expectEqual(pardes.Pane.Mode.normal, pane.mode);
+ try std.testing.expectEqual(panes.Text.Mode.normal, pane.body.mode);
p.update(.{ .key = .{ .cp = 'b', .ctrl = true } });
- try std.testing.expectEqual(pardes.Pane.Mode.tty, pane.mode);
+ try std.testing.expectEqual(panes.Text.Mode.tty, pane.body.mode);
try std.testing.expectEqualStrings(" Togglettymode Keep", pane.tag_tail[0..pane.tag_tail_len]);
}
@@ -71,19 +71,19 @@ test "Mode from actual tag Exec preserves parked file and output insert transact
p.update(.{ .key = .{ .cp = 'x', .text = "x" } });
try std.testing.expectEqualStrings("界xab\n", pane.file.?.content);
try clickModeTag(p);
- try std.testing.expectEqual(pardes.Pane.Mode.insert, pane.tag_mode);
- if (normal_tag) pane.mode = .normal;
+ try std.testing.expectEqual(panes.Text.Mode.insert, pane.tag_mode);
+ if (normal_tag) pane.body.mode = .normal;
p.update(.{ .key = .{ .cp = pardes.Key.tab } });
- try std.testing.expectEqual(pardes.Pane.Mode.normal, pane.mode);
+ try std.testing.expectEqual(panes.Text.Mode.normal, pane.body.mode);
try std.testing.expect(!pane.tag_edit);
- try std.testing.expect(pane.append_at == null);
+ try std.testing.expect(pane.body.append_at == null);
p.update(.{ .key = .{ .cp = 'u' } });
try std.testing.expectEqualStrings("ab\n", pane.file.?.content);
p.update(.{ .key = .{ .cp = 'a' } });
p.update(.{ .key = .{ .cp = 'z', .text = "z" } });
- try std.testing.expect(pane.append_at != null);
+ try std.testing.expect(pane.body.append_at != null);
try mode(p, 0, .normal);
- try std.testing.expect(pane.append_at == null);
+ try std.testing.expect(pane.body.append_at == null);
p.update(.{ .key = .{ .cp = 'u' } });
try std.testing.expectEqualStrings("ab\n", pane.file.?.content);
}
diff --git a/test/output.zig b/test/output.zig
index 7c5f7f9b..c245e5f5 100644
--- a/test/output.zig
+++ b/test/output.zig
@@ -61,10 +61,10 @@ test "search tint survives wrapping and theme changes while selections remain au
light_matches += 1;
}
try std.testing.expectEqual(@as(usize, 3), light_matches);
- pane.mode = .normal;
- pane.cur_row = 0;
- pane.cur_col = @intCast(std.mem.indexOf(u8, text, "abc").? + 2);
- pane.vsel = .{ .active = true, .row = 0, .col = pane.cur_col - 2, .explicit = true };
+ pane.body.mode = .normal;
+ pane.body.cur_row = 0;
+ pane.body.cur_col = @intCast(std.mem.indexOf(u8, text, "abc").? + 2);
+ pane.body.vsel = .{ .active = true, .row = 0, .col = pane.body.cur_col - 2, .explicit = true };
const selected = try p.render(frame.allocator());
for (selected.cells) |cell|
try std.testing.expect(!std.meta.eql(cell.style.bg, pardes.Color{ .rgb = p.theme().search_bg.? }));
@@ -200,46 +200,46 @@ test "reference Look selects the next sorted row from the captured request and k
const source = p.panes[0].?;
const response = "m.zig:5:5-8 later\nz.zig:1:1 last-file\nm.zig:1:7-10 earlier\nm.zig:3:5-8 current\na.zig:1:1 first-file\nm.zig:4:5-8 next\n";
const sorted = "a.zig:1:1 first-file\nm.zig:1:7-10 earlier\nm.zig:3:5-8 current\nm.zig:4:5-8 next\nm.zig:5:5-8 later\nz.zig:1:1 last-file\n";
- source.cur_row = 2;
- source.cur_col = 4;
+ source.body.cur_row = 2;
+ source.body.cur_col = 4;
p.lspRequest(0, .references, "");
const request = p.lsp_wait.?.id;
- source.cur_row = 4;
+ source.body.cur_row = 4;
p.lspResponse(request, response);
const rid = source.search_pane orelse return error.MissingResults;
const results = p.panes[rid].?;
try expectResultRows(sorted, &results.file.?);
try std.testing.expectEqual(@as(usize, 0), p.active);
- try std.testing.expectEqual(@as(i32, 3), source.cur_row);
- try std.testing.expect(source.vsel.active);
- try std.testing.expectEqual(@as(i32, 4), @min(source.cur_col, source.vsel.col));
- try std.testing.expectEqual(@as(i32, 7), @max(source.cur_col, source.vsel.col));
- try std.testing.expectEqual(@as(i32, 3), results.cur_row);
+ try std.testing.expectEqual(@as(i32, 3), source.body.cur_row);
+ try std.testing.expect(source.body.vsel.active);
+ try std.testing.expectEqual(@as(i32, 4), @min(source.body.cur_col, source.body.vsel.col));
+ try std.testing.expectEqual(@as(i32, 7), @max(source.body.cur_col, source.body.vsel.col));
+ try std.testing.expectEqual(@as(i32, 3), results.body.cur_row);
try std.testing.expectEqual(@as(usize, 3), source.search_row.?);
try std.testing.expectEqual(results.serial, p.look_walk_owner.?);
try std.testing.expectEqual(@as(i32, 3), results.look_at.?.row);
const available = p.freeSlot();
p.update(.{ .key = .{ .cp = 'n' } });
try std.testing.expectEqual(rid, p.active);
- try std.testing.expectEqual(@as(i32, 4), results.cur_row);
+ try std.testing.expectEqual(@as(i32, 4), results.body.cur_row);
try std.testing.expectEqual(available, p.freeSlot());
p.update(.{ .key = .{ .cp = 'N' } });
- try std.testing.expectEqual(@as(i32, 3), results.cur_row);
+ try std.testing.expectEqual(@as(i32, 3), results.body.cur_row);
p.active = 0;
- source.cur_row = 4;
- source.cur_col = 4;
+ source.body.cur_row = 4;
+ source.body.cur_col = 4;
p.lspRequest(0, .references, "");
p.lspResponse(p.lsp_wait.?.id, response);
try std.testing.expect(std.mem.endsWith(u8, p.panes[p.active].?.file.?.path, "/z.zig"));
- try std.testing.expectEqual(@as(i32, 5), results.cur_row);
+ try std.testing.expectEqual(@as(i32, 5), results.body.cur_row);
try std.testing.expectEqual(@as(usize, 5), source.search_row.?);
const last = p.active;
p.lspRequest(last, .references, "");
p.lspResponse(p.lsp_wait.?.id, response);
try std.testing.expect(std.mem.endsWith(u8, p.panes[p.active].?.file.?.path, "/a.zig"));
const wrapped = p.panes[p.panes[last].?.search_pane.?].?;
- try std.testing.expectEqual(@as(i32, 0), wrapped.cur_row);
+ try std.testing.expectEqual(@as(i32, 0), wrapped.body.cur_row);
try std.testing.expectEqual(wrapped.serial, p.look_walk_owner.?);
}
@@ -280,7 +280,7 @@ test "a single language location opens the full spaced filename" {
p.lspRequest(0, .references, "");
p.lspResponse(p.lsp_wait.?.id, "with space.zig:2:1 second\n");
try std.testing.expect(std.mem.endsWith(u8, p.panes[p.active].?.file.?.path, "/with space.zig"));
- try std.testing.expectEqual(@as(i32, 1), p.panes[p.active].?.cur_row);
+ try std.testing.expectEqual(@as(i32, 1), p.panes[p.active].?.body.cur_row);
for (p.panes) |slot| {
const pane = slot orelse continue;
if (pane.file) |file| try std.testing.expect(file.output == null);
@@ -316,19 +316,19 @@ test "reordered identical results preserve the selected row and warm line index"
const index = try panes.File.lineIndex(p.gpa, file);
const content = file.content.ptr;
const revision = file.revision;
- result.cur_row = 1;
- result.cur_col = 0;
- result.vsel = .{ .active = true, .explicit = true, .row = 1, .col = 9 };
- result.select = true;
- const selected = result.vsel;
+ result.body.cur_row = 1;
+ result.body.cur_col = 0;
+ result.body.vsel = .{ .active = true, .explicit = true, .row = 1, .col = 9 };
+ result.body.select = true;
+ const selected = result.body.vsel;
try panes.Output.fillResults(p, 0, "/tmp", .{ .query = .references }, "new request", try p.gpa.dupe(u8, "a.zig:10:1 second\na.zig:2:1 first\n"), 0);
try expectResultRows(sorted, file);
try std.testing.expectEqual(content, file.content.ptr);
try std.testing.expectEqual(index.ptr, file.line_starts.ptr);
try std.testing.expectEqual(revision, file.revision);
- try std.testing.expectEqual(selected, result.vsel);
- try std.testing.expect(result.select);
- try std.testing.expectEqual(@as(i32, 1), result.cur_row);
+ try std.testing.expectEqual(selected, result.body.vsel);
+ try std.testing.expect(result.body.select);
+ try std.testing.expectEqual(@as(i32, 1), result.body.cur_row);
try std.testing.expectEqual(@as(usize, 1), source.search_row.?);
}
@@ -390,7 +390,7 @@ test "result stepping reaches an unterminated last row" {
try std.testing.expect(pardes.test_api.searchStep(p, 0, 1));
try std.testing.expectEqual(@as(usize, 1), source.search_row.?);
const result = p.panes[source.search_pane.?].?;
- try std.testing.expectEqual(@as(i32, 1), result.cur_row);
+ try std.testing.expectEqual(@as(i32, 1), result.body.cur_row);
}
test "Mini uses OS source precedence and refreshes one independent snapshot" {
@@ -708,10 +708,10 @@ fn projectPaths(cwd_buf: *[4096]u8, path_buf: *[4096]u8) !ProjectPaths {
fn selectedOutputText(pane: *const pardes.Pane) ?[]const u8 {
const file = pane.file orelse return null;
- if (!pane.vsel.active or pane.vsel.row != pane.cur_row or pane.cur_row < 0) return null;
- const line = modal.lineSlice(file.content, @intCast(pane.cur_row));
- const lo: usize = @intCast(@max(0, @min(pane.vsel.col, pane.cur_col)));
- const hi: usize = @intCast(@max(0, @max(pane.vsel.col, pane.cur_col)));
+ if (!pane.body.vsel.active or pane.body.vsel.row != pane.body.cur_row or pane.body.cur_row < 0) return null;
+ const line = modal.lineSlice(file.content, @intCast(pane.body.cur_row));
+ const lo: usize = @intCast(@max(0, @min(pane.body.vsel.col, pane.body.cur_col)));
+ const hi: usize = @intCast(@max(0, @max(pane.body.vsel.col, pane.body.cur_col)));
if (lo >= line.len) return "";
return line[lo..@min(line.len, hi + 1)];
}
@@ -735,7 +735,7 @@ test "n/N in ordinary text skips comment slashes and retains real paths" {
}) |step| {
p.update(.{ .key = .{ .cp = step.key } });
try std.testing.expectEqual(@as(usize, 0), p.active);
- try std.testing.expectEqual(step.row, pane.cur_row);
+ try std.testing.expectEqual(step.row, pane.body.cur_row);
try std.testing.expectEqualStrings(step.text, selectedOutputText(pane) orelse "");
try std.testing.expectEqual(available, p.freeSlot());
}
@@ -788,7 +788,7 @@ test "n/N skips formatted context and selects comment match locations" {
p.update(.{ .key = .{ .cp = step.key } });
try std.testing.expectEqual(id, p.active);
const row = matches[step.match];
- try std.testing.expectEqual(@as(i32, @intCast(row)), result.cur_row);
+ try std.testing.expectEqual(@as(i32, @intCast(row)), result.body.cur_row);
const line = modal.lineSlice(file.content, row);
try std.testing.expectEqualStrings(line[0..file.location_rows[row].location_end], selectedOutputText(result) orelse "");
try std.testing.expectEqual(available, p.freeSlot());
@@ -799,9 +799,9 @@ test "n/N skips formatted context and selects comment match locations" {
pardes.look.armLookWalk(restored, id);
const restored_result = restored.panes[id].?;
restored.update(.{ .key = .{ .cp = 'n' } });
- try std.testing.expectEqual(@as(i32, @intCast(matches[0])), restored_result.cur_row);
+ try std.testing.expectEqual(@as(i32, @intCast(matches[0])), restored_result.body.cur_row);
restored.update(.{ .key = .{ .cp = 'N' } });
- try std.testing.expectEqual(@as(i32, @intCast(matches[1])), restored_result.cur_row);
+ try std.testing.expectEqual(@as(i32, @intCast(matches[1])), restored_result.body.cur_row);
const restored_file = &restored_result.file.?;
const last = modal.lineSlice(restored_file.content, matches[1]);
try std.testing.expectEqualStrings(last[0..restored_file.location_rows[matches[1]].location_end], selectedOutputText(restored_result) orelse "");
@@ -825,18 +825,18 @@ test "n/N selects one output location per row and opens nothing" {
p.update(.{ .key = .{ .cp = 'n' } });
try std.testing.expectEqual(rid, p.active);
try std.testing.expectEqual(panes_before, p.freeSlot());
- try std.testing.expect(results.vsel.active and results.vsel.explicit);
+ try std.testing.expect(results.body.vsel.active and results.body.vsel.explicit);
try std.testing.expectEqualStrings("build.zig:1:1", selectedOutputText(results) orelse "");
try std.testing.expectEqual(panes.Output.Grain.line, panes.Output.grain(results.file.?.output));
p.update(.{ .key = .{ .cp = 'n' } });
- try std.testing.expectEqual(@as(i32, 1), results.cur_row);
+ try std.testing.expectEqual(@as(i32, 1), results.body.cur_row);
try std.testing.expectEqualStrings("mise.toml", selectedOutputText(results) orelse "");
p.update(.{ .key = .{ .cp = 'n' } });
- try std.testing.expectEqual(@as(i32, 3), results.cur_row); // row 2 is not look-able
+ try std.testing.expectEqual(@as(i32, 3), results.body.cur_row); // row 2 is not look-able
try std.testing.expectEqualStrings("uucode_config.zig:7:1", selectedOutputText(results) orelse "");
p.update(.{ .key = .{ .cp = 'n' } });
- try std.testing.expectEqual(@as(i32, 0), results.cur_row); // ring seam
+ try std.testing.expectEqual(@as(i32, 0), results.body.cur_row); // ring seam
p.update(.{ .key = .{ .cp = Key.enter } });
try std.testing.expect(p.freeSlot() != panes_before);
@@ -861,16 +861,16 @@ test "n/N resumes the result output whose Look moved focus away" {
try std.testing.expect(p.executeBuiltinLine(0, "Look target"));
const rid = p.panes[0].?.search_pane orelse return error.MissingResults;
const results = p.panes[rid].?;
- const first = results.cur_row;
+ const first = results.body.cur_row;
try std.testing.expectEqual(@as(usize, 0), p.active);
try std.testing.expect(results.look_at != null);
try std.testing.expectEqual(results.serial, p.look_walk_owner orelse return error.MissingLookOwner);
p.update(.{ .key = .{ .cp = 'n' } });
try std.testing.expectEqual(rid, p.active);
- try std.testing.expectEqual(first + 1, results.cur_row);
+ try std.testing.expectEqual(first + 1, results.body.cur_row);
p.update(.{ .key = .{ .cp = 'N' } });
- try std.testing.expectEqual(first, results.cur_row);
+ try std.testing.expectEqual(first, results.body.cur_row);
// A later no-match answer has no position to resume and therefore cannot
// steal the provenance established by the Look above.
@@ -888,7 +888,7 @@ test "n/N resumes the result output whose Look moved focus away" {
try std.testing.expectEqual(owner, p.look_walk_owner.?);
p.update(.{ .key = .{ .cp = 'n' } });
try std.testing.expectEqual(rid, p.active);
- try std.testing.expectEqual(first + 1, results.cur_row);
+ try std.testing.expectEqual(first + 1, results.body.cur_row);
// Emptying the owner itself keeps its identity as the ring's starting
// point. Deleting it then leaves a stale serial, never an id that can bind
@@ -920,7 +920,7 @@ test "N exactly reverses n across output panes and the ring seam" {
const here = struct {
fn at(pp: *Pardes) Mark {
const pane = pp.panes[pp.active].?;
- return .{ .pane = pp.active, .row = pane.cur_row, .col = pane.cur_col };
+ return .{ .pane = pp.active, .row = pane.body.cur_row, .col = pane.body.cur_col };
}
}.at;
p.update(.{ .key = .{ .cp = 'n' } });
@@ -957,7 +957,7 @@ test "ThemeSel groups native themes first and skips headings in both directions"
const list = p.panes[tid].?;
const content = list.file.?.content;
try std.testing.expectEqual(@as(usize, 0), p.active);
- try std.testing.expectEqual(@as(i32, 0), list.cur_row);
+ try std.testing.expectEqual(@as(i32, 0), list.body.cur_row);
try std.testing.expectEqual(@as(usize, 0), list.file.?.scroll);
try std.testing.expectEqualStrings("# Pardes themes", modal.lineSlice(content, 0));
try std.testing.expectEqualStrings("# Legacy and imported themes", modal.lineSlice(content, pardes.native_theme_count + 2));
@@ -1024,10 +1024,10 @@ test "identical result refresh keeps warm content caches without allocation" {
const id = source.search_pane orelse return error.MissingResults;
const result = p.panes[id].?;
const file = &result.file.?;
- result.cur_row = 1;
- result.cur_col = 12;
- result.vsel = .{ .active = true, .explicit = true, .row = 0, .col = 2 };
- result.select = true;
+ result.body.cur_row = 1;
+ result.body.cur_col = 12;
+ result.body.vsel = .{ .active = true, .explicit = true, .row = 0, .col = 2 };
+ result.body.select = true;
file.scroll = 1;
result.hscroll = 3;
panes.File.refreshHighlights(p);
@@ -1040,7 +1040,7 @@ test "identical result refresh keeps warm content caches without allocation" {
const body_ptr = file.content.ptr;
const style_ptr = file.highlights.ptr;
const highlight_start = file.highlight_start;
- const selected = result.vsel;
+ const selected = result.body.vsel;
const event_node = pardes.ctlfs.Node.of(result.serial, .event);
const opened = pardes.ctlfs.handle(p, .{ .tag = 0, .op = .open, .node = event_node });
try std.testing.expectEqual(.ok, opened.status);
@@ -1071,10 +1071,10 @@ test "identical result refresh keeps warm content caches without allocation" {
try std.testing.expectEqual(freed + text.len, allocator.freed_bytes);
try std.testing.expectEqual(deallocations + 1, allocator.deallocations);
try std.testing.expect(!allocator.has_induced_failure);
- try std.testing.expectEqual(selected, result.vsel);
- try std.testing.expect(result.select);
- try std.testing.expectEqual(@as(i32, 1), result.cur_row);
- try std.testing.expectEqual(@as(i32, 12), result.cur_col);
+ try std.testing.expectEqual(selected, result.body.vsel);
+ try std.testing.expect(result.body.select);
+ try std.testing.expectEqual(@as(i32, 1), result.body.cur_row);
+ try std.testing.expectEqual(@as(i32, 12), result.body.cur_col);
try std.testing.expectEqual(@as(usize, 1), file.scroll);
try std.testing.expectEqual(@as(i32, 3), result.hscroll);
try std.testing.expectEqualStrings("after", file.output.?.arg());
@@ -1093,9 +1093,9 @@ test "identical result refresh keeps warm content caches without allocation" {
try std.testing.expectEqualSlices(usize, &.{ 0, 6 }, file.line_starts);
try std.testing.expectEqual(@as(usize, 0), file.highlights.len);
try std.testing.expect(file.syntax_dirty);
- try std.testing.expect(!result.vsel.active and !result.select);
- 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.select);
+ 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), file.scroll);
try std.testing.expectEqual(@as(i32, 0), result.hscroll);
try std.testing.expect(source.search_row == null);
@@ -1211,15 +1211,15 @@ test "result alignment chunks keep seventeen matches independent and refresh sta
const content = file.content.ptr;
const revision = file.revision;
const index = try panes.File.lineIndex(p.gpa, file);
- result.cur_row = 8;
- result.cur_col = @intCast(file.location_rows[8].code_start);
+ result.body.cur_row = 8;
+ result.body.cur_col = @intCast(file.location_rows[8].code_start);
try panes.Output.fillResults(p, 0, "/", origin, "chunks", try p.gpa.dupe(u8, input.items), 8);
try std.testing.expectEqual(result_id, source.search_pane.?);
try std.testing.expectEqual(content, file.content.ptr);
try std.testing.expectEqual(revision, file.revision);
try std.testing.expectEqual(index.ptr, file.line_starts.ptr);
try std.testing.expectEqual(@as(usize, 8), source.search_row.?);
- try std.testing.expectEqual(@as(i32, 8), result.cur_row);
+ try std.testing.expectEqual(@as(i32, 8), result.body.cur_row);
for (file.location_rows, starts) |row, start| try std.testing.expectEqual(start, row.code_start);
// Simulate a restored view made by the previous global-padding
@@ -1561,11 +1561,11 @@ test "stacked search and LSP results retain source tint navigation and dump owne
const number = std.mem.indexOf(u8, file.content, "42").?;
try std.testing.expectEqual(@intFromEnum(pardes.syntax.Syn.number), file.highlights[number]);
p.active = id;
- pane.mode = .normal;
+ pane.body.mode = .normal;
pardes.look.armLookWalk(p, id);
for ([_]struct { key: u21, match: usize }{ .{ .key = 'n', .match = 0 }, .{ .key = 'n', .match = 1 }, .{ .key = 'N', .match = 0 } }) |step| {
p.update(.{ .key = .{ .cp = step.key } });
- try std.testing.expectEqual(@as(i32, @intCast(matches[step.match])), pane.cur_row);
+ try std.testing.expectEqual(@as(i32, @intCast(matches[step.match])), pane.body.cur_row);
const row = file.location_rows[matches[step.match]];
const line = modal.lineSlice(file.content, matches[step.match]);
try std.testing.expectEqualStrings(line[0..row.location_end], selectedOutputText(pane) orelse "");
@@ -1587,7 +1587,7 @@ test "stacked search and LSP results retain source tint navigation and dump owne
restored.active = id;
pardes.look.armLookWalk(restored, id);
restored.update(.{ .key = .{ .cp = 'N' } });
- try std.testing.expectEqual(@as(i32, @intCast(matches[1])), restored.panes[id].?.cur_row);
+ try std.testing.expectEqual(@as(i32, @intCast(matches[1])), restored.panes[id].?.body.cur_row);
try std.testing.expectEqualStrings(source_text, source.file.?.content);
}
}
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);
}
}
}
diff --git a/test/pdf.zig b/test/pdf.zig
index 8e87dfb1..52fb62aa 100644
--- a/test/pdf.zig
+++ b/test/pdf.zig
@@ -13,7 +13,7 @@ const Pardes = pardes.Pardes;
const Builtin = builtins.registry.Builtin();
const Key = pardes.Key;
const Event = pardes.Event;
-const Mode = pardes.Pane.Mode;
+const Mode = panes.Text.Mode;
const Surface = pardes.Surface;
const ImagePlace = pardes.ImagePlace;
const PdfFitMode = panes.Pdf.FitMode;
@@ -457,8 +457,8 @@ test "watched PDF reload replaces MuPDF state and preserves the reading view" {
anchor_fraction * @as(f64, @floatFromInt(state.page_heights[2]));
state.scroll_to_page_pending = false;
state.layout_anchor_pending = false;
- pane.cur_row = 9;
- pane.cur_col = 8;
+ pane.body.cur_row = 9;
+ pane.body.cur_col = 8;
try tmp.dir.writeFile(std.testing.io, .{ .sub_path = "live.pdf", .data = replacement });
try std.testing.expect(p.reloadWatchedFile(0, &.{}));
@@ -482,8 +482,8 @@ test "watched PDF reload replaces MuPDF state and preserves the reading view" {
try std.testing.expect(state.layout_anchor_pending);
try std.testing.expectEqual(@as(usize, 2), state.layout_anchor_page);
try std.testing.expectApproxEqAbs(anchor_fraction, state.layout_anchor_fraction, 0.0001);
- 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);
_ = state.ensureText(p.pdf_gpa);
const text_lines = std.mem.count(u8, state.text, "\n") + 1;
try std.testing.expect(state.text_scroll < text_lines);
@@ -690,8 +690,8 @@ test "MuPDF pane renders, navigates, searches, and round-trips its page" {
p.update(.{ .key = .{ .cp = '4' } });
p.update(.{ .key = .{ .cp = 'g' } });
p.update(.{ .key = .{ .cp = '?' } });
- try std.testing.expectEqual(.none, pane.normal.prefix);
- try std.testing.expectEqual(@as(u32, 0), pane.normal.count);
+ try std.testing.expectEqual(.none, pane.body.normal.prefix);
+ try std.testing.expectEqual(@as(u32, 0), pane.body.normal.count);
p.update(.{ .key = .{ .cp = 'j' } });
try std.testing.expectEqual(row_scroll, pane.pdf.?.document_scroll_y);
@@ -893,9 +893,9 @@ test "MuPDF pane renders, navigates, searches, and round-trips its page" {
p.update(.{ .key = .{ .cp = 'n' } });
try std.testing.expectEqual(results_id, p.active);
const results_pane = p.panes[results_id].?;
- try std.testing.expect(results_pane.vsel.active and results_pane.vsel.explicit);
- try std.testing.expectEqual(@as(i32, 0), results_pane.cur_row);
- try std.testing.expectEqual(@as(i32, 0), results_pane.cur_col);
+ try std.testing.expect(results_pane.body.vsel.active and results_pane.body.vsel.explicit);
+ try std.testing.expectEqual(@as(i32, 0), results_pane.body.cur_row);
+ try std.testing.expectEqual(@as(i32, 0), results_pane.body.cur_col);
p.update(.{ .key = .{ .cp = Key.enter } });
try std.testing.expectEqual(@as(usize, 0), p.active);
try std.testing.expectEqualStrings("Pardes", pane.pdf.?.search_query);
@@ -1097,15 +1097,15 @@ test "PDF normal adapter consumes unsupported actions and navigates page fallbac
p.update(.{ .key = .{ .cp = '|' } });
try std.testing.expectEqual(page_before_noop, pv.page);
try std.testing.expectEqual(revision_before_noop, pv.next_raster_revision);
- try std.testing.expectEqual(@as(u32, 0), pane.normal.count);
- try std.testing.expectEqual(.none, pane.normal.prefix);
- try std.testing.expect(!pane.vsel.active and !pane.msel.active and pane.nsel == 0);
+ try std.testing.expectEqual(@as(u32, 0), pane.body.normal.count);
+ try std.testing.expectEqual(.none, pane.body.normal.prefix);
+ try std.testing.expect(!pane.body.vsel.active and !pane.body.msel.active and pane.body.nsel == 0);
try std.testing.expect(!pane.tag_edit);
// Cross-pane BODY-NORMAL actions keep their established shared paths.
p.update(.{ .key = .{ .cp = ':' } });
try std.testing.expect(pane.tag_edit);
- try std.testing.expectEqual(Mode.normal, pane.mode);
+ try std.testing.expectEqual(Mode.normal, pane.body.mode);
p.update(.{ .key = .{ .cp = Key.escape } });
try std.testing.expect(!pane.tag_edit);
p.update(.{ .key = .{ .cp = ' ' } });
@@ -1167,8 +1167,8 @@ test "Escape cancels PDF chrome in place and Shift-Escape leaves the pane" {
try std.testing.expect(!pv.highlights_dirty and !pv.search_reveal_pending);
try std.testing.expectEqual(page_before, pv.page);
try std.testing.expectEqual(scroll_before, pv.document_scroll_y);
- try std.testing.expectEqual(@as(u32, 0), pane.normal.count);
- try std.testing.expectEqual(.none, pane.normal.prefix);
+ try std.testing.expectEqual(@as(u32, 0), pane.body.normal.count);
+ try std.testing.expectEqual(.none, pane.body.normal.prefix);
// A second Escape on a bare document is inert rather than an exit.
p.update(.{ .key = .{ .cp = Key.escape } });
try std.testing.expectEqual(@as(usize, 0), p.active);
@@ -1781,8 +1781,8 @@ test "PDF native mouse selection, Look, and highlights share page geometry" {
const page_before = pv.page;
const scroll_before = pv.document_scroll_y;
const sels_before = pane.sel;
- const cursor_before = .{ pane.cur_row, pane.cur_col };
- const modal_before = .{ pane.msel, pane.vsel, pane.nsel };
+ const cursor_before = .{ pane.body.cur_row, pane.body.cur_col };
+ const modal_before = .{ pane.body.msel, pane.body.vsel, pane.body.nsel };
const selection_before = pv.selection orelse return error.MissingPdfSelection;
const selection_quads_before = try gpa.dupe(pdf_impl.Quad, selection_before.quads);
defer gpa.free(selection_quads_before);
@@ -1836,8 +1836,8 @@ test "PDF native mouse selection, Look, and highlights share page geometry" {
try std.testing.expectEqual(page_before, pv.page);
try std.testing.expectEqual(scroll_before, pv.document_scroll_y);
try std.testing.expect(std.meta.eql(sels_before, pane.sel));
- try std.testing.expectEqual(cursor_before, .{ pane.cur_row, pane.cur_col });
- try std.testing.expect(std.meta.eql(modal_before, .{ pane.msel, pane.vsel, pane.nsel }));
+ try std.testing.expectEqual(cursor_before, .{ pane.body.cur_row, pane.body.cur_col });
+ try std.testing.expect(std.meta.eql(modal_before, .{ pane.body.msel, pane.body.vsel, pane.body.nsel }));
const selection_after = pv.selection orelse return error.HoverDroppedPdfSelection;
try std.testing.expectEqualSlices(pdf_impl.Quad, selection_quads_before, selection_after.quads);
try std.testing.expectEqualStrings(selection_text_before, pv.selection_text);
@@ -1938,7 +1938,7 @@ test "PDF native mouse selection, Look, and highlights share page geometry" {
try std.testing.expect(panes.Pdf.beginSelection(p, pane, word_col, selected_row));
p.update(.{ .key = .{ .cp = 'v' } });
try std.testing.expect(pv.selection != null);
- try std.testing.expect(!pane.vsel.active);
+ try std.testing.expect(!pane.body.vsel.active);
p.update(.{ .mouse = .{ .button = config.select_button, .kind = .press, .col = word_col, .row = selected_row } });
p.update(.{ .mouse = .{ .button = config.select_button, .kind = .release, .col = word_col, .row = selected_row } });
try std.testing.expect(pv.selection == null);
diff --git a/test/perf.zig b/test/perf.zig
index 6ce8f014..8eec1ed0 100644
--- a/test/perf.zig
+++ b/test/perf.zig
@@ -229,7 +229,7 @@ fn measureStartup(io: std.Io, reps: usize, json: bool) !void {
try std.json.Stringify.valueAlloc(gpa, result, .{})
else
try std.fmt.allocPrint(gpa, "{s}: boot {d} ns (cold {d}), first frame {d} ns, {d} allocations / {d} B, peak {d} B", .{
- result.case, result.init_median_ns, result.cold_ns, result.frame_median_ns,
+ result.case, result.init_median_ns, result.cold_ns, result.frame_median_ns,
result.allocations, result.allocated_bytes, result.peak_bytes,
});
defer gpa.free(text);
@@ -473,7 +473,7 @@ fn measure(op: Op, fx: Fixture, path: []const u8, expected_bytes: usize, reps: u
for (0..warmup + reps) |n| {
seek(pane, fx, n);
_ = try frame(core); // settle the view at the new spot, untimed
- const before = .{ .row = pane.cur_row, .col = pane.cur_col, .scroll = pane.scroll(), .len = pane.file.?.content.len };
+ const before = .{ .row = pane.body.cur_row, .col = pane.body.cur_col, .scroll = pane.scroll(), .len = pane.file.?.content.len };
const rect = core.rects[id];
const wheel_col = rect.x + pardes.config.GUTTER;
const wheel_row = if (core.settings.tag_bottom) rect.y else rect.y + pardes.BOX_H;
@@ -492,16 +492,16 @@ fn measure(op: Op, fx: Fixture, path: []const u8, expected_bytes: usize, reps: u
const dt = nowNs() -| t0;
switch (op) {
.open => unreachable,
- .render => if (pane.cur_row != before.row or pane.cur_col != before.col or pane.file.?.content.len != before.len)
+ .render => if (pane.body.cur_row != before.row or pane.body.cur_col != before.col or pane.file.?.content.len != before.len)
return error.RenderChangedDocument,
- .key_down => if (pane.cur_row != before.row + 1) return error.DownDidNotMove,
- .key_right => if (pane.cur_row != before.row or pane.cur_col != before.col + 1) return error.RightDidNotMove,
+ .key_down => if (pane.body.cur_row != before.row + 1) return error.DownDidNotMove,
+ .key_right => if (pane.body.cur_row != before.row or pane.body.cur_col != before.col + 1) return error.RightDidNotMove,
.page_down => if (pane.scroll() <= before.scroll and before.scroll < @as(i32, @intCast(fx.lines)) - pane.rows)
return error.PageDidNotScroll,
.wheel => if (pane.scroll() <= before.scroll and before.scroll < @as(i32, @intCast(fx.lines)) - pane.rows)
return error.WheelDidNotScroll,
.edit_char => {
- if (pane.file.?.content.len != before.len + 1 or pane.cur_row != before.row or pane.cur_col != before.col + 1)
+ if (pane.file.?.content.len != before.len + 1 or pane.body.cur_row != before.row or pane.body.cur_col != before.col + 1)
return error.CharacterWasNotInserted;
const line = pardes.panes.File.sourceLine(pane, before.row);
if (line[@intCast(before.col)] != 'x') return error.CharacterWasNotInserted;
@@ -521,13 +521,13 @@ fn measureTerm(op: TermOp, fx: TermFixture, reps: usize) !Cell {
defer core.deinit();
const pane = core.panes[0] orelse return error.MissingTerminal;
const state = pane.terminal orelse return error.MissingTerminal;
- if (op == .key_down or op == .edit_char) pane.mode = .normal;
+ if (op == .key_down or op == .edit_char) pane.body.mode = .normal;
if (op == .edit_char) {
core.update(.{ .key = .{ .cp = 'i', .text = "i" } });
pump(core);
}
_ = try frame(core);
- const motion_rows = if (op == .key_down) (try pardes.edit.paneCursorLines(core, pane)).len else 0;
+ const motion_rows = if (op == .key_down) (try pardes.edit.paneCursorLines(core, &pane.body)).len else 0;
if (op == .key_down and motion_rows < 3) return error.EmptyTerminalFixture;
var cols = screen_cols;
@@ -535,16 +535,16 @@ fn measureTerm(op: TermOp, fx: TermFixture, reps: usize) !Cell {
for (0..warmup + reps) |n| {
if (op == .key_down) {
const span = @max(1, motion_rows * 8 / 10);
- pane.cur_row = @intCast(@min(motion_rows - 2, motion_rows / 10 + (n *% 7919) % span));
- pane.cur_col = 0;
- pane.cur_pinned = true;
- pane.sticky_col = -1;
+ pane.body.cur_row = @intCast(@min(motion_rows - 2, motion_rows / 10 + (n *% 7919) % span));
+ pane.body.cur_col = 0;
+ pane.body.cur_pinned = true;
+ pane.body.sticky_col = -1;
pane.ensureCursorVisible();
_ = try frame(core);
}
const before = .{
- .row = pane.cur_row,
- .col = pane.cur_col,
+ .row = pane.body.cur_row,
+ .col = pane.body.cur_col,
.edit_len = if (pane.ovl) |overlay| overlay.text.len else 0,
.replay_head = state.replay.head,
.replay_len = state.replay.len,
@@ -570,7 +570,7 @@ fn measureTerm(op: TermOp, fx: TermFixture, reps: usize) !Cell {
_ = try frame(core);
const dt = nowNs() -| t0;
switch (op) {
- .render => if (pane.cur_row != before.row or pane.cur_col != before.col or
+ .render => if (pane.body.cur_row != before.row or pane.body.cur_col != before.col or
state.replay.head != before.replay_head or state.replay.len != before.replay_len)
return error.RenderChangedTerminal,
.output => {
@@ -590,12 +590,12 @@ fn measureTerm(op: TermOp, fx: TermFixture, reps: usize) !Cell {
state.vt.screens.active.pages.rows != pane.rows) return error.TerminalDidNotResize,
.resize_cols => if (pane.cols == before.cols or pane.rows != before.rows or
state.vt.screens.active.pages.cols != pane.cols) return error.TerminalDidNotResize,
- .key_down => if (pane.cur_row != before.row + 1) return error.DownDidNotMove,
+ .key_down => if (pane.body.cur_row != before.row + 1) return error.DownDidNotMove,
.edit_char => {
const overlay = pane.ovl orelse return error.CharacterWasNotInserted;
- if (overlay.text.len != before.edit_len + 1 or pane.cur_row != before.row or pane.cur_col != before.col + 1)
+ if (overlay.text.len != before.edit_len + 1 or pane.body.cur_row != before.row or pane.body.cur_col != before.col + 1)
return error.CharacterWasNotInserted;
- const line = pardes.modal.lineSlice(overlay.text, @intCast(pane.cur_row - overlay.row));
+ const line = pardes.modal.lineSlice(overlay.text, @intCast(pane.body.cur_row - overlay.row));
if (before.col < 0 or before.col >= line.len or line[@intCast(before.col)] != 'x')
return error.CharacterWasNotInserted;
},
@@ -711,7 +711,7 @@ const UndoOutput = struct {
fn measureUndoOutput(core: *pardes.Pardes, counter: *Allocations, arena: *std.heap.ArenaAllocator, samples: []u64) ![3]UndoOutput {
const pane = core.panes[0].?;
const pages = &pane.terminal.?.vt.screens.active.pages;
- if (pane.ed_undo_len != 0 or pane.ed_redo_len != 0) return error.UnexpectedTerminalHistory;
+ if (pane.body.ed_undo_len != 0 or pane.body.ed_redo_len != 0) return error.UnexpectedTerminalHistory;
if (pane.ovl) |overlay| core.gpa.free(overlay.text);
pane.ovl = null;
var result: [3]UndoOutput = undefined;
@@ -722,17 +722,17 @@ fn measureUndoOutput(core: *pardes.Pardes, counter: *Allocations, arena: *std.he
const first: i32 = @intCast(@min(128, pages.total_rows - 2));
for (0..depth) |index| {
pane.ovl = .{ .row = first, .rows = 2, .text = try std.fmt.allocPrint(core.gpa, "saved edit {d}\nsecond row", .{index}) };
- pane.cur_row = first + 1;
- pane.cur_col = 1;
- pane.vsel = .{ .active = true, .row = first, .col = 0 };
+ pane.body.cur_row = first + 1;
+ pane.body.cur_col = 1;
+ pane.body.vsel = .{ .active = true, .row = first, .col = 0 };
pardes.panes.Terminal.pushUndo(core, pane);
core.gpa.free(pane.ovl.?.text);
pane.ovl = null;
- if (pane.ed_undo_len != index + 1) return error.TerminalUndoSnapshotFailed;
+ if (pane.body.ed_undo_len != index + 1) return error.TerminalUndoSnapshotFailed;
}
defer {
- for (pane.ed_undo[0..pane.ed_undo_len]) |snapshot| if (snapshot.ovl) |overlay| core.gpa.free(overlay.text);
- pane.ed_undo_len = 0;
+ for (pane.body.ed_undo[0..pane.body.ed_undo_len]) |snapshot| if (snapshot.ovl) |overlay| core.gpa.free(overlay.text);
+ pane.body.ed_undo_len = 0;
}
pardes.panes.Terminal.enterTty(core, 0);
pump(core);
@@ -767,7 +767,7 @@ fn measureUndoOutput(core: *pardes.Pardes, counter: *Allocations, arena: *std.he
if (pages.countTrackedPins() != tracked_before + 2) return error.TerminalPinsLeaked;
const expected: i32 = if (start.garbage) 0 else @intCast((pages.pointFromPin(.screen, start.*) orelse return error.TerminalAnchorLost).screen.y);
const last: i32 = if (end.garbage) 0 else @intCast((pages.pointFromPin(.screen, end.*) orelse return error.TerminalAnchorLost).screen.y);
- for (pane.ed_undo[0..pane.ed_undo_len], 0..) |snapshot, index| {
+ for (pane.body.ed_undo[0..pane.body.ed_undo_len], 0..) |snapshot, index| {
const overlay = snapshot.ovl orelse return error.TerminalUndoTextLost;
var expected_buffer: [64]u8 = undefined;
const text = try std.fmt.bufPrint(&expected_buffer, "saved edit {d}\nsecond row", .{index});
@@ -812,7 +812,7 @@ fn measureTerminalSession(io: std.Io, mib: usize, reps: usize, json: bool) !void
pump(core);
const pane = core.panes[0] orelse return error.MissingTerminal;
const state = pane.terminal orelse return error.MissingTerminal;
- pane.mode = .tty;
+ pane.body.mode = .tty;
pane.tty_filter = false;
var arena: std.heap.ArenaAllocator = .init(counter.allocator());
defer arena.deinit();
@@ -855,17 +855,17 @@ fn measureTerminalSession(io: std.Io, mib: usize, reps: usize, json: bool) !void
pump(core);
_ = try core.render(arena.allocator());
const first_modal_ns = nowNs() - modal_begin;
- if (pane.mode != .normal or !pane.cur_pinned or pane.cur_row != first_row - 1) return error.FirstModalKeyDidNotMove;
+ if (pane.body.mode != .normal or !pane.body.cur_pinned or pane.body.cur_row != first_row - 1) return error.FirstModalKeyDidNotMove;
for (modal_samples, 0..) |*sample, index| {
const down = index % 2 == 0;
- const before = pane.cur_row;
+ const before = pane.body.cur_row;
_ = arena.reset(.retain_capacity);
const begin = nowNs();
core.update(.{ .key = .{ .cp = if (down) 'j' else 'k' } });
pump(core);
_ = try core.render(arena.allocator());
sample.* = nowNs() - begin;
- if (pane.cur_row != before + @as(i32, if (down) 1 else -1)) return error.ModalKeyDidNotMove;
+ if (pane.body.cur_row != before + @as(i32, if (down) 1 else -1)) return error.ModalKeyDidNotMove;
}
core.update(.{ .key = .{ .cp = core.opts.tty_toggle, .ctrl = true } });
pump(core);
@@ -883,8 +883,8 @@ fn measureTerminalSession(io: std.Io, mib: usize, reps: usize, json: bool) !void
const live_after_modal = counter.live;
var overlay_median_ns: [2]u64 = undefined;
var overlay_p95_ns: [2]u64 = undefined;
- pane.mode = .normal;
- pane.cur_pinned = true;
+ pane.body.mode = .normal;
+ pane.body.cur_pinned = true;
pane.ovl = .{ .row = 0, .rows = 1, .text = try core.gpa.dupe(u8, "edited output") };
for (0..2) |phase| {
for (modal_samples, 0..) |*sample, index| {
@@ -897,8 +897,8 @@ fn measureTerminalSession(io: std.Io, mib: usize, reps: usize, json: bool) !void
pump(core);
const cursor_row = pardes.panes.Terminal.gridOffset(pane) + @as(i32, pardes.panes.Terminal.gridCursor(pane).y);
pane.ovl.?.row = if (phase == 0) 0 else cursor_row - 1;
- pane.cur_row = pane.ovl.?.row;
- pane.cur_col = 0;
+ pane.body.cur_row = pane.ovl.?.row;
+ pane.body.cur_col = 0;
const surface = try core.render(arena.allocator());
sample.* = nowNs() - begin;
try checkTerminalTail(core, surface, tail_id);
@@ -1146,11 +1146,11 @@ fn seek(pane: *pardes.Pane, fx: Fixture, n: usize) void {
const row = fx.lines / 10 + (n *% 7919) % span;
f.scroll = @min(row, fx.lines -| 1);
f.syntax_dirty = true;
- pane.cur_row = @intCast(f.scroll);
- pane.cur_col = if (fx.cols > 200) @intCast(fx.cols * 3 / 4) else 0;
- pane.cur_pinned = true;
- pane.hscroll = @max(0, pane.cur_col - 40);
- pane.sticky_col = -1;
+ pane.body.cur_row = @intCast(f.scroll);
+ pane.body.cur_col = if (fx.cols > 200) @intCast(fx.cols * 3 / 4) else 0;
+ pane.body.cur_pinned = true;
+ pane.hscroll = @max(0, pane.body.cur_col - 40);
+ pane.body.sticky_col = -1;
}
fn boot() !*pardes.Pardes {