From 0b6bd969ce9982aa7c8b31c38e64034d3d949b8e Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Tue, 15 Sep 2026 18:19:26 -0300 Subject: Mark omitted source after result declaration context with ellipses --- docs/config.md | 2 ++ src/locations.zig | 5 +++++ test/output.zig | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+) diff --git a/docs/config.md b/docs/config.md index ffd1fb3f..be8a28de 100644 --- a/docs/config.md +++ b/docs/config.md @@ -167,6 +167,8 @@ still stop on matches. With `tscontext` enabled, asterisks after a match location show its declaration depth (for example, `main.zig:42 ***`). Ordinary neighboring source lines retain syntax colors; declaration headers do not. +A declaration context line ends with ` ...` when source lines are omitted +before the next displayed row from that file. Open file buffers supply context from their current edits. Missing files still leave the original result available. These settings apply to subsequent result generation and survive `Dump`/`Restore`. Invalid fields reject the entire diff --git a/src/locations.zig b/src/locations.zig index 43d99005..45d72c57 100644 --- a/src/locations.zig +++ b/src/locations.zig @@ -256,6 +256,11 @@ pub fn format(p: *pardes.Pardes, dir: []const u8, input: []const u8, anchor: ?us try out.writer.writeByte('\t'); const code_start = out.written().len - before; try out.writer.writeAll(row.code); + if (row.declaration and index + 1 < pending.items.len) { + const next = pending.items[index + 1]; + if (std.mem.eql(u8, row.path, next.path) and next.at.line -| row.at.line > 1) + try out.writer.writeAll(" ..."); + } if (index + 1 < pending.items.len or std.mem.endsWith(u8, input, "\n")) try out.writer.writeByte('\n'); const owned_path = try p.gpa.dupe(u8, row.path); errdefer p.gpa.free(owned_path); diff --git a/test/output.zig b/test/output.zig index b0f964ee..128d6ff5 100644 --- a/test/output.zig +++ b/test/output.zig @@ -1269,3 +1269,68 @@ test "result alignment chunks assign boundary context to nearest match with prev } } } + +test "declaration context ellipses mark only final header lines before omitted source" { + if (!pardes.syntax.enabled) return error.SkipZigTest; + const text = "const Outer = struct {\n" ++ + "\n" ++ + " pub fn run(\n" ++ + " value: u32,\n" ++ + " ) void {\n" ++ + " const skipped = 1;\n" ++ + " const Inner = struct {\n" ++ + " pub fn inner(\n" ++ + " input: u32,\n" ++ + " ) void {\n" ++ + " // neighboring source\n" ++ + " _ = input;\n" ++ + " // trailing neighbor\n" ++ + " }\n" ++ + " };\n" ++ + " _ = value;\n" ++ + " }\n" ++ + "};\n"; + for ([_]panes.Output.Origin{ .search, .{ .query = .references } }) |origin| { + for ([_]bool{ false, true }) |visible| { + for ([_]u8{ 0, 1 }) |neighbors| { + const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true }); + defer p.deinit(); + const source = try p.setTestFile(text); + p.gpa.free(source.file.?.path); + source.file.?.path = try p.gpa.dupe(u8, "/ellipsis-context.zig"); + p.locations_config = .{ .context = neighbors, .tscontext = true, .tslocations = visible }; + const input = try std.fmt.allocPrint(p.gpa, "{s}:12:17 {s}\n{s}:16:9 {s}\n", .{ + source.file.?.path, modal.lineSlice(text, 11), source.file.?.path, modal.lineSlice(text, 15), + }); + try panes.Output.fillResults(p, 0, "/", origin, "ellipsis", input, 1); + const file = &p.panes[source.search_pane.?].?.file.?; + var marked: usize = 0; + var matches: usize = 0; + var continuation_lines: usize = 0; + for (file.location_rows, 0..) |row, index| { + const shown = modal.lineSlice(file.content, index); + const original = modal.lineSlice(text, row.at.line - 1); + const expected_mark = row.at.line == 1 or row.at.line == 5 or (neighbors == 0 and row.at.line == 10); + if (expected_mark) { + try std.testing.expect(row.kind == .context and row.declaration); + try std.testing.expectEqualStrings(original, shown[row.code_start .. shown.len - " ...".len]); + try std.testing.expect(std.mem.endsWith(u8, shown, " ...")); + marked += 1; + } else try std.testing.expectEqualStrings(original, shown[row.code_start..]); + if (row.at.line == 4 or row.at.line == 9) continuation_lines += 1; + if (row.kind == .match) { + matches += 1; + try std.testing.expect(row.location_end > 0); + if (row.at.line == 16) try std.testing.expectEqual(index, source.search_row.?); + } else if (row.declaration) { + try std.testing.expectEqual(visible, row.location_end > 0); + } else try std.testing.expectEqual(@as(usize, 0), row.location_end); + } + try std.testing.expectEqual(@as(usize, if (neighbors == 0) 3 else 2), marked); + try std.testing.expectEqual(@as(usize, 2), matches); + try std.testing.expectEqual(@as(usize, 2), continuation_lines); + try std.testing.expectEqualStrings(text, source.file.?.content); + } + } + } +} -- cgit v1.3