Files
codex/codex-rs/tui/src/chatwidget/exec_state.rs
T
Eric TrautandGitHub 92930a8d40 Refactor chatwidget state into modules (#22269)
## Why

`chatwidget.rs` is still carrying too many unrelated responsibilities in
one file. After #21866 consolidated some of the state it tracks, this
starts the next phase by moving coherent state/helper clusters out of
the main module without changing behavior.

This PR is intentionally mechanical: it only moves existing functions,
structs, and helpers into focused modules so the boundaries are easier
to review before the less mechanical refactors that should follow.

## What Changed

- Moved user-message, composer, queue, pending steer, and merge/remap
helpers into `codex-rs/tui/src/chatwidget/user_messages.rs`.
- Added `codex-rs/tui/src/chatwidget/exec_state.rs` for unified exec
bookkeeping helpers.
- Added `codex-rs/tui/src/chatwidget/rate_limits.rs` for rate-limit
warning, prompt, and error classification state.
- Moved plugin list fetch and install auth-flow state into
`codex-rs/tui/src/chatwidget/plugins.rs`.
- Made a couple of test-only `VecDeque` imports explicit now that those
tests no longer inherit the parent module import.

## Verification

- `cargo test -p codex-tui` was run

## Follow-On Refactor Phases

This PR is phase 1: mechanical helper and state moves. Planned follow-up
PRs:

- Phase 2: extract input and submission flow, including queued user
messages, shell prompt submission, pending steer restoration, and thread
input snapshot/restore behavior.
- Phase 3: extract protocol, replay, streaming, and tool lifecycle
handling, while preserving active-cell grouping, transcript
invalidation, interrupt deferral, and final-message separator behavior.
- Phase 4: extract settings, popups, and status surfaces, including
model/reasoning/collaboration/personality popups, permission prompts,
rate-limit UI, and connectors helpers.
- Phase 5: clean up the remaining constructor and orchestration code
once the larger behavior domains have moved out, leaving `chatwidget.rs`
as the composition layer.
2026-05-12 17:33:33 -07:00

84 lines
2.3 KiB
Rust

//! Unified exec bookkeeping state and helpers for `ChatWidget`.
use codex_app_server_protocol::CommandExecutionSource as ExecCommandSource;
use codex_protocol::parse_command::ParsedCommand;
use crate::exec_command::split_command_string;
pub(super) struct RunningCommand {
pub(super) command: Vec<String>,
pub(super) parsed_cmd: Vec<ParsedCommand>,
pub(super) source: ExecCommandSource,
}
pub(super) struct UnifiedExecProcessSummary {
pub(super) key: String,
pub(super) call_id: String,
pub(super) command_display: String,
pub(super) recent_chunks: Vec<String>,
}
pub(super) struct UnifiedExecWaitState {
command_display: String,
}
impl UnifiedExecWaitState {
pub(super) fn new(command_display: String) -> Self {
Self { command_display }
}
pub(super) fn is_duplicate(&self, command_display: &str) -> bool {
self.command_display == command_display
}
}
#[derive(Clone, Debug)]
pub(super) struct UnifiedExecWaitStreak {
pub(super) process_id: String,
pub(super) command_display: Option<String>,
}
impl UnifiedExecWaitStreak {
pub(super) fn new(process_id: String, command_display: Option<String>) -> Self {
Self {
process_id,
command_display: command_display.filter(|display| !display.is_empty()),
}
}
pub(super) fn update_command_display(&mut self, command_display: Option<String>) {
if self.command_display.is_some() {
return;
}
self.command_display = command_display.filter(|display| !display.is_empty());
}
}
pub(super) fn is_unified_exec_source(source: ExecCommandSource) -> bool {
matches!(
source,
ExecCommandSource::UnifiedExecStartup | ExecCommandSource::UnifiedExecInteraction
)
}
pub(super) fn is_standard_tool_call(parsed_cmd: &[ParsedCommand]) -> bool {
!parsed_cmd.is_empty()
&& parsed_cmd
.iter()
.all(|parsed| !matches!(parsed, ParsedCommand::Unknown { .. }))
}
pub(super) fn command_execution_command_and_parsed(
command: &str,
command_actions: &[codex_app_server_protocol::CommandAction],
) -> (Vec<String>, Vec<ParsedCommand>) {
(
split_command_string(command),
command_actions
.iter()
.cloned()
.map(codex_app_server_protocol::CommandAction::into_core)
.collect(),
)
}