diff options
| author | Gabriel Schneider <[email protected]> | 2026-07-29 10:20:50 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-08-01 15:02:07 -0300 |
| commit | cc173a821bd6fd84fa6e7c2f272b7e049c7a1aaa (patch) | |
| tree | 23dadf74493c0172ea7fced1dff44d2a4178c752 /test/snapshots/leader.snap | |
| parent | 4e642c1d6688baf3b98f269818b66cc7cc194c5f (diff) | |
| download | pardes-cc173a821bd6fd84fa6e7c2f272b7e049c7a1aaa.tar.gz pardes-cc173a821bd6fd84fa6e7c2f272b7e049c7a1aaa.zip | |
lsp: writer seam, ZLS introspection builtins, ctrl-click goto, SPC l group
THE SEAM TAKES A WRITER. `lsp.query`'s `out` is a `*std.Io.Writer`, not a
`*std.ArrayList(u8)`. 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 — the invalid-free class of bug has
nowhere left to live. It also deleted a parameter from five functions: they
only ever took a `gpa` to allocate rows, and 0.16's unused-parameter error
found every one. `lsp.row()` lost its allocator argument too.
Since a Writer cannot rewind or be counted, `query` renders into a scratch
Allocating first: the log wants an exact row count, and `explain` throws the
rows away and prints narration in their place.
INTROSPECTION. `SPC l i` (Lspinfo) and `SPC l w` (Lspwhy), in the `l` group
that now holds every language command (see below).
They exist because of the seam's own contract: a backend never fails loudly,
which is right for an editor, but it makes a broken backend and a correct one
that found nothing look identical from the outside. Every query now leaves a
record — kind, file, offset, duration, row count, and THE ERROR `run` returned,
which `catch {}` swallowed and which was visible nowhere. Lspinfo prints those,
plus which ZLS is compiled in, which zig lib dir and whether it actually opens
(the usual cause of "gd does nothing in std"), and what the backend answers
versus refuses. It answers from ANY pane, including one with no file, because
it is about the backend — which matters precisely when the pane you are sitting
in is the problem; both shells now send status for a file-less pane.
Lspwhy narrates the REAL resolution path. The trace is threaded through `goto`
itself, so what it prints is the position context the analyser returned and the
branch that actually stopped. A debug view that re-derives the logic beside it
is one that can disagree with it.
CTRL-CLICK IS gd. Mouse gained a `ctrl` field, set by both shells (SDL asked
directly via GetModState rather than read off key-event bookkeeping, which a
click with no prior keypress would miss). The flag rides the 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.
The snapshot DSL gained a `ctrl-` button prefix (SGR bit 4, what a terminal
sends and what vaxis decodes). test/snapshots/lspdebug.snap covers all three,
including a PLAIN click in the same spot that must NOT jump — without it the
test would pass on a bug that made every click a goto. Durations cannot live in
a golden, so PARDES_LSP_NOTIME (set by the harness, like PARDES_DUMP) omits
them.
58 snapshot scripts, hxdiff 360, hxparity 440, unit 46, gui build: all green.
lspbench: 17/17, 0 false claims.
THE WHOLE LANGUAGE GROUP LIVES UNDER SPC l.
pardes keeps its own leader letters back. `SPC d` is Del again, `SPC k` is
Kill, `SPC s d`/`SPC s r` are Dump/Restore and `SPC h t` is Tutor — exactly
where they were before the language work touched them.
The previous pass put the LSP commands on helix's bare `<space>` letters and
moved pardes's builtins out of the way (Kill k->q, Del d->wc, Dump/Restore
s?->f?, Tutor ht->T). That was the wrong trade. Those five are the most-pressed
keys in the editor and predate the language work; an LSP command is something
you reach for deliberately and can afford one keystroke more.
So every LSP command keeps HELIX'S OWN LETTER and gains the `l` prefix:
`<space>k` -> `SPC l k` (hover), `<space>d` -> `SPC l d` (diagnostics),
r/a/h/s/S/D likewise. Nothing to re-learn but the prefix, and `Lspinfo`/
`Lspwhy` were already there.
THE GOTOS ARE UNTOUCHED. `gd` `gD` `gy` `gi` `gr`, `]d`/`[d`, `]D`/`[D`, `=`
and ctrl-click all stay exactly as helix has them — they never collided with
anything, so there was never a reason to move them, and they are the ones you
actually press mid-edit.
leader.snap is restored to the pre-LSP script (its `key q` unmapped-key step
works again now that Kill is back on `k`) plus one new step for `SPC l ?`. Its
`SPC ?` root listing had to stop waiting on Restore: the full list grew to 33
rows and row 21 falls off the pane, so it watches an early row instead.
DEPENDENCY IMPORTS NOW RESOLVE. `gd` on `@import("vaxis")` opens vaxis's root
file; before, it silently did nothing while `std` worked perfectly.
The asymmetry was not a wiring mistake. ZLS's uriFromImportStr answers exactly
three ways: a relative `.zig`/`.zon` path from disk, `std` from `zig_lib_dir`
(one directory, which we supply), and EVERY OTHER NAME only by running
`zig build --build-runner` to discover the module graph. That last branch needs
`zig_exe_path`, which this backend sets to null on purpose — so every
dependency import returned `.none`. Confirmed twice over: in ZLS's source, and
by `SPC l w` on the import string, which printed the STOP line naming exactly
that branch. (The introspection builtin diagnosing its own backend on its first
real outing is a decent argument for having built it.)
We never needed a compiler for this: build.zig IS the module graph. It folds
`root_mod.import_table` into a name -> root-source-file table at configure
time and passes it as a build option; the backend consults it precisely where
ZLS gave up. Correct by construction — a dependency added or renamed in
build.zig cannot forget to update it — and it costs no subprocess, no build
step and no runtime work. `SPC l i` now lists the table, since "is this name
even importable" is the first question when a jump does nothing.
Two limits, both stated in the code: a module whose root is a GENERATED file
is skipped (it has no path until make() runs), and a file inside a dependency
importing that dependency's OWN internal module name is still a miss — that
would mean running its build.zig.
TRAP: the table is folded out of root_mod.import_table, so `addOptions` had to
move BELOW every `addImport` call. Attached where it was, the table is empty.
TOPBAR GAINS `Help`, WHICH IS WHY `SPC ?` LOOKED BROKEN.
A bare `pardes` boots straight into tty mode (main.zig: `args.len == 1`), where
every printable key belongs to the shell — so SPC never reaches the leader, and
`SPC ?`, the one thing that would tell you the leader exists, is exactly the
thing you cannot press. Ctrl-b first and it all works; nothing was broken. But
"the help is unreachable until you already know the escape hatch" is a bad
answer, and there was no mouse route either: Help was the one builtin missing
from the bar.
Row 0 is not a pane, so a middle-click there is dispatched before any pane's
mode is consulted — the word works in tty mode, which is the only reason it
earns the width. APPENDED, not inserted, so every existing topbar word keeps
its column and no golden's click coordinates move. test/snapshots/ttyhelp.snap
pins it from a bare boot: click Help, get the list, shell still TTY at its
prompt, then Ctrl-b + SPC ? for the keyboard route.
All 58 goldens carry row 0, so all 58 moved. Verified mechanically that the
only changes are the row-0 text and the row-0 style run (0-47 -> 0-52), plus:
dump/restore record the topbar inside their .zon, and tagnav's `$`+Enter now
executes `Help` rather than `Grep` because the bar's last word changed — still
exactly what that step's comment claims it tests.
THE DEPENDENCY FIX HAS A CEILING, NOW STATED. The module map is consulted from
OUR goto handler, not from inside ZLS, so the analyser still cannot type the
`vaxis` const: `gd` on `@import("vaxis")` opens the file, `gd` on `vaxis.init`
finds nothing. That is now spelled out at the top of lsp_zls.zig and on
moduleRoot rather than left implied, and `SPC l w` detects the case by name —
if the left side of a failed field access is a known dependency it says so,
instead of the generic "could not resolve". Lifting it means giving ZLS a real
BuildConfig, either by letting it run the build runner (a subprocess, and with
no cross-query cache that is once per keypress) or by synthesizing one into
BuildFile.impl. Both are real work and neither is smuggled in.
Also fixed while there: the field-access miss was only explained when ZLS
returned null, but it returns an EMPTY SLICE when it typed the left side and
found no such member. Both are "gd did nothing" from the outside; both are
explained now.
Diffstat (limited to 'test/snapshots/leader.snap')
| -rw-r--r-- | test/snapshots/leader.snap | 53 |
1 files changed, 30 insertions, 23 deletions
diff --git a/test/snapshots/leader.snap b/test/snapshots/leader.snap index e06d5a3c..7cd0b98d 100644 --- a/test/snapshots/leader.snap +++ b/test/snapshots/leader.snap @@ -6,10 +6,6 @@ # pane with no file behind it, like +Search). The paths, the Help lines and # the execute dispatch are all folded out of ONE enum at comptime — so # executing the WORD `Help` runs the same builtin the leader does. -# -# The single-letter slots k/r/a/h/s/S/d/D belong to helix's LSP commands, so -# pardes's own builtins live around them: Kill on `q`, Del in the window group -# as `w c`, Dump/Restore in the file group, Tutor on `T`. file cmds.txt Help start 40 100 cmds.txt wait 8000 Kill Newcol @@ -19,10 +15,10 @@ stable 700 20000 key space stable 400 5000 snap spc -# ... and grows as the path is typed (`f` = the file group) -key f +# ... and grows as the path is typed (`h` = the docs group) +key h stable 400 5000 -snap spc-f +snap spc-h # Esc abandons the sequence: indicator gone, nothing ran, cursor untouched key esc settle 100 @@ -31,43 +27,43 @@ snap abandoned # an UNMAPPED key abandons too, rather than waiting: a typo must not leave the # next keystroke armed at a builtin that closes panes key space -key z +key q stable 400 5000 snap unmapped # executing the WORD `Help` (middle-click) runs the builtin — the enum IS the # lookup, so a name works anywhere text lives. Every builtin, with its keys. press middle 9 3 release middle 9 3 -wait 10000 SPC T +wait 10000 SPC h t stable 700 15000 snap help-word -# `SPC f ?`: only the `f` group, rewritten into the SAME +Help buffer +# `SPC h ?`: only the `h` group, rewritten into the SAME +Help buffer key space -key f +key h key ? -wait 10000 under SPC f +wait 10000 under SPC h stable 700 15000 snap help-group -# `SPC T`: the Tutor builtin, zero arguments. It runs from the +Help pane, +# `SPC h t`: the Tutor builtin, zero arguments. It runs from the +Help pane, # but that is an output pane and not a document — so the tutor lands under # cmds.txt, the real doc, with the listing left at the foot of the column. key space -key T +key h +key t wait 10000 PARDES TUTOR stable 700 15000 snap tutor -# `SPC w c`: Del is pane-scoped — it closes the tutor, focus falls back. It -# sits in the window group because closing a pane IS a window operation, and -# because `d` now belongs to the diagnostics picker. +# `SPC d`: Del is pane-scoped — it closes the tutor, focus falls back key space -key w -key c +key d stable 700 15000 snap deleted -# `SPC ?` at the root lists everything again +# `SPC ?` at the root lists everything again. Waits on an EARLY row: the full +# listing outgrew this pane when the language group landed (Restore, which this +# used to watch for, is now row 21 of 33 and falls off the bottom). key space key ? -wait 10000 SPC f r +wait 10000 SPC c n stable 700 15000 snap help-all # `SPC t ?`: the toggle group, seven of them now that the image renderer @@ -79,14 +75,25 @@ key ? wait 10000 Petscii stable 700 15000 snap help-toggles -# `SPC w ?`: the window group — the four focus moves, the terminal hop, and -# Del. They are the tail of the full listing above and fall off its bottom. +# `SPC w ?`: the window group, whose five builtins are the tail of the full +# listing above and fall off the bottom of this pane there key space key w key ? wait 10000 Toggleterm stable 700 15000 snap help-window +# `SPC l ?`: the LANGUAGE group — every LSP command lives here rather than on +# the bare `<space>` letters helix uses, so `d` stays Del and `k` stays Kill. +# Each one keeps helix's own letter INSIDE the group (hover k, rename r, code +# action a, symbols s/S, diagnostics d/D, select-refs h), plus the two +# introspection builtins that are ours: i and w. +key space +key l +key ? +wait 10000 WsDiagnostics +stable 700 15000 +snap help-language # Esc in the BODY of an output buffer IS Del: +Help has no file behind it and # nothing worth keeping, so the key that elsewhere only drops a selection # dismisses the whole pane and hands its height back to the pane above. |
