Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions codex-rs/core/config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,15 @@
},
"type": "object"
},
"DiffBackgroundMode": {
"enum": [
"auto",
"off",
"theme",
"custom"
],
"type": "string"
},
"FeedbackConfigToml": {
"additionalProperties": false,
"properties": {
Expand Down Expand Up @@ -1396,6 +1405,25 @@
"description": "Enable animations (welcome screen, shimmer effects, spinners). Defaults to `true`.",
"type": "boolean"
},
"diff_add_bg": {
"default": null,
"description": "Custom insert-line background color (`#RRGGBB`).\n\nUsed when `diff_background = \"custom\"`.",
"type": "string"
},
"diff_background": {
"allOf": [
{
"$ref": "#/definitions/DiffBackgroundMode"
}
],
"default": "auto",
"description": "Controls how diff add/remove backgrounds are rendered in the TUI.\n\n- `auto` (default): Use built-in adaptive add/remove backgrounds. - `off`: Disable add/remove line backgrounds. - `theme`: Derive add/remove backgrounds from the active syntax theme (`markup.inserted`/`markup.deleted` with diff fallbacks). - `custom`: Use user-provided custom colors from `diff_add_bg` / `diff_del_bg`."
},
"diff_del_bg": {
"default": null,
"description": "Custom delete-line background color (`#RRGGBB`).\n\nUsed when `diff_background = \"custom\"`.",
"type": "string"
},
"notification_method": {
"allOf": [
{
Expand Down
78 changes: 78 additions & 0 deletions codex-rs/core/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::config::edit::ConfigEdit;
use crate::config::edit::ConfigEditsBuilder;
use crate::config::types::AppsConfigToml;
use crate::config::types::DEFAULT_OTEL_ENVIRONMENT;
use crate::config::types::DiffBackgroundMode;
use crate::config::types::History;
use crate::config::types::McpServerConfig;
use crate::config::types::McpServerDisabledReason;
Expand Down Expand Up @@ -298,6 +299,15 @@ pub struct Config {
/// Syntax highlighting theme override (kebab-case name).
pub tui_theme: Option<String>,

/// Controls how diff add/remove backgrounds are rendered in the TUI.
pub tui_diff_background: DiffBackgroundMode,

/// Custom insert-line background color (`#RRGGBB`).
pub tui_diff_add_bg: Option<String>,

/// Custom delete-line background color (`#RRGGBB`).
pub tui_diff_del_bg: Option<String>,

/// The directory that should be treated as the current working directory
/// for the session. All relative paths inside the business-logic layer are
/// resolved against this path.
Expand Down Expand Up @@ -2197,6 +2207,13 @@ impl Config {
.unwrap_or_default(),
tui_status_line: cfg.tui.as_ref().and_then(|t| t.status_line.clone()),
tui_theme: cfg.tui.as_ref().and_then(|t| t.theme.clone()),
tui_diff_background: cfg
.tui
.as_ref()
.map(|t| t.diff_background)
.unwrap_or_default(),
tui_diff_add_bg: cfg.tui.as_ref().and_then(|t| t.diff_add_bg.clone()),
tui_diff_del_bg: cfg.tui.as_ref().and_then(|t| t.diff_del_bg.clone()),
otel: {
let t: OtelConfigToml = cfg.otel.unwrap_or_default();
let log_user_prompt = t.log_user_prompt.unwrap_or(false);
Expand Down Expand Up @@ -2622,6 +2639,22 @@ theme = "dracula"
assert_eq!(parsed.tui.as_ref().and_then(|t| t.theme.as_deref()), None);
}

#[test]
fn tui_diff_background_deserializes_from_toml() {
let cfg = r##"
[tui]
diff_background = "custom"
diff_add_bg = "#213A2B"
diff_del_bg = "#4A221D"
"##;
let parsed =
toml::from_str::<ConfigToml>(cfg).expect("TOML deserialization should succeed");
let tui = parsed.tui.expect("config should include tui section");
assert_eq!(tui.diff_background, DiffBackgroundMode::Custom);
assert_eq!(tui.diff_add_bg.as_deref(), Some("#213A2B"));
assert_eq!(tui.diff_del_bg.as_deref(), Some("#4A221D"));
}

#[test]
fn tui_config_missing_notifications_field_defaults_to_enabled() {
let cfg = r#"
Expand All @@ -2639,9 +2672,42 @@ theme = "dracula"
notification_method: NotificationMethod::Auto,
animations: true,
show_tooltips: true,
show_compact_summary: true,
alternate_screen: AltScreenMode::Auto,
status_line: None,
theme: None,
diff_background: DiffBackgroundMode::Auto,
diff_add_bg: None,
diff_del_bg: None,
}
);
}

#[test]
fn tui_config_can_disable_compact_summary() {
let cfg = r#"
[tui]
show_compact_summary = false
"#;

let parsed = toml::from_str::<ConfigToml>(cfg)
.expect("TUI config with show_compact_summary should succeed");
let tui = parsed.tui.expect("config should include tui section");

assert_eq!(
tui,
Tui {
notifications: Notifications::Enabled(true),
notification_method: NotificationMethod::Auto,
animations: true,
show_tooltips: true,
show_compact_summary: false,
alternate_screen: AltScreenMode::Auto,
status_line: None,
theme: None,
diff_background: DiffBackgroundMode::Auto,
diff_add_bg: None,
diff_del_bg: None,
}
);
}
Expand Down Expand Up @@ -4799,6 +4865,9 @@ model_verbosity = "high"
tui_alternate_screen: AltScreenMode::Auto,
tui_status_line: None,
tui_theme: None,
tui_diff_background: DiffBackgroundMode::Auto,
tui_diff_add_bg: None,
tui_diff_del_bg: None,
otel: OtelConfig::default(),
},
o3_profile_config
Expand Down Expand Up @@ -4925,6 +4994,9 @@ model_verbosity = "high"
tui_alternate_screen: AltScreenMode::Auto,
tui_status_line: None,
tui_theme: None,
tui_diff_background: DiffBackgroundMode::Auto,
tui_diff_add_bg: None,
tui_diff_del_bg: None,
otel: OtelConfig::default(),
};

Expand Down Expand Up @@ -5049,6 +5121,9 @@ model_verbosity = "high"
tui_alternate_screen: AltScreenMode::Auto,
tui_status_line: None,
tui_theme: None,
tui_diff_background: DiffBackgroundMode::Auto,
tui_diff_add_bg: None,
tui_diff_del_bg: None,
otel: OtelConfig::default(),
};

Expand Down Expand Up @@ -5159,6 +5234,9 @@ model_verbosity = "high"
tui_alternate_screen: AltScreenMode::Auto,
tui_status_line: None,
tui_theme: None,
tui_diff_background: DiffBackgroundMode::Auto,
tui_diff_add_bg: None,
tui_diff_del_bg: None,
otel: OtelConfig::default(),
};

Expand Down
33 changes: 33 additions & 0 deletions codex-rs/core/src/config/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,39 @@ pub struct Tui {
/// Use `/theme` in the TUI or see `$CODEX_HOME/themes` for custom themes.
#[serde(default)]
pub theme: Option<String>,

/// Controls how diff add/remove backgrounds are rendered in the TUI.
///
/// - `auto` (default): Use built-in adaptive add/remove backgrounds.
/// - `off`: Disable add/remove line backgrounds.
/// - `theme`: Derive add/remove backgrounds from the active syntax theme
/// (`markup.inserted`/`markup.deleted` with diff fallbacks).
/// - `custom`: Use user-provided custom colors from `diff_add_bg` /
/// `diff_del_bg`.
#[serde(default)]
pub diff_background: DiffBackgroundMode,

/// Custom insert-line background color (`#RRGGBB`).
///
/// Used when `diff_background = "custom"`.
#[serde(default)]
pub diff_add_bg: Option<String>,

/// Custom delete-line background color (`#RRGGBB`).
///
/// Used when `diff_background = "custom"`.
#[serde(default)]
pub diff_del_bg: Option<String>,
}

#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Default, JsonSchema)]
#[serde(rename_all = "kebab-case")]
pub enum DiffBackgroundMode {
#[default]
Auto,
Off,
Theme,
Custom,
}

const fn default_true() -> bool {
Expand Down
Loading
Loading