diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-15 13:21:29 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-09-15 17:24:42 -0300 |
| commit | 2bdde8c5ec1049ea0f575c6f9165ed4cef00ea50 (patch) | |
| tree | 0d7879e387223bd19d78a295bee0ba7ab3a62e00 /test/panes.zig | |
| parent | 8ec8924cd577f71953f8e420af1cd60da92f3300 (diff) | |
| download | pardes-2bdde8c5ec1049ea0f575c6f9165ed4cef00ea50.tar.gz pardes-2bdde8c5ec1049ea0f575c6f9165ed4cef00ea50.zip | |
Align location results and configure source context
Diffstat (limited to 'test/panes.zig')
| -rw-r--r-- | test/panes.zig | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/test/panes.zig b/test/panes.zig index 073a9668..97dc3927 100644 --- a/test/panes.zig +++ b/test/panes.zig @@ -1597,6 +1597,132 @@ const OutputTests = struct { const fromWord = panes.Output.fromWord; const fillResults = panes.Output.fillResults; + test "Locations align Unicode paths by display width and preserve source indentation" { + const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true }); + defer p.deinit(); + _ = try p.setTestFile("notes\n"); + try fillResults(p, 0, "/", .search, "alignment", try p.gpa.dupe(u8, "/界.zig:2:1 first\n/longer-name.zig:12:3 \tsecond\n"), null); + const result = p.panes[p.panes[0].?.search_pane.?].?; + const file = &result.file.?; + try std.testing.expectEqual(@as(usize, 2), file.location_rows.len); + var column: ?usize = null; + for (file.location_rows, 0..) |row, i| { + const line = modal.lineSlice(file.content, i); + try std.testing.expectEqual(.match, row.kind); + const current = panes.File.displayWidth(line[0..row.code_start]); + if (column) |previous| try std.testing.expectEqual(previous, current); + column = current; + const expected = if (std.mem.eql(u8, row.path, "/界.zig")) " first" else "\tsecond"; + try std.testing.expectEqualStrings(expected, line[row.code_start..]); + } + } + + test "Locations context uses unsaved sources and navigation visits only matches" { + if (!syntax.enabled) return error.SkipZigTest; + const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 100, .rows = 30 }); + defer p.deinit(); + const source = "const Box = struct {\n" ++ + " pub fn run() void {\n" ++ + " // unsaved before\n" ++ + " first();\n" ++ + " // shared context\n" ++ + " second();\n" ++ + " // unsaved after\n" ++ + " }\n};\n"; + const pane = try TreeContextTests.setZigFile(p, source); + p.locations_config.context = 1; + p.locations_config.tscontext = true; + p.locations_config.tslocations = false; + const path = pane.file.?.path; + const input = try std.fmt.allocPrint(p.gpa, "{s}:6:9 second();\n{s}:4:9 first();\n", .{ path, path }); + // Original first result is the later source match: sorting and inserted + // context must both preserve its anchor. + try fillResults(p, 0, "/", .search, "context", input, 0); + const result = p.panes[pane.search_pane.?].?; + const file = &result.file.?; + const expected_lines = [_]usize{ 1, 2, 3, 4, 5, 6, 7 }; + try std.testing.expectEqual(expected_lines.len, file.location_rows.len); + var matches: [2]usize = undefined; + var count: usize = 0; + for (file.location_rows, expected_lines, 0..) |row, expected_line, i| { + try std.testing.expectEqual(expected_line, row.at.line); + try std.testing.expectEqualStrings(path, row.path); + const line = modal.lineSlice(file.content, i); + if (row.kind == .match) { + matches[count] = i; + count += 1; + } else { + try std.testing.expect(std.mem.startsWith(u8, line, "| ")); + try std.testing.expect(!panes.Output.isResultRow(file, i)); + try std.testing.expectEqualStrings(modal.lineSlice(source, expected_line - 1), line[row.code_start..]); + } + if (expected_line <= 2) try std.testing.expectEqual(@as(usize, 0), row.location_end); + } + try std.testing.expectEqual(@as(usize, 2), count); + 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.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.expect(pardes.test_api.searchStep(p, 0, 1)); + try std.testing.expectEqual(matches[1], pane.search_row.?); + + pane.search_row = null; + try std.testing.expect(pardes.test_api.searchStep(p, 0, 1)); + try std.testing.expectEqual(matches[0], pane.search_row.?); + var frame = std.heap.ArenaAllocator.init(p.gpa); + defer frame.deinit(); + _ = try p.render(frame.allocator()); + const declaration = file.location_rows[0]; + const keyword = declaration.code_start + std.mem.indexOf(u8, modal.lineSlice(source, 0), "struct").?; + const styles = file.highlights[keyword..][0.."struct".len]; + var colored = false; + for (styles) |style| colored = colored or style != 0; + try std.testing.expect(colored); + + try p.dumpState(); + const restored = try Pardes.initFromDump(p.gpa, .{ .tty_only = true }, p.dump_out.?); + defer restored.deinit(); + const restored_source = restored.panes[0].?; + const restored_id = pane.search_pane.?; + const restored_result = restored.panes[restored_id].?; + const restored_file = &restored_result.file.?; + try std.testing.expectEqualStrings(file.content, restored_file.content); + try std.testing.expectEqual(file.location_rows.len, restored_file.location_rows.len); + for (file.location_rows, restored_file.location_rows) |before, after| { + try std.testing.expectEqual(before.kind, after.kind); + try std.testing.expectEqualStrings(before.path, after.path); + try std.testing.expectEqual(before.at, after.at); + try std.testing.expectEqual(before.location_end, after.location_end); + try std.testing.expectEqual(before.code_start, after.code_start); + try std.testing.expectEqualSlices(u8, before.colors, after.colors); + } + _ = try restored.render(frame.allocator()); + try std.testing.expectEqualSlices(u8, styles, restored_file.highlights[keyword..][0.."struct".len]); + // Search links are transient UI state; the restored output metadata + // still governs stepping when that output is attached to a source. + restored_source.search_pane = restored_id; + restored_source.search_row = null; + try std.testing.expect(pardes.test_api.searchStep(restored, 0, 1)); + try std.testing.expectEqual(matches[0], restored_source.search_row.?); + try std.testing.expect(pardes.test_api.searchStep(restored, 0, 1)); + try std.testing.expectEqual(matches[1], restored_source.search_row.?); + try std.testing.expect(pardes.test_api.searchStep(restored, 0, -1)); + try std.testing.expectEqual(matches[0], restored_source.search_row.?); + + // Once an edit invalidates source metadata, the explicit marker still + // prevents context declarations from becoming search destinations. + panes.File.setContent(p, file, try p.gpa.dupe(u8, file.content)); + try std.testing.expectEqual(@as(usize, 0), file.location_rows.len); + pane.search_row = null; + try std.testing.expect(pardes.test_api.searchStep(p, 0, 1)); + try std.testing.expectEqual(matches[0], pane.search_row.?); + try std.testing.expect(pardes.test_api.searchStep(p, 0, 1)); + try std.testing.expectEqual(matches[1], pane.search_row.?); + } + test "replacing generated Help clears stale selection before executing a new row" { const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 120, .rows = 40 }); defer p.deinit(); |
