mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2026-08-07 14:16:56 +02:00
parent
64c83b5460
commit
eb028c85fc
12 changed files with 322 additions and 216 deletions
|
|
@ -26,28 +26,41 @@ tui_view!(self: State {
|
|||
let widget = draw(move|to: &mut Tui|self.interpret(to, &src)); // FIXME this forcefills
|
||||
let sidebar = bg(Color::Rgb(20, 20, 20), north(code, title)).max_w(40);
|
||||
let content = bg(Color::Rgb(64, 64, 64), widget);
|
||||
east(sidebar, content)
|
||||
east(sidebar, ShowSizeOf(content))
|
||||
//self.size.of(bg(Color::Rgb(10, 10, 10), south(east(sidebar, content), code)).full_w())
|
||||
//self.size.of(bg(Color::Rgb(10, 10, 10), east(sidebar, content)).full_w())
|
||||
});
|
||||
|
||||
impl_keywords!(Tui, XYWH<u16>, State [
|
||||
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
|
||||
]);
|
||||
|
||||
impl Interpret<Tui, Option<XYWH<u16>>> for State {
|
||||
fn interpret_word (&self, to: &mut Tui, sym: &impl Language) -> Perhaps<XYWH<u16>> {
|
||||
match sym.src()? {
|
||||
Some(":foo") => "foo".draw(to),
|
||||
Some(":bar") => "bar".draw(to),
|
||||
Some(":foobar") => "FOOBAR".draw(to),
|
||||
_ => todo!()
|
||||
src => todo!("src: {src:?}")
|
||||
}
|
||||
}
|
||||
fn interpret_expr (&self, to: &mut Tui, src: &impl Expression) -> Perhaps<XYWH<u16>> {
|
||||
Ok(Some(if let Some(area) = eval_view(self, to, src)? {
|
||||
area
|
||||
} else if let Some(area) = Tui::eval_view(self, to, src)? {
|
||||
area
|
||||
if let Some(area) = self.keyword(to, src)? {
|
||||
Ok(Some(area))
|
||||
} else {
|
||||
return Err(format!("App::interpret_expr: unexpected: {src:?}").into())
|
||||
}))
|
||||
Err(format!("App::interpret_expr: unexpected: {src:?}").into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -89,7 +102,7 @@ const VIEWS: &'static [&'static str] = &[
|
|||
stringify! { :foobar },
|
||||
stringify! { (text FOOBAR) },
|
||||
stringify! { (bg (g 8) :foobar) },
|
||||
stringify! { (fill/xy :foobar) },
|
||||
//stringify! { (fill/xy :foobar) },
|
||||
stringify! { (bsp/s (text foo) (text bar)) },
|
||||
stringify! { (bsp/s :foo :bar) },
|
||||
stringify! { (bsp/s (bg (g 16) :foo) (bg (g 32) :bar)) },
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{*, draw::*, layout::*};
|
||||
use crate::*;
|
||||
use Azimuth::*;
|
||||
|
||||
pub struct Align<T>(
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{*, draw::*, layout::*};
|
||||
use crate::*;
|
||||
|
||||
pub struct Origin<T>(
|
||||
pub(crate) Option<Azimuth>,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{*, draw::*};
|
||||
use crate::*;
|
||||
|
||||
/// Define inner drawing area.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{*, draw::*};
|
||||
use crate::*;
|
||||
|
||||
/// Move content in the negative direction of one or both axes.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{*, draw::*};
|
||||
use crate::*;
|
||||
|
||||
/// Move content in the positive direction of one or both axes.
|
||||
///
|
||||
|
|
|
|||
443
src/lib.rs
443
src/lib.rs
|
|
@ -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,107 +1908,264 @@ 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("/");
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
#[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();
|
||||
// First `frags.next()` calls returns the namespace.
|
||||
match frags.next() {
|
||||
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())
|
||||
});
|
||||
|
||||
Some("when") => when(
|
||||
state.namespace(arg0?)?.unwrap(),
|
||||
draw(move|output: &mut O|{state.interpret(output, &arg1)})
|
||||
).draw(output),
|
||||
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())
|
||||
});
|
||||
|
||||
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),
|
||||
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())
|
||||
});
|
||||
|
||||
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),
|
||||
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())
|
||||
});
|
||||
|
||||
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)
|
||||
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())
|
||||
});
|
||||
}
|
||||
|
||||
fn invalid_variant <T> (
|
||||
pub fn invalid_variant <T> (
|
||||
name: &str,
|
||||
frag: impl Language,
|
||||
expr: impl Language,
|
||||
|
|
@ -2082,4 +2176,3 @@ macro_rules! eval_xy (
|
|||
head.src()?.unwrap_or_default().split("/").next()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use super::{*, draw::*};
|
||||
use crate::*;
|
||||
|
||||
/// Draw border around item shrunk by 1 on each side.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use super::{*, draw::*, Color::*};
|
||||
use crate::{*, Color::*};
|
||||
|
||||
/// ```
|
||||
/// let _ = tengri::button_2("", "", true);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use super::{*, draw::*, Color::*};
|
||||
use crate::*;
|
||||
|
||||
/// Stackably padded.
|
||||
///
|
||||
|
|
@ -18,10 +18,10 @@ pub const HI: &'static str = "▀";
|
|||
|
||||
/// A phat line
|
||||
fn phat_lo (fg: Color, bg: Color) -> impl Draw<Tui> {
|
||||
fg_bg(fg, bg, x_repeat(self::phat::LO)).exact_h(1)
|
||||
fg_bg(fg, bg, x_repeat(LO)).exact_h(1)
|
||||
}
|
||||
|
||||
/// A phat line
|
||||
fn phat_hi (fg: Color, bg: Color) -> impl Draw<Tui> {
|
||||
fg_bg(fg, bg, x_repeat(self::phat::HI)).exact_h(1)
|
||||
fg_bg(fg, bg, x_repeat(HI)).exact_h(1)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use super::{*, draw::*};
|
||||
use crate::*;
|
||||
use ratatui::{prelude::{Position}};
|
||||
|
||||
pub const fn x_repeat (c: &str) -> impl Draw<Tui> {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use super::{*, draw::*, Color::*};
|
||||
use crate::{*, Color::*};
|
||||
use ratatui::{prelude::{Position}};
|
||||
|
||||
pub const ICON_DEC_V: &[char] = &['▲'];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue