aboutsummaryrefslogtreecommitdiff
path: root/src/config
diff options
context:
space:
mode:
authorCHIH,GODLEE <61595521+ChihGodlee@users.noreply.github.com>2026-05-18 20:27:43 +0800
committerGitHub <noreply@github.com>2026-05-18 15:27:43 +0300
commit3189ede2b9225b1b930cc43368248c6b4f3a4daf (patch)
tree24252debe6f388edfe0e621462f1bf38d5b46b20 /src/config
parentc9eb7520e66c2a941c020e96e8242de66847f29d (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.rs44
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);