-
Notifications
You must be signed in to change notification settings - Fork 3.5k
feat(tui): compact and hidden presets for the bottom chrome (#5950) #5973
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -322,6 +322,8 @@ fn show_single_setting(app: &App, key: &str) -> CommandResult { | |
| app.active_context_window_source.display_label(), | ||
| )), | ||
| "stream_chunk_timeout_secs" => Some(app.stream_chunk_timeout_secs.to_string()), | ||
| "posture_bar" => Some(app.posture_bar.as_setting().to_string()), | ||
| "metrics_line" => Some(app.metrics_line.as_setting().to_string()), | ||
| "locale" | "language" => Some(locale_display(app.ui_locale).to_string()), | ||
| "theme" | "ui_theme" => Some( | ||
| if app | ||
|
|
@@ -867,6 +869,20 @@ fn config_editability_audit(app: &App) -> CommandResult { | |
| "/config stream_chunk_timeout_secs <0|1..3600> --save", | ||
| "Writes [tui].stream_chunk_timeout_secs and updates the running stream timeout.", | ||
| ), | ||
| ( | ||
| "posture_bar", | ||
| app.posture_bar.as_setting().to_string(), | ||
| "runtime+persisted", | ||
| "/config posture_bar <full|compact|hidden> --save", | ||
| "Writes [tui].posture_bar; hidden gives the row to the transcript, compact keeps the posture chips only.", | ||
| ), | ||
| ( | ||
| "metrics_line", | ||
| app.metrics_line.as_setting().to_string(), | ||
| "runtime+persisted", | ||
| "/config metrics_line <full|compact|hidden> --save", | ||
| "Writes [tui].metrics_line; hidden gives the row to the transcript, compact drops the telemetry and help hint.", | ||
| ), | ||
| ( | ||
| "subagents.enabled", | ||
| subagents_config_display_value(&config, "enabled"), | ||
|
|
@@ -2364,6 +2380,40 @@ pub fn set_config_value(app: &mut App, key: &str, value: &str, persist: bool) -> | |
| "provider_url must be saved with --save; client base URL is loaded from config on startup. Restart and re-open your session after saving.", | ||
| ); | ||
| } | ||
| // The two bottom-chrome rows' size presets (`tui.posture_bar`, | ||
| // `tui.metrics_line`, #5950). Live on the next frame; `--save` | ||
| // writes the `[tui]` key. `/statusline` composes what is in a row; | ||
| // this only decides whether and how much of it paints. | ||
| row_key @ ("posture_bar" | "metrics_line") => { | ||
| let Some(preset) = crate::config::ChromeRowPreset::from_setting(value) else { | ||
| return CommandResult::error(format!( | ||
| "{row_key} must be one of: {}", | ||
| crate::config::ChromeRowPreset::SETTINGS.join(", ") | ||
|
Comment on lines
+2389
to
+2391
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
For every non-English UI locale, invalid preset feedback—and the success/session-only responses later in this branch—remains hard-coded English. These user-visible command messages should use AGENTS.md reference: crates/tui/AGENTS.md:L25-L26 Useful? React with 👍 / 👎. |
||
| )); | ||
| }; | ||
| if row_key == "posture_bar" { | ||
| app.posture_bar = preset; | ||
| } else { | ||
| app.metrics_line = preset; | ||
| } | ||
|
Comment on lines
+2394
to
+2398
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When Useful? React with 👍 / 👎. |
||
| app.needs_redraw = true; | ||
| let value = preset.as_setting(); | ||
| if persist { | ||
| return match persist_table_string_key( | ||
| app.config_path.as_deref(), | ||
| "tui", | ||
| row_key, | ||
| value, | ||
|
Comment on lines
+2402
to
+2406
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When Codewhale is launched with Useful? React with 👍 / 👎. |
||
| ) { | ||
| Ok(path) => CommandResult::message(format!( | ||
| "{row_key} = {value} (saved to {})", | ||
| path.display() | ||
| )), | ||
| Err(err) => CommandResult::error(format!("Failed to save: {err}")), | ||
| }; | ||
| } | ||
| return CommandResult::message(format!("{row_key} = {value} (session only)")); | ||
| } | ||
| "stream_chunk_timeout_secs" => { | ||
| let raw = match value.trim().parse::<u64>() { | ||
| Ok(value) => value, | ||
|
|
@@ -4822,6 +4872,68 @@ context_window = 262144 | |
| )); | ||
| } | ||
|
|
||
| /// The bottom-chrome row presets (#5950) apply on the next frame and | ||
| /// `--save` writes the `[tui]` key; an unknown preset names the three. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [INFO] Only metrics_line --save persistence is covered; posture_bar save path lacks direct test The new config test exercises live |
||
| #[test] | ||
| fn config_command_row_presets_apply_live_and_persist_to_tui_table() { | ||
| use crate::config::ChromeRowPreset; | ||
| let nanos = SystemTime::now() | ||
| .duration_since(UNIX_EPOCH) | ||
| .unwrap() | ||
| .as_nanos(); | ||
| let temp_root = env::temp_dir().join(format!( | ||
| "codewhale-tui-row-presets-test-{}-{}", | ||
| std::process::id(), | ||
| nanos | ||
| )); | ||
| fs::create_dir_all(&temp_root).unwrap(); | ||
| let _guard = EnvGuard::new(&temp_root); | ||
| let config_path = temp_root.join("custom-config.toml"); | ||
| let mut app = create_test_app(); | ||
| app.config_path = Some(config_path.clone()); | ||
| assert_eq!(app.posture_bar, ChromeRowPreset::Full); | ||
| assert_eq!(app.metrics_line, ChromeRowPreset::Full); | ||
|
|
||
| let live = config_command(&mut app, Some("posture_bar compact")); | ||
| assert!(!live.is_error, "{live:?}"); | ||
| assert_eq!(app.posture_bar, ChromeRowPreset::Compact); | ||
| assert_eq!( | ||
| live.message.as_deref(), | ||
| Some("posture_bar = compact (session only)") | ||
| ); | ||
| assert_eq!( | ||
| config_command(&mut app, Some("posture_bar")) | ||
| .message | ||
| .as_deref(), | ||
| Some("posture_bar = compact") | ||
| ); | ||
|
|
||
| let saved = config_command(&mut app, Some("metrics_line HIDDEN --save")); | ||
| assert!(!saved.is_error, "{saved:?}"); | ||
| assert_eq!(app.metrics_line, ChromeRowPreset::Hidden); | ||
| let body = fs::read_to_string(&config_path).unwrap(); | ||
| assert!(body.contains("[tui]"), "{body}"); | ||
| assert!(body.contains("metrics_line = \"hidden\""), "{body}"); | ||
| assert!( | ||
| !body.contains("posture_bar"), | ||
| "session-only value must not be saved: {body}" | ||
| ); | ||
|
|
||
| let bad = config_command(&mut app, Some("metrics_line tiny")); | ||
| assert!(bad.is_error); | ||
| assert!( | ||
| bad.message | ||
| .as_deref() | ||
| .is_some_and(|m| m.contains("metrics_line must be one of: full, compact, hidden")), | ||
| "{bad:?}" | ||
| ); | ||
| assert_eq!( | ||
| app.metrics_line, | ||
| ChromeRowPreset::Hidden, | ||
| "a bad value changes nothing" | ||
| ); | ||
| } | ||
|
|
||
| #[test] | ||
| fn config_command_stream_chunk_timeout_rejects_invalid_input() { | ||
| let _lock = lock_test_env(); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1811,6 +1811,20 @@ pub struct TuiConfig { | |
| /// in `~/.deepseek/config.toml`. | ||
| #[serde(default, deserialize_with = "deser_status_items")] | ||
| pub status_items: Option<Vec<StatusItem>>, | ||
| /// How much of the posture bar — the first row under the composer — to | ||
| /// paint: `full` (default), `compact`, or `hidden`. `hidden` gives the | ||
| /// row back to the transcript; `compact` keeps the row and starts its | ||
| /// shed ladder past the clocks, counts and hints (#5950). | ||
| /// | ||
| /// `status_items` still composes what is *in* the row; this only decides | ||
| /// the row's size. Absent from an older `config.toml` means `full`. | ||
| #[serde(default)] | ||
| pub posture_bar: Option<ChromeRowPreset>, | ||
| /// The same three settings for the metrics line under the posture bar. | ||
| /// `compact` keeps the route, the context reading, the cost and the | ||
| /// balance and drops the telemetry and the help hint (#5950). | ||
| #[serde(default)] | ||
| pub metrics_line: Option<ChromeRowPreset>, | ||
| /// Ordered list of optional header items the user wants visible. | ||
| /// | ||
| /// `None` (the field missing from `config.toml`) preserves the built-in | ||
|
|
@@ -1860,6 +1874,52 @@ pub struct TuiConfig { | |
| pub composer_arrows_scroll: Option<bool>, | ||
| } | ||
|
|
||
| /// How much of one bottom-chrome row to paint (#5950). One value for each | ||
| /// of the two rows under the composer — [`TuiConfig::posture_bar`] and | ||
| /// [`TuiConfig::metrics_line`] — so a small tmux pane can give one or both | ||
| /// rows back to the transcript without touching `status_items`. | ||
| /// | ||
| /// `compact` is not a second renderer: it starts the row's existing shed | ||
| /// ladder at a fixed rung and lets width shed the rest, so what it keeps is | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [INFO] Case sensitivity differs between /config and config.toml
|
||
| /// exactly what a narrow row keeps. | ||
| #[derive(Debug, Clone, Copy, Default, Deserialize, PartialEq, Eq)] | ||
| #[serde(rename_all = "snake_case")] | ||
| pub enum ChromeRowPreset { | ||
| /// Every fact the row owns, shed only by width. | ||
| #[default] | ||
| Full, | ||
| /// The row's shed ladder started past its most expendable rungs. | ||
| Compact, | ||
| /// No row: the transcript takes the line. | ||
| Hidden, | ||
| } | ||
|
|
||
| impl ChromeRowPreset { | ||
| /// Every setting value, in the order `/config` names them. | ||
| pub const SETTINGS: [&'static str; 3] = ["full", "compact", "hidden"]; | ||
|
|
||
| /// Stable name used in `config.toml` and `/config`. | ||
| #[must_use] | ||
| pub const fn as_setting(self) -> &'static str { | ||
| match self { | ||
| Self::Full => "full", | ||
| Self::Compact => "compact", | ||
| Self::Hidden => "hidden", | ||
| } | ||
| } | ||
|
|
||
| /// Reverse of [`Self::as_setting`]; `None` for anything else. | ||
| #[must_use] | ||
| pub fn from_setting(value: &str) -> Option<Self> { | ||
| match value.trim().to_ascii_lowercase().as_str() { | ||
| "full" => Some(Self::Full), | ||
| "compact" => Some(Self::Compact), | ||
| "hidden" => Some(Self::Hidden), | ||
| _ => None, | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// High-level notification trigger override. See | ||
| /// [`TuiConfig::notification_condition`]. | ||
| #[derive(Debug, Clone, Copy, Deserialize, PartialEq, Eq)] | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔍 Remove branch changelog edits
The contribution rules reserve both changelogs for batched updates on
main. This PR modifies both files and creates avoidable merge conflicts.Was this helpful? React with 👍 or 👎 to provide feedback.