diff options
| author | Rudolf S. <rud.schmidt@gmail.com> | 2026-09-07 14:04:54 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-09-07 14:04:54 +0200 |
| commit | 482818130407691154d1635d4029b95d0e730104 (patch) | |
| tree | 5f72ac0992b43a48a670bd3265fc5a2aeae366c8 /src/config | |
| parent | 4b5e9bda239a0b6903889062d756424578e94691 (diff) | |
feat: make ui.pane_borders a three-state auto/always/off mode (#3234)
* feat: make ui.pane_borders a three-state auto/always/off mode
Legacy booleans keep parsing (true = auto, false = off); "always" frames
a lone pane while pane_outer_borders is enabled.
* fix: align pane border reload test and documentation
---------
Co-authored-by: Rudolf Schmidt <me@rudionrails.com>
Co-authored-by: Jonathan Liebig <jonathan.liebig@gmail.com>
Diffstat (limited to 'src/config')
| -rw-r--r-- | src/config/model.rs | 95 |
1 files changed, 89 insertions, 6 deletions
diff --git a/src/config/model.rs b/src/config/model.rs index a400382c..604fe9ad 100644 --- a/src/config/model.rs +++ b/src/config/model.rs @@ -844,6 +844,60 @@ pub enum TabBarPositionConfig { Bottom, } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub enum PaneBordersConfig { + #[default] + Auto, + Always, + Off, +} + +impl PaneBordersConfig { + pub fn draws_borders(self) -> bool { + !matches!(self, Self::Off) + } + + pub fn shows_borders(self, multi_pane: bool) -> bool { + self.draws_borders() && (multi_pane || matches!(self, Self::Always)) + } +} + +impl<'de> Deserialize<'de> for PaneBordersConfig { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + struct PaneBordersVisitor; + + impl<'de> de::Visitor<'de> for PaneBordersVisitor { + type Value = PaneBordersConfig; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("\"auto\", \"always\", \"off\", or a legacy boolean") + } + + fn visit_bool<E: de::Error>(self, value: bool) -> Result<Self::Value, E> { + Ok(if value { + PaneBordersConfig::Auto + } else { + PaneBordersConfig::Off + }) + } + + fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> { + match value { + "auto" => Ok(PaneBordersConfig::Auto), + "always" => Ok(PaneBordersConfig::Always), + "off" => Ok(PaneBordersConfig::Off), + other => Err(E::invalid_value(de::Unexpected::Str(other), &self)), + } + } + } + + deserializer.deserialize_any(PaneBordersVisitor) + } +} + #[derive(Debug, Deserialize)] #[serde(default)] pub struct UiConfig { @@ -876,8 +930,12 @@ pub struct UiConfig { pub prompt_new_tab_name: bool, /// Ask for a workspace name before interactive creation. Default: false. pub prompt_new_workspace_name: bool, - /// Draw borders around split panes. Default: true. - pub pane_borders: bool, + /// Draw borders around split panes. auto draws them only for split panes, + /// always also frames a lone pane (only while pane_outer_borders is + /// enabled, since every edge of a lone pane is an outer edge), off + /// disables them. Legacy booleans map true to auto and false to off. + /// Default: auto. + pub pane_borders: PaneBordersConfig, /// Draw borders along the outside edge of the pane area. Default: true. pub pane_outer_borders: bool, /// Draw interactive scrollbars beside terminal panes. Default: true. @@ -1115,7 +1173,7 @@ impl Default for UiConfig { confirm_close: true, prompt_new_tab_name: true, prompt_new_workspace_name: false, - pane_borders: true, + pane_borders: PaneBordersConfig::Auto, pane_outer_borders: true, pane_scrollbars: true, pane_gaps: true, @@ -1390,9 +1448,34 @@ status_indicators = "symbols" } #[test] + fn pane_borders_legacy_booleans_map_to_modes() { + let enabled: Config = toml::from_str("[ui]\npane_borders = true").unwrap(); + assert_eq!(enabled.ui.pane_borders, PaneBordersConfig::Auto); + + let disabled: Config = toml::from_str("[ui]\npane_borders = false").unwrap(); + assert_eq!(disabled.ui.pane_borders, PaneBordersConfig::Off); + + let auto: Config = toml::from_str("[ui]\npane_borders = \"auto\"").unwrap(); + assert_eq!(auto.ui.pane_borders, PaneBordersConfig::Auto); + + let off: Config = toml::from_str("[ui]\npane_borders = \"off\"").unwrap(); + assert_eq!(off.ui.pane_borders, PaneBordersConfig::Off); + + let unknown = toml::from_str::<Config>("[ui]\npane_borders = \"framed\"") + .unwrap_err() + .to_string(); + assert!(unknown.contains("\"auto\", \"always\", \"off\", or a legacy boolean")); + + let wrong_type = toml::from_str::<Config>("[ui]\npane_borders = 3") + .unwrap_err() + .to_string(); + assert!(wrong_type.contains("\"auto\", \"always\", \"off\", or a legacy boolean")); + } + + #[test] fn pane_appearance_defaults_and_parse() { let default_config = Config::default(); - assert!(default_config.ui.pane_borders); + assert_eq!(default_config.ui.pane_borders, PaneBordersConfig::Auto); assert!(default_config.ui.pane_outer_borders); assert!(default_config.ui.pane_scrollbars); assert!(default_config.ui.pane_gaps); @@ -1407,7 +1490,7 @@ status_indicators = "symbols" let toml = r#" [ui] -pane_borders = false +pane_borders = "always" pane_outer_borders = false pane_scrollbars = false pane_gaps = true @@ -1424,7 +1507,7 @@ tab_bar_right = [ tab_bar_right_separator = " ยท " "#; let config: Config = toml::from_str(toml).unwrap(); - assert!(!config.ui.pane_borders); + assert_eq!(config.ui.pane_borders, PaneBordersConfig::Always); assert!(!config.ui.pane_outer_borders); assert!(!config.ui.pane_scrollbars); assert!(config.ui.pane_gaps); |
