use crate::{ConnectionKind, Profile}; use std::collections::HashSet; #[derive(Debug, Clone, PartialEq, Eq)] pub struct ShortcutBinding { pub command: String, pub binding: String, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct AppConfig { pub profiles: Vec, pub theme_id: String, pub shortcuts: Vec, pub restore_workspace: bool, } impl AppConfig { pub fn default_linux() -> Self { let shell = std::env::var("SHELL").unwrap_or_else(|_| "/bin/bash".to_string()); Self { profiles: vec![Profile::new( "local", "Local Shell", ConnectionKind::LocalShell, &shell, ) .expect("default local profile is valid")], theme_id: "rabby-dark".to_string(), shortcuts: Vec::new(), restore_workspace: true, } } pub fn validate(&self) -> Result<(), String> { if self.theme_id.trim().is_empty() { return Err("theme id is required".to_string()); } let mut profile_ids = HashSet::new(); for profile in &self.profiles { if !profile_ids.insert(profile.id.as_str()) { return Err(format!("duplicate profile id: {}", profile.id)); } } Ok(()) } } #[cfg(test)] mod tests { use super::*; use crate::{ConnectionKind, Profile}; #[test] fn default_config_includes_local_shell_profile() { let config = AppConfig::default_linux(); assert_eq!(config.theme_id, "rabby-dark"); assert!(config.restore_workspace); assert!(config .profiles .iter() .any(|profile| profile.kind == ConnectionKind::LocalShell)); } #[test] fn duplicate_profile_ids_fail_validation() { let mut config = AppConfig::default_linux(); config.profiles.push( Profile::new("local", "Duplicate", ConnectionKind::LocalShell, "/bin/sh").unwrap(), ); let err = config.validate().unwrap_err(); assert!(err.contains("duplicate profile")); } #[test] fn empty_theme_id_fails_validation() { let mut config = AppConfig::default_linux(); config.theme_id = " ".to_string(); let err = config.validate().unwrap_err(); assert!(err.contains("theme")); } }