summaryrefslogtreecommitdiff
path: root/test/output.zig
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/output.zig
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/output.zig')
-rw-r--r--test/output.zig128
1 files changed, 64 insertions, 64 deletions
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);
}
}