Skip to content

fix: stop teardown drains at the first non-mouse event - #57

Merged
BinaryMuse merged 1 commit into
mainfrom
mkt/drain-keeps-keystrokes
Aug 10, 2026
Merged

fix: stop teardown drains at the first non-mouse event#57
BinaryMuse merged 1 commit into
mainfrom
mkt/drain-keeps-keystrokes

Conversation

@BinaryMuse

@BinaryMuse BinaryMuse commented Aug 10, 2026

Copy link
Copy Markdown
Member

Dogfooding atuin's eye-declare search surfaced this: all three teardown drains (async driver shutdown, init-exit shutdown, and the RawModeGuard drop fallback) read and discard every event type for up to 50ms, so keystrokes typed immediately after an app exits can be silently eaten.

The spray of stale mouse reports is contiguous, so the drain now stops at the first non-mouse event, leaving everything not yet read in the tty for the shell.

Correction from review: the cap is one crossterm buffer chunk, not one event. Crossterm reads the tty up to 1 KiB per syscall and queues every event it parses, so anything sharing a chunk with the first non-mouse event is consumed with it and cannot be handed back — ttys have no peek, and TIOCSTI is disabled on modern kernels. This PR is still a strict improvement (it stops all subsequent chunk reads, and the drain only continues through a dense spray — a 5ms gap ends it, so only keys typed into the spray are at risk), but a true byte-granular drain requires eye owning the input path instead of reading through crossterm. That design — which also addresses the CPR startup-latency and reader-thread-lock issues, with a PTY regression harness — is tracked as ATU-580.

All three mouse-report drains (driver shutdown, init-exit shutdown, and
the RawModeGuard drop fallback) read and discarded every event type for
up to 50ms, so keystrokes typed immediately after an app exited could
be eaten. The spray is contiguous: stop at the first non-mouse event,
leaving everything not yet read in the tty for the shell.

This shrinks the loss window but cannot cap it at one event: crossterm
reads the tty in 1KiB chunks and queues every event it parses, so
whatever shared a chunk with that first non-mouse event is consumed
along with it — ttys have no peek and TIOCSTI is disabled on modern
kernels, so consumed input cannot be handed back. A true byte-granular
drain requires owning the input path instead of reading through
crossterm; tracked as ATU-580.
@BinaryMuse
BinaryMuse force-pushed the mkt/drain-keeps-keystrokes branch from 2b5c986 to be0c465 Compare August 10, 2026 16:30
@BinaryMuse
BinaryMuse marked this pull request as ready for review August 10, 2026 16:31
@greptile-apps

greptile-apps Bot commented Aug 10, 2026

Copy link
Copy Markdown

Greptile Summary

The PR improves terminal teardown by stopping mouse-report drains at the first non-mouse event, reducing the amount of user input consumed after application exit.

  • Applies the behavior consistently to async shutdown, init-exit shutdown, and the RawModeGuard fallback.
  • Documents crossterm’s chunk-buffering limitation.

Confidence Score: 5/5

The PR appears safe to merge with its remaining crossterm buffering limitation clearly documented.

The changed drains consistently stop after observing a non-mouse event, and no unacknowledged concrete failure was established.

Important Files Changed

Filename Overview
crates/eye_declare/src/driver_tokio.rs Updates async and pre-loop synchronous drains to continue only for mouse events.
crates/eye_declare/src/runtime.rs Applies matching stop-on-non-mouse behavior to the drop-time fallback drain.

Reviews (1): Last reviewed commit: "fix: stop teardown drains at the first n..." | Re-trigger Greptile

@BinaryMuse
BinaryMuse merged commit d3a246b into main Aug 10, 2026
6 checks passed
@BinaryMuse
BinaryMuse deleted the mkt/drain-keeps-keystrokes branch August 10, 2026 16:34
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.

1 participant