mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
198 lines
7.7 KiB
Rust
198 lines
7.7 KiB
Rust
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<Arc<str>>,
|
|
/// Description of configuration
|
|
pub info: Option<Arc<str>>,
|
|
/// 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<Path>, _watch: bool) -> Usually<Self> {
|
|
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<TokenIter>;4]> {
|
|
let mut name: Option<TokenIter> = None;
|
|
let mut info: Option<TokenIter> = None;
|
|
let mut view: Option<TokenIter> = None;
|
|
let mut keys: Option<TokenIter> = 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<Arc<str>> {
|
|
iter.next().and_then(|x|if let Value::Str(x) = x.value {
|
|
Some(x.into())
|
|
} else {
|
|
None
|
|
})
|
|
}
|
|
|
|
fn parse_name (mut iter: TokenIter) -> Option<Arc<str>> {
|
|
iter.next().and_then(|x|if let Value::Str(x) = x.value {
|
|
Some(x.into())
|
|
} else {
|
|
None
|
|
})
|
|
}
|
|
|
|
fn parse_view (iter: Option<TokenIter>) -> Usually<TokenIter> {
|
|
if let Some(view) = iter {
|
|
Ok(view)
|
|
} else {
|
|
Err(format!("missing view definition").into())
|
|
}
|
|
}
|
|
|
|
fn parse_keys (base: &impl AsRef<Path>, iter: Option<TokenIter<'static>>)
|
|
-> Usually<InputMap<'static, Tek, TekCommand, TuiIn, TokenIter<'static>>>
|
|
{
|
|
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<Path>) -> Usually<&'static str> {
|
|
Ok(leak(String::from_utf8(std::fs::read(path.as_ref())?)?))
|
|
}
|
|
|
|
fn leak (x: impl AsRef<str>) -> &'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"),
|
|
];
|