summaryrefslogtreecommitdiff
path: root/src/lsp/lsp.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/lsp/lsp.zig')
-rw-r--r--src/lsp/lsp.zig36
1 files changed, 32 insertions, 4 deletions
diff --git a/src/lsp/lsp.zig b/src/lsp/lsp.zig
index abb91874..b8356724 100644
--- a/src/lsp/lsp.zig
+++ b/src/lsp/lsp.zig
@@ -7,10 +7,12 @@
//! language query is just another thing that answers later.
//!
//! Every backend renders into ONE format: `+Search` rows. A location is
-//! `path:LINE:COL text`, which is what look.zig already resolves and what n/N
-//! already steps, so a multi-result answer IS helix's picker and a single
-//! result IS a jump — with no picker UI written for it. Free text (hover,
-//! a rename's diff) rides the same buffer as plain lines.
+//! `path:LINE:COL text` — or `path:LINE:COL-ENDCOL text` where the protocol
+//! answered with a real range, which a look then SELECTS — and that is what
+//! look.zig already resolves and what n/N already steps, so a multi-result
+//! answer IS helix's picker and a single result IS a jump, with no picker UI
+//! written for it. Free text (hover, a rename's diff) rides the same buffer as
+//! plain lines.
//!
//! `query` is the ONLY thing an implementation supplies. Swapping backends is
//! swapping this one function, which is also how the three competing
@@ -101,6 +103,32 @@ pub fn row(
}) catch {};
}
+/// The same row for a protocol RANGE: `path:LINE:COL-ENDCOL`, which a look
+/// SELECTS rather than parking on its first cell — so `gd` lands on the whole
+/// name and a references list steps symbol by symbol with each one highlighted
+/// (config.range_sep spells the dash; `-` is written out here for the same
+/// reason `:` is).
+///
+/// `end_col` is the protocol's own EXCLUSIVE end character, which is already
+/// the 1-based inclusive column pardes wants, so the conversion is the absence
+/// of one. A span that is empty or crosses lines falls back to the point row:
+/// the only multi-line ranges here are whole declarations, and a goto onto one
+/// wants the cursor at its name, not its body painted.
+pub fn spanRow(
+ out: *std.Io.Writer,
+ path: []const u8,
+ line: usize,
+ col: usize,
+ end_line: usize,
+ end_col: usize,
+ text: []const u8,
+) void {
+ if (end_line != line or end_col <= col) return row(out, path, line, col, text);
+ out.print("{s}:{d}:{d}-{d} {s}\n", .{
+ path, line + 1, col + 1, end_col, std.mem.trim(u8, text, " \t\r\n"),
+ }) catch {};
+}
+
/// Byte offset -> (line, column), both 0-based. Every backend needs it to turn
/// an AST token into a row, so it lives here rather than three times over.
pub fn lineCol(source: []const u8, offset: usize) struct { line: usize, col: usize } {