diff options
Diffstat (limited to 'src/lsp')
| -rw-r--r-- | src/lsp/lsp.zig | 26 | ||||
| -rw-r--r-- | src/lsp/lsp_client.zig | 14 |
2 files changed, 34 insertions, 6 deletions
diff --git a/src/lsp/lsp.zig b/src/lsp/lsp.zig index 43f94f95..33e95570 100644 --- a/src/lsp/lsp.zig +++ b/src/lsp/lsp.zig @@ -31,8 +31,34 @@ pub const Req = struct { offset: u32, arg: []const u8 = "", root: []const u8 = "", + /// For `explain`: the query it narrates, read from `arg` (`<kind> + /// <arg>`) by `explaining`; a definition when none was asked before. + explains: Kind = .definition, }; +/// An `explain` request made the one it narrates: `explains` and `arg` set +/// from its `<kind> <arg>`; any other request as it is. +pub fn explaining(req: Req) Req { + if (req.kind != .explain) return req; + var r = req; + const sp = std.mem.indexOfScalar(u8, req.arg, ' ') orelse req.arg.len; + const named = std.meta.stringToEnum(Kind, req.arg[0..sp]) orelse .definition; + r.explains = if (named == .explain or named == .status) .definition else named; + r.arg = if (sp < req.arg.len) req.arg[sp + 1 ..] else ""; + return r; +} + +test "an explain request narrates the query named in its arg, a definition by default" { + const base: Req = .{ .kind = .explain, .path = "/x.zig", .source = "", .offset = 0 }; + var r = base; + r.arg = "hover "; + try std.testing.expectEqual(Kind.hover, explaining(r).explains); + r.arg = "rename newName"; + try std.testing.expectEqual(Kind.rename, explaining(r).explains); + try std.testing.expectEqualStrings("newName", explaining(r).arg); + try std.testing.expectEqual(Kind.definition, explaining(base).explains); +} + /// Every language, Zig's (zls) included, through the protocol client, which /// runs its server as a child process. None on the web or the board. const backends = if (@import("pardes_config").platform == .web or @import("pardes_config").platform == .esp32p4) diff --git a/src/lsp/lsp_client.zig b/src/lsp/lsp_client.zig index 7704d0ad..0c5e3b7e 100644 --- a/src/lsp/lsp_client.zig +++ b/src/lsp/lsp_client.zig @@ -405,8 +405,9 @@ const Trace = struct { // ------------------------------------------------------------------- query -pub fn query(gpa: std.mem.Allocator, arena: std.mem.Allocator, req: lsp.Req, out: *std.Io.Writer) !void { +pub fn query(gpa: std.mem.Allocator, arena: std.mem.Allocator, asked: lsp.Req, out: *std.Io.Writer) !void { _ = gpa; + const req = lsp.explaining(asked); if (req.kind == .status) return status(req, out); var tr: Trace = .{ .on = req.kind == .explain }; @@ -443,8 +444,8 @@ pub fn query(gpa: std.mem.Allocator, arena: std.mem.Allocator, req: lsp.Req, out fn traceOut(tr: *const Trace, req: lsp.Req, out: *std.Io.Writer, rows: usize, us: u64) std.Io.Writer.Error!void { if (req.kind != .explain) return; - try out.print("lsp explain — the definition query at byte {d} of {s}\n\n", .{ - req.offset, if (req.path.len == 0) "(no file)" else std.fs.path.basename(req.path), + try out.print("lsp explain — the {s} query at byte {d} of {s}\n\n", .{ + @tagName(req.explains), req.offset, if (req.path.len == 0) "(no file)" else std.fs.path.basename(req.path), }); try out.writeAll(tr.buf[0..tr.len]); if (hideTime()) @@ -488,9 +489,10 @@ fn answer(arena: std.mem.Allocator, si: usize, req: lsp.Req, out: *std.Io.Writer } fn run(c: *Conn, si: usize, arena: std.mem.Allocator, req: lsp.Req, out: *std.Io.Writer, tr: *Trace) Err!void { - // `explain` narrates the definition query — dispatch below on the - // effective kind so the trace follows the code `gd` really runs. - const kind: lsp.Kind = if (req.kind == .explain) .definition else req.kind; + // `explain` narrates the last query asked (a definition, `gd`, when + // none was) — dispatch below on the effective kind so the trace + // follows the code that query really runs. + const kind: lsp.Kind = if (req.kind == .explain) req.explains else req.kind; // Both arg-taking kinds are useless without one, and an empty // workspace/symbol query means "every symbol in the project". |
