mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2026-07-17 15:56:57 +02:00
This commit is contained in:
parent
4e8d58d793
commit
b0fbe3c173
18 changed files with 1724 additions and 1808 deletions
220
src/eval.rs
Normal file
220
src/eval.rs
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
use crate::*;
|
||||
|
||||
/// Interpret layout operation.
|
||||
///
|
||||
/// ```
|
||||
/// # use tengri::*;
|
||||
/// struct Target { xywh: XYWH<u16> /*platform-specific*/}
|
||||
/// impl tengri::Out for Target {
|
||||
/// type Unit = u16;
|
||||
/// fn area (&self) -> XYWH<u16> { self.xywh }
|
||||
/// fn area_mut (&mut self) -> &mut XYWH<u16> { &mut self.xywh }
|
||||
/// fn show <'t, T: Draw<Self> + ?Sized> (&mut self, area: XYWH<u16>, content: &'t T) {}
|
||||
/// }
|
||||
///
|
||||
/// struct State {/*app-specific*/}
|
||||
/// impl<'b> Namespace<'b, bool> for State {}
|
||||
/// impl<'b> Namespace<'b, u16> for State {}
|
||||
/// impl Understand<Target, ()> for State {}
|
||||
///
|
||||
/// # fn main () -> tengri::Usually<()> {
|
||||
/// let state = State {};
|
||||
/// let mut target = Target { xywh: Default::default() };
|
||||
/// eval_view(&state, &mut target, &"")?;
|
||||
/// eval_view(&state, &mut target, &"(when true (text hello))")?;
|
||||
/// eval_view(&state, &mut target, &"(either true (text hello) (text world))")?;
|
||||
/// // TODO test all
|
||||
/// # Ok(()) }
|
||||
/// ```
|
||||
#[cfg(feature = "dsl")] pub fn eval_view <'a, O: Screen + 'a, S> (
|
||||
state: &S, output: &mut O, expr: &'a impl Expression
|
||||
) -> Usually<bool> where
|
||||
S: Understand<O, ()>
|
||||
+ for<'b>Namespace<'b, bool>
|
||||
+ for<'b>Namespace<'b, O::Unit>
|
||||
{
|
||||
// First element of expression is used for dispatch.
|
||||
// Dispatch is proto-namespaced using 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
|
||||
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.
|
||||
match frags.next() {
|
||||
|
||||
Some("when") => output.place(&when(
|
||||
state.namespace(arg0?)?.unwrap(),
|
||||
move|output: &mut O|state.understand(output, &arg1)
|
||||
)),
|
||||
|
||||
Some("either") => output.place(&either(
|
||||
state.namespace(arg0?)?.unwrap(),
|
||||
move|output: &mut O|state.understand(output, &arg1),
|
||||
move|output: &mut O|state.understand(output, &arg2),
|
||||
)),
|
||||
|
||||
Some("bsp") => output.place(&{
|
||||
let a = move|output: &mut O|state.understand(output, &arg0);
|
||||
let b = move|output: &mut O|state.understand(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.understand(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.understand(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:?}")
|
||||
}
|
||||
}),
|
||||
|
||||
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.understand(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("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.understand(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.understand(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.understand(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:?}")
|
||||
}
|
||||
}),
|
||||
|
||||
_ => return Ok(false)
|
||||
|
||||
};
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
/// Interpret TUI-specific layout operation.
|
||||
///
|
||||
/// ```
|
||||
/// use tengri::{Namespace, Understand, Tui, ratatui::prelude::Color};
|
||||
///
|
||||
/// struct State;
|
||||
/// impl<'b> Namespace<'b, bool> for State {}
|
||||
/// impl<'b> Namespace<'b, u16> for State {}
|
||||
/// impl<'b> Namespace<'b, Color> for State {}
|
||||
/// impl Understand<Tui, ()> for State {}
|
||||
/// # fn main () -> tengri::Usually<()> {
|
||||
/// let state = State;
|
||||
/// let mut out = TuiOut::default();
|
||||
/// tengri::eval_view_tui(&state, &mut out, "")?;
|
||||
/// tengri::eval_view_tui(&state, &mut out, "text Hello world!")?;
|
||||
/// tengri::eval_view_tui(&state, &mut out, "fg (g 0) (text Hello world!)")?;
|
||||
/// tengri::eval_view_tui(&state, &mut out, "bg (g 2) (text Hello world!)")?;
|
||||
/// tengri::eval_view_tui(&state, &mut out, "(bg (g 3) (fg (g 4) (text Hello world!)))")?;
|
||||
/// # Ok(()) }
|
||||
/// ```
|
||||
pub fn eval_view_tui <'a, S> (
|
||||
state: &S, output: &mut Buffer, expr: impl Expression + 'a
|
||||
) -> Usually<bool> where
|
||||
S: Understand<TuiOut, ()>
|
||||
+ for<'b>Namespace<'b, bool>
|
||||
+ for<'b>Namespace<'b, u16>
|
||||
+ for<'b>Namespace<'b, Color>
|
||||
{
|
||||
// See `tengri::eval_view`
|
||||
let head = expr.head()?;
|
||||
let mut frags = head.src()?.unwrap_or_default().split("/");
|
||||
let args = expr.tail();
|
||||
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") => {
|
||||
if let Some(src) = args?.src()? { output.place(&src) }
|
||||
},
|
||||
|
||||
Some("fg") => {
|
||||
let arg0 = arg0?.expect("fg: expected arg 0 (color)");
|
||||
let color = Namespace::namespace(state, arg0)?.unwrap_or_else(||panic!("fg: {arg0:?}: not a color"));
|
||||
let thunk = Thunk::new(move|output: &mut Buffer|state.understand(output, &arg1).unwrap());
|
||||
output.place(&TuiOut::fg(color, thunk))
|
||||
},
|
||||
|
||||
Some("bg") => {
|
||||
//panic!("expr: {expr:?}\nhead: {head:?}\nfrags: {frags:?}\nargs: {args:?}\narg0: {arg0:?}\ntail0: {tail0:?}\narg1: {arg1:?}\ntail1: {tail1:?}\narg2: {arg2:?}");
|
||||
//panic!("head: {head:?}\narg0: {arg0:?}\narg1: {arg1:?}\narg2: {arg2:?}");;
|
||||
//panic!("head: {head:?}\narg0: {arg0:?}\narg1: {arg1:?}\narg2: {arg2:?}");
|
||||
let arg0 = arg0?.expect("bg: expected arg 0 (color)");
|
||||
let color = Namespace::namespace(state, arg0)?.unwrap_or_else(||panic!("bg: {arg0:?}: not a color"));
|
||||
let thunk = Thunk::new(move|output: &mut Buffer|state.understand(output, &arg1).unwrap());
|
||||
output.place(&TuiOut::bg(color, thunk))
|
||||
},
|
||||
|
||||
_ => return Ok(false)
|
||||
|
||||
};
|
||||
Ok(true)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue