Skip to content

fix(tui): replace alternate scroll heuristic with MouseCapture#89

Merged
yishuiliunian merged 2 commits intomainfrom
fix/mouse-capture-scroll
Apr 6, 2026
Merged

fix(tui): replace alternate scroll heuristic with MouseCapture#89
yishuiliunian merged 2 commits intomainfrom
fix/mouse-capture-scroll

Conversation

@yishuiliunian
Copy link
Copy Markdown
Contributor

Summary

  • Replace unreliable batch-counting scroll detection (alternate scroll mode \x1b[?1007h + arrow_count >= 2) with crossterm's EnableMouseCapture for deterministic MouseEvent::ScrollUp/Down
  • Up/Down arrow keys now always route to history navigation, mouse scroll always routes to content scroll — no heuristics
  • Text selection via Shift+click/drag (standard TUI convention)

Changes

  • terminal.rs: Remove custom EnableAlternateScroll/DisableAlternateScroll, use EnableMouseCapture/DisableMouseCapture
  • event.rs: Add AppEvent::ScrollUp/ScrollDown variants, handle CrosstermEvent::Mouse, drain-buffer optimization
  • tui_loop.rs: Remove batch detection logic (arrow_count/is_scroll_burst), handle ScrollUp/ScrollDown directly
  • scroll_burst_test.rsscroll_test.rs: Rewrite without batch simulation
  • e2e_scroll_test.rs: Rewrite with AppEvent::ScrollUp/Down injection

Test plan

  • bazel test //crates/loopal-tui:loopal-tui_test — 50/50 pass
  • bazel build //... --config=clippy — zero warnings
  • CI passes

…terministic scroll detection (#88)

The previous approach used xterm alternate scroll mode (\x1b[?1007h) to
convert mouse wheel events into Up/Down arrow key sequences, then relied
on batch-counting heuristics (≥2 arrows per batch = scroll) to distinguish
scroll from keyboard input. This was fundamentally unreliable across
different terminal emulators and system load conditions.

Switch to crossterm's EnableMouseCapture which provides actual
MouseEvent::ScrollUp/ScrollDown events, making the distinction
deterministic. Up/Down arrow keys now always route to history navigation.
@yishuiliunian yishuiliunian merged commit dd839b1 into main Apr 6, 2026
3 checks passed
@yishuiliunian yishuiliunian deleted the fix/mouse-capture-scroll branch April 6, 2026 06:02
yishuiliunian added a commit that referenced this pull request Apr 6, 2026
…ror misclassification (#89)

When thinking mode is active, Anthropic's API rejects assistant-message
prefill ("conversation must end with a user message"). The auto-continuation
flow in turn_exec records an assistant message then loops back, violating
this constraint. The error was also misclassified as ContextOverflow because
`invalid_request_error` matched too broadly.

- Narrow ContextOverflow detection to exclude generic `invalid_request_error`
- Add `ThinkingCapability::forbids_prefill()` (true only for Anthropic)
- Add `needs_continuation_injection()` gating on capability + thinking state
- Inject synthetic user message at all 3 continue points when needed
- Fix stop-hook feedback path: create proper User message instead of
  appending to (wrong-role) last message via `append_warnings_to_last_user`
- Preserve assistant-prefill for non-Anthropic providers (OpenAI, Google)
yishuiliunian added a commit that referenced this pull request Apr 6, 2026
…ror misclassification (#89) (#90)

When thinking mode is active, Anthropic's API rejects assistant-message
prefill ("conversation must end with a user message"). The auto-continuation
flow in turn_exec records an assistant message then loops back, violating
this constraint. The error was also misclassified as ContextOverflow because
`invalid_request_error` matched too broadly.

- Narrow ContextOverflow detection to exclude generic `invalid_request_error`
- Add `ThinkingCapability::forbids_prefill()` (true only for Anthropic)
- Add `needs_continuation_injection()` gating on capability + thinking state
- Inject synthetic user message at all 3 continue points when needed
- Fix stop-hook feedback path: create proper User message instead of
  appending to (wrong-role) last message via `append_warnings_to_last_user`
- Preserve assistant-prefill for non-Anthropic providers (OpenAI, Google)
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