use crate::*; use std::path::PathBuf; /// Configuration #[derive(Default, Debug)] pub struct Configuration { /// Path of configuration entrypoint pub path: PathBuf, /// Name of configuration pub name: Option>, /// Description of configuration pub info: Option>, /// View definition pub view: TokenIter<'static>, // Input keymap pub keys: InputMap<'static, Tek, TekCommand, TuiIn, TokenIter<'static>> } impl Configuration { pub fn new (path: &impl AsRef, _watch: bool) -> Usually { let text = read_and_leak(path.as_ref())?; let [name, info, view, keys] = Self::parse(TokenIter::from(text))?; Ok(Self { path: path.as_ref().into(), info: info.map(Self::parse_info).flatten(), name: name.map(Self::parse_name).flatten(), view: Self::parse_view(view)?, keys: Self::parse_keys(&path, keys)?, }) } fn parse (iter: TokenIter) -> Usually<[Option;4]> { let mut name: Option = None; let mut info: Option = None; let mut view: Option = None; let mut keys: Option = None; for token in iter { match token.value { Value::Exp(_, mut exp) => { let next = exp.next(); match next { Some(Token { value: Value::Key(sym), .. }) => match sym { "name" => name = Some(exp), "info" => info = Some(exp), "keys" => keys = Some(exp), "view" => view = Some(exp), _ => return Err( format!("(e3) unexpected symbol {sym:?}").into() ) }, _ => return Err( format!("(e2) unexpected exp {:?}", next.map(|x|x.value)).into() ) } }, t => return Err( format!("(e1) unexpected token {token:?}").into() ) }; } Ok([name, info, view, keys]) } fn parse_info (mut iter: TokenIter) -> Option> { iter.next().and_then(|x|if let Value::Str(x) = x.value { Some(x.into()) } else { None }) } fn parse_name (mut iter: TokenIter) -> Option> { iter.next().and_then(|x|if let Value::Str(x) = x.value { Some(x.into()) } else { None }) } fn parse_view (iter: Option) -> Usually { if let Some(view) = iter { Ok(view) } else { Err(format!("missing view definition").into()) } } fn parse_keys (base: &impl AsRef, iter: Option>) -> Usually>> { if iter.is_none() { return Err(format!("missing keys definition").into()) } let mut keys = iter.unwrap(); let mut map = InputMap::default(); while let Some(token) = keys.next() { if let Value::Exp(_, mut exp) = token.value { let next = exp.next(); if let Some(Token { value: Value::Key(sym), .. }) = next { match sym { "layer" => { let next = exp.next(); if let Some(Token { value: Value::Str(path), .. }) = next { let path = base.as_ref().parent().unwrap().join(unquote(path)); if !std::fs::exists(&path)? { return Err(format!("(e5) not found: {path:?}").into()) } map.add_layer(read_and_leak(path)?.into()); } else { return Err(format!("(e4) unexpected non-string {next:?}").into()) } }, "layer-if" => { let mut cond = None; let next = exp.next(); if let Some(Token { value: Value::Sym(sym), .. }) = next { cond = Some(leak(sym)); } else { return Err(format!("(e4) unexpected non-symbol {next:?}").into()) }; let next = exp.next(); if let Some(Token { value: Value::Str(path), .. }) = next { let path = base.as_ref().parent().unwrap().join(unquote(path)); if !std::fs::exists(&path)? { return Err(format!("(e5) not found: {path:?}").into()) } print!("{path:?}..."); let keys = read_and_leak(path)?.into(); println!("ok"); let cond = cond.unwrap(); map.add_layer_if( Box::new(|state|{ Context::get(state, &Value::Sym(cond)).unwrap_or(false) }), keys ); } else { return Err(format!("(e4) unexpected non-symbol {next:?}").into()) } }, _ => return Err(format!("(e3) unexpected symbol {sym:?}").into()) } } else { return Err(format!("(e2) unexpected exp {:?}", next.map(|x|x.value)).into()) } } else { return Err(format!("(e1) unexpected token {token:?}").into()) } } Ok(map) } } fn read_and_leak (path: impl AsRef) -> Usually<&'static str> { Ok(leak(String::from_utf8(std::fs::read(path.as_ref())?)?)) } fn leak (x: impl AsRef) -> &'static str { Box::leak(x.as_ref().into()) } fn unquote (x: &str) -> &str { let mut chars = x.chars(); chars.next(); //chars.next_back(); chars.as_str() } macro_rules! default_config { ($path:literal) => { ($path, include_str!($path)) }; } pub const DEFAULT_CONFIGS: &'static [(&'static str, &'static str)] = &[ default_config!("../../../config/config_arranger.edn"), default_config!("../../../config/config_groovebox.edn"), default_config!("../../../config/config_sampler.edn"), default_config!("../../../config/config_sequencer.edn"), default_config!("../../../config/config_transport.edn"), default_config!("../../../config/keys_arranger.edn"), default_config!("../../../config/keys_clip.edn"), default_config!("../../../config/keys_clip_length.edn"), default_config!("../../../config/keys_clip_rename.edn"), default_config!("../../../config/keys_clock.edn"), default_config!("../../../config/keys_editor.edn"), default_config!("../../../config/keys_global.edn"), default_config!("../../../config/keys_groovebox.edn"), default_config!("../../../config/keys_mix.edn"), default_config!("../../../config/keys_pool.edn"), default_config!("../../../config/keys_pool_file.edn"), default_config!("../../../config/keys_sampler.edn"), default_config!("../../../config/keys_scene.edn"), default_config!("../../../config/keys_sequencer.edn"), default_config!("../../../config/keys_track.edn"), ];