diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-27 23:06:11 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:14 -0300 |
| commit | 95a3a1bb822e583988bfe0f312d0ef219b27a454 (patch) | |
| tree | 95306e8d3f36f8af05b3ea919f6cdef1e94a028b /test/output.zig | |
| parent | c8f0c25a854b8e169db08a84d1fdcd915a70aaa0 (diff) | |
| download | pardes-95a3a1bb822e583988bfe0f312d0ef219b27a454.tar.gz pardes-95a3a1bb822e583988bfe0f312d0ef219b27a454.zip | |
Give a pane's body its own Text holding the cursor, selections, mode and undo
acme keeps what edits a text in its Text (dat.h:171-190) and the window
holds a body and a tag of that type. The cursor, the selections, the modal
state and the edit-buffer undo move off Pane into Text.zig, Pane holds
them as its body, and the edit and normal-mode operations take the Text
they edit. Nothing changes in behaviour; this is the step that lets the
tag become a second Text.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'test/output.zig')
| -rw-r--r-- | test/output.zig | 128 |
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); } } |
