A minibuffer refusal stands while the user fixes it (improvise-su4u)
#233 clears the status message at the start of every TUI keypress. In a text-entry mode the message sits beside the prompt, and a formula that does not parse keeps the editor open with the error. So the error vanished on the first correcting key. press now remembers the mode and the message. It clears the message as before and dispatches the key. It puts the stale message back only if the key left the user in the same text-entry mode and wrote no message of its own. Editing keys keep the refusal on screen, a key's own message still wins, and leaving the minibuffer (a successful commit or Esc) drops it. The mode check is observed, not predicted: which keys commit is the keymap's knowledge, and the TUI loop does not copy it. Rivals, each injected into press and restored: never restoring (#233), restoring over a key's own message, and restoring whatever the mode each fail a distinct step of the test. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
This commit is contained in:
@@ -424,3 +424,50 @@ is always drawn. So a browser user sees a message briefly and never loses the
|
||||
hint. The TUI now does the same, on a keypress rather than a timer, because a
|
||||
terminal status row has one line to share and a keypress is the event the TUI
|
||||
already has.
|
||||
|
||||
### Except while a minibuffer stays open under it (improvise-su4u)
|
||||
|
||||
In a text-entry mode `minibuffer_line` draws the message to the right of the
|
||||
prompt. Since improvise-v4hg, a formula that does not parse keeps the user in
|
||||
`FormulaEdit` with the error. Under the plain rule, the error vanished on the
|
||||
first correcting key: one Backspace and the user was fixing text they could no
|
||||
longer see the complaint about. The same happened to any refusal that leaves
|
||||
the user in a minibuffer.
|
||||
|
||||
**The rule: a key that leaves the user in the same text-entry mode, and says
|
||||
nothing of its own, puts the stale message back.** `press` remembers the mode
|
||||
and the message, clears the message as before, dispatches the key, and then
|
||||
restores the message only if all three of these hold:
|
||||
- the mode before the key had a minibuffer;
|
||||
- the mode after the key is the same mode;
|
||||
- the key wrote no message of its own.
|
||||
|
||||
So:
|
||||
|
||||
- editing keys keep the refusal on screen until the user acts on it;
|
||||
- a key's own message always wins, so a second refused `Enter` shows the new
|
||||
error, not the old one;
|
||||
- leaving the minibuffer, by a successful commit or by `Esc`, drops it, exactly
|
||||
as the plain rule does.
|
||||
|
||||
**Rejected alternatives.**
|
||||
|
||||
- *Expire only on the commit key.* That needs to know which keys commit, which
|
||||
is the keymap's knowledge (`TextEntry::commit`), and a second copy of it in
|
||||
the TUI loop. "The mode did not change" is observed rather than predicted,
|
||||
like gotcha 31's `ReturnToNormalUnlessMoved`.
|
||||
- *Never clear in a text-entry mode.* The message would then outlive `Esc` and
|
||||
stand in the mode the user returns to, which is the cq3d bug again.
|
||||
- *Compare the message after the key with the stale one.* A key that wrote the
|
||||
same text would be indistinguishable from a key that wrote none. Clearing
|
||||
first and restoring only an empty slot has no such ambiguity.
|
||||
|
||||
The mode test is equality of the whole `AppMode`. An edit that stayed in "a"
|
||||
minibuffer but a different one does not count as staying. No shipped key does
|
||||
that, but it would be leaving one prompt for another, and the message belonged
|
||||
to the first.
|
||||
|
||||
**The browser is not covered by this.** There, `status_msg` is a toast that
|
||||
hides after `TOAST_MS` (six seconds), and the minibuffer element draws only the
|
||||
prompt and the text. A refusal therefore disappears on a timer, whatever the
|
||||
user is doing. That is a different mechanism and has not been changed here.
|
||||
|
||||
Reference in New Issue
Block a user