From 4a3c5a48224cf542429504e8728e10c802e1fd52 Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Tue, 15 Sep 2026 18:27:49 -0300 Subject: Highlight exact source occurrences in LSP references and goto results --- src/lsp/lsp_zls.zig | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) (limited to 'src/lsp/lsp_zls.zig') diff --git a/src/lsp/lsp_zls.zig b/src/lsp/lsp_zls.zig index 47e6a165..68538125 100644 --- a/src/lsp/lsp_zls.zig +++ b/src/lsp/lsp_zls.zig @@ -512,7 +512,7 @@ fn rowForToken(arena: std.mem.Allocator, base: []const u8, th: Analyser.TokenWit if (th.token >= tree.tokens.len) return; const r = offsets.tokenToRange(tree, th.token, enc); const path = lsp.rel(base, th.handle.uri.toFsPath(arena) catch return); - try lsp.spanRow(out, path, r.start.line, r.start.character, r.end.line, r.end.character, lineAt(tree.source, r.start.line)); + try lsp.sourceSpanRow(out, path, r.start.line, r.start.character, r.end.line, r.end.character, lineAt(tree.source, r.start.line)); } // ---------------------------------------------------------------- goto @@ -667,7 +667,7 @@ fn goto( const t2 = &nd.handle.tree; const rr = offsets.nodeToRange(t2, nd.node, enc); const path = lsp.rel(base, nd.handle.uri.toFsPath(arena) catch continue); - try lsp.spanRow(out, path, rr.start.line, rr.start.character, rr.end.line, rr.end.character, lineAt(t2.source, rr.start.line)); + try lsp.sourceSpanRow(out, path, rr.start.line, rr.start.character, rr.end.line, rr.end.character, lineAt(t2.source, rr.start.line)); }, } } @@ -1165,7 +1165,7 @@ fn references( try lsp.edit(out, at, at + want.len); } else { const r = offsets.tokenToRange(tree, tok, enc); - try lsp.spanRow(out, path, r.start.line, r.start.character, r.end.line, r.end.character, lines.?.line(r.start.line)); + try lsp.sourceSpanRow(out, path, r.start.line, r.start.character, r.end.line, r.end.character, lines.?.line(r.start.line)); } } } @@ -1474,3 +1474,31 @@ test "LSP ZLS rename refuses a partial edit set beyond its row budget" { } } } + +test "LSP source snippets retain native definition and reference indentation" { + const source = "const Outer = struct {\n" ++ + "\t const value: u32 = 1;\n" ++ + "\t fn use() void {\n" ++ + "\t\t_ = value;\n" ++ + "\t }\n" ++ + "};\n"; + const gpa = std.testing.allocator; + for ([_]lsp.Kind{ .definition, .declaration, .references }) |kind| { + var arena: std.heap.ArenaAllocator = .init(gpa); + defer arena.deinit(); + var out: std.Io.Writer.Allocating = .init(gpa); + defer out.deinit(); + try query(gpa, arena.allocator(), .{ + .kind = kind, + .path = "/source-snippet.zig", + .root = "/", + .source = source, + .offset = @intCast(std.mem.lastIndexOf(u8, source, "value").?), + }, &out.writer); + const definition = "source-snippet.zig:2:10-14 \t const value: u32 = 1;\n"; + try std.testing.expectEqualStrings(if (kind == .references) + definition ++ "source-snippet.zig:4:7-11 \t\t_ = value;\n" + else + definition, out.written()); + } +} -- cgit v1.3