use crate::*; /// Configuration. /// /// Contains mode, view, and bind definitions. #[derive(Default, Debug)] pub struct Config { pub dirs: BaseDirectories, pub modes: Modes, pub views: Views, pub binds: Binds, } impl Config { const CONFIG: &'static str = "tek.edn"; const DEFAULTS: &'static str = include_str!("./tek.edn"); pub fn new (dirs: Option) -> Self { Self { dirs: dirs.unwrap_or_else(||BaseDirectories::with_profile("tek", "v0")), ..Default::default() } } pub fn init (&mut self) -> Usually<()> { self.init_file(Self::CONFIG, Self::DEFAULTS, |cfgs, dsl|cfgs.load(&dsl))?; Ok(()) } pub fn init_file ( &mut self, path: &str, defaults: &str, mut each: impl FnMut(&mut Self, &str)->Usually<()> ) -> Usually<()> { if self.dirs.find_config_file(path).is_none() { println!("Creating {path:?}"); std::fs::write(self.dirs.place_config_file(path)?, defaults)?; } Ok(if let Some(path) = self.dirs.find_config_file(path) { println!("Loading {path:?}"); let src = std::fs::read_to_string(&path)?; src.as_str().each(move|item|each(self, item))?; } else { return Err(format!("{path}: not found").into()) }) } pub fn load (&mut self, dsl: impl Dsl) -> Usually<()> { dsl.each(|item|if let Some(expr) = item.expr()? { let head = expr.head()?; let tail = expr.tail()?; let name = tail.head()?; let body = tail.tail()?; println!("Config::load: {} {} {}", head.unwrap_or_default(), name.unwrap_or_default(), body.unwrap_or_default()); match head { Some("mode") if let Some(name) = name => Mode::>::load_into(&self.modes, &name, &body)?, Some("keys") if let Some(name) = name => EventMap::>::load_into(&self.binds, &name, &body)?, Some("view") if let Some(name) = name => { self.views.write().unwrap().insert(name.into(), body.src()?.unwrap_or_default().into()); }, _ => return Err(format!("Config::load: expected view/keys/mode, got: {item:?}").into()) } Ok(()) } else { return Err(format!("Config::load: expected expr, got: {item:?}").into()) }) } }