|
|
|
|
@ -41,6 +41,33 @@ macro_rules! features {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
macro_rules! fn_kw_layout {
|
|
|
|
|
($name:ident |$state:ident, $output: ident, $expr:ident| $body:block) => {
|
|
|
|
|
pub fn $name <O: Screen, S> (
|
|
|
|
|
$state: &S, $output: &mut O, $expr: &str
|
|
|
|
|
) -> Perhaps<XYWH<O::Unit>> where
|
|
|
|
|
S: Interpret<O, Option<XYWH<O::Unit>>>
|
|
|
|
|
+ for<'b> Namespace<'b, bool>
|
|
|
|
|
+ for<'b> Namespace<'b, O::Unit>
|
|
|
|
|
+ for<'b> Namespace<'b, Option<O::Unit>>
|
|
|
|
|
$body
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
macro_rules! fn_kw_layout_tui {
|
|
|
|
|
($name:ident |$state:ident, $output: ident, $expr:ident| $body:block) => {
|
|
|
|
|
pub fn $name <S> (
|
|
|
|
|
$state: &S, $output: &mut Tui, $expr: &str
|
|
|
|
|
) -> Perhaps<XYWH<u16>> where
|
|
|
|
|
S: Interpret<Tui, Option<XYWH<u16>>>
|
|
|
|
|
+ for<'b> Namespace<'b, bool>
|
|
|
|
|
+ for<'b> Namespace<'b, u16>
|
|
|
|
|
+ for<'b> Namespace<'b, Option<u16>>
|
|
|
|
|
+ for<'b> Namespace<'b, Color>
|
|
|
|
|
$body
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "lang")] pub use ::dizzle::{Usually, Perhaps};
|
|
|
|
|
#[cfg(feature = "lang")] use ::dizzle::*;
|
|
|
|
|
|
|
|
|
|
@ -168,7 +195,7 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
|
|
|
|
|
/// 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 {
|
|
|
|
|
$name:literal, $output:ident, $state:ident, $value:expr, $arg0:expr, $Enum:ident {
|
|
|
|
|
$($v:literal => $V:ident),* $(,)?
|
|
|
|
|
}
|
|
|
|
|
) => {{
|
|
|
|
|
@ -187,7 +214,7 @@ macro_rules! eval_xy (
|
|
|
|
|
// (fill/xy ...)
|
|
|
|
|
(
|
|
|
|
|
$name:expr => $expr:expr, $head:expr, $output:ident, $state:ident,
|
|
|
|
|
$variant:expr, $xy:ident, $x:ident, $y:ident, $arg: ident,
|
|
|
|
|
$variant:expr, $xy:ident, $x:ident, $y:ident, $arg:expr,
|
|
|
|
|
) => {{
|
|
|
|
|
// frags.next(): 2nd slash-delimited fragment: /x, /y, /xy
|
|
|
|
|
let variant = $variant;
|
|
|
|
|
@ -210,7 +237,7 @@ macro_rules! eval_xy (
|
|
|
|
|
// (push/xy n m ...)
|
|
|
|
|
(
|
|
|
|
|
$name:expr => $expr:expr, $head:expr, $output:ident, $state:ident,
|
|
|
|
|
$variant:expr, $xy:ident, $x:ident, $y:ident, $arg0: ident, $arg1: ident, $arg2: ident,
|
|
|
|
|
$variant:expr, $xy:ident, $x:ident, $y:ident, $arg0:expr, $arg1:expr, $arg2:expr,
|
|
|
|
|
) => {{
|
|
|
|
|
// frags.next(): 2nd slash-delimited fragment: /x, /y, /xy
|
|
|
|
|
let variant = $variant;
|
|
|
|
|
@ -483,7 +510,7 @@ macro_rules! eval_xy (
|
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use tengri::*;
|
|
|
|
|
/// let _ = draw(|to: &mut Tui|Ok(Some(to.1)));
|
|
|
|
|
/// let _ = draw(|to: &mut Tui|Ok(Some(to.area()))); // draws nothing
|
|
|
|
|
/// ```
|
|
|
|
|
pub const fn draw <T: Screen, F: FnOnce(&mut T)->Perhaps<XYWH<T::Unit>>> (
|
|
|
|
|
item: F
|
|
|
|
|
@ -1550,96 +1577,6 @@ macro_rules! eval_xy (
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Interpret TUI-specific layout operation.
|
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// use tengri::{*, dizzle::*, ratatui::prelude::Color};
|
|
|
|
|
///
|
|
|
|
|
/// #[namespace(bool)]
|
|
|
|
|
/// #[namespace(u8)]
|
|
|
|
|
/// #[namespace(u16)]
|
|
|
|
|
/// #[namespace(Color get_color)]
|
|
|
|
|
/// struct State;
|
|
|
|
|
///
|
|
|
|
|
/// impl Interpret<Tui, Option<XYWH<u16>>> for State {
|
|
|
|
|
/// fn interpret_expr <'a> (&'a self, _: &mut Tui, lang: &'a impl Expression)
|
|
|
|
|
/// -> Usually<Option<XYWH<u16>>>
|
|
|
|
|
/// {
|
|
|
|
|
/// Ok(None)
|
|
|
|
|
/// }
|
|
|
|
|
/// }
|
|
|
|
|
///
|
|
|
|
|
/// fn get_color (state: &State, src: impl Language) -> Perhaps<Color> {
|
|
|
|
|
/// Ok(if let Some(color) = Tui::eval_color_expr(state, &src)? {
|
|
|
|
|
/// Some(color)
|
|
|
|
|
/// } else if let Some(sym) = src.word()? {
|
|
|
|
|
/// Some(match sym {
|
|
|
|
|
/// ":color/bg" => Color::Rgb(28, 32, 36),
|
|
|
|
|
/// ":color/fg" => Color::Rgb(98, 92, 96),
|
|
|
|
|
/// _ => return Err(format!("not a color: {sym}").into())
|
|
|
|
|
/// })
|
|
|
|
|
/// } else {
|
|
|
|
|
/// return Err(format!("not a color: {:?}", src.src()?).into())
|
|
|
|
|
/// })
|
|
|
|
|
/// }
|
|
|
|
|
///
|
|
|
|
|
/// # fn main () -> tengri::Usually<()> {
|
|
|
|
|
/// let state = State;
|
|
|
|
|
/// let mut out = Tui::new(80, 25);
|
|
|
|
|
/// Tui::eval_view(&state, &mut out, "")?;
|
|
|
|
|
/// Tui::eval_view(&state, &mut out, "text Hello world!")?;
|
|
|
|
|
/// Tui::eval_view(&state, &mut out, "fg (g 0) (text Hello world!)")?;
|
|
|
|
|
/// Tui::eval_view(&state, &mut out, "bg (g 2) (text Hello world!)")?;
|
|
|
|
|
/// Tui::eval_view(&state, &mut out, "(bg (g 3) (fg (g 4) (text Hello world!)))")?;
|
|
|
|
|
/// # Ok(()) }
|
|
|
|
|
/// ```
|
|
|
|
|
pub fn eval_view <'a, S> (
|
|
|
|
|
state: &S, to: &mut Tui, expr: impl Expression + 'a
|
|
|
|
|
) -> Perhaps<XYWH<u16>> where
|
|
|
|
|
S: Interpret<Tui, Option<XYWH<u16>>>
|
|
|
|
|
+ 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();
|
|
|
|
|
match frags.next() {
|
|
|
|
|
Some("text") => {
|
|
|
|
|
if let Some(src) = args?.src()? {
|
|
|
|
|
src.draw(to)
|
|
|
|
|
} else {
|
|
|
|
|
return Ok(None)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
Some("fg") => {
|
|
|
|
|
let arg0 = arg0?.expect("fg: expected arg 0 (color)");
|
|
|
|
|
if let Some(color) = Namespace::namespace(state, arg0)? {
|
|
|
|
|
fg(color, draw(move|to: &mut Tui|state.interpret(to, &arg1))).draw(to)
|
|
|
|
|
} else {
|
|
|
|
|
return Err(format!("fg: {arg0:?}: not a color").into())
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
Some("bg") => {
|
|
|
|
|
let arg0 = arg0?.expect("bg: expected arg 0 (color)");
|
|
|
|
|
if let Some(color) = Namespace::namespace(state, arg0)? {
|
|
|
|
|
bg(color, draw(move|to: &mut Tui|state.interpret(to, &arg1))).draw(to)
|
|
|
|
|
} else {
|
|
|
|
|
return Err(format!("bg: {arg0:?}: not a color").into())
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
_ => return Ok(None)
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn eval_color_expr (state: &impl for<'a> Namespace<'a, u8>, src: impl Language)
|
|
|
|
|
-> Perhaps<Color>
|
|
|
|
|
{
|
|
|
|
|
@ -1971,115 +1908,271 @@ macro_rules! eval_xy (
|
|
|
|
|
#[cfg(feature = "eval")] mod eval {
|
|
|
|
|
use crate::*;
|
|
|
|
|
|
|
|
|
|
/// Interpret layout operation.
|
|
|
|
|
///
|
|
|
|
|
/// ```
|
|
|
|
|
/// # use tengri::{*, dizzle::*};
|
|
|
|
|
/// # use ::tengri::{*, dizzle::*, ratatui::prelude::Color};
|
|
|
|
|
///
|
|
|
|
|
/// struct State {/*app-specific*/}
|
|
|
|
|
/// impl<'b> Namespace<'b, u16> for State {}
|
|
|
|
|
/// impl<'b> Namespace<'b, bool> for State {}
|
|
|
|
|
/// impl<'b> Namespace<'b, Option<u16>> for State {}
|
|
|
|
|
/// impl Interpret<Tui, Option<XYWH<u16>>> for State {}
|
|
|
|
|
/// #[namespace(bool)]
|
|
|
|
|
/// #[namespace(u8)]
|
|
|
|
|
/// #[namespace(u16)]
|
|
|
|
|
/// #[namespace(Option<u16>)]
|
|
|
|
|
/// #[namespace(Color get_color)]
|
|
|
|
|
/// struct App;
|
|
|
|
|
///
|
|
|
|
|
/// fn get_color (state: &App, src: impl Language) -> Perhaps<Color> {
|
|
|
|
|
/// Ok(if let Some(color) = Tui::eval_color_expr(state, &src)? {
|
|
|
|
|
/// Some(color)
|
|
|
|
|
/// } else if let Some(sym) = src.word()? {
|
|
|
|
|
/// Some(match sym {
|
|
|
|
|
/// ":color/bg" => Color::Rgb(28, 32, 36),
|
|
|
|
|
/// ":color/fg" => Color::Rgb(98, 92, 96),
|
|
|
|
|
/// _ => return Err(format!("not a color: {sym}").into())
|
|
|
|
|
/// })
|
|
|
|
|
/// } else {
|
|
|
|
|
/// return Err(format!("not a color: {:?}", src.src()?).into())
|
|
|
|
|
/// })
|
|
|
|
|
/// }
|
|
|
|
|
///
|
|
|
|
|
/// impl Interpret<Tui, Option<XYWH<u16>>> for App {
|
|
|
|
|
/// fn interpret_expr <'a> (&'a self, _: &mut Tui, lang: &'a impl Expression)
|
|
|
|
|
/// -> Usually<Option<XYWH<u16>>>
|
|
|
|
|
/// {
|
|
|
|
|
/// Ok(None)
|
|
|
|
|
/// }
|
|
|
|
|
/// }
|
|
|
|
|
///
|
|
|
|
|
/// impl Keywords<Tui, XYWH<u16>> for App {
|
|
|
|
|
/// fn keywords () -> impl Iterator<Item = fn(&Self, &mut Tui, &str) -> Perhaps<XYWH<u16>>> {
|
|
|
|
|
/// [
|
|
|
|
|
/// kw_when, kw_either, kw_split, kw_align,
|
|
|
|
|
/// kw_exact, kw_fixed, kw_min, kw_max, kw_push,
|
|
|
|
|
/// kw_tui_text, kw_tui_fg, kw_tui_bg
|
|
|
|
|
/// ].into_iter()
|
|
|
|
|
/// }
|
|
|
|
|
/// }
|
|
|
|
|
///
|
|
|
|
|
/// # fn main () -> tengri::Usually<()> {
|
|
|
|
|
/// let state = State {};
|
|
|
|
|
/// let mut target = Tui::new(80, 25);
|
|
|
|
|
/// eval_view(&state, &mut target, &"")?;
|
|
|
|
|
/// eval_view(&state, &mut target, &"(whe true (text hello))")?;
|
|
|
|
|
/// eval_view(&state, &mut target, &"(either true (text hello) (text world))")?;
|
|
|
|
|
/// // TODO test all
|
|
|
|
|
/// let state = App;
|
|
|
|
|
/// let mut out = Tui::new(80, 25);
|
|
|
|
|
/// Tui::eval_view(&state, &mut out, "")?;
|
|
|
|
|
/// Tui::eval_view(&state, &mut out, "text Hello world!")?;
|
|
|
|
|
/// Tui::eval_view(&state, &mut out, "fg (g 0) (text Hello world!)")?;
|
|
|
|
|
/// Tui::eval_view(&state, &mut out, "bg (g 2) (text Hello world!)")?;
|
|
|
|
|
/// Tui::eval_view(&state, &mut out, "(bg (g 3) (fg (g 4) (text Hello world!)))")?;
|
|
|
|
|
/// # Ok(()) }
|
|
|
|
|
/// ```
|
|
|
|
|
pub fn eval_view <'a, O: Screen + 'a, S> (
|
|
|
|
|
state: &S, output: &mut O, expr: &'a impl Expression
|
|
|
|
|
) -> Perhaps<XYWH<O::Unit>> where
|
|
|
|
|
S: Interpret<O, Option<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 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();
|
|
|
|
|
// First `frags.next()` calls returns the namespace.
|
|
|
|
|
match frags.next() {
|
|
|
|
|
|
|
|
|
|
Some("when") => when(
|
|
|
|
|
state.namespace(arg0?)?.unwrap(),
|
|
|
|
|
draw(move|output: &mut O|{state.interpret(output, &arg1)})
|
|
|
|
|
).draw(output),
|
|
|
|
|
|
|
|
|
|
Some("either") => either(
|
|
|
|
|
state.namespace(arg0?)?.unwrap(),
|
|
|
|
|
draw(move|output: &mut O|{state.interpret(output, &arg1)}),
|
|
|
|
|
draw(move|output: &mut O|{state.interpret(output, &arg2)}),
|
|
|
|
|
).draw(output),
|
|
|
|
|
|
|
|
|
|
Some("bsp") => eval_enum!("bsp", output, state, frags.next(), arg0, Split {
|
|
|
|
|
"n" => North, "s" => South, "e" => East, "w" => West, "a" => Above, "b" => Below
|
|
|
|
|
}).stack(
|
|
|
|
|
draw(move|output: &mut O|{state.interpret(output, &arg0)}),
|
|
|
|
|
draw(move|output: &mut O|{state.interpret(output, &arg1)}),
|
|
|
|
|
).draw(output),
|
|
|
|
|
|
|
|
|
|
Some("align") => draw(move|output: &mut O|{state.interpret(output, &arg0)})
|
|
|
|
|
.align(eval_enum!("align", output, state, frags.next(), arg0, Azimuth {
|
|
|
|
|
"c" => C, "x" => X, "y" => Y,
|
|
|
|
|
"n" => N, "s" => S, "e" => E, "w" => W,
|
|
|
|
|
"nw" => NW, "sw" => SW, "ne" => NE, "se" => SE,
|
|
|
|
|
})).draw(output),
|
|
|
|
|
|
|
|
|
|
Some("exact") => eval_xy!(
|
|
|
|
|
"exact" => expr, head, output, state, frags.next(), exact_wh, exact_w, exact_h, arg0, arg1, arg2,
|
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
Some("fixed") => eval_xy!(
|
|
|
|
|
"fixed" => expr, head, output, state, frags.next(), exact_wh, exact_w, exact_h, arg0, arg1, arg2,
|
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
Some("min") => eval_xy!(
|
|
|
|
|
"min" => expr, head, output, state, frags.next(), min_wh, min_w, min_h, arg0, arg1, arg2,
|
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
Some("max") => eval_xy!(
|
|
|
|
|
"max" => expr, head, output, state, frags.next(), max_wh, max_w, max_h, arg0, arg1, arg2,
|
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
Some("push") => eval_xy!(
|
|
|
|
|
"push" => expr, head, output, state, frags.next(), push_xy, push_x, push_y, arg0, arg1, arg2,
|
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
Some("fill") => eval_xy!(
|
|
|
|
|
"fill" => expr, head, output, state, frags.next(), full_wh, full_w, full_h, arg0,
|
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
_ => return Ok(None)
|
|
|
|
|
|
|
|
|
|
pub trait Keywords <U, V>: 'static {
|
|
|
|
|
fn keywords () -> impl Iterator<Item = fn(&Self, &mut U, &str) -> Perhaps<V>>;
|
|
|
|
|
fn keyword (&self, to: &mut U, expr: &impl Expression) -> Perhaps<V> {
|
|
|
|
|
if let Some(expr) = expr.src()? {
|
|
|
|
|
for keyword in Self::keywords() {
|
|
|
|
|
if let Some(result) = keyword(self, to, &expr)? {
|
|
|
|
|
return Ok(Some(result))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Ok(None)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn invalid_variant <T> (
|
|
|
|
|
name: &str,
|
|
|
|
|
frag: impl Language,
|
|
|
|
|
expr: impl Language,
|
|
|
|
|
head: impl Language,
|
|
|
|
|
) -> Usually<T> {
|
|
|
|
|
unimplemented!(
|
|
|
|
|
"{name}/{frag:?} ({expr:?}) ({head:?}) ({:?})",
|
|
|
|
|
head.src()?.unwrap_or_default().split("/").next()
|
|
|
|
|
)
|
|
|
|
|
#[macro_export] macro_rules! impl_keywords {
|
|
|
|
|
($T:ty, $U:ty, $V:ty [ $($kw:ident),* ]) => {
|
|
|
|
|
impl Keywords<$T, $U> for $V {
|
|
|
|
|
fn keywords () -> impl Iterator<Item = fn(&Self, &mut $T, &str) -> Perhaps<$U>> {
|
|
|
|
|
[ $($kw),* ].into_iter()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn_kw_layout!(kw_when |state, output, expr| {
|
|
|
|
|
Ok(matches!(expr.head()?, Some("when")).then(||{
|
|
|
|
|
when(state.namespace(expr.tail().head())?.unwrap(),
|
|
|
|
|
draw(move|output: &mut O|{state.interpret(output, &expr.tail().tail().head())})
|
|
|
|
|
).draw(output)
|
|
|
|
|
}).transpose()?.flatten())
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
fn_kw_layout!(kw_either |state, output, expr| {
|
|
|
|
|
Ok(matches!(expr.head()?, Some("either")).then(||{
|
|
|
|
|
either(state.namespace(expr.tail().head()?)?.unwrap(),
|
|
|
|
|
draw(move|output: &mut O|{
|
|
|
|
|
state.interpret(output, &expr.tail().tail().head()?)
|
|
|
|
|
}),
|
|
|
|
|
draw(move|output: &mut O|{
|
|
|
|
|
state.interpret(output, &expr.tail().tail().tail().head()?)
|
|
|
|
|
}),
|
|
|
|
|
).draw(output)
|
|
|
|
|
}).transpose()?.flatten())
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
fn_kw_layout!(kw_split |state, output, expr| {
|
|
|
|
|
let head = expr.head();
|
|
|
|
|
let mut frags = head.src()?.unwrap_or_default().split("/");
|
|
|
|
|
Ok(matches!(frags.next(), Some("bsp")).then(||{
|
|
|
|
|
eval_enum!("bsp", output, state, frags.next(), expr.tail().head()?, Split {
|
|
|
|
|
"n" => North,
|
|
|
|
|
"s" => South,
|
|
|
|
|
"e" => East,
|
|
|
|
|
"w" => West,
|
|
|
|
|
"a" => Above,
|
|
|
|
|
"b" => Below
|
|
|
|
|
}).stack(
|
|
|
|
|
draw(move|output: &mut O|{
|
|
|
|
|
state.interpret(output, &expr.tail().tail().head()?)
|
|
|
|
|
}),
|
|
|
|
|
draw(move|output: &mut O|{
|
|
|
|
|
state.interpret(output, &expr.tail().tail().tail().head()?)
|
|
|
|
|
}),
|
|
|
|
|
).draw(output)
|
|
|
|
|
}).transpose()?.flatten())
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
fn_kw_layout!(kw_align |state, output, expr| {
|
|
|
|
|
Ok(matches!(expr.head()?, Some("align")).then(||{
|
|
|
|
|
draw(move|output: &mut O|{state.interpret(output, &expr.tail().head())}).align(
|
|
|
|
|
eval_enum!("align", output, state,
|
|
|
|
|
expr.head().src()?.unwrap_or_default().split("/").skip(1).next(),
|
|
|
|
|
expr.tail().head(),
|
|
|
|
|
Azimuth {
|
|
|
|
|
"c" => C, "x" => X, "y" => Y,
|
|
|
|
|
"n" => N, "s" => S, "e" => E, "w" => W,
|
|
|
|
|
"nw" => NW, "sw" => SW, "ne" => NE, "se" => SE,
|
|
|
|
|
})
|
|
|
|
|
).draw(output)
|
|
|
|
|
}).transpose()?.flatten())
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
fn_kw_layout!(kw_exact |state, output, expr| {
|
|
|
|
|
Ok(matches!(expr.head()?, Some("exact")).then(||{
|
|
|
|
|
let head = expr.head()?;
|
|
|
|
|
let args = expr.tail();
|
|
|
|
|
let arg0 = args.head();
|
|
|
|
|
let tail0 = args.tail();
|
|
|
|
|
let arg1 = tail0.head();
|
|
|
|
|
let tail1 = tail0.tail();
|
|
|
|
|
let arg2 = tail1.head();
|
|
|
|
|
let mut frags = head.src()?.unwrap_or_default().split("/").skip(1);
|
|
|
|
|
eval_xy!("exact" => expr, head, output, state, frags.next(), exact_wh, exact_w, exact_h,
|
|
|
|
|
arg0, arg1, arg2,)
|
|
|
|
|
}).transpose()?.flatten())
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
fn_kw_layout!(kw_fixed |state, output, expr| {
|
|
|
|
|
Ok(matches!(expr.head()?, Some("exact")).then(||{
|
|
|
|
|
let head = expr.head()?;
|
|
|
|
|
let args = expr.tail();
|
|
|
|
|
let arg0 = args.head();
|
|
|
|
|
let tail0 = args.tail();
|
|
|
|
|
let arg1 = tail0.head();
|
|
|
|
|
let tail1 = tail0.tail();
|
|
|
|
|
let arg2 = tail1.head();
|
|
|
|
|
let mut frags = head.src()?.unwrap_or_default().split("/").skip(1);
|
|
|
|
|
eval_xy!("fixed" => expr, head, output, state, frags.next(), exact_wh, exact_w, exact_h,
|
|
|
|
|
arg0, arg1, arg2,)
|
|
|
|
|
}).transpose()?.flatten())
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
fn_kw_layout!(kw_min |state, output, expr| {
|
|
|
|
|
Ok(matches!(expr.head()?, Some("exact")).then(||{
|
|
|
|
|
let head = expr.head()?;
|
|
|
|
|
let args = expr.tail();
|
|
|
|
|
let arg0 = args.head();
|
|
|
|
|
let tail0 = args.tail();
|
|
|
|
|
let arg1 = tail0.head();
|
|
|
|
|
let tail1 = tail0.tail();
|
|
|
|
|
let arg2 = tail1.head();
|
|
|
|
|
let mut frags = head.src()?.unwrap_or_default().split("/").skip(1);
|
|
|
|
|
eval_xy!("min" => expr, head, output, state, frags.next(), min_wh, min_w, min_h,
|
|
|
|
|
arg0, arg1, arg2,)
|
|
|
|
|
}).transpose()?.flatten())
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
fn_kw_layout!(kw_max |state, output, expr| {
|
|
|
|
|
Ok(matches!(expr.head()?, Some("exact")).then(||{
|
|
|
|
|
let head = expr.head()?;
|
|
|
|
|
let args = expr.tail();
|
|
|
|
|
let arg0 = args.head();
|
|
|
|
|
let tail0 = args.tail();
|
|
|
|
|
let arg1 = tail0.head();
|
|
|
|
|
let tail1 = tail0.tail();
|
|
|
|
|
let arg2 = tail1.head();
|
|
|
|
|
let mut frags = head.src()?.unwrap_or_default().split("/").skip(1);
|
|
|
|
|
eval_xy!("max" => expr, head, output, state, frags.next(), max_wh, max_w, max_h,
|
|
|
|
|
arg0, arg1, arg2,)
|
|
|
|
|
}).transpose()?.flatten())
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
fn_kw_layout!(kw_push |state, output, expr| {
|
|
|
|
|
Ok(matches!(expr.head()?, Some("push")).then(||{
|
|
|
|
|
let head = expr.head()?;
|
|
|
|
|
let args = expr.tail();
|
|
|
|
|
let arg0 = args.head();
|
|
|
|
|
let tail0 = args.tail();
|
|
|
|
|
let arg1 = tail0.head();
|
|
|
|
|
let tail1 = tail0.tail();
|
|
|
|
|
let arg2 = tail1.head();
|
|
|
|
|
let mut frags = head.src()?.unwrap_or_default().split("/").skip(1);
|
|
|
|
|
eval_xy!("push" => expr, head, output, state, frags.next(), push_xy, push_x, push_y,
|
|
|
|
|
arg0, arg1, arg2,)
|
|
|
|
|
}).transpose()?.flatten())
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "term")] fn_kw_layout_tui!(kw_tui_text |state, output, expr| {
|
|
|
|
|
Ok(matches!(expr.head()?, Some("text")).then(||{
|
|
|
|
|
let args = expr.tail();
|
|
|
|
|
let arg0 = args.head();
|
|
|
|
|
let tail0 = args.tail();
|
|
|
|
|
let arg1 = tail0.head();
|
|
|
|
|
if let Some(src) = args?.src()? {
|
|
|
|
|
src.draw(output)
|
|
|
|
|
} else {
|
|
|
|
|
return Ok(None)
|
|
|
|
|
}
|
|
|
|
|
}).transpose()?.flatten())
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "term")] fn_kw_layout_tui!(kw_tui_fg |state, output, expr| {
|
|
|
|
|
Ok(matches!(expr.head()?, Some("fg")).then(||{
|
|
|
|
|
let args = expr.tail();
|
|
|
|
|
let arg0 = args.head();
|
|
|
|
|
let tail0 = args.tail();
|
|
|
|
|
let arg1 = tail0.head();
|
|
|
|
|
if let Some(color) = Namespace::namespace(
|
|
|
|
|
state, arg0?.expect("fg: expected arg 0 (color)")
|
|
|
|
|
)? {
|
|
|
|
|
fg(color, draw(move|to: &mut Tui|state.interpret(to, &arg1))).draw(output)
|
|
|
|
|
} else {
|
|
|
|
|
return Err(format!("fg: {arg0:?}: not a color").into())
|
|
|
|
|
}
|
|
|
|
|
}).transpose()?.flatten())
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "term")] fn_kw_layout_tui!(kw_tui_bg |state, output, expr| {
|
|
|
|
|
Ok(matches!(expr.head()?, Some("bg")).then(||{
|
|
|
|
|
let head = expr.head()?;
|
|
|
|
|
let args = expr.tail();
|
|
|
|
|
let arg0 = args.head();
|
|
|
|
|
let tail0 = args.tail();
|
|
|
|
|
let arg1 = tail0.head();
|
|
|
|
|
let mut frags = head.src()?.unwrap_or_default().split("/");
|
|
|
|
|
let arg0 = arg0?.expect("bg: expected arg 0 (color)");
|
|
|
|
|
if let Some(color) = Namespace::namespace(state, arg0)? {
|
|
|
|
|
bg(color, draw(move|to: &mut Tui|state.interpret(to, &arg1))).draw(output)
|
|
|
|
|
} else {
|
|
|
|
|
return Err(format!("bg: {arg0:?}: not a color").into())
|
|
|
|
|
}
|
|
|
|
|
}).transpose()?.flatten())
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn invalid_variant <T> (
|
|
|
|
|
name: &str,
|
|
|
|
|
frag: impl Language,
|
|
|
|
|
expr: impl Language,
|
|
|
|
|
head: impl Language,
|
|
|
|
|
) -> Usually<T> {
|
|
|
|
|
unimplemented!(
|
|
|
|
|
"{name}/{frag:?} ({expr:?}) ({head:?}) ({:?})",
|
|
|
|
|
head.src()?.unwrap_or_default().split("/").next()
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|