diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-06-06 17:41:44 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-06-06 17:42:38 +0300 |
| commit | 4001fd2ec8ff05a982da18744b8cbde9df3ab530 (patch) | |
| tree | f8dbf984cff9a4b025e86481d3f70c89322bd79f /src/config | |
| parent | 048d8a29195d580014b24ee3fc7e89ac6bdfee8a (diff) | |
feat: improve toast ergonomics
refs #486
Diffstat (limited to 'src/config')
| -rw-r--r-- | src/config/model.rs | 123 |
1 files changed, 122 insertions, 1 deletions
diff --git a/src/config/model.rs b/src/config/model.rs index 3b8b2cb7..c36150f6 100644 --- a/src/config/model.rs +++ b/src/config/model.rs @@ -8,6 +8,8 @@ use super::{ DEFAULT_MOUSE_SCROLL_LINES, DEFAULT_SCROLLBACK_LIMIT_BYTES, }; +pub const MAX_TOAST_DELAY_SECONDS: u64 = 3600; + #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, Default)] #[serde(rename_all = "lowercase")] pub enum UpdateChannelConfig { @@ -50,6 +52,28 @@ pub enum ToastDelivery { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, Default)] +#[serde(rename_all = "kebab-case")] +pub enum ToastHerdrPosition { + TopLeft, + TopRight, + BottomLeft, + #[default] + BottomRight, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, Default)] +#[serde(rename_all = "kebab-case")] +pub enum ToastClipboardPosition { + TopLeft, + TopCenter, + TopRight, + BottomLeft, + #[default] + BottomCenter, + BottomRight, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, Default)] #[serde(rename_all = "lowercase")] pub enum AgentPanelScopeConfig { Current, @@ -122,6 +146,22 @@ fn parse_right_click_passthrough_modifier(value: &str) -> Option<Option<KeyModif #[derive(Debug, Clone)] pub struct ToastConfig { pub delivery: ToastDelivery, + pub delay_seconds: u64, + pub herdr: HerdrToastConfig, + pub clipboard: ClipboardToastConfig, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] +#[serde(default)] +pub struct HerdrToastConfig { + pub position: ToastHerdrPosition, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] +#[serde(default)] +pub struct ClipboardToastConfig { + pub enabled: bool, + pub position: ToastClipboardPosition, } #[derive(Debug, Clone, Default, PartialEq, Eq)] @@ -600,6 +640,26 @@ impl Default for ToastConfig { fn default() -> Self { Self { delivery: ToastDelivery::Off, + delay_seconds: 1, + herdr: HerdrToastConfig::default(), + clipboard: ClipboardToastConfig::default(), + } + } +} + +impl Default for HerdrToastConfig { + fn default() -> Self { + Self { + position: ToastHerdrPosition::BottomRight, + } + } +} + +impl Default for ClipboardToastConfig { + fn default() -> Self { + Self { + enabled: true, + position: ToastClipboardPosition::BottomCenter, } } } @@ -614,6 +674,9 @@ impl<'de> Deserialize<'de> for ToastConfig { struct RawToastConfig { delivery: Option<ToastDelivery>, enabled: Option<bool>, + delay_seconds: Option<u64>, + herdr: HerdrToastConfig, + clipboard: ClipboardToastConfig, } let raw = RawToastConfig::deserialize(deserializer)?; @@ -622,7 +685,19 @@ impl<'de> Deserialize<'de> for ToastConfig { Some(false) | None => ToastDelivery::Off, }; let delivery = raw.delivery.unwrap_or(legacy_delivery); - Ok(Self { delivery }) + let default = Self::default(); + let delay_seconds = raw.delay_seconds.unwrap_or(default.delay_seconds); + if delay_seconds > MAX_TOAST_DELAY_SECONDS { + return Err(de::Error::custom(format!( + "ui.toast.delay_seconds must be between 0 and {MAX_TOAST_DELAY_SECONDS}" + ))); + } + Ok(Self { + delivery, + delay_seconds, + herdr: raw.herdr, + clipboard: raw.clipboard, + }) } } @@ -984,9 +1059,40 @@ mouse_scroll_lines = 0 let toml = r#" [ui.toast] delivery = "terminal" +delay_seconds = 2 + +[ui.toast.herdr] +position = "top-left" + +[ui.toast.clipboard] +enabled = false +position = "top-center" "#; let config: Config = toml::from_str(toml).unwrap(); assert_eq!(config.ui.toast.delivery, ToastDelivery::Terminal); + assert_eq!(config.ui.toast.delay_seconds, 2); + assert_eq!(config.ui.toast.herdr.position, ToastHerdrPosition::TopLeft); + assert!(!config.ui.toast.clipboard.enabled); + assert_eq!( + config.ui.toast.clipboard.position, + ToastClipboardPosition::TopCenter + ); + } + + #[test] + fn toast_config_defaults_preserve_existing_behavior_with_delay() { + let config = Config::default(); + assert_eq!(config.ui.toast.delivery, ToastDelivery::Off); + assert_eq!(config.ui.toast.delay_seconds, 1); + assert_eq!( + config.ui.toast.herdr.position, + ToastHerdrPosition::BottomRight + ); + assert!(config.ui.toast.clipboard.enabled); + assert_eq!( + config.ui.toast.clipboard.position, + ToastClipboardPosition::BottomCenter + ); } #[test] @@ -1031,6 +1137,21 @@ delivery = "terminal" } #[test] + fn toast_config_rejects_unbounded_delay() { + let toml = format!( + r#" +[ui.toast] +delay_seconds = {} +"#, + MAX_TOAST_DELAY_SECONDS + 1 + ); + + let error = toml::from_str::<Config>(&toml).unwrap_err().to_string(); + + assert!(error.contains("ui.toast.delay_seconds must be between 0 and 3600")); + } + + #[test] fn missing_onboarding_shows_setup() { let config = Config::default(); assert!(config.should_show_onboarding()); |
