summaryrefslogtreecommitdiff
path: root/src/lsp/lsp.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-07-31 11:42:18 -0300
committerGabriel Schneider <[email protected]>2026-08-01 15:02:08 -0300
commit911215846f1d5a9b2e37a00e74fb9266d4a0884a (patch)
tree31413ca3336cbbd1933d9dc3e24f09a3b8ef46b4 /src/lsp/lsp.zig
parent0b7a480bef38b209741c520e2478d178767a9e51 (diff)
downloadpardes-911215846f1d5a9b2e37a00e74fb9266d4a0884a.tar.gz
pardes-911215846f1d5a9b2e37a00e74fb9266d4a0884a.zip
a Look path can name a range, and search selects what it found
file:LINE:COL-ENDLINE:ENDCOL, with the two short forms people actually type reading naturally: file:412:9-21 on one line, file:412-418 whole ones. Ends are inclusive. A path feature, not a search feature — a ranged path typed in a tag or middle-clicked out of a shell's output selects just the same; search is only its first consumer. The dash is the fussy part. `-` was already a file char, so a ranged word survives click expansion whole, but a range needs a number on BOTH sides or my-file:10, build-2 and 2026-07-30 would stop being paths. Table-driven test in look.zig for exactly that. Selecting goes through the cellRange/setPaneRange pair the multi-cursor work left, and hxOff clamps both ends, so a stale range selects what still exists rather than crashing or reaching past EOF — pinned with an 8:6-400:9 range in a nine-line file. Producers: / search, Grep, and five LSP sites through a new spanRow — goto, references, rename tokens and both symbol lists were throwing away real protocol ranges at path:line:col. Left alone deliberately: Find rows are bare paths with nothing to span, a jump is a spot not a span, and the diagnostic and format paths only ever have a point, where half a range would be worse than none. One knock-on worth knowing: n now leaves an EXPLICIT selection, so a topbar execute chords it. grep.snap's no-match step was silently becoming `Grep TARGET`; it runs from the leader path now, which never chords, and the dedicated chord steps stayed where they were.
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 } {