fix: harden mode acceptance startup

Give the daemon its normal five-second handshake window before switching
the mode-system acceptance client to short frame polling. Document reload
and session-persistence boundaries and correct stale describe-key guidance.
This commit is contained in:
Levi Neuwirth 2026-07-22 08:18:18 -04:00
parent 692c3c5fdc
commit 4c382ae797
3 changed files with 15 additions and 5 deletions

View File

@ -316,6 +316,9 @@ silently change an existing API unrelated to describe-key.
views. The hidden-buffer (registry-only) gap is pre-existing: those views. The hidden-buffer (registry-only) gap is pre-existing: those
buffers receive neither language detection nor syntax attachment and buffers receive neither language detection nor syntax attachment and
need their own fix. need their own fix.
An explicit nil clear is persistent across switches, not across a future
reload path that deliberately fires `buffer.after-load`; reload re-detects
the language just like a fresh open.
4. **GPU optimistic-edit bypass is a non-issue for mode-scoped 4. **GPU optimistic-edit bypass is a non-issue for mode-scoped
bindings** — the GPU frontend optimistically inserts plain printable bindings** — the GPU frontend optimistically inserts plain printable
characters (outside `BUILTIN_PAIR_CHARS`) and Tab without round-tripping characters (outside `BUILTIN_PAIR_CHARS`) and Tab without round-tripping
@ -342,6 +345,10 @@ silently change an existing API unrelated to describe-key.
side-quest (`side-quest-backlog.md:43`). This framing just wires the side-quest (`side-quest-backlog.md:43`). This framing just wires the
mechanism; modeline detection can override the initialized mode via mechanism; modeline detection can override the initialized mode via
`pmacs.buffer.set_major_mode` when it lands. `pmacs.buffer.set_major_mode` when it lands.
- **Explicit-mode session persistence** — desktop restore reopens files and
recovers detected modes through `buffer.after-load`, but explicit overrides
and clears are not serialized. Design that with session/settings persistence,
not as hidden state in this wiring layer.
- **Mode help display** (`describe-mode`) — straightforward once the mode - **Mode help display** (`describe-mode`) — straightforward once the mode
is stored, but not table-stakes for wiring. is stored, but not table-stakes for wiring.

View File

@ -8552,9 +8552,9 @@ mod tests {
/// T M5.6f: `M-x editor.describe-instance-buffer` switches the /// T M5.6f: `M-x editor.describe-instance-buffer` switches the
/// active window to *pmacs-instance* and binds buffer-local `q` /// active window to *pmacs-instance* and binds buffer-local `q`
/// to `buffer.kill-this`. The buffer-local binding is verified by /// to `buffer.kill-this`. Resolve directly against the keymap stack
/// resolving directly against the keymap stack — `pmacs.describe.key` /// to pin the exact buffer-local scope independently of the Lua
/// only consults global scope. /// describe-key rendering surface.
#[test] #[test]
fn editor_describe_instance_buffer_switches_and_binds_q() { fn editor_describe_instance_buffer_switches_and_binds_q() {
let mut state = EditorState::new(); let mut state = EditorState::new();

View File

@ -71,8 +71,8 @@ impl Grid {
fn attach(daemon: &TestDaemon) -> (Client, Grid) { fn attach(daemon: &TestDaemon) -> (Client, Grid) {
let mut stream = daemon.connect(); let mut stream = daemon.connect();
stream stream
.set_read_timeout(Some(Duration::from_millis(100))) .set_read_timeout(Some(Duration::from_secs(5)))
.expect("set daemon read timeout"); .expect("set daemon handshake timeout");
let hello: Hello = read_message(&mut stream).expect("read daemon Hello"); let hello: Hello = read_message(&mut stream).expect("read daemon Hello");
assert_eq!(hello.protocol_version, PROTOCOL_VERSION); assert_eq!(hello.protocol_version, PROTOCOL_VERSION);
write_message( write_message(
@ -84,6 +84,9 @@ fn attach(daemon: &TestDaemon) -> (Client, Grid) {
}, },
) )
.expect("attach grid frontend"); .expect("attach grid frontend");
stream
.set_read_timeout(Some(Duration::from_millis(100)))
.expect("set daemon frame timeout");
let deadline = Instant::now() + Duration::from_secs(5); let deadline = Instant::now() + Duration::from_secs(5);
let mut grid = Grid::new(); let mut grid = Grid::new();