mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2026-07-17 15:56:57 +02:00
fixes and refactors
- use macros for the evals - move some space stuff into submodules - partial update to doctests
This commit is contained in:
parent
b44dc02f33
commit
e074712459
9 changed files with 464 additions and 380 deletions
211
src/eval.rs
211
src/eval.rs
|
|
@ -1,10 +1,65 @@
|
|||
use crate::{*, term::*, draw::*, ratatui::prelude::*};
|
||||
use dizzle::*;
|
||||
use crate::{*, term::*, draw::*, space::*, lang::*, ratatui::prelude::*};
|
||||
|
||||
/// Some layout operations exist in XY, X, and Y variants that take 3 or 2 arguments.
|
||||
/// Their handling in [eval_view] is uniform and goes like this:
|
||||
macro_rules! eval_xy ((
|
||||
$name:expr, $expr:expr, $head:expr, $output:ident, $state:ident,
|
||||
$variant:expr, $arg0: ident, $arg1: ident, $arg2: ident,
|
||||
$xy:ident, $x:ident, $y:ident
|
||||
) => {{
|
||||
let variant = $variant;
|
||||
let cb = thunk(move|output: &mut O|$state.interpret(output, &match variant {
|
||||
Some("x") | Some("y") => $arg1,
|
||||
Some("xy") | None => $arg2,
|
||||
_ => panic!("{}: unsupported axis {variant:?}; try /x, /y, /xy", $name)
|
||||
}));
|
||||
match variant {
|
||||
// XY variant (can be omitted)
|
||||
Some("xy") | None => xy_push(
|
||||
$state.namespace($arg0?)?.unwrap(),
|
||||
$state.namespace($arg1?)?.unwrap(),
|
||||
cb
|
||||
).draw($output),
|
||||
// X variant
|
||||
Some("x") => x_push(
|
||||
$state.namespace($arg0?)?.unwrap(),
|
||||
cb
|
||||
).draw($output),
|
||||
// Y variant
|
||||
Some("y") => y_push(
|
||||
$state.namespace($arg0?)?.unwrap(),
|
||||
cb
|
||||
).draw($output),
|
||||
// Other namespace members are invalid
|
||||
frag => {
|
||||
let name = $name;
|
||||
let expr = $expr;
|
||||
let head = $head;
|
||||
unimplemented!(
|
||||
"{name}/{frag:?} ({expr:?}) ({head:?}) ({:?})",
|
||||
head.src()?.unwrap_or_default().split("/").next()
|
||||
)
|
||||
}
|
||||
}
|
||||
}});
|
||||
|
||||
/// Some layout operations exist in multiple variants that take a single argument.
|
||||
/// Their handling in [eval_view] is uniform and goes like this:
|
||||
macro_rules! eval_enum ((
|
||||
$name:literal, $output:ident, $state:ident, $value:expr, $arg0: ident, $Enum:ident {
|
||||
$($v:literal => $V:ident),* $(,)?
|
||||
}
|
||||
) => {{
|
||||
match $value {
|
||||
$(Some($v) => $Enum::$V,)*
|
||||
frag => unimplemented!("{}/{frag:?}", $name)
|
||||
}
|
||||
}});
|
||||
|
||||
/// Interpret layout operation.
|
||||
///
|
||||
/// ```
|
||||
/// # use tengri::*;
|
||||
/// # use tengri::{*, space::*};
|
||||
/// struct Target { xywh: XYWH<u16> /*platform-specific*/}
|
||||
/// impl tengri::Out for Target {
|
||||
/// type Unit = u16;
|
||||
|
|
@ -27,137 +82,87 @@ use dizzle::*;
|
|||
/// // TODO test all
|
||||
/// # Ok(()) }
|
||||
/// ```
|
||||
#[cfg(feature = "dsl")] pub fn eval_view <'a, O: Screen + 'a, S> (
|
||||
pub fn eval_view <'a, O: Screen + 'a, S> (
|
||||
state: &S, output: &mut O, expr: &'a impl Expression
|
||||
) -> Usually<bool> where
|
||||
S: Interpret<O, ()>
|
||||
+ for<'b>Namespace<'b, bool>
|
||||
+ for<'b>Namespace<'b, O::Unit>
|
||||
S: Interpret<O, XYWH<O::Unit>>
|
||||
+ for<'b> Namespace<'b, bool>
|
||||
+ for<'b> Namespace<'b, O::Unit>
|
||||
+ for<'b> Namespace<'b, Option<O::Unit>>
|
||||
{
|
||||
// First element of expression is used for dispatch.
|
||||
// Dispatch is proto-namespaced using separator character
|
||||
// First element of expression is name of the operation.
|
||||
// These are quasi-namespaced using the separator character, `/`.
|
||||
let head = expr.head()?;
|
||||
let mut frags = head.src()?.unwrap_or_default().split("/");
|
||||
|
||||
// The rest of the tokens in the expr are arguments.
|
||||
// Their meanings depend on the dispatched operation
|
||||
// Here we just reference them, so that they are in scope.
|
||||
// Dereferencing them happens in the dispatch branch.
|
||||
let args = expr.tail();
|
||||
let arg0 = args.head();
|
||||
let tail0 = args.tail();
|
||||
let arg1 = tail0.head();
|
||||
let tail1 = tail0.tail();
|
||||
let arg2 = tail1.head();
|
||||
// And we also have to do the above binding dance
|
||||
// so that the Perhaps<token>s remain in scope.
|
||||
|
||||
// First `frags.next()` calls returns the namespace.
|
||||
match frags.next() {
|
||||
|
||||
Some("when") => output.place(&when(
|
||||
Some("when") => when(
|
||||
state.namespace(arg0?)?.unwrap(),
|
||||
move|output: &mut O|state.interpret(output, &arg1)
|
||||
)),
|
||||
thunk(move|output: &mut O|state.interpret(output, &arg1))
|
||||
).draw(output),
|
||||
|
||||
Some("either") => output.place(&either(
|
||||
Some("either") => either(
|
||||
state.namespace(arg0?)?.unwrap(),
|
||||
move|output: &mut O|state.interpret(output, &arg1),
|
||||
move|output: &mut O|state.interpret(output, &arg2),
|
||||
)),
|
||||
thunk(move|output: &mut O|state.interpret(output, &arg1)),
|
||||
thunk(move|output: &mut O|state.interpret(output, &arg2)),
|
||||
).draw(output),
|
||||
|
||||
Some("bsp") => output.place(&{
|
||||
let a = move|output: &mut O|state.interpret(output, &arg0);
|
||||
let b = move|output: &mut O|state.interpret(output, &arg1);
|
||||
bsp(match frags.next() {
|
||||
Some("n") => Alignment::N,
|
||||
Some("s") => Alignment::S,
|
||||
Some("e") => Alignment::E,
|
||||
Some("w") => Alignment::W,
|
||||
Some("a") => Alignment::A,
|
||||
Some("b") => Alignment::B,
|
||||
frag => unimplemented!("bsp/{frag:?}")
|
||||
}, a, b)
|
||||
}),
|
||||
|
||||
Some("align") => output.place(&{
|
||||
let a = move|output: &mut O|state.interpret(output, &arg0).unwrap();
|
||||
align(match frags.next() {
|
||||
Some("c") => Alignment::Center,
|
||||
Some("n") => Alignment::N,
|
||||
Some("s") => Alignment::S,
|
||||
Some("e") => Alignment::E,
|
||||
Some("w") => Alignment::W,
|
||||
Some("x") => Alignment::X,
|
||||
Some("y") => Alignment::Y,
|
||||
frag => unimplemented!("align/{frag:?}")
|
||||
}, a)
|
||||
}),
|
||||
|
||||
Some("fill") => output.place(&{
|
||||
let a = move|output: &mut O|state.interpret(output, &arg0).unwrap();
|
||||
match frags.next() {
|
||||
Some("xy") | None => fill_wh(a),
|
||||
Some("x") => fill_w(a),
|
||||
Some("y") => fill_h(a),
|
||||
frag => unimplemented!("fill/{frag:?}")
|
||||
// Second `frags.next()` calls returns the namespace member.
|
||||
Some("bsp") => eval_enum!(
|
||||
"bsp", output, state, frags.next(), arg0, Split {
|
||||
"n" => North, "s" => South, "e" => East, "w" => West, "a" => Above, "b" => Below
|
||||
}
|
||||
}),
|
||||
).half(
|
||||
thunk(move|output: &mut O|state.interpret(output, &arg0)),
|
||||
thunk(move|output: &mut O|state.interpret(output, &arg1)),
|
||||
).draw(output),
|
||||
|
||||
Some("exact") => output.place(&{
|
||||
let axis = frags.next();
|
||||
let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("exact: unsupported axis {axis:?}") };
|
||||
let cb = move|output: &mut O|state.interpret(output, &arg).unwrap();
|
||||
match axis {
|
||||
Some("xy") | None => exact_wh(state.namespace(arg0?)?.unwrap(), state.namespace(arg1?)?.unwrap(), cb),
|
||||
Some("x") => exact_w(state.namespace(arg0?)?.unwrap(), cb),
|
||||
Some("y") => exact_h(state.namespace(arg0?)?.unwrap(), cb),
|
||||
frag => unimplemented!("exact/{frag:?} ({expr:?}) ({head:?}) ({:?})",
|
||||
head.src()?.unwrap_or_default().split("/").next())
|
||||
Some("align") => eval_enum!(
|
||||
"align", output, state, frags.next(), arg0, Origin {
|
||||
"c" => C, "n" => N, "s" => S, "e" => E, "w" => W, "x" => X, "y" => Y
|
||||
}
|
||||
}),
|
||||
).align(
|
||||
thunk(move|output: &mut O|state.interpret(output, &arg0))
|
||||
).draw(output),
|
||||
|
||||
Some("min") => output.place(&{
|
||||
let axis = frags.next();
|
||||
let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("min: unsupported axis {axis:?}") };
|
||||
let cb = move|output: &mut O|state.interpret(output, &arg).unwrap();
|
||||
match axis {
|
||||
Some("xy") | None => min_wh(state.namespace(arg0?)?.unwrap(), state.namespace(arg1?)?.unwrap(), cb),
|
||||
Some("x") => min_w(state.namespace(arg0?)?.unwrap(), cb),
|
||||
Some("y") => min_h(state.namespace(arg0?)?.unwrap(), cb),
|
||||
frag => unimplemented!("min/{frag:?}")
|
||||
}
|
||||
}),
|
||||
|
||||
Some("max") => output.place(&{
|
||||
let axis = frags.next();
|
||||
let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("max: unsupported axis {axis:?}") };
|
||||
let cb = move|output: &mut O|state.interpret(output, &arg).unwrap();
|
||||
match axis {
|
||||
Some("xy") | None => max_wh(state.namespace(arg0?)?.unwrap(), state.namespace(arg1?)?.unwrap(), cb),
|
||||
Some("x") => max_w(state.namespace(arg0?)?.unwrap(), cb),
|
||||
Some("y") => max_h(state.namespace(arg0?)?.unwrap(), cb),
|
||||
frag => unimplemented!("max/{frag:?}")
|
||||
}
|
||||
}),
|
||||
|
||||
Some("push") => output.place(&{
|
||||
let axis = frags.next();
|
||||
let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("push: unsupported axis {axis:?}") };
|
||||
let cb = move|output: &mut O|state.interpret(output, &arg);
|
||||
match axis {
|
||||
Some("xy") | None => push_xy(state.namespace(arg0?)?.unwrap(), state.namespace(arg1?)?.unwrap(), cb),
|
||||
Some("x") => push_x(state.namespace(arg0?)?.unwrap(), cb),
|
||||
Some("y") => push_y(state.namespace(arg0?)?.unwrap(), cb),
|
||||
frag => unimplemented!("push/{frag:?}")
|
||||
}
|
||||
}),
|
||||
Some("exact") => eval_xy!(
|
||||
"exact", expr, head, output, state, frags.next(), arg0, arg1, arg2, wh_exact, w_exact, h_exact
|
||||
),
|
||||
Some("min") => eval_xy!(
|
||||
"min", expr, head, output, state, frags.next(), arg0, arg1, arg2, wh_min, w_min, h_min
|
||||
),
|
||||
Some("max") => eval_xy!(
|
||||
"max", expr, head, output, state, frags.next(), arg0, arg1, arg2, wh_max, w_max, h_max
|
||||
),
|
||||
Some("push") => eval_xy!(
|
||||
"push", expr, head, output, state, frags.next(), arg0, arg1, arg2, xy_push, x_push, y_push
|
||||
),
|
||||
|
||||
_ => return Ok(false)
|
||||
|
||||
};
|
||||
}?;
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
|
||||
/// Interpret TUI-specific layout operation.
|
||||
///
|
||||
/// ```
|
||||
/// use tengri::{Namespace, Interpret, Tui, ratatui::prelude::Color};
|
||||
/// use tengri::{lang::{Namespace, Interpret}, term::Tui, ratatui::prelude::Color};
|
||||
///
|
||||
/// struct State;
|
||||
/// impl<'b> Namespace<'b, bool> for State {}
|
||||
|
|
@ -189,8 +194,6 @@ pub fn eval_view_tui <'a, S> (
|
|||
let arg0 = args.head();
|
||||
let tail0 = args.tail();
|
||||
let arg1 = tail0.head();
|
||||
let tail1 = tail0.tail();
|
||||
let arg2 = tail1.head();
|
||||
match frags.next() {
|
||||
|
||||
Some("text") => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue