The BottomPane is the interactive footer component of the TUI, responsible for text input, attachment handling, and transient UI overlays. It owns the ChatComposer (editable prompt input with text element tracking, mention resolution, and paste detection) and a stack of BottomPaneView implementations (popups/modals) that temporarily replace the composer for focused interactions like selection lists and approval prompts.
For conversation display and history management, see ChatWidget and Conversation Display. For status line configuration and rendering, see Status Line and Footer Rendering. For approval overlay specifics, see Interactive Overlays and Approvals.
The BottomPane acts as a container and input router that coordinates between the persistent composer and transient view overlays:
Sources: codex-rs/tui/src/bottom_pane/mod.rs145-174 codex-rs/tui/src/bottom_pane/chat_composer.rs287-339
The BottomPane struct maintains the composer, view stack, and runtime state:
| Field | Type | Purpose |
|---|---|---|
composer | ChatComposer | Persistent text input state |
view_stack | Vec<Box<dyn BottomPaneView>> | Stack of transient overlays |
status | Option<StatusIndicatorWidget> | Task progress indicator |
unified_exec_footer | UnifiedExecFooter | Exec session summary |
queued_user_messages | QueuedUserMessages | Queued input while task runs |
is_task_running | bool | Whether agent turn is active |
has_input_focus | bool | Whether pane has keyboard focus |
esc_backtrack_hint | bool | Whether to show Esc hint |
Sources: codex-rs/tui/src/bottom_pane/mod.rs145-174
Input routing is layered: active views consume keys first, then the composer, then unhandled keys propagate to ChatWidget for process-level decisions (interrupt, quit):
Sources: codex-rs/tui/src/bottom_pane/mod.rs327-390 codex-rs/chatwidget.rs1234-1280
on_ctrl_c gives views and the composer a chance to consume Ctrl+C before propagating to the parent for interrupt/quit decisions:
Sources: codex-rs/tui/src/bottom_pane/mod.rs400-421
The ChatComposer maintains text editing state, attachment tracking, and popup coordination:
| Field | Type | Purpose |
|---|---|---|
textarea | TextArea | Editable text buffer |
textarea_state | RefCell<TextAreaState> | Cursor and scroll state |
active_popup | ActivePopup | Command/file/skill popup state |
history | ChatComposerHistory | Cross-session + local history |
attached_images | Vec<AttachedImage> | Local image attachments |
remote_image_urls | Vec<String> | Remote image URLs |
mention_bindings | HashMap<u64, ComposerMentionBinding> | Skill/app mention resolution |
paste_burst | PasteBurst | Non-bracketed paste detector |
steer_enabled | bool | Whether Enter submits / Tab queues |
Sources: codex-rs/tui/src/bottom_pane/chat_composer.rs287-339
The composer handles key events through a state machine that coordinates popup visibility, text editing, and submission paths:
Sources: codex-rs/tui/src/bottom_pane/chat_composer.rs1-112 codex-rs/tui/src/bottom_pane/chat_composer.rs765-950
The ActivePopup enum ensures at most one popup is visible at a time:
Popups are synchronized after each key event via sync_popups, which shows/hides/updates popups based on cursor position and buffer content.
Sources: codex-rs/tui/src/bottom_pane/chat_composer.rs354-359 codex-rs/tui/src/bottom_pane/chat_composer.rs1510-1677
Text elements represent non-plain-text ranges (image placeholders, mentions) within the text buffer. They are preserved across edits and submission:
| Field | Type | Description |
|---|---|---|
byte_range | ByteRange | Start/end byte offsets |
placeholder_text | Option<String> | Display text (e.g. "[Image #1]") |
When text is edited, element ranges are rebased to track insertions/deletions. On submission, elements are pruned to remove deleted placeholders and trimmed to match the final text.
Sources: codex-rs/protocol/src/user_input.rs47-100 codex-rs/tui/src/bottom_pane/chat_composer.rs2465-2608
Sources: codex-rs/tui/src/bottom_pane/chat_composer.rs1870-2013 codex-rs/tui/src/bottom_pane/chat_composer.rs2465-2608
Skill and app mentions (e.g. $my-skill, $slack) are resolved to canonical paths during submission:
$ to trigger skill popupTextElement rangemention_bindings maps element ID → ComposerMentionBinding { mention, path }take_mention_bindings produces MentionBinding list for protocol layerSources: codex-rs/tui/src/bottom_pane/chat_composer.rs341-351 codex-rs/tui/src/bottom_pane/chat_composer.rs2729-2754
On terminals without bracketed paste (notably Windows), pastes arrive as rapid KeyCode::Char events. The PasteBurst state machine buffers these to avoid transient UI effects:
ASCII chars are held briefly to avoid flicker if a burst is detected. Non-ASCII chars (IME input) are not held, but can still retro-activate burst detection.
Sources: codex-rs/tui/src/bottom_pane/paste_burst.rs1-20 codex-rs/tui/src/bottom_pane/chat_composer.rs74-105
The composer integrates paste burst detection at key points:
| Method | Role |
|---|---|
handle_input_basic | Flushes due bursts, then intercepts plain chars to buffer or insert |
handle_non_ascii_char | Handles IME path without holding first char |
flush_paste_burst_if_due | Called from UI ticks to turn pending bursts into paste or typed chars |
handle_paste | Expands pending paste placeholders, inserts text, tracks large paste |
Sources: codex-rs/tui/src/bottom_pane/chat_composer.rs1773-1869 codex-rs/tui/src/bottom_pane/chat_composer.rs1870-2013
When steer_enabled is true, Enter submits immediately and Tab requests queuing behavior:
When steer_enabled is false, Enter always submits and Tab inserts a tab character.
Sources: codex-rs/tui/src/bottom_pane/chat_composer.rs995-1054 codex-rs/tui/src/chatwidget.rs1234-1280
Sources: codex-rs/tui/src/bottom_pane/chat_composer.rs2465-2608 codex-rs/tui/src/chatwidget.rs1281-1378
The footer is composed of multiple rendering layers:
Sources: codex-rs/tui/src/bottom_pane/chat_composer.rs583-708 codex-rs/tui/src/bottom_pane/mod.rs570-729
Footer hints adapt based on context:
| Condition | Displayed Hints |
|---|---|
| Task running + status visible | Esc to interrupt |
| Quit shortcut armed | Ctrl+C again to quit |
| Backtrack available | Esc to revert |
| Shift+Enter available | Shift+Enter for newline |
| Steer enabled | Enter to submit, Tab to queue |
Sources: codex-rs/tui/src/bottom_pane/footer.rs1-300 codex-rs/tui/src/bottom_pane/chat_composer.rs487-581
All transient overlays implement BottomPaneView:
Sources: codex-rs/tui/src/bottom_pane/bottom_pane_view.rs1-50
Sources: codex-rs/tui/src/bottom_pane/mod.rs318-390
| View | Purpose | File |
|---|---|---|
CommandPopup | Slash command picker | codex-rs/tui/src/bottom_pane/command_popup.rs |
FileSearchPopup | File mention picker | codex-rs/tui/src/bottom_pane/file_search_popup.rs |
SkillPopup | Skill/app mention picker | codex-rs/tui/src/bottom_pane/skill_popup.rs |
ApprovalOverlay | Approval prompts | codex-rs/tui/src/bottom_pane/approval_overlay.rs |
SelectionView | Generic list picker | codex-rs/tui/src/bottom_pane/list_selection_view.rs |
CustomPromptView | Prompt browser | codex-rs/tui/src/bottom_pane/custom_prompt_view.rs |
Refresh this wiki