Merge pull request #131 from levineuwirth/mode-system-handoff

Record landed mode system
This commit is contained in:
Levi Neuwirth 2026-07-22 12:50:12 +00:00 committed by GitHub
commit d5d9b9c1ca
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 53 additions and 50 deletions

View File

@ -1,6 +1,6 @@
# Active work — cross-machine resume ledger # Active work — cross-machine resume ledger
**Snapshot: 2026-07-21.** This file records volatile work that has not **Snapshot: 2026-07-22.** This file records volatile work that has not
landed on `main`. Read it after `docs/agent-handoff.md`. Remove completed landed on `main`. Read it after `docs/agent-handoff.md`. Remove completed
entries when their PR merges; do not let this become a second permanent entries when their PR merges; do not let this become a second permanent
backlog. backlog.
@ -14,8 +14,8 @@ backlog.
machine-local: `origin` may name this canonical URL, a release mirror, machine-local: `origin` may name this canonical URL, a release mirror,
or something else, and therefore has no authority by name alone. or something else, and therefore has no authority by name alone.
- Canonical base at this snapshot: - Canonical base at this snapshot:
`githubsucks/main` @ `f1a2f75` (#128 documentation merge; runtime remains `githubsucks/main` @ `b4b925d` (mode system wiring #129 merged;
config registry #127 at protocol v18). protocol v18).
- On the transfer source, `origin/main` named a release mirror at - On the transfer source, `origin/main` named a release mirror at
`d3fa632` and lagged badly. On the current destination, `origin` names `d3fa632` and lagged badly. On the current destination, `origin` names
the canonical URL. This difference is why all recovery begins by the canonical URL. This difference is why all recovery begins by
@ -49,44 +49,19 @@ git worktree list
git status --short --branch git status --short --branch
``` ```
The first command must expose `f1a2f75` or a newer intentional main. The first command must expose `b4b925d` or a newer intentional main.
If it does not, stop and repair the remote/fetch configuration. If it does not, stop and repair the remote/fetch configuration.
## Mode system wiring lane
- Portable branch: `githubsucks/mode-system-wiring`
- PR: #129, <https://github.com/levineuwirth/pmacs/pull/129>
- Base: canonical `main` @ `f1a2f75` (protocol v18).
- Approved framing commit: `424f82b`
- Implementation checkpoint: `99cd7ec`
- State: implementation complete and awaiting user review. One detected major
mode is stored per buffer; dispatch, describe-key, show-key, and encoded
help links resolve it; after-load initializes it once; explicit overrides
and clears survive switches; the existing statusline provider path renders
it per window. No protocol change.
- Verification at `99cd7ec`: formatting and Clippy clean; 1,742 default +
1,918 CRDT library tests; 8 default + 9 CRDT touched acceptance tests; 114
M4 tests; 109 required-GPU tests; workspace sweep 2,867 passed across 81
suites (19 ignored, 1 filtered); diff check clean.
Recovery worktree on a machine that does not already own the branch:
```sh
git worktree add --track \
-b mode-system-wiring \
../pmacs-mode-system \
githubsucks/mode-system-wiring
```
## Vterm Stage 2 framing lane ## Vterm Stage 2 framing lane
- Portable branch: `githubsucks/vterm-framing` - Portable branch: `githubsucks/vterm-framing`
- Approved framing head: `fb4f8f0` - Approved framing head: `fb4f8f0`
- Base: canonical `main` @ `643d1e1` (Vterm Stage 1 / PR #126 merged). - Base: canonical `main` @ `643d1e1` (Vterm Stage 1 / PR #126 merged).
`main` has since advanced to `f1a2f75` (config registry #127 plus the #128 `main` has since advanced to `b4b925d` (config registry #127, the #128
documentation merge, with no runtime overlap with vterm); cut the Stage 2 documentation merge, and mode system wiring #129); cut the Stage 2 lane
lane from current `main`, not from `643d1e1`. from current `main`, not from `643d1e1`.
- State: `docs/vterm-framing.md` Revision 7 is framing-only, reviewed, and - State: `docs/vterm-framing.md` Revision 7 is framing-only, reviewed, and
approved for implementation. It closes the final `at_bottom`, terminal approved for implementation. It closes the final `at_bottom`, terminal
`C-c` binding-reachability, and context-implicit Lua failure-mode findings. `C-c` binding-reachability, and context-implicit Lua failure-mode findings.

View File

@ -1,9 +1,9 @@
# Agent handoff — cross-machine continuity # Agent handoff — cross-machine continuity
**Last updated: 2026-07-21, after the config registry (#127) and Vterm **Last updated: 2026-07-22, after mode system wiring (#129) landed on
Stage 1 terminal core (#126) both landed on `main`, atop completed `main`, atop the config registry (#127), Vterm Stage 1 terminal core
Themes Arc 4 (#120/#124/#125). Vterm Stages 2 and 3 are not (#126), and completed Themes Arc 4 (#120/#124/#125). Vterm Stages 2 and 3
implemented.** are not implemented.**
This file is the This file is the
bridge between development machines. If you are an agent reading bridge between development machines. If you are an agent reading
this on a fresh clone: this document plus the `docs/*-framing.md` this on a fresh clone: this document plus the `docs/*-framing.md`
@ -15,9 +15,9 @@ reads it the way you just did.
For volatile branches, checkpoints, verification, and recovery For volatile branches, checkpoints, verification, and recovery
commands, read `docs/active-work.md` immediately after this file. commands, read `docs/active-work.md` immediately after this file.
## 1. Where the project stands (2026-07-21) ## 1. Where the project stands (2026-07-22)
- `main` @ `2e37c04` (config registry #127), protocol **v18** - `main` @ `b4b925d` (mode system wiring #129), protocol **v18**
(`SUPPORTED=[6..18]`; v16 = `ThemeFacts`, v17 = `FontFacts`, v18 = (`SUPPORTED=[6..18]`; v16 = `ThemeFacts`, v17 = `FontFacts`, v18 =
`StatuslineSegments`). `StatuslineSegments`).
- **Config registry LANDED — #127** (`docs/config-registry-framing.md` - **Config registry LANDED — #127** (`docs/config-registry-framing.md`
@ -40,8 +40,8 @@ commands, read `docs/active-work.md` immediately after this file.
local → global → default; **`get(name)` resolves the GLOBAL CHAIN local → global → default; **`get(name)` resolves the GLOBAL CHAIN
ONLY** and never consults an ambient buffer. Per-language and ONLY** and never consults an ambient buffer. Per-language and
per-project are *patterns* (a hook calling `set_local`), not scopes per-project are *patterns* (a hook calling `set_local`), not scopes
the registry knows about. Mode scope is impossible until the mode the registry knows about. Mode keymaps now resolve through #129, but
system is wired — every editor `KeymapStack::resolve` passes `&[]`. `pmacs.config` deliberately remains global + buffer-local.
- Buffer-locals live in a registry side table purged at - Buffer-locals live in a registry side table purged at
`after_buffer_removed`, beside the keymap purge. `after_buffer_removed`, beside the keymap purge.
- Listeners: commit → snapshot → **drop the borrow** → re-enter Lua; - Listeners: commit → snapshot → **drop the borrow** → re-enter Lua;
@ -61,6 +61,25 @@ commands, read `docs/active-work.md` immediately after this file.
their legacy coercion** — the registry is strict, the legacy setters their legacy coercion** — the registry is strict, the legacy setters
stay lenient (`trim_on_save("yes")`, `interval_ms(1500.7)`). stay lenient (`trim_on_save("yes")`, `interval_ms(1500.7)`).
- `M-x describe-setting` renders into `*help*`. - `M-x describe-setting` renders into `*help*`.
- **Mode system wiring LANDED — #129** (`docs/mode-system-wiring-framing.md`;
merge `b4b925d`; one review round). The existing mode-keymap substrate is
now live without a protocol change.
- `Buffer.major_mode: Option<String>` owns the single major mode. The
detected language name initializes it once on `buffer.after-load`, before
grammar gating, so server-only languages work; switches never rewrite it.
Explicit overrides and clears survive switches. A future reload that fires
after-load re-detects, and explicit mode state is not session-persisted.
- Dispatch borrows the zero-or-one mode through `Option<&str>::as_slice()`
and `&[&str]`: no hot-path mode allocation. Resolution remains
buffer-local → mode → global, and registry/keymap borrows end before Lua
command invocation.
- Lua surfaces: `pmacs.buffer.major_mode` / `set_major_mode` and
`pmacs.editor.active_modes`. `pmacs.describe.key`, `pmacs.help.show_key`,
and followed percent-encoded `@mode:` links use the same effective context;
`pmacs.keymap.lookup` remains raw-global.
- The built-in `mode` statusline provider reads `ctx.buffer`, so passive
splits render their own mode. Real-daemon acceptance covers all ten framing
criteria across both Lua backends and Linux/macOS CI.
- **Syntax-highlight / language-detection side-quest (#114#118) - **Syntax-highlight / language-detection side-quest (#114#118)
LANDED** — a one-shot arc built in sibling worktrees off main while LANDED** — a one-shot arc built in sibling worktrees off main while
the user's themes lane (`theme-faces`) ran concurrently in the shared the user's themes lane (`theme-faces`) ran concurrently in the shared
@ -253,6 +272,8 @@ commands, read `docs/active-work.md` immediately after this file.
cross-cutting substrate ranked first on cross-cutting substrate ranked first on
`docs/side-quest-backlog.md`'s north star, and it unblocks the `docs/side-quest-backlog.md`'s north star, and it unblocks the
editing/indent/comment items that were config-blocked. editing/indent/comment items that were config-blocked.
- **Mode system wiring COMPLETE (#129)** — major-mode keymaps,
introspection, lifecycle initialization, and statusline display shipped.
- Remaining ranked arcs: 6 folding, 7 DAP, 8 GPU splits, plus the - Remaining ranked arcs: 6 folding, 7 DAP, 8 GPU splits, plus the
`.ipynb` arc (its JSON-grammar prerequisite shipped in #123). `.ipynb` arc (its JSON-grammar prerequisite shipped in #123).
@ -433,6 +454,14 @@ acceptance.
and go through `pmacs.command.invoke("buffer.save")`. Caught only and go through `pmacs.command.invoke("buffer.save")`. Caught only
because the *other* case failed and the cause was chased instead of because the *other* case failed and the cause was chased instead of
the assertion adjusted. the assertion adjusted.
- **Real-grid acceptance must budget for macOS startup and path width.**
A 100 ms first-Hello timeout failed under loaded macOS CI; use the normal
five-second handshake window, then short polling reads. An 80-column split
also clipped a custom statusline segment after macOS's long
`/var/folders/...` temp path while passing on Linux; size the grid for the
longest supported fixture path (the mode-system test uses 160 columns per
split).
## 6. Named deferrals (the standing backlog, consolidated) ## 6. Named deferrals (the standing backlog, consolidated)
@ -475,6 +504,9 @@ setters (`async_config` ×2, `killring.max`, the `enable` booleans) and
currently accepted for `autosave.interval-ms`, where a per-buffer currently accepted for `autosave.interval-ms`, where a per-buffer
value is meaningless. value is meaningless.
**Tab width is NOT a config gap** — see §5. **Tab width is NOT a config gap** — see §5.
Mode system (SHIPPED #129): minor modes, `buffer.after-mode-change`,
mode-scoped settings, modeline detection, `describe-mode`, and persistence of
explicit major-mode overrides/clears across sessions.
Highlight/detection (from the #114#118 side-quest + injections #122): Highlight/detection (from the #114#118 side-quest + injections #122):
locals-query processing (run each grammar's LOCALS_QUERY so locals-query processing (run each grammar's LOCALS_QUERY so
`#is?`/`#is-not? local` is honored instead of the current fail-closed `#is?`/`#is-not? local` is honored instead of the current fail-closed

View File

@ -130,8 +130,8 @@ The direct continuation of the #114#118 grammar/detection stack.
decision. Deferred from #127 on those grounds. decision. Deferred from #127 on those grounds.
- **Real `read_only` buffer flag** on both edit paths — true immutability - **Real `read_only` buffer flag** on both edit paths — true immutability
for panels / REPL / generated buffers. for panels / REPL / generated buffers.
- **Mode system wiring** — dispatch passes an empty mode list (`&[]`); - ~~**Mode system wiring**~~**SHIPPED as #129.** Per-buffer major modes
mode-scoped keybindings unresolved everywhere. now drive key dispatch, effective-key introspection, and statusline display.
- **Buffer-aware edit epoch + origin-pinned `after-edit` fan-out** — a - **Buffer-aware edit epoch + origin-pinned `after-edit` fan-out** — a
command that edits buffer A then switches to B currently evades command that edits buffer A then switches to B currently evades
`didChange` / reparse / autosave observers. `didChange` / reparse / autosave observers.
@ -237,17 +237,13 @@ guides (visual, not color).
## North star (highest-leverage first) ## North star (highest-leverage first)
**Both original north-star items have now shipped** — multi-language **The original north-star items and mode-system wiring have now shipped** —
injections (#122) and the config registry (#127) — and JSON + YAML multi-language injections (#122), the config registry (#127), JSON + YAML
(#123) merged too. The remaining board: (#123), and mode-system wiring (#129). The remaining board:
1. **Locals-query processing** — restores `.builtin` styling for 1. **Locals-query processing** — restores `.builtin` styling for
non-shadowed builtins, the last rough edge of the highlight stack. non-shadowed builtins, the last rough edge of the highlight stack.
2. **Mode-system wiring** — every editor `KeymapStack::resolve` still 2. **Tab-width rendering parity** — five constants across two crates
passes `&[]`, so mode-scoped keybindings and any mode-scoped setting
remain unreachable. Promoted here because #127 made it the largest
remaining scoping gap.
3. **Tab-width rendering parity** — five constants across two crates
with two different values, and no tab expansion at all on the GPU with two different values, and no tab expansion at all on the GPU
main text path. Explicitly NOT a config-registry task; see the entry main text path. Explicitly NOT a config-registry task; see the entry
under "Cross-cutting substrate". under "Cross-cutting substrate".