diff options
| author | CHIH,GODLEE <61595521+ChihGodlee@users.noreply.github.com> | 2026-05-18 20:27:43 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-05-18 15:27:43 +0300 |
| commit | 3189ede2b9225b1b930cc43368248c6b4f3a4daf (patch) | |
| tree | 24252debe6f388edfe0e621462f1bf38d5b46b20 /src/config | |
| parent | c9eb7520e66c2a941c020e96e8242de66847f29d (diff) | |
feat: configure sidebar min/max width via [ui] (#135)
* feat: configure sidebar min/max width via [ui]
Expose the previously hardcoded MIN_SIDEBAR_WIDTH / MAX_SIDEBAR_WIDTH
clamps as [ui] sidebar_min_width / sidebar_max_width. Defaults remain
18 / 36 so existing configs are unchanged. Hot-reload is wired through
the existing [ui] block; reload re-clamps the live width to the new
bounds so tightening takes effect immediately.
Reject inverted bounds (min > max) at every entry point so a bad config
can never reach u16::clamp(min, max), which panics: App::new falls back
to defaults, and apply_live_config treats the whole [ui] section as
invalid and returns a partial reload report.
refs #132
* test: keep sidebar reload width within bounds
refs #132
---------
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
Diffstat (limited to 'src/config')
| -rw-r--r-- | src/config/model.rs | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/src/config/model.rs b/src/config/model.rs index 60a8859c..673eec02 100644 --- a/src/config/model.rs +++ b/src/config/model.rs @@ -48,6 +48,19 @@ pub struct ConfigReloadReport { pub diagnostics: Vec<String>, } +/// Validate `[ui]` sidebar bound configuration. +/// +/// Returns `Some((min, max))` when `min <= max`, `None` otherwise. The two +/// values are funneled through this helper before they reach any +/// `u16::clamp(min, max)` call site (`u16::clamp` panics when `min > max`). +pub fn validated_sidebar_bounds(min: u16, max: u16) -> Option<(u16, u16)> { + if min <= max { + Some((min, max)) + } else { + None + } +} + #[derive(Debug, Default, Deserialize)] #[serde(default)] pub struct Config { @@ -147,6 +160,10 @@ pub struct IndexedKeysConfig { #[serde(default)] pub struct UiConfig { pub sidebar_width: u16, + /// Minimum sidebar width (columns) when expanded. Default: 18. + pub sidebar_min_width: u16, + /// Maximum sidebar width (columns) when expanded. Default: 36. + pub sidebar_max_width: u16, /// Capture mouse input for Herdr's mouse UI. Default: true. pub mouse_capture: bool, /// Ask for confirmation before closing a workspace. Default: true. @@ -224,6 +241,8 @@ impl Default for UiConfig { fn default() -> Self { Self { sidebar_width: 26, + sidebar_min_width: 18, + sidebar_max_width: 36, mouse_capture: true, confirm_close: true, prompt_new_tab_name: true, @@ -315,6 +334,31 @@ prompt_new_tab_name = false } #[test] + fn sidebar_bounds_default_and_parse() { + let default_config = Config::default(); + assert_eq!(default_config.ui.sidebar_min_width, 18); + assert_eq!(default_config.ui.sidebar_max_width, 36); + + let toml = r#" +[ui] +sidebar_min_width = 12 +sidebar_max_width = 80 +"#; + let config: Config = toml::from_str(toml).unwrap(); + assert_eq!(config.ui.sidebar_min_width, 12); + assert_eq!(config.ui.sidebar_max_width, 80); + } + + #[test] + fn validated_sidebar_bounds_rejects_inverted() { + assert_eq!(validated_sidebar_bounds(18, 36), Some((18, 36))); + assert_eq!(validated_sidebar_bounds(20, 20), Some((20, 20))); + assert_eq!(validated_sidebar_bounds(0, u16::MAX), Some((0, u16::MAX))); + assert_eq!(validated_sidebar_bounds(50, 30), None); + assert_eq!(validated_sidebar_bounds(u16::MAX, 0), None); + } + + #[test] fn mouse_capture_default_on_and_parse() { let default_config = Config::default(); assert!(default_config.ui.mouse_capture); |
