# Language intelligence Native hosts, including detached sessions, run language queries on workers. Every language, Zig included, goes through the protocol client in `src/lsp/lsp_client.zig`, which runs its server as a child process: Zig's is `zls`, which must be on PATH. Web and board builds have no language backend. `Lspinfo` (`SPC l i`) reports backend versions, server state, capabilities, recent timings and errors. `Lspwhy` (`SPC l w`) traces resolution at the cursor. ## Commands | Keys | Action | |---|---| | `gd`, `gD`, `gy`, `gi`, `gr` | Definition, declaration, type, implementation, references | | `SPC l k` | Hover | | `SPC l r` | Rename | | `SPC l a` | Code action | | `SPC l h` | Select references | | `SPC l s`, `SPC l S` | Document and workspace symbols | | `SPC l d`, `SPC l D` | Document and workspace diagnostics | | `]d`, `[d`, `]D`, `[D` | Next, previous, last and first diagnostic | | `=` | Format | | Ctrl-click | Definition | | Insert-mode Tab after `.` | Candidate declarations | | `SPC l c`, `SPC l C` | Incoming and outgoing calls | | `SPC l t`, `SPC l T` | Supertypes and subtypes | A single goto result jumps directly; several results open a reusable search buffer. `n`/`N` select result rows and Enter opens them. Hover opens prose. Locations use one-based `path:line:column` or `path:line:column-endcolumn`. Paths below the requesting pane's directory are relative to that directory; other paths stay absolute. Completion lists declarations and inserts nothing. An unanswered Tab indents only if the cursor has not moved since the request. Multicursor Tab indents without starting a query. Formatting and same-file rename apply as one undo transaction. A workspace rename spanning other files opens a preview; it does not partially apply the rename. ## Configuration and testing `PARDES_LSP_ZIG`, `_RS`, `_C`, `_GO`, `_TS` and `_PY` override the server executable for each language. An empty value disables that server. `Lspinfo` shows the effective settings. The protocol client keeps one child server per configured language, negotiates position encoding, and handles both push and pull diagnostics. Startup and request waits have deadlines; failed starts back off before retrying. Worker status messages reach the host event queue. `zig build lspbench -- probe gd :` queries the same backend from the command line. `zig build lspbench` measures it. The Zig snapshot tests (lsp, lspcomplete, lspdebug and the rest) run the real `zls`; the protocol ones use a Zig mock server with deterministic answers while exercising the real client, including process startup, framing, edits and undo. `zig build fs-test` also checks language-worker delivery in TTY and detached sessions over 9P. ## Ownership `host_io.Lsp.Job` owns copies of the source, path, argument and root. Workers never read the live core. A request ID and pane serial reject obsolete replies; mutating replies also require the original file revision. Restore cancels owned work before replacing the core. Backends implement `query`, `speaks` and `supports` in `src/lsp/`. The first backend supporting the file and query answers; status queries visit all of them. Results are written to the caller's writer. Use `lsp.row` or `spanRow` for locations, `edit` for rename ranges, and `put` for replacement text. Edit records use half-open byte offsets into the request's source snapshot. The core validates the complete response before applying it.