use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AlertEvent {
Bell,
CommandComplete,
NewTab,
TabClose,
}
impl AlertEvent {
pub fn display_name(&self) -> &'static str {
match self {
AlertEvent::Bell => "Bell",
AlertEvent::CommandComplete => "Command Complete",
AlertEvent::NewTab => "New Tab",
AlertEvent::TabClose => "Tab Close",
}
}
pub fn all() -> &'static [AlertEvent] {
&[
AlertEvent::Bell,
AlertEvent::CommandComplete,
AlertEvent::NewTab,
AlertEvent::TabClose,
]
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AlertSoundConfig {
#[serde(default = "crate::defaults::bool_true")]
pub enabled: bool,
#[serde(default = "crate::defaults::bell_sound")]
pub volume: u8,
#[serde(default)]
pub sound_file: Option<String>,
#[serde(default = "default_alert_frequency")]
pub frequency: f32,
#[serde(default = "default_alert_duration_ms")]
pub duration_ms: u64,
}
fn default_alert_frequency() -> f32 {
800.0
}
fn default_alert_duration_ms() -> u64 {
100
}
impl Default for AlertSoundConfig {
fn default() -> Self {
Self {
enabled: true,
volume: 50,
sound_file: None,
frequency: 800.0,
duration_ms: 100,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum BellAudio<'a> {
Silent,
Tone(u8),
Alert(&'a AlertSoundConfig),
}
pub fn bell_audio(
bell_volume: u8,
alert_sounds: &std::collections::HashMap<AlertEvent, AlertSoundConfig>,
) -> BellAudio<'_> {
match alert_sounds.get(&AlertEvent::Bell) {
Some(alert) if alert.enabled => {
if alert.volume > 0 {
BellAudio::Alert(alert)
} else {
BellAudio::Silent
}
}
_ if bell_volume > 0 => BellAudio::Tone(bell_volume),
_ => BellAudio::Silent,
}
}
#[cfg(test)]
mod bell_audio_tests {
use super::*;
use std::collections::HashMap;
fn bell_entry(enabled: bool, volume: u8) -> HashMap<AlertEvent, AlertSoundConfig> {
let mut map = HashMap::new();
map.insert(
AlertEvent::Bell,
AlertSoundConfig {
enabled,
volume,
..AlertSoundConfig::default()
},
);
map
}
#[test]
fn volume_plays_the_tone_when_no_alert_sound_is_set() {
assert_eq!(bell_audio(60, &HashMap::new()), BellAudio::Tone(60));
assert_eq!(bell_audio(0, &HashMap::new()), BellAudio::Silent);
}
#[test]
fn a_disabled_alert_entry_no_longer_silences_the_volume() {
assert_eq!(bell_audio(60, &bell_entry(false, 50)), BellAudio::Tone(60));
}
#[test]
fn an_enabled_alert_sound_plays_even_with_volume_zero() {
let map = bell_entry(true, 40);
assert!(matches!(bell_audio(0, &map), BellAudio::Alert(a) if a.volume == 40));
assert!(matches!(bell_audio(80, &map), BellAudio::Alert(_)));
}
#[test]
fn an_enabled_alert_sound_at_volume_zero_is_silent() {
assert_eq!(bell_audio(80, &bell_entry(true, 0)), BellAudio::Silent);
}
}