aboutsummaryrefslogtreecommitdiff
path: root/src/config
diff options
context:
space:
mode:
authorRudolf S. <rud.schmidt@gmail.com>2026-09-07 14:04:54 +0200
committerGitHub <noreply@github.com>2026-09-07 14:04:54 +0200
commit482818130407691154d1635d4029b95d0e730104 (patch)
tree5f72ac0992b43a48a670bd3265fc5a2aeae366c8 /src/config
parent4b5e9bda239a0b6903889062d756424578e94691 (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.rs95
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);