summaryrefslogtreecommitdiff
path: root/src/lsp.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/lsp.zig')
-rw-r--r--src/lsp.zig37
1 files changed, 27 insertions, 10 deletions
diff --git a/src/lsp.zig b/src/lsp.zig
index fe492c62..536047a3 100644
--- a/src/lsp.zig
+++ b/src/lsp.zig
@@ -50,6 +50,17 @@ pub const Kind = enum {
/// SPC h
select_refs,
+ // The two introspection kinds. A backend that answers nothing is
+ // indistinguishable from a backend that is broken, so these exist to tell
+ // those apart — they are the only Kinds whose answer is ABOUT the backend
+ // rather than about the code.
+ /// SPC l i — configuration, capabilities and the recent-query log
+ status,
+ /// SPC l w — why the query at the cursor answers what it does. Narrates
+ /// the REAL resolution path rather than re-deriving it, so it cannot drift
+ /// away from what `gd` actually did.
+ explain,
+
/// Whether an answer of exactly one row should JUMP rather than open a
/// results buffer. Helix: the five gotos jump on a single location and
/// show a picker on several; a symbol list is always a picker.
@@ -66,6 +77,8 @@ pub const Kind = enum {
return switch (k) {
.hover => "+Hover",
.code_action, .format, .rename => "+Lsp",
+ // prose about the backend, never a list of locations
+ .status, .explain => "+Lsp",
else => "+Search",
};
}
@@ -94,14 +107,13 @@ pub const Req = struct {
/// Emit one `path:LINE:COL text` row. Line and column are 1-based, the way
/// every other row in a `+Search` buffer is (and the way look.zig parses one).
pub fn row(
- gpa: std.mem.Allocator,
- out: *std.ArrayList(u8),
+ out: *std.Io.Writer,
path: []const u8,
line: usize,
col: usize,
text: []const u8,
) void {
- out.print(gpa, "{s}:{d}:{d} {s}\n", .{
+ out.print("{s}:{d}:{d} {s}\n", .{
path, line + 1, col + 1, std.mem.trim(u8, text, " \t\r\n"),
}) catch {};
}
@@ -115,14 +127,19 @@ pub fn lineCol(source: []const u8, offset: usize) struct { line: usize, col: usi
return .{ .line = line, .col = upto.len - bol };
}
-/// Answer `req`, appending rows to `out`. Runs on a worker thread with no
+/// Answer `req`, writing rows to `out`. Runs on a worker thread with no
/// access to the core: everything it may read is in `req`.
///
-/// `arena` is freed wholesale when the query returns; `gpa` owns only what
-/// goes into `out`. Errors are not reported — a backend that cannot answer
-/// appends nothing, and the core treats "no rows" as "no result", which is
-/// also what a language server that is still starting up looks like.
-pub fn query(gpa: std.mem.Allocator, arena: std.mem.Allocator, req: Req, out: *std.ArrayList(u8)) void {
+/// `out` is a plain `std.Io.Writer` — the shell owns the buffer behind it (an
+/// `Io.Writer.Allocating`), so a backend never allocates the result, never
+/// frees it, and cannot get the allocator wrong. Write failures are the
+/// writer's problem; a backend may ignore them.
+///
+/// `arena` is freed wholesale when the query returns; `gpa` is for a backend's
+/// own longer-lived scratch. Errors are not reported — a backend that cannot
+/// answer writes nothing, and the core treats "no rows" as "no result", which
+/// is also what a language server still starting up looks like.
+pub fn query(gpa: std.mem.Allocator, arena: std.mem.Allocator, req: Req, out: *std.Io.Writer) void {
backend.query(gpa, arena, req, out);
}
@@ -131,7 +148,7 @@ pub fn query(gpa: std.mem.Allocator, arena: std.mem.Allocator, req: Req, out: *s
/// effect, and cannot build ZLS anyway, so there it is the empty backend the
/// base tree shipped with.
const backend = if (@import("pardes_config").zls_backend) @import("lsp_zls.zig") else struct {
- pub fn query(_: std.mem.Allocator, _: std.mem.Allocator, _: Req, _: *std.ArrayList(u8)) void {}
+ pub fn query(_: std.mem.Allocator, _: std.mem.Allocator, _: Req, _: *std.Io.Writer) void {}
pub const supports: std.EnumSet(Kind) = .initEmpty();
};