diff --git a/codex-rs/core/config.schema.json b/codex-rs/core/config.schema.json index 9d7257a39..8688e45d5 100644 --- a/codex-rs/core/config.schema.json +++ b/codex-rs/core/config.schema.json @@ -1185,7 +1185,7 @@ }, "status_line": { "default": null, - "description": "Ordered list of status line item identifiers.\n\nWhen set, the TUI renders the selected items as the status line.", + "description": "Ordered list of status line item identifiers.\n\nWhen set, the TUI renders the selected items as the status line. When unset, the TUI defaults to: `model-with-reasoning`, `context-remaining`, and `current-dir`.", "items": { "type": "string" }, diff --git a/codex-rs/core/src/config/edit.rs b/codex-rs/core/src/config/edit.rs index c9dbd0ac3..07443fa66 100644 --- a/codex-rs/core/src/config/edit.rs +++ b/codex-rs/core/src/config/edit.rs @@ -56,12 +56,6 @@ pub enum ConfigEdit { } pub fn status_line_items_edit(items: &[String]) -> ConfigEdit { - if items.is_empty() { - return ConfigEdit::ClearPath { - segments: vec!["tui".to_string(), "status_line".to_string()], - }; - } - let mut array = toml_edit::Array::new(); for item in items { array.push(item.clone()); diff --git a/codex-rs/core/src/config/mod.rs b/codex-rs/core/src/config/mod.rs index 3bd47ad16..db8ad218f 100644 --- a/codex-rs/core/src/config/mod.rs +++ b/codex-rs/core/src/config/mod.rs @@ -258,6 +258,9 @@ pub struct Config { pub tui_alternate_screen: AltScreenMode, /// Ordered list of status line item identifiers for the TUI. + /// + /// When unset, the TUI defaults to: `model-with-reasoning`, `context-remaining`, and + /// `current-dir`. pub tui_status_line: Option>, /// The directory that should be treated as the current working directory diff --git a/codex-rs/core/src/config/types.rs b/codex-rs/core/src/config/types.rs index 36dd9924e..bdffa705f 100644 --- a/codex-rs/core/src/config/types.rs +++ b/codex-rs/core/src/config/types.rs @@ -619,6 +619,8 @@ pub struct Tui { /// Ordered list of status line item identifiers. /// /// When set, the TUI renders the selected items as the status line. + /// When unset, the TUI defaults to: `model-with-reasoning`, `context-remaining`, and + /// `current-dir`. #[serde(default)] pub status_line: Option>, } diff --git a/codex-rs/tui/src/app.rs b/codex-rs/tui/src/app.rs index dd019946f..323769dab 100644 --- a/codex-rs/tui/src/app.rs +++ b/codex-rs/tui/src/app.rs @@ -2516,11 +2516,7 @@ impl App { .await; match apply_result { Ok(()) => { - self.config.tui_status_line = if ids.is_empty() { - None - } else { - Some(ids.clone()) - }; + self.config.tui_status_line = Some(ids.clone()); self.chat_widget.setup_status_line(items); } Err(err) => { diff --git a/codex-rs/tui/src/chatwidget.rs b/codex-rs/tui/src/chatwidget.rs index 2201435ca..6d112f5ad 100644 --- a/codex-rs/tui/src/chatwidget.rs +++ b/codex-rs/tui/src/chatwidget.rs @@ -249,6 +249,8 @@ use strum::IntoEnumIterator; const USER_SHELL_COMMAND_HELP_TITLE: &str = "Prefix a command with ! to run it locally"; const USER_SHELL_COMMAND_HELP_HINT: &str = "Example: !ls"; const DEFAULT_OPENAI_BASE_URL: &str = "https://api.openai.com/v1"; +const DEFAULT_STATUS_LINE_ITEMS: [&str; 3] = + ["model-with-reasoning", "context-remaining", "current-dir"]; // Track information about an in-flight exec command. struct RunningCommand { command: Vec, @@ -953,12 +955,11 @@ impl ChatWidget { /// Applies status-line item selection from the setup view to in-memory config. /// - /// An empty selection is normalized to `None` so the status line is fully disabled and the - /// behavior matches an unset `tui.status_line` config value. + /// An empty selection persists as an explicit empty list. pub(crate) fn setup_status_line(&mut self, items: Vec) { tracing::info!("status line setup confirmed with items: {items:#?}"); let ids = items.iter().map(ToString::to_string).collect::>(); - self.config.tui_status_line = if ids.is_empty() { None } else { Some(ids) }; + self.config.tui_status_line = Some(ids); self.refresh_status_line(); } @@ -2692,13 +2693,9 @@ impl ChatWidget { widget .bottom_pane .set_steer_enabled(widget.config.features.enabled(Feature::Steer)); - widget.bottom_pane.set_status_line_enabled( - widget - .config - .tui_status_line - .as_ref() - .is_some_and(|items| !items.is_empty()), - ); + widget + .bottom_pane + .set_status_line_enabled(!widget.configured_status_line_items().is_empty()); widget.bottom_pane.set_collaboration_modes_enabled( widget.config.features.enabled(Feature::CollaborationModes), ); @@ -2859,13 +2856,9 @@ impl ChatWidget { widget .bottom_pane .set_steer_enabled(widget.config.features.enabled(Feature::Steer)); - widget.bottom_pane.set_status_line_enabled( - widget - .config - .tui_status_line - .as_ref() - .is_some_and(|items| !items.is_empty()), - ); + widget + .bottom_pane + .set_status_line_enabled(!widget.configured_status_line_items().is_empty()); widget.bottom_pane.set_collaboration_modes_enabled( widget.config.features.enabled(Feature::CollaborationModes), ); @@ -3015,13 +3008,9 @@ impl ChatWidget { widget .bottom_pane .set_steer_enabled(widget.config.features.enabled(Feature::Steer)); - widget.bottom_pane.set_status_line_enabled( - widget - .config - .tui_status_line - .as_ref() - .is_some_and(|items| !items.is_empty()), - ); + widget + .bottom_pane + .set_status_line_enabled(!widget.configured_status_line_items().is_empty()); widget.bottom_pane.set_collaboration_modes_enabled( widget.config.features.enabled(Feature::CollaborationModes), ); @@ -4349,8 +4338,9 @@ impl ChatWidget { } fn open_status_line_setup(&mut self) { + let configured_status_line_items = self.configured_status_line_items(); let view = StatusLineSetupView::new( - self.config.tui_status_line.as_deref(), + Some(configured_status_line_items.as_slice()), self.app_event_tx.clone(), ); self.bottom_pane.show_view(Box::new(view)); @@ -4363,10 +4353,7 @@ impl ChatWidget { let mut invalid = Vec::new(); let mut invalid_seen = HashSet::new(); let mut items = Vec::new(); - let Some(config_items) = self.config.tui_status_line.as_ref() else { - return (items, invalid); - }; - for id in config_items { + for id in self.configured_status_line_items() { match id.parse::() { Ok(item) => items.push(item), Err(_) => { @@ -4379,6 +4366,15 @@ impl ChatWidget { (items, invalid) } + fn configured_status_line_items(&self) -> Vec { + self.config.tui_status_line.clone().unwrap_or_else(|| { + DEFAULT_STATUS_LINE_ITEMS + .iter() + .map(ToString::to_string) + .collect() + }) + } + fn status_line_cwd(&self) -> &Path { self.current_cwd.as_ref().unwrap_or(&self.config.cwd) }