diff options
| -rw-r--r-- | docs/config.md | 3 | ||||
| -rw-r--r-- | src/locations.zig | 2 | ||||
| -rw-r--r-- | test/panes.zig | 47 |
3 files changed, 45 insertions, 7 deletions
diff --git a/docs/config.md b/docs/config.md index 3a6d00d2..b0065ad2 100644 --- a/docs/config.md +++ b/docs/config.md @@ -146,7 +146,8 @@ LocationsConfig context:5 tscontext:on tslocations:off ``` - `context` is the number of source lines above and below each match (default - `0`). Overlapping context is shown once. + `0`). Overlapping context is shown once. These neighboring lines omit their + locations and keep their code aligned with the matching result. - `tscontext` includes enclosing tree-sitter declaration headers in source order (default `off`). - `tslocations` shows locations beside those declaration headers (default diff --git a/src/locations.zig b/src/locations.zig index 5e588dbe..ebc87a2e 100644 --- a/src/locations.zig +++ b/src/locations.zig @@ -194,7 +194,7 @@ pub fn format(p: *pardes.Pardes, dir: []const u8, input: []const u8, anchor: ?us const offset = @intFromPtr(line.ptr) - @intFromPtr(source.ptr); const declaration = kind & 2 != 0; const colors = if (!declaration and offset + line.len <= source_colors.len) source_colors[offset..][0..line.len] else &.{}; - try appendContext(arena, &pending, path, line, row, declaration, declaration and !p.locations_config.tslocations, colors); + try appendContext(arena, &pending, path, line, row, declaration, !declaration or !p.locations_config.tslocations, colors); } } } diff --git a/test/panes.zig b/test/panes.zig index 9972df84..8c140001 100644 --- a/test/panes.zig +++ b/test/panes.zig @@ -1966,6 +1966,39 @@ const OutputTests = struct { } } + test "Locations neighboring context hides addresses without changing source alignment" { + for ([_]bool{ false, true }) |tslocations| { + const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true }); + defer p.deinit(); + const source = "\tbefore\n\tmatch\n after\n"; + const pane = try TreeContextTests.setZigFile(p, source); + p.locations_config = .{ .context = 1, .tscontext = false, .tslocations = tslocations }; + const path = pane.file.?.path; + try fillResults(p, 0, "/", .search, "neighbors", try std.fmt.allocPrint(p.gpa, "{s}:2:1 \tmatch\n", .{path}), 0); + const file = &p.panes[pane.search_pane.?].?.file.?; + try std.testing.expectEqual(@as(usize, 3), file.location_rows.len); + const match = file.location_rows[1]; + const match_line = modal.lineSlice(file.content, 1); + const alignment = panes.File.displayWidth(match_line[0..match.code_start]); + try std.testing.expect(match.location_end > 0); + try std.testing.expect(std.mem.startsWith(u8, match_line, path)); + for (file.location_rows, 0..) |row, index| { + const line = modal.lineSlice(file.content, index); + try std.testing.expectEqualStrings(path, row.path); + try std.testing.expectEqual(index + 1, row.at.line); + try std.testing.expect(!row.declaration); + try std.testing.expectEqual(alignment, panes.File.displayWidth(line[0..row.code_start])); + try std.testing.expectEqualStrings(modal.lineSlice(source, index), line[row.code_start..]); + if (index != 1) { + try std.testing.expectEqual(@as(usize, 0), row.location_end); + try std.testing.expectEqual(@as(usize, 0), std.mem.trim(u8, line[0..row.code_start], " \t").len); + try std.testing.expect(!panes.Output.isResultRow(file, index)); + } + } + try std.testing.expectEqual(@as(usize, 1), panes.Output.nextResult(file.content, file.location_rows, path, .{})); + } + } + 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 }); @@ -2001,7 +2034,7 @@ const OutputTests = struct { matches[count] = i; count += 1; } else { - if (row.location_end > 0) try std.testing.expect(std.mem.startsWith(u8, line, path)); + try std.testing.expectEqual(@as(usize, 0), row.location_end); try std.testing.expect(!panes.Output.isResultRow(file, i)); try std.testing.expectEqualStrings(modal.lineSlice(source, expected_line - 1), line[row.code_start..]); } @@ -2069,15 +2102,15 @@ const OutputTests = struct { try std.testing.expect(pardes.test_api.searchStep(restored, 0, -1)); try std.testing.expectEqual(matches[0], restored_source.search_row.?); - // Editing drops source metadata. Hidden declarations remain skipped, - // while flush-left visible context becomes an ordinary location. + // Editing drops source metadata; hidden context padding still keeps + // those rows out of match navigation. 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(@as(usize, 2), 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.expect(pardes.test_api.searchStep(p, 0, 1)); + try std.testing.expectEqual(matches[1], pane.search_row.?); } test "Locations visible declarations are muted and stars count scopes rather than signature lines" { @@ -2122,6 +2155,10 @@ const OutputTests = struct { try std.testing.expect(row.location_end > 0); try std.testing.expect(std.mem.startsWith(u8, line, path)); try std.testing.expectEqualStrings(path, panes.Output.location(line).path); + } else { + try std.testing.expect(!row.declaration); + try std.testing.expectEqual(@as(usize, 0), row.location_end); + try std.testing.expectEqualStrings(modal.lineSlice(source, row.at.line - 1), line[row.code_start..]); } } try std.testing.expectEqual(@as(usize, 2), matches); |
