diff options
Diffstat (limited to 'src/lsp.zig')
| -rw-r--r-- | src/lsp.zig | 37 |
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(); }; |
