Skip to content

fix(tui): user-input modal clips options and hides typed input — fixed 22-row cap, centered overlay, no scroll, no back-navigation, undocumented #6045

Description

@7jrxt42BxFZo4iAnN4CX

Problem

When the model asks a question via request_user_input, the dialog is unreliable on real terminals: content gets cut off, the underlying conversation becomes invisible, and mistakes are irreversible.

Concrete failures (reproduced on a 141×38 terminal):

  1. Options are clipped. The modal is capped at 22 rows of height. A question with several options (each with a description) plus the header and hint rows overflows, and everything past the cap is silently cut off. I often cannot see which option is currently selected — the selection highlight is below the visible area.
  2. Typed input is invisible. The "Custom response" input line is appended after all options in the render output. With a long question and several options it falls below the 22-row cap, so while typing I cannot see what I am writing. There is no cursor tracking and no scroll-into-view.
  3. The dialog opens centered and disables transcript scrolling. The popup is vertically centered over the conversation (Layout [Min(0), Length(height), Min(0)]), and while any modal is open the event loop routes every key to the modal (view_stack.handle_key() with continue). PageUp/PageDown and the other transcript-scroll bindings never run. Questions are usually based on the on-screen conversation, so covering it and forbidding scroll forces me to answer from memory.
  4. No way to go back or correct. Left/Right arrows are unhandled (_ => ViewAction::None), and there is no previous-question stack: advance_question moves forward only, and Esc in selection mode cancels the whole dialog. An accidental Enter on the wrong option is irreversible.
  5. Resizing the terminal does not help. The height is desired.clamp(6, 22).min((r.height * 60 / 100).clamp(6, 22)).min(r.height) — the 22-row cap dominates for any terminal ≥ 37 rows (38 → 22, 50 → 22, 100 → 22). Smaller terminals get even less. The width is also capped at 110 columns, so on wide terminals long questions wrap into more lines and exhaust the height budget faster.
  6. The modal is undocumented. No hotkey, no "Custom response" behavior, no layout expectations appear anywhere in docs/GUIDE.md, docs/KEYS.md, or the TUI docs. There is no collapse/minimize action either — Esc is the only escape, and it cancels the request.

Root cause (code)

  • crates/tui/src/tui/user_input.rs:540-556compact_popup_rect: hard height cap clamp(6, 22) + 60% of terminal, width cap min(110), [Min(0), Length(height), Min(0)] vertical centering.
  • crates/tui/src/tui/user_input.rs:205-244handle_selecting_key: only Up/Down/j/k, digits, Space, Enter, Esc; Left/Right and any "back" action are absent.
  • crates/tui/src/tui/user_input.rs:430-450 (render) — "Custom response" line appended last; no scroll-into-view.
  • crates/tui/src/tui/ui/event_loop.rs:4791-4809 — non-empty view_stackview_stack.handle_key(key) + continue; transcript scroll handlers at ~5640+ unreachable while a modal is open.

Expected behavior

Matches how opencode handles model questions:

  • Bottom-anchored sheet instead of a centered overlay, so the conversation stays visible above it.
  • Scrolling works: either the transcript remains scrollable while the dialog is open, or the dialog itself scrolls internally (selected option and typed text always visible, no silent clipping).
  • Back-navigation to the previous question (and a documented way to correct an accidentally submitted answer, e.g. an explicit "go back" binding rather than Esc-cancels-everything).
  • Adaptive height: no fixed cap that clips content; the dialog grows or scrolls.

Related

#6003 — the same question/approval flow hardcodes a 300-second wait (USER_INPUT_TIMEOUT, crates/tui/src/core/engine/approval.rs:15; APPROVAL_DECISION_TIMEOUT, crates/tui/src/runtime_threads.rs:547) with no config or kill switch. Both issues are the same UX surface: I'd gently suggest treating them together — a dialog that clips the answer and then silently cancels it after five minutes breaks the workflow twice. Making the timeout configurable/disableable (and the dialog usable at all) is important for anyone who runs local, unattended, or review-heavy sessions.

Acceptance criteria

  • On a 141×38 (and 80×24) terminal, all options and the selected highlight are visible without terminal-specific hacks.
  • Typed "Custom response" text is always visible while typing (scroll-into-view or guaranteed layout position).
  • The conversation transcript is visible and scrollable while the dialog is open (or the dialog is internally scrollable with the transcript preserved).
  • It is possible to go back to a previous question and change an answer.
  • Resizing the terminal neither clips content nor is required to reveal it.
  • The modal and its keys are documented (GUIDE/KEYS), including the back-navigation binding.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions