tui: split remaining composer draft and footer state (#22656)

## Why

[#22581](https://github.com/openai/codex/pull/22581) started separating
the chat composer’s responsibilities, but `ChatComposer` still owned the
remaining editable draft state alongside footer/status presentation
state. This follow-up makes those ownership lines explicit so future
composer changes have a smaller blast radius and `BottomPane` does not
need to keep exposing scattered draft getters.

This is just a refactor. No functional or behavioral changes are
intended.

## What changed

- Move the remaining editable composer state into
`bottom_pane/chat_composer/draft_state.rs`.
- Move footer and status-row presentation state into
`bottom_pane/chat_composer/footer_state.rs`.
- Add an internal `ComposerDraftSnapshot` for restore flows, replacing
several ad hoc `BottomPane` pass-through reads.
- Rewire the related history-search and thread-input restore paths to
use the extracted state.

## Verification

- `RUST_MIN_STACK=8388608 cargo test -p codex-tui`
- `cargo insta pending-snapshots`
This commit is contained in:
Eric Traut authored and GitHub committed 2026-05-15 09:12:52 -07:00
1 parent 68ccfdc905
commit 7fa0007ea8
6 files changed
+1006 -760

No files matched your search

+13 -11
View File
@@ -152,12 +152,13 @@ impl ChatWidget {
return None;
}
let composer = self.bottom_pane.composer_draft_snapshot();
let existing_message = UserMessage {
text: self.bottom_pane.composer_text(),
text_elements: self.bottom_pane.composer_text_elements(),
local_images: self.bottom_pane.composer_local_images(),
remote_image_urls: self.bottom_pane.remote_image_urls(),
mention_bindings: self.bottom_pane.composer_mention_bindings(),
text: composer.text,
text_elements: composer.text_elements,
local_images: composer.local_images,
remote_image_urls: composer.remote_image_urls,
mention_bindings: composer.mention_bindings,
};
let rejected_messages = self
@@ -236,13 +237,14 @@ impl ChatWidget {
}
pub(crate) fn capture_thread_input_state(&self) -> Option<ThreadInputState> {
let draft = self.bottom_pane.composer_draft_snapshot();
let composer = ThreadComposerState {
text: self.bottom_pane.composer_text(),
text_elements: self.bottom_pane.composer_text_elements(),
local_images: self.bottom_pane.composer_local_images(),
remote_image_urls: self.bottom_pane.remote_image_urls(),
mention_bindings: self.bottom_pane.composer_mention_bindings(),
pending_pastes: self.bottom_pane.composer_pending_pastes(),
text: draft.text,
text_elements: draft.text_elements,
local_images: draft.local_images,
remote_image_urls: draft.remote_image_urls,
mention_bindings: draft.mention_bindings,
pending_pastes: draft.pending_pastes,
};
Some(ThreadInputState {
composer: composer.has_content().then_some(composer),