Skip to content

fix(tui): queued-message edit shortcut unreachable in some terminals#12240

Merged
etraut-openai merged 1 commit intoopenai:mainfrom
fcoury:fix/4490-edit-queued-mac-term
Feb 21, 2026
Merged

fix(tui): queued-message edit shortcut unreachable in some terminals#12240
etraut-openai merged 1 commit intoopenai:mainfrom
fcoury:fix/4490-edit-queued-mac-term

Conversation

@fcoury
Copy link
Copy Markdown
Contributor

@fcoury fcoury commented Feb 19, 2026

Problem

The TUI's "edit queued message" shortcut (Alt+Up) is either silently swallowed or recognized as another key combination by Apple Terminal, Warp, and VSCode's integrated terminal on macOS. Users in those environments see the hint but pressing the keys does nothing.

Mental model

When a model turn is in progress the user can still type follow-up messages. These are queued and displayed below the composer with a hint line showing how to pop the most recent one back into the editor. The hint text and the actual key handler must agree on which shortcut is used, and that shortcut must actually reach the TUI—i.e. it must not be intercepted by the host terminal.

Three terminals are known to intercept Alt+Up: Apple Terminal (remaps it to cursor movement), Warp (consumes it for its own command palette), and VSCode (maps it to "move line up"). For these we use Shift+Left instead.

image

macOS Native Terminal Warp VSCode Terminal
SCR-20260219-kigi SCR-20260219-krrf SCR-20260219-ksbz

Non-goals

  • Making the binding user-configurable at runtime (deferred to a broader keybinding-config effort).
  • Remapping any other shortcuts that might be terminal-specific.

Tradeoffs

  • Exhaustive match instead of a wildcard default. The queued_message_edit_binding_for_terminal function explicitly lists every TerminalName variant. This is intentional: adding a new terminal to the enum will produce a compile error, forcing the author to decide which binding that terminal should use.

  • Binding lives on ChatWidget, hint lives on QueuedUserMessages. The key event handler that actually acts on the press is in ChatWidget, but the rendered hint text is inside QueuedUserMessages. These are kept in sync by ChatWidget calling bottom_pane.set_queued_message_edit_binding(self.queued_message_edit_binding) during construction. A mismatch would show the wrong hint but would not lose data.

Architecture

  graph TD
      TI["terminal_info().name"] --> FN["queued_message_edit_binding_for_terminal(name)"]
      FN --> KB["KeyBinding"]
      KB --> CW["ChatWidget.queued_message_edit_binding<br/><i>key event matching</i>"]
      KB --> BP["BottomPane.set_queued_message_edit_binding()"]
      BP --> QUM["QueuedUserMessages.edit_binding<br/><i>rendered in hint line</i>"]

      subgraph "Special terminals (Shift+Left)"
          AT["Apple Terminal"]
          WT["Warp"]
          VS["VSCode"]
      end

      subgraph "Default (Alt+Up)"
          GH["Ghostty"]
          IT["iTerm2"]
          OT["Others…"]
      end

      AT --> FN
      WT --> FN
      VS --> FN
      GH --> FN
      IT --> FN
      OT --> FN
Loading

No new crates or public API surface. The only cross-crate dependency added is codex_core::terminal::{TerminalName, terminal_info}, which already existed for telemetry.

Observability

No new logging. Terminal detection already emits a tracing::debug! log line at startup with the detected terminal name, which is sufficient to diagnose binding mismatches.

Tests

  • Existing alt_up_edits_most_recent_queued_message test is preserved and explicitly sets the Alt+Up binding to isolate from the host terminal.
  • New parameterized async tests verify Shift+Left works for Apple Terminal, Warp, and VSCode.
  • A sync unit test asserts the mapping table covers the three special terminals (Shift+Left) and that iTerm2 still gets Alt+Up.

Fixes #4490

Copilot AI review requested due to automatic review settings February 19, 2026 14:59
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes issue #4490 where the "edit queued message" keyboard shortcut (Alt+Up) is intercepted by certain terminals (Apple Terminal, Warp, VSCode) on macOS, preventing users from editing queued messages during a model turn. The solution implements terminal-specific key binding selection, using Shift+Left for problematic terminals while keeping Alt+Up for others.

Changes:

  • Introduced queued_message_edit_binding_for_terminal() function that maps terminal types to appropriate key bindings using exhaustive matching
  • Modified ChatWidget constructors to detect terminal type and set the appropriate binding at initialization
  • Updated key event handling to use dynamic binding instead of hard-coded Alt+Up
  • Added set_queued_message_edit_binding() method to BottomPane and QueuedUserMessages to synchronize displayed hints with actual bindings
  • Added comprehensive test coverage for terminal-specific bindings

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
codex-rs/tui/src/chatwidget.rs Added terminal detection function, updated all three constructors to initialize binding, replaced hard-coded Alt+Up handler with dynamic binding check
codex-rs/tui/src/bottom_pane/mod.rs Added set_queued_message_edit_binding() method to propagate binding to queued messages widget
codex-rs/tui/src/bottom_pane/queued_user_messages.rs Made edit binding configurable, updated widget to use dynamic binding in hint display
codex-rs/tui/src/chatwidget/tests.rs Updated existing test to explicitly set Alt+Up binding, added new tests for Shift+Left behavior in problematic terminals, added unit test verifying binding mappings

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@fcoury
Copy link
Copy Markdown
Contributor Author

fcoury commented Feb 19, 2026

@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown
Contributor

Codex Review: Didn't find any major issues. Bravo.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Copy Markdown
Contributor

@joshka-oai joshka-oai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - on VSCode I see Opt+Up gets interpreted as Ctrl+Up btw. I'm unsure if this is default or something configured. So we could keep things there and just detect that instead. To test, gh clone crossterm-rs/crossterm then run cargo run --example event-read

@fcoury
Copy link
Copy Markdown
Contributor Author

fcoury commented Feb 19, 2026

LGTM - on VSCode I see Opt+Up gets interpreted as Ctrl+Up btw. I'm unsure if this is default or something configured. So we could keep things there and just detect that instead. To test, gh clone crossterm-rs/crossterm then run cargo run --example event-read

I rolled my own tiny crate using crossterm for it. The only small difference is that it also allows toggling kitty support on and off: https://github.com/fcoury/ktt

@charley-oai
Copy link
Copy Markdown
Contributor

Thoughts about this PR as an alternative solution? I only tested on mac terminal and mac vscode terminal, but for me option+up gets encoded as ctrl+up so just making those keybindings accept either option+ or ctrl+ seems to work well (but maybe this wouldn't work for other terminals? Not sure if that alt/option -> ctrl remapping is just on mac)
#12248

@charley-oai
Copy link
Copy Markdown
Contributor

charley-oai commented Feb 20, 2026

@joshka-oai pointed out we should probably be more explicit about keybindings on different terminals, as this PR accomplishes

Although personally I would prefer the mac / mac-vscode keybindings to still be option+backspace / option+delete / option+up (which are seemingly mapped to ctrl+backspace / ctrl+delete / ctrl+up for some reason?) if reasonable

@fcoury
Copy link
Copy Markdown
Contributor Author

fcoury commented Feb 20, 2026

Although personally I would prefer the mac / mac-vscode keybindings to still be option+backspace / option+delete / option+up (which are seemingly mapped to ctrl+backspace / ctrl+delete / ctrl+up for some reason?) if reasonable

@charley-oai I totally agree with your opinion here.

I evaluated Ctrl+Up as the first option. The only reason I gave up was that on the bundled macOS Terminal.app, it still is recognized as only Up by crossterm:

image

Vs. Ghostty for instance and others where it is properly recognized.

image

That's the only reason I went with Shift+Left -- it was recognized on the three places where we needed this contingency.

@etraut-openai etraut-openai merged commit a5d0757 into openai:main Feb 21, 2026
32 of 39 checks passed
@github-actions github-actions bot locked and limited conversation to collaborators Feb 21, 2026
@fcoury fcoury deleted the fix/4490-edit-queued-mac-term branch February 21, 2026 01:01
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Edit Queued Message with Option + Up (⌥↑ edit) Not Working on MacOS terminal or iTerm.

5 participants