summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/lsp-evaluation.md23
-rw-r--r--docs/lsp.md65
2 files changed, 63 insertions, 25 deletions
diff --git a/docs/lsp-evaluation.md b/docs/lsp-evaluation.md
index ae822213..5f660640 100644
--- a/docs/lsp-evaluation.md
+++ b/docs/lsp-evaluation.md
@@ -2,16 +2,16 @@
Same core, same seam (`src/lsp.zig`), same 17-probe harness (`zig build lspbench`)
over the same corpus. Three jj workspaces, three independent implementations,
-one function each.
+one function each. C landed; see **Decision** below.
| | **A · stdlib** | **B · client** | **C · in-process** |
|---|---|---|---|
-| workspace | `pardes-ws-ast` | `pardes-ws-proto` | `pardes-ws-inproc` |
+| change | `nvqpknzm` | `stuurqqt` | **landed** |
| what it is | `std.zig.Ast` + `AstGen`, hand-rolled scope walk | `zls` as a child process, JSON-RPC over a socketpair | ZLS linked as a Zig module, analyser called directly |
| **probes correct** | 12 / 17 | **17 / 17** | **17 / 17** |
| **false claims** | 0 | 0 | 0 |
| **implementation LOC** | 622 (+307 test) | 721 | **540** (+29 build) |
-| new dependency | **none** | a `zls` binary at runtime | ZLS source (path dep) |
+| new dependency | **none** | a `zls` binary at runtime | ZLS source (fetched into `zig-pkg/`) |
| binary size vs base | +6 MiB | +14 MiB | +35 MiB |
| memory | 3.7 MiB | 1.1 MiB **+ 37 MiB in the child** | 5.5 MiB |
| processes | **1** | 2 | **1** |
@@ -82,7 +82,22 @@ All three keep the 56 existing snapshot scripts green, add a 57th driving the
real binary through the helix keymap, and pass `hxdiff` (360) and `hxparity`
(440) with no new waivers.
-## Recommendation
+## Decision
+
+**C landed.** It is what `src/lsp_zls.zig` is, and ZLS is now a fetched
+dependency (`build.zig.zon`, pinned to commit `3e0d0820` on the 0.16.x branch)
+so it sits in `zig-pkg/` like everything else and the build is reproducible
+from the .zon alone — no path dependency on a local checkout.
+
+A and B were not deleted, only un-worktree'd. They remain whole commits:
+
+- **A · stdlib** — change `nvqpknzm`
+- **B · client** — change `stuurqqt`
+
+Both are one `jj new <change>` away if the multi-language argument below wins
+later, or if the ZLS coupling ever needs backing out.
+
+## Recommendation (as written before the decision)
**C (in-process), with B as the answer to a question pardes has not asked yet.**
diff --git a/docs/lsp.md b/docs/lsp.md
index 987e901c..2a4c8784 100644
--- a/docs/lsp.md
+++ b/docs/lsp.md
@@ -77,29 +77,49 @@ Verified against `helix-term/src/keymap/default.rs`, not from memory.
| `gy` | type definition | |
| `gi` | implementation | |
| `gr` | references | |
-| `SPC k` | hover | opens `+Hover` |
-| `SPC r` | rename | tag input, like Find/Grep |
-| `SPC a` | code action | |
-| `SPC h` | select references | |
-| `SPC s` / `SPC S` | document / workspace symbols | `S` takes a query |
-| `SPC d` / `SPC D` | document / workspace diagnostics | |
+| `SPC l k` | hover | opens `+Hover` |
+| `SPC l r` | rename | tag input, like Find/Grep |
+| `SPC l a` | code action | |
+| `SPC l h` | select references | |
+| `SPC l s` / `SPC l S` | document / workspace symbols | `S` takes a query |
+| `SPC l d` / `SPC l D` | document / workspace diagnostics | |
| `]d` / `[d` | next / prev diagnostic | steps the list, asks for one if absent |
| `]D` / `[D` | last / first diagnostic | |
| `=` | format | |
+| `Ctrl`+left-click | definition | the mouse spelling of `gd` |
-`g` and `[`/`]` had **no conflicts** — `gd/gD/gy/gi/gr` and `]d/[d` were all
-free. The `SPC` letters were not, so pardes's own builtins moved out of helix's
-way rather than the reverse:
+Ctrl-click rides the ordinary left-click drag rather than firing on the press:
+a click does not place the modal cursor until RELEASE, so a query asked at
+press time would answer about wherever the cursor previously sat. A ctrl-DRAG
+still selects, and still asks about where it started.
-| builtin | was | now | why |
-|---|---|---|---|
-| Kill | `SPC k` | `SPC q` | `k` is hover; `q` is quit everywhere else |
-| Del | `SPC d` | `SPC w c` | `d` is diagnostics; closing a pane IS a window op, and `c` is helix's own spelling for close in its window mode |
-| Dump | `SPC s d` | `SPC f d` | `s` is symbols; writing a session file is a file operation |
-| Restore | `SPC s r` | `SPC f r` | same |
-| Tutor | `SPC h t` | `SPC T` | frees `h` for select-references |
+**The gotos are helix's exactly; the leader commands are helix's letters under
+an `l` prefix.** `g` and `[`/`]` had no conflicts — `gd/gD/gy/gi/gr` and
+`]d/[d` were all free, so they stay where helix puts them. The bare `<space>`
+letters were NOT free, and an earlier pass took them anyway, displacing `SPC d`
+(Del), `SPC k` (Kill), `SPC s?` (Dump/Restore) and `SPC h t` (Tutor). That is
+the wrong trade: those are pardes's most-pressed keys and predate the language
+work, whereas an LSP command is something you reach for deliberately and can
+afford one keystroke more. So every one of them keeps helix's own letter and
+gains the prefix — `<space>k` becomes `SPC l k`, `<space>d` becomes `SPC l d`
+— and nothing pardes had moved at all.
-A three-exception muscle-memory map is not a map. That is the whole argument.
+Two more live in the same group because they belong to it, not to helix:
+
+| keys | builtin | what it shows |
+|---|---|---|
+| `SPC l i` | `Lspinfo` | which ZLS, which stdlib (and whether it opens), what the backend answers and refuses, plus the last 24 queries with timings, row counts and **the errors `query` swallowed** |
+| `SPC l w` | `Lspwhy` | why the definition query at the cursor answers what it does |
+
+These exist because of the seam's own contract: a backend never fails loudly,
+which is right for an editor — a thrown analyser must not take the process with
+it — but it makes a broken backend and a correct one that found nothing look
+identical. `Lspwhy` narrates the REAL resolution path (the position context is
+the analyser's own answer, threaded out through a trace) rather than
+re-deriving it beside the code, because a debug view that reimplements the
+logic is one that can disagree with it. `Lspinfo` answers from ANY pane,
+including one with no file, since it is about the backend rather than a
+document — which matters precisely when the pane you are in is the problem.
`K` is **not** hover — in helix it is `keep_selections`. It was checked; do not
"fix" it.
@@ -110,16 +130,19 @@ A three-exception muscle-memory map is not a map. That is the whole argument.
nothing else:
```zig
-pub fn query(gpa, arena, req: Req, out: *std.ArrayList(u8)) void
+pub fn query(gpa, arena, req: Req, out: *std.Io.Writer) void
pub const supports: std.EnumSet(Kind)
pub const backend_name = "..."
```
`query` runs on a worker thread with no access to the core — everything it may
read is in `req` (`path`, `source` (NUL-terminated), `offset`, `arg`, `root`).
-`arena` is freed wholesale on return; `gpa` owns only what goes into `out`.
-Use `lsp.row()` to emit a location and `lsp.lineCol()` to convert an offset,
-so every backend's rows are byte-identical in shape.
+`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. `arena` is freed wholesale on return;
+`gpa` is for a backend's own scratch. Use `lsp.row()` to emit a location and
+`lsp.lineCol()` to convert an offset, so every backend's rows are
+byte-identical in shape.
## How the implementations are judged