8000 fix(terminal): let Ctrl+Shift+R leave a dead program's alternate screen again by jpstratman · Pull Request #359 · amirlehmam/wmux · GitHub
[go: up one dir, main page]

Skip to content

fix(terminal): let Ctrl+Shift+R leave a dead program's alternate screen again - #359

Merged
amirlehmam merged 9 commits into
amirlehmam:masterfrom
jpstratman:fix/reset-leave-alt-screen-on-prompt
Oct 25, 2026
Merged

amirlehmam merged 9 commits into
amirlehmam:masterfrom
jpstratman:fix/reset-leave-alt-screen-on-prompt

Conversation

@jpstratman
@jpstratman jpstratman commented Oct 24, 2026 •
Copy link
Copy Markdown
Contributor

Fixes #357. Since #347 the reset leaves the alternate screen only when the shell has reported it's back at its prompt, and only wmux's PowerShell integration reports that, so cmd, Git Bash, WSL, SSH and nested shells lost the #175 recovery. The reset now also reads the pane's own output, and can be forced.

How the reset decides

  • A prompt mark (OSC 133;A) drawn on the alternate screen since it was last entered means the program that entered it is gone, so the reset leaves. This overrides a running report, which in SSH, WSL and nested shells belongs to the outer shell.
  • A program entering the alternate screen (DECSET 47/1047/1049, including re-entry from a prompt already there) since the last such mark means something may still be drawing, so the reset keeps it, even when PowerShell without PSReadLine reports idle.
  • A command started from a prompt on the alternate screen (OSC 133;C) keeps it until the command ends (133;D) or the next prompt. The PowerShell and bash integrations and Starship send C. cmd doesn't, so it behaves as above.
  • With none of these, the Reset terminal state leaves the alternate screen while the program is still running #347 shell-state rule decides.
  • When the reset keeps the screen, a short notice says so, and a separate second press within 5 seconds forces it. Key auto-repeat doesn't count, so holding the chord resets once. The window and the notice end as soon as the program leaves the alternate screen or a new one enters it. The new palette entry "Reset terminal state (leave alternate screen)" forces it directly.

Design choices

  • Prompt marks come from the existing handlePromptMark parse, recorded even when the prompt log is off, so there's no second OSC handler.
  • The notice is a new non-modal overlay (ResetNotice.tsx). A notification raises an OS toast and a pane ring, which is too much here, and a [wmux] line written into xterm would land inside the running program's frame.
  • The notice keeps its role="status 8000 " region mounted and toggles only its text, so screen readers announce it. It sits above the prompt outline and below the find bar.
  • The ?1049h that a remount snapshot replays is ignored, so a rebuilt terminal doesn't read as a program entering the alternate screen.

Manual verification

In a wmux-dev.ps1 -Preview instance: a Git Bash pane stuck after printf '\e[?1049h\e[H' stays on the alternate screen after one press with the notice shown, and returns to the normal screen with its scrollback on the second. Holding the chord resets once and keeps the screen. A cmd pane leaves on one press. The #347 script under PowerShell keeps its screen while it runs, the notice disappears when it exits, and the prompt doesn't overprint. A Start-Sleep 10 run from a stuck PowerShell prompt keeps the screen while it runs, and one press leaves after it finishes.

… panes that report no shell state (amirlehmam#357)

Since amirlehmam#347 the manual reset left the alternate screen only when the shell
had reported idle or interrupted, and only wmux's PowerShell integration
reports that. In cmd, Git Bash, WSL, SSH, nested shells and PowerShell
without the integration, a pane stuck on a dead program's alternate screen
could no longer be recovered (amirlehmam#175), and nothing said why.

The decision now reads the pane's own output first (utils/alt-screen-owner):
an OSC 133;A drawn on the alternate screen means a shell is prompting there,
so the reset leaves it even under a stale `running` from an outer shell; a
DECSET 47/1047/1049 since then (a TUI started from that prompt) means a
program may be drawing, so it keeps, even when PowerShell without PSReadLine
reads `idle`. The prompt mark comes from the prompt log's existing OSC 133
parse. The amirlehmam#347 shell-state rule decides only when the stream said neither.

A reset that keeps the alternate screen shows a non-modal notice, and a
second press within 5 s forces it. The command palette gets "Reset terminal
state (leave alternate screen)". Strings in en and fr.

Fixes amirlehmam#357
@jpstratman
jpstratman marked this pull request as ready for review October 24, 2026 21:04
jpstratman and others added 8 commits October 24, 2026 16:24
A reset that keeps the alternate screen arms a second press to force it,
and Windows starts repeating a held key well inside that 5 s window. Holding
Ctrl+Shift+R therefore forced a live program off its screen, which is amirlehmam#347
again. Repeat keydowns of the reset binding are still claimed, so the chord
reaches nothing else, but no longer run the reset.

No minimum gap between presses: a deliberate quick double press is the
"leave it anyway" the notice invites, and the repeat flag already covers
the held chord.

Refs amirlehmam#357
… changes

A reset that kept the alternate screen armed a second press for 5 s, and
nothing disarmed it when that screen went away. Resetting in vim, quitting
it and reopening it within the window let the next press force the live
vim off its screen, and the notice stayed up after the program had exited.

Returning to the normal buffer and a new DECSET 47/1047/1049 now both clear
the arm and hide the notice: each means the screen the reset was about is
no longer the one on display.

Refs amirlehmam#357
…t runs

A prompt mark on the alternate screen meant "the shell owns it" until the
next DECSET, so it outranked a fresh `running` report. On a local
PowerShell pane stuck on a dead program's screen, running an inline program
from that prompt (Claude Code's inline mode, a dev server) and then
resetting left the screen under it, where origin/master kept it.

An OSC 133;C seen on the alternate buffer now records that a command is
running from that prompt, and the reset keeps the screen until the next
133;A or 133;D. C and D come from the prompt log's existing OSC 133 parse,
like A. The PowerShell and bash integrations and Starship emit C; cmd
does not, so a cmd pane behaves as before. In ssh, wsl and nested shells
the outer shell's C lands on the normal buffer and is ignored, so its
stale `running` still cannot block a leave once the inner prompt is drawn.

Refs amirlehmam#357
…entry

A terminal rebuilt from a remount snapshot replays `?1049h`, which the
reset's CSI hook read as a program entering the screen, so a screen the
shell owned asked for an extra press. DECSETs are now ignored while the
snapshot is being written: a per-surface flag is set before the write and
cleared in its callback, and also when the tracker is disposed, since a
terminal disposed before the snapshot parsed never runs the callback. The
record itself is module state and survives the remount.

Refs amirlehmam#357
…eal xterm

The `entersAlternateScreen([[1049, 1]])` case asserted a parameter shape
xterm never produces: for `?1049:1h` it hands the hook `[1049, [1]]` and
switches buffers. Replace it with real-xterm writes of ?47h, ?1047h,
?1049h, ?1049;1006h, ?1006;1049h and ?1049:1h, the private modes that
must not count, and RIS (ESC c) clearing the record, the force window and
the notice.

Refs amirlehmam#357
ResetNotice mounted its role="status" node already holding its text, which
screen readers often do not announce. The region now stays mounted and only
its text changes; empty, it draws nothing, without display:none, which
would take it out of the accessibility tree.

The notice also sat at z-index 25, under the prompt outline (27), which is
up to half the pane wide and could cover part of it. It is now 28, below
the find bar, and on the z-index ladder in prompt-marks.css. It is never
hit-testable, so the outline stays usable underneath.

Refs amirlehmam#357
# Conflicts:
#	src/renderer/hooks/useTerminal.ts
@amirlehmam
amirlehmam merged commit a39f57a into 790E amirlehmam:master Oct 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Reset terminal state can't leave the alternate screen in panes that don't report shell state

2 participants

0