fix config and compilation; add arg! macro

This commit is contained in:
i do not exist 2026-08-30 22:30:30 +03:00
parent e29f8de174
commit 1082f62696
2 changed files with 70 additions and 85 deletions

View file

@ -23,7 +23,7 @@ pub fn config_init <C: AsRef<Config>> (config: C) -> Usually<C> {
pub fn config_load <C: AsRef<Config>, L: Language> (config: C, src: L) -> Usually<C> { pub fn config_load <C: AsRef<Config>, L: Language> (config: C, src: L) -> Usually<C> {
config.as_ref().clear(); config.as_ref().clear();
config.as_ref().stamp.store(quanta::Clock::new().raw(), Relaxed); config.as_ref().stamp.store(quanta::Clock::new().raw(), Relaxed);
src.each(config, |c, s|config_load_item(c, s)) src.each(config, |c, s|config_load_item(c, s.trim()))
} }
pub fn config_load_item <C: AsRef<Config>, L: Language> (config: C, src: L) -> Usually<C> { pub fn config_load_item <C: AsRef<Config>, L: Language> (config: C, src: L) -> Usually<C> {
@ -263,9 +263,9 @@ impl View<Tui, App> {
Usually<Arc<Box<dyn Fn(&App, &mut Tui)->Drawn<u16> + Send + Sync>>> Usually<Arc<Box<dyn Fn(&App, &mut Tui)->Drawn<u16> + Send + Sync>>>
{ {
let source = source.as_ref(); let source = source.as_ref();
let layer = if let Some(expr) = source.expr()? { let layer = if let Ok(Some(expr)) = source.expr() {
Self::compile_expr(expr.into())? Self::compile_expr(expr.into())?
} else if let Some(word) = source.word()? { } else if let Ok(Some(word)) = source.word() {
Self::compile_word(word.into())? Self::compile_word(word.into())?
} else { } else {
return Err(format!("not word/expr:\n{source:?}").into()) return Err(format!("not word/expr:\n{source:?}").into())
@ -276,15 +276,24 @@ impl View<Tui, App> {
fn compile_expr (expr: Arc<str>) -> fn compile_expr (expr: Arc<str>) ->
Usually<Arc<Box<dyn Fn(&App, &mut Tui)->Drawn<u16> + Send + Sync>>> Usually<Arc<Box<dyn Fn(&App, &mut Tui)->Drawn<u16> + Send + Sync>>>
{ {
macro_rules! arg {
($src:expr, $head:expr, $index:expr, $name:expr) => {
$src.nth($index)?
.ok_or_else(||Box::<dyn Error>::from(format!(
"{}: no arg #{} ({}) in {}", $head, $index, $name, $src
)))?
};
}
Ok(Arc::new(if let Some(head) = expr.head()? && let Some(ns) = head.split('/').next() { Ok(Arc::new(if let Some(head) = expr.head()? && let Some(ns) = head.split('/').next() {
match ns { match ns {
"when" => { "when" => {
let cond = Arc::from(expr.nth(1)?.ok_or_else(||Box::<dyn Error>::from("when: no arg0: condition"))?); let cond = Arc::from(arg!(expr, head, 1, "condition"));
let cond = move|state: &App|state.namespace(&cond)?.ok_or_else(||Box::<dyn Error>::from("when: no condition value")); let cond = move|state: &App|state.namespace(&cond)?.ok_or_else(||Box::<dyn Error>::from("when: no condition value"));
let thunk = expr.nth(2)?.ok_or_else(||Box::<dyn Error>::from("when: no arg1: content"))?; let thunk = Self::compile(arg!(expr, head, 2, "content"))?;
let thunk = Self::compile(thunk)?;
Self::boxed(move|state, screen|{ Self::boxed(move|state, screen|{
when( when(
cond(state)?, cond(state)?,
@ -294,12 +303,10 @@ impl View<Tui, App> {
}, },
"either" => { "either" => {
let cond = Arc::from(expr.nth(1)?.ok_or_else(||Box::<dyn Error>::from("either: no arg0: condition"))?); let cond = Arc::from(arg!(expr, head, 1, "condition"));
let cond = move|state: &App|state.namespace(&cond)?.ok_or_else(||Box::<dyn Error>::from("either: no condition value")); let cond = move|state: &App|state.namespace(&cond)?.ok_or_else(||Box::<dyn Error>::from("either: no condition value"));
let a = expr.nth(2)?.ok_or_else(||Box::<dyn Error>::from("either: no arg1: content"))?; let a = Self::compile(arg!(expr, head, 2, "content A"))?;
let a = Self::compile(a)?; let b = Self::compile(arg!(expr, head, 3, "content B"))?;
let b = expr.nth(3)?.ok_or_else(||Box::<dyn Error>::from("either: no arg2: content"))?;
let b = Self::compile(b)?;
Self::boxed(move|state, screen|{ Self::boxed(move|state, screen|{
either( either(
cond(state)?, cond(state)?,
@ -309,7 +316,7 @@ impl View<Tui, App> {
}) })
}, },
"bsp" | "split" => { "bsp" | "split" | "stack" => {
let split = head.split('/').skip(1).next(); let split = head.split('/').skip(1).next();
let split = match split { let split = match split {
Some("n") => Split::North, Some("n") => Split::North,
@ -320,8 +327,8 @@ impl View<Tui, App> {
Some("b") => Split::Below, Some("b") => Split::Below,
_ => return Err(format!("invalid split: {split:?}").into()) _ => return Err(format!("invalid split: {split:?}").into())
}; };
let a = Self::compile(expr.nth(1)?.ok_or_else(||Box::<dyn Error>::from("either: no arg0: content"))?)?; let a = Self::compile(arg!(expr, head, 1, "content A"))?;
let b = Self::compile(expr.nth(2)?.ok_or_else(||Box::<dyn Error>::from("either: no arg1: content"))?)?; let b = Self::compile(arg!(expr, head, 2, "content B"))?;
Self::boxed(move|state, screen|{ Self::boxed(move|state, screen|{
split.stack( split.stack(
draw(|screen|a(state, screen)), draw(|screen|a(state, screen)),
@ -346,8 +353,7 @@ impl View<Tui, App> {
Some("y") => Azimuth::Y, Some("y") => Azimuth::Y,
_ => return Err(format!("invalid azimuth: {azimuth:?}").into()) _ => return Err(format!("invalid azimuth: {azimuth:?}").into())
}; };
let thunk = Self::compile(expr.nth(2)? let thunk = Self::compile(arg!(expr, head, 1, "content"))?;
.ok_or_else(||Box::<dyn Error>::from("either: no arg1: content"))?)?;
Self::boxed(move|state, screen|{ Self::boxed(move|state, screen|{
Align( Align(
Some(azimuth), Some(azimuth),
@ -356,9 +362,8 @@ impl View<Tui, App> {
}) })
}, },
"full" => { "full" | "fill" => {
let thunk = Self::compile(expr.nth(2)? let thunk = Self::compile(arg!(expr, head, 1, "content"))?;
.ok_or_else(||Box::<dyn Error>::from("either: no arg1: content"))?)?;
match head.split('/').skip(1).next() { match head.split('/').skip(1).next() {
Some("w") | Some("x") => Self::boxed(move|state, screen|{ Some("w") | Some("x") => Self::boxed(move|state, screen|{
Full::W(draw(|screen|thunk(state, screen))).draw(screen) Full::W(draw(|screen|thunk(state, screen))).draw(screen)
@ -366,83 +371,56 @@ impl View<Tui, App> {
Some("h") | Some("y") => Self::boxed(move|state, screen|{ Some("h") | Some("y") => Self::boxed(move|state, screen|{
Full::H(draw(|screen|thunk(state, screen))).draw(screen) Full::H(draw(|screen|thunk(state, screen))).draw(screen)
}), }),
Some("wh") | Some("xy") => Self::boxed(move|state, screen|{ Some("wh") | Some("xy") | None => Self::boxed(move|state, screen|{
Full::WH(draw(|screen|thunk(state, screen))).draw(screen) Full::WH(draw(|screen|thunk(state, screen))).draw(screen)
}), }),
_ => unreachable!() _ => unreachable!()
} }
}, },
"exact" | "min" | "max" | "push" | "pull" => { "exact" | "min" | "max" | "push" | "pull" | "pad" => {
match head.split('/').skip(1).next() { match head.split('/').skip(1).next() {
Some("w") | Some("x") => { Some("w") | Some("x") => {
let value = Arc::from(expr.nth(1)?.ok_or_else(||Box::<dyn Error>::from("{}: no arg1: value"))?); let value = Arc::from(arg!(expr, head, 1, "value"));
let value = move|state: &App|state.namespace(&value); let value = move|state: &App|state.namespace(&value);
let thunk = Self::compile(expr.nth(2)?.ok_or_else(||Box::<dyn Error>::from("either: no arg2: content"))?)?; let thunk = Self::compile(arg!(expr, head, 2, "content"))?;
match ns { match ns {
"exact" => Self::boxed(move|state, screen|Exact::W( "exact" => Self::boxed(move|state, screen|Exact::W(draw(|screen|thunk(state, screen)), value(state)?).draw(screen)),
draw(|screen|thunk(state, screen)), value(state)? "push" => Self::boxed(move|state, screen|Push::X(draw(|screen|thunk(state, screen)), value(state)?).draw(screen)),
).draw(screen)), "pull" => Self::boxed(move|state, screen|Pull::X(draw(|screen|thunk(state, screen)), value(state)?).draw(screen)),
"push" => Self::boxed(move|state, screen|Push::X( "pad" => Self::boxed(move|state, screen|Pad::X(draw(|screen|thunk(state, screen)), value(state)?).draw(screen)),
draw(|screen|thunk(state, screen)), value(state)? "min" => Self::boxed(move|state, screen|Min::W(draw(|screen|thunk(state, screen)), value(state)?).draw(screen)),
).draw(screen)), "max" => Self::boxed(move|state, screen|Max::W(draw(|screen|thunk(state, screen)), value(state)?).draw(screen)),
"pull" => Self::boxed(move|state, screen|Pull::X(
draw(|screen|thunk(state, screen)), value(state)?
).draw(screen)),
"min" => Self::boxed(move|state, screen|Min::W(
draw(|screen|thunk(state, screen)), value(state)?
).draw(screen)),
"max" => Self::boxed(move|state, screen|Max::W(
draw(|screen|thunk(state, screen)), value(state)?
).draw(screen)),
_ => unreachable!() _ => unreachable!()
} }
}, },
Some("h") | Some("y") => { Some("h") | Some("y") => {
let value = Arc::from(expr.nth(1)?.ok_or_else(||Box::<dyn Error>::from("{}: no arg1: value"))?); let value = Arc::from(arg!(expr, head, 1, "value"));
let value = move|state: &App|state.namespace(&value); let value = move|state: &App|state.namespace(&value);
let thunk = Self::compile(expr.nth(2)?.ok_or_else(||Box::<dyn Error>::from("either: no arg2: content"))?)?; let thunk = Self::compile(arg!(expr, head, 2, "content"))?;
match ns { match ns {
"exact" => Self::boxed(move|state, screen|Exact::H( "exact" => Self::boxed(move|state, screen|Exact::H(draw(|screen|thunk(state, screen)), value(state)?).draw(screen)),
draw(|screen|thunk(state, screen)), value(state)? "push" => Self::boxed(move|state, screen|Push::Y(draw(|screen|thunk(state, screen)), value(state)?).draw(screen)),
).draw(screen)), "pull" => Self::boxed(move|state, screen|Pull::Y(draw(|screen|thunk(state, screen)), value(state)?).draw(screen)),
"push" => Self::boxed(move|state, screen|Push::Y( "pad" => Self::boxed(move|state, screen|Pad::Y(draw(|screen|thunk(state, screen)), value(state)?).draw(screen)),
draw(|screen|thunk(state, screen)), value(state)? "min" => Self::boxed(move|state, screen|Min::H(draw(|screen|thunk(state, screen)), value(state)?).draw(screen)),
).draw(screen)), "max" => Self::boxed(move|state, screen|Max::H(draw(|screen|thunk(state, screen)), value(state)?).draw(screen)),
"pull" => Self::boxed(move|state, screen|Pull::Y(
draw(|screen|thunk(state, screen)), value(state)?
).draw(screen)),
"min" => Self::boxed(move|state, screen|Min::H(
draw(|screen|thunk(state, screen)), value(state)?
).draw(screen)),
"max" => Self::boxed(move|state, screen|Max::H(
draw(|screen|thunk(state, screen)), value(state)?
).draw(screen)),
_ => unreachable!() _ => unreachable!()
} }
}, },
Some("wh") | Some("xy") => { Some("wh") | Some("xy") | None => {
let value1 = Arc::from(expr.nth(1)?.ok_or_else(||Box::<dyn Error>::from("{}: no arg1: value"))?); let value1 = Arc::from(arg!(expr, head, 1, "value"));
let value1 = move|state: &App|state.namespace(&value1); let value1 = move|state: &App|state.namespace(&value1);
let value2 = Arc::from(expr.nth(2)?.ok_or_else(||Box::<dyn Error>::from("{}: no arg2: value"))?); let value2 = Arc::from(arg!(expr, head, 2, "value"));
let value2 = move|state: &App|state.namespace(&value2); let value2 = move|state: &App|state.namespace(&value2);
let thunk = Self::compile(expr.nth(3)?.ok_or_else(||Box::<dyn Error>::from("either: no arg3: content"))?)?; let thunk = Self::compile(arg!(expr, head, 3, "content"))?;
match ns { match ns {
"exact" => Self::boxed(move|state, screen|Exact::WH( "exact" => Self::boxed(move|state, screen|Exact::WH(draw(|screen|thunk(state, screen)), value1(state)?, value2(state)?).draw(screen)),
draw(|screen|thunk(state, screen)), value1(state)?, value2(state)? "push" => Self::boxed(move|state, screen|Push::XY(draw(|screen|thunk(state, screen)), value1(state)?, value2(state)?).draw(screen)),
).draw(screen)), "pull" => Self::boxed(move|state, screen|Pull::XY(draw(|screen|thunk(state, screen)), value1(state)?, value2(state)?).draw(screen)),
"push" => Self::boxed(move|state, screen|Push::XY( "pad" => Self::boxed(move|state, screen|Pad::XY(draw(|screen|thunk(state, screen)), value1(state)?, value2(state)?).draw(screen)),
draw(|screen|thunk(state, screen)), value1(state)?, value2(state)? "min" => Self::boxed(move|state, screen|Min::WH(draw(|screen|thunk(state, screen)), value1(state)?, value2(state)?).draw(screen)),
).draw(screen)), "max" => Self::boxed(move|state, screen|Max::WH(draw(|screen|thunk(state, screen)), value1(state)?, value2(state)?).draw(screen)),
"pull" => Self::boxed(move|state, screen|Pull::XY(
draw(|screen|thunk(state, screen)), value1(state)?, value2(state)?
).draw(screen)),
"min" => Self::boxed(move|state, screen|Min::WH(
draw(|screen|thunk(state, screen)), value1(state)?, value2(state)?
).draw(screen)),
"max" => Self::boxed(move|state, screen|Max::WH(
draw(|screen|thunk(state, screen)), value1(state)?, value2(state)?
).draw(screen)),
_ => unreachable!() _ => unreachable!()
} }
}, },
@ -451,9 +429,9 @@ impl View<Tui, App> {
}, },
"fg" | "bg" => { "fg" | "bg" => {
let color = Arc::from(expr.nth(1)?.ok_or_else(||Box::<dyn Error>::from("{}: no arg1: color"))?); let color = Arc::from(arg!(expr, head, 1, "color"));
let color = move|state: &App|state.namespace(&color); let color = move|state: &App|state.namespace(&color);
let thunk = Self::compile(expr.nth(2)?.ok_or_else(||Box::<dyn Error>::from("either: no arg2: thunk"))?)?; let thunk = Self::compile(arg!(expr, head, 2, "content"))?;
match ns { match ns {
"fg" => Self::boxed(move|state, screen|fg( "fg" => Self::boxed(move|state, screen|fg(
color(state)?.unwrap_or_default(), draw(|screen|thunk(state, screen)) color(state)?.unwrap_or_default(), draw(|screen|thunk(state, screen))

View file

@ -1,8 +1,8 @@
(view :logo (text tek)) (view :logo (text tek))
(view :browse (bsp/s (view :browse (bsp/s
(pad 3 1 :browse-title) (pad/xy 3 1 :browse-title)
(fg (g 96) browser)) (fg (g 96) browser)))
(mode :transport (mode :transport
(name Transport) (name Transport)
@ -82,22 +82,29 @@
(mode browse (keys :browse)) (mode browse (keys :browse))
(mode rename (keys :pool/rename)) (mode rename (keys :pool/rename))
(mode length (keys :pool/length)) (mode length (keys :pool/length))
(bsp/s (exact/h 1 :transport) (view
(bsp/n (exact/h 1 :status) (bsp/s (exact/h 1 :transport)
(fill (bsp/a (fill/xy (align/e :pool)) :editor))))) (bsp/n (exact/h 1 :status)
(fill/xy (bsp/a (fill/xy (align/e :pool))
:editor))))))
(mode :sampler (name Sampler) (info Sample player.) (mode :sampler (name Sampler) (info Sample player.)
(keys :sampler/directions :sampler/record :sampler/play) (keys :sampler/directions :sampler/record :sampler/play)
(bsp/s (exact/h 1 :transport) (view
(bsp/n (exact/h 1 :status) (bsp/s (exact/h 1 :transport)
(fill :samples/grid)))) (bsp/n (exact/h 1 :status)
(fill/xy :samples/grid)))))
(mode :groovebox (name Groovebox) (info Sequencer with sampler.) (mode :groovebox (name Groovebox) (info Sequencer with sampler.)
(keys :clock :editor :sampler :global) (keys :clock :editor :sampler :global)
(mode browse (keys :browse)) (mode browse (keys :browse))
(mode rename (keys :pool-rename)) (mode rename (keys :pool-rename))
(mode length (keys :pool-length)) (mode length (keys :pool-length))
(bsp/w :meters/output (bsp/e :meters/input (bsp/w :groove/meta :groove/editor)))) (view
(bsp/w :meters/output
(bsp/e :meters/input
(bsp/w :groove/meta
:groove/editor)))))
(view :groove/meta (fill/y (align/n (stack/s :midi-ins/status :midi-outs/status :audio-ins/status :audio-outs/status :pool)))) (view :groove/meta (fill/y (align/n (stack/s :midi-ins/status :midi-outs/status :audio-ins/status :audio-outs/status :pool))))