From 291ab632245c8beb83973da4f5157eb7b40cc7eb Mon Sep 17 00:00:00 2001 From: facile pop culture reference Date: Wed, 19 Aug 2026 18:21:34 +0300 Subject: [PATCH] smizzle --- Justfile | 19 ++++++------ bacon.toml | 12 ++++++-- dizzle | 2 +- examples/mode_01.rs | 2 +- examples/mode_02.rs | 33 +++++++++------------ src/layout/axis.rs | 68 +++++++++++++++++++++++-------------------- src/layout/azimuth.rs | 5 ++-- src/layout/cond.rs | 10 +++---- src/lib.rs | 16 +++++----- src/term/keys.rs | 2 +- src/term/modify.rs | 25 ++++++++-------- 11 files changed, 98 insertions(+), 96 deletions(-) diff --git a/Justfile b/Justfile index bc55ceb..f176db2 100644 --- a/Justfile +++ b/Justfile @@ -1,6 +1,9 @@ +export CARGO_INCREMENTAL := '0' +export RUSTFLAGS := '-Zmacro-backtrace -Cinstrument-coverage' +export RUSTDOCFLAGS := '-Zmacro-backtrace -Cinstrument-coverage' export LLVM_PROFILE_FILE := "cov/cargo-test-%p-%m.profraw" -grcov-binary := "--binary-path ./target/coverage/deps/" -grcov-ignore := "--ignore-not-existing --ignore '../*' --ignore \"/*\" --ignore 'target/*'" +grcov-binary := "--binary-path ./target/coverage/build/tengri" +grcov-ignore := ""#--ignore-not-existing --ignore '../*' --ignore \"/*\" --ignore 'target/*'" [private] default: @@ -10,24 +13,20 @@ bacon: bacon -s cov: - CARGO_INCREMENTAL=0 RUSTFLAGS='-Cinstrument-coverage' \ - time cargo test -j4 --workspace --profile coverage + time cargo test -j4 --workspace --profile coverage rm -rf target/coverage/html || true time grcov . -s . {{grcov-binary}} {{grcov-ignore}} -t html -o target/coverage/html && reset cov-md: - CARGO_INCREMENTAL=0 RUSTFLAGS='-Cinstrument-coverage' \ - time cargo test -j4 --workspace --profile coverage + time cargo test -j4 --workspace --profile coverage time grcov . -s . {{grcov-binary}} {{grcov-ignore}} -t markdown | sort cov-md-ci: - CARGO_INCREMENTAL=0 RUSTFLAGS='-Cinstrument-coverage' \ - time cargo test -j4 --workspace --profile coverage -- --skip test_tui_engine + time cargo test -j4 --workspace --profile coverage -- --skip test_tui_engine time grcov . -s . {{grcov-binary}} {{grcov-ignore}} -t markdown | sort doc: - CARGO_INCREMENTAL=0 RUSTFLAGS='-Cinstrument-coverage' RUSTDOCFLAGS='-Cinstrument-coverage' \ - cargo doc + cargo doc mode MODE: cargo run --example "mode_{{MODE}}" diff --git a/bacon.toml b/bacon.toml index a189527..7238fc8 100644 --- a/bacon.toml +++ b/bacon.toml @@ -1,14 +1,15 @@ -default_job = "check-all" +default_job = "coverage" env.CARGO_TERM_COLOR = "always" +env.RUSTFLAGS = "-Zmacro-backtrace" [keybindings] c = "job:check" +C = "job:clippy" d = "job:doc" D = "job:doc-open" t = "job:test" -T = "job:nextest" -l = "job:clippy" +T = "job:coverage" [jobs] @@ -27,6 +28,11 @@ command = ["cargo", "test"] need_stdout = true watch = ["tengri"] +[jobs.coverage] +command = ["just", "cov"] +need_stdout = true +watch = ["src", "proc"] + [jobs.doc] command = ["cargo", "doc", "--no-deps"] need_stdout = false diff --git a/dizzle b/dizzle index 648be30..3c80e3b 160000 --- a/dizzle +++ b/dizzle @@ -1 +1 @@ -Subproject commit 648be30918bef0a975bd225c0499911aaa88bc13 +Subproject commit 3c80e3bb8c1d104f61f212b4961d927ac845e289 diff --git a/examples/mode_01.rs b/examples/mode_01.rs index 7392e15..414f779 100644 --- a/examples/mode_01.rs +++ b/examples/mode_01.rs @@ -27,7 +27,7 @@ tui_keys!(self: State, input { }); tui_view!(self: State { - let title = "Demo [Mode 01]"; + let title = "Demo [Mode 01"; let items = self.history.iter().take(10).map(|x|format!("{x:?}")).join("\n"); let history = format!("History: {}\n{items}", self.history.len()); let cursor = format!("Counter: {}", self.cursor); diff --git a/examples/mode_02.rs b/examples/mode_02.rs index ab8b3e8..8399fa0 100644 --- a/examples/mode_02.rs +++ b/examples/mode_02.rs @@ -23,7 +23,7 @@ tui_view!(self: State { let heading = format!("Demo [Mode 02]\nExample {}/{}\nSize {:?}", index, VIEWS.len(), &wh); let title = bg(Color::Rgb(60, 10, 10), heading); let code = bg(Color::Rgb(10, 60, 10), format!("Source:\n{}", src).max_h(10)); - let widget = draw(move|to: &mut Tui|self.interpret(to, &src)); // FIXME this forcefills + 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, ShowSizeOf(content)) @@ -31,22 +31,8 @@ tui_view!(self: State { //self.size.of(bg(Color::Rgb(10, 10, 10), east(sidebar, content)).full_w()) }); -impl_keywords!(Tui, XYWH, State [ - kw_when, - kw_either, - kw_split, - kw_align, - kw_exact, - kw_min, - kw_max, - kw_push, - kw_tui_text, - kw_tui_fg, - kw_tui_bg -]); - impl<'a> Interpret<'a, Tui, Option>> for State { - fn interpret_word + ?Sized> (&'a self, to: &mut Tui, lang: &'a L) + fn interpret_word (&'a self, to: &mut Tui, lang: &'a L) -> Drawn<'a, u16> { match lang.src()? { @@ -56,13 +42,20 @@ impl<'a> Interpret<'a, Tui, Option>> for State { src => todo!("src: {src:?}") } } - fn interpret_expr + ?Sized> (&self, to: &mut Tui, src: &'a L) + fn interpret_expr (&'a self, to: &mut Tui, src: &'a L) -> Drawn<'a, u16> { - if let Some(area) = self.keyword(to, src)? { - Ok(Some(area)) + if let Some(src) = src.src()? { + interpret_keyword!(self, to, src, [ + kw_when, kw_either, + kw_split, kw_align, + kw_exact, kw_min, kw_max, + kw_push, kw_pull, + kw_tui_text, kw_tui_fg, kw_tui_bg + ]); + Err(format!("interpret_expr: unexpected: {src:?}").into()) } else { - Err(format!("App::interpret_expr: unexpected: {src:?}").into()) + Err(format!("interpret_expr: no keyword: {src:?}").into()) } } } diff --git a/src/layout/axis.rs b/src/layout/axis.rs index 600c8b6..32d0b20 100644 --- a/src/layout/axis.rs +++ b/src/layout/axis.rs @@ -29,12 +29,12 @@ pub enum Pad<'a, S: Screen, I: Draw<'a, S>, X: Into>> { } /// ``` -/// # fn test_layout_full () -> Usually<()> { +/// # use ::tengri::*; fn test_layout_full () -> Usually<()> { /// assert_eq!(check_layout("1")?, Some(XYWH(1u16, 1, 1, 1))); /// assert_eq!(check_layout("1".full_w())?, Some(XYWH(1u16, 1, 80, 1))); /// assert_eq!(check_layout("1".full_h())?, Some(XYWH(1u16, 1, 1, 25))); /// assert_eq!(check_layout("1".full_wh())?, Some(XYWH(1u16, 1, 80, 25))); -/// # Ok(()) }} +/// # Ok(()) } /// ``` pub trait LayoutFull<'a, S: Screen>: Draw<'a, S> + Sized { fn full_w (self) -> Full<'a, S, Self> { Full::W(self) } @@ -43,12 +43,12 @@ pub trait LayoutFull<'a, S: Screen>: Draw<'a, S> + Sized { } /// ``` -/// # fn test_layout_exact () -> Usually<()> { +/// # use ::tengri::*; fn test_layout_exact () -> Usually<()> { /// assert_eq!(check_layout("FOOBAR\nKILROY")?, Some(XYWH(1, 1, 6, 2))); /// assert_eq!(check_layout("FOOBAR\nKILROY".exact_w(3))?, Some(XYWH(1, 1, 3, 2))); /// assert_eq!(check_layout("FOOBAR\nKILROY".exact_h(1))?, Some(XYWH(1, 1, 6, 1))); /// assert_eq!(check_layout("FOOBAR\nKILROY".exact_wh(2, 1))?, Some(XYWH(1, 1, 2, 1))); -/// # Ok(()) }} +/// # Ok(()) } /// ``` pub trait LayoutExact<'a, S: Screen>: Draw<'a, S> + Sized { fn exact_w > + Copy> (self, w: X) @@ -60,12 +60,12 @@ pub trait LayoutExact<'a, S: Screen>: Draw<'a, S> + Sized { } /// ``` -/// # fn test_layout_min () -> Usually<()> { +/// # use ::tengri::*; fn test_layout_min () -> Usually<()> { /// assert_eq!(check_layout("1".min_w(5))?, Some(XYWH(1u16, 1, 5, 1))); /// assert_eq!(check_layout("1".min_h(5))?, Some(XYWH(1u16, 1, 1, 5))); /// assert_eq!(check_layout("1".min_wh(5, 5))?, Some(XYWH(1u16, 1, 5, 5))); /// assert_eq!(check_layout("123456".min_w(5))?, Some(XYWH(1u16, 1, 6, 1))); -/// # Ok(()) }} +/// # Ok(()) } /// ``` pub trait LayoutMin<'a, S: Screen>: Draw<'a, S> + Sized { fn min_w > + Copy> (self, w: X) @@ -95,7 +95,7 @@ pub trait LayoutPad<'a, S: Screen>: Draw<'a, S> + Sized { } /// ``` -/// # fn test_layout_pull () -> Usually<()> { +/// # use ::tengri::*; fn test_layout_pull () -> Usually<()> { /// assert_eq!(check_layout("1")?, Some(XYWH(1u16, 1, 1, 1))); /// assert_eq!(check_layout("1".push_x(1))?, Some(XYWH(2u16, 1, 1, 1))); /// assert_eq!(check_layout("1".push_y(1))?, Some(XYWH(1u16, 2, 1, 1))); @@ -112,7 +112,7 @@ pub trait LayoutPush<'a, S: Screen>: Draw<'a, S> + Sized { } /// ``` -/// # fn test_layout_push () -> Usually<()> { +/// # use ::tengri::*; fn test_layout_push () -> Usually<()> { /// assert_eq!(check_layout("1")?, Some(XYWH(1u16, 1, 1, 1))); /// assert_eq!(check_layout("1".pull_x(1))?, Some(XYWH(0u16, 1, 1, 1))); /// assert_eq!(check_layout("1".pull_y(1))?, Some(XYWH(1u16, 0, 1, 1))); @@ -160,14 +160,14 @@ where let thunk = draw(move|screen|ok_flat(expr.last()?.map(|x: &'a str|state.interpret(screen, x)))); Ok(match expr.head()? { Some("exact/w") => thunk.exact_w( - state.namespace(expr.nth(1)?)? + state.namespace(&expr.nth(1)?)? ).draw(to)?, Some("exact/h") => thunk.exact_h( - state.namespace(expr.nth(1)?)? + state.namespace(&expr.nth(1)?)? ).draw(to)?, Some("exact/wh") => thunk.exact_wh( - state.namespace(expr.nth(1)?)?, - state.namespace(expr.nth(2)?)?, + state.namespace(&expr.nth(1)?)?, + state.namespace(&expr.nth(2)?)?, ).draw(to)?, _ => return Err(format!("invalid variant: {:?}", expr.head()?).into()) }) @@ -186,14 +186,14 @@ where let thunk = draw(move|screen|ok_flat(expr.last()?.map(|x: &'a str|state.interpret(screen, x)))); Ok(match expr.head()? { Some("min/w") => thunk.min_w( - state.namespace(expr.nth(1)?)? + state.namespace(&expr.nth(1)?)? ).draw(to)?, Some("min/h") => thunk.min_h( - state.namespace(expr.nth(1)?)? + state.namespace(&expr.nth(1)?)? ).draw(to)?, Some("min/wh") => thunk.min_wh( - state.namespace(expr.nth(1)?)?, - state.namespace(expr.nth(2)?)?, + state.namespace(&expr.nth(1)?)?, + state.namespace(&expr.nth(2)?)?, ).draw(to)?, _ => return Err(format!("invalid variant: {:?}", expr.head()?).into()) }) @@ -212,14 +212,14 @@ where let thunk = draw(move|screen|ok_flat(expr.last()?.map(|x: &'a str|state.interpret(screen, x)))); Ok(match expr.head()? { Some("max/w") => thunk.max_w( - state.namespace(expr.nth(1)?)? + state.namespace(&expr.nth(1)?)? ).draw(to)?, Some("max/h") => thunk.max_h( - state.namespace(expr.nth(1)?)? + state.namespace(&expr.nth(1)?)? ).draw(to)?, Some("max/wh") => thunk.max_wh( - state.namespace(expr.nth(1)?)?, - state.namespace(expr.nth(2)?)?, + state.namespace(&expr.nth(1)?)?, + state.namespace(&expr.nth(2)?)?, ).draw(to)?, _ => return Err(format!("invalid variant: {:?}", expr.head()?).into()) }) @@ -237,9 +237,12 @@ where { let thunk = draw(move|screen|ok_flat(expr.last()?.map(|x: &'a str|state.interpret(screen, x)))); Ok(match expr.head()? { - Some("push/w") => thunk.push_x(state.namespace(expr.nth(1)?)?).draw(to)?, - Some("push/h") => thunk.push_y(state.namespace(expr.nth(1)?)?).draw(to)?, - Some("push/wh") => thunk.push_xy(state.namespace(expr.nth(1)?)?, state.namespace(expr.nth(2)?)?,).draw(to)?, + Some("push/w") => thunk.push_x(state.namespace(&expr.nth(1)?)?).draw(to)?, + Some("push/h") => thunk.push_y(state.namespace(&expr.nth(1)?)?).draw(to)?, + Some("push/wh") => thunk.push_xy( + state.namespace(&expr.nth(1)?)?, + state.namespace(&expr.nth(2)?)?, + ).draw(to)?, _ => return Err(format!("invalid variant: {:?}", expr.head()?).into()) }) } @@ -256,9 +259,12 @@ where { let thunk = draw(move|screen|ok_flat(expr.last()?.map(|x: &'a str|state.interpret(screen, x)))); Ok(match expr.head()? { - Some("pull/w") => thunk.pull_x(state.namespace(expr.nth(1)?)?).draw(to)?, - Some("pull/h") => thunk.pull_y(state.namespace(expr.nth(1)?)?).draw(to)?, - Some("pull/wh") => thunk.pull_xy(state.namespace(expr.nth(1)?)?, state.namespace(expr.nth(2)?)?,).draw(to)?, + Some("pull/w") => thunk.pull_x(state.namespace(&expr.nth(1)?)?).draw(to)?, + Some("pull/h") => thunk.pull_y(state.namespace(&expr.nth(1)?)?).draw(to)?, + Some("pull/wh") => thunk.pull_xy( + state.namespace(&expr.nth(1)?)?, + state.namespace(&expr.nth(2)?)?, + ).draw(to)?, _ => return Err(format!("invalid variant: {:?}", expr.head()?).into()) }) } @@ -276,14 +282,14 @@ where let thunk = draw(move|screen|ok_flat(expr.last()?.map(|x: &'a str|state.interpret(screen, x)))); Ok(match expr.head()? { Some("pad/w") => thunk.pad_w( - state.namespace(expr.nth(1)?)? + state.namespace(&expr.nth(1)?)? ).draw(to)?, Some("pad/h") => thunk.pad_h( - state.namespace(expr.nth(1)?)? + state.namespace(&expr.nth(1)?)? ).draw(to)?, Some("pad/wh") => thunk.pad_wh( - state.namespace(expr.nth(1)?)?, - state.namespace(expr.nth(2)?)?, + state.namespace(&expr.nth(1)?)?, + state.namespace(&expr.nth(2)?)?, ).draw(to)?, _ => return Err(format!("invalid variant: {:?}", expr.head()?).into()) }) @@ -438,6 +444,6 @@ impl<'a, S: Screen, T: Draw<'a, S>> LayoutPull<'a, S> for T {} impl<'a, S: Screen, T: Draw<'a, S>> LayoutPad<'a, S> for T {} -#[cfg(test)] fn check_layout <'a> (t: impl Draw<'a, Tui>) -> Drawn<'a, u16> { +pub fn check_layout <'a> (t: impl Draw<'a, Tui>) -> Drawn<'a, u16> { Tui::Layout(XYWH(1u16, 1, 80, 25)).size(None, t) } diff --git a/src/layout/azimuth.rs b/src/layout/azimuth.rs index 484bfc7..bd6bbee 100644 --- a/src/layout/azimuth.rs +++ b/src/layout/azimuth.rs @@ -185,8 +185,9 @@ pub struct Pair(Split, A, B); /// ``` /// # fn test_split_stack () -> Usually<()> { +/// use ::tengri::*; /// use Split::*; -/// fn size_of , B: Draw> (stack: &Pair) -> Drawn<'a, S::Unit> { +/// fn size_of <'a, A: Draw<'a, Tui>, B: Draw<'a, Tui>> (stack: &Pair) -> Drawn<'a, S::Unit> { /// Tui::Layout(XYWH(0, 0, 80, 25)).size(None, stack) /// } /// assert_eq!(size_of(&split(East, "foo", "bar"))?, Some(XYWH(0, 0, 6, 1))); @@ -238,7 +239,7 @@ fn draw_stacks <'a, S: Screen> ( } /// ``` -/// # fn test_stack_areas () -> Usually<()> { +/// # use ::tengri::*; fn test_stack_areas () -> Usually<()> { /// let area = XYWH(0u16, 0, 80, 25); /// assert_eq!(stack_areas(&Split::East, &mut Tui::Layout(area), &"foo", &"bar")?, ( /// Some(XYWH(0u16, 0, 3, 1)), diff --git a/src/layout/cond.rs b/src/layout/cond.rs index 6315d34..761a3d0 100644 --- a/src/layout/cond.rs +++ b/src/layout/cond.rs @@ -3,15 +3,14 @@ use crate::*; fn_kw_layout!(kw_when |state, output, expr| { let thunk = draw(move|screen|ok_flat(expr.nth(2)?.map(|x: &'a str|state.interpret(screen, x)))); ok_flat(matches!(expr.head()?, Some("when")).then(||{ - when(state.namespace(expr.nth(1)?)?.unwrap(), thunk) .draw(output) + when(state.namespace(&expr.nth(1)?)?.unwrap(), thunk) .draw(output) })) }); /// Only render when condition is true. /// /// ``` -/// # use tengri::*; -/// # fn test () -> impl Draw { +/// # use ::tengri::*; fn test <'a> () -> impl Draw<'a, Tui> { /// when(true, "Yes") /// # } /// ``` @@ -23,15 +22,14 @@ fn_kw_layout!(kw_either |state, output, expr| { let thunk_a = draw(move|screen|ok_flat(expr.nth(2)?.map(|x: &'a str|state.interpret(screen, x)))); let thunk_b = draw(move|screen|ok_flat(expr.nth(3)?.map(|x: &'a str|state.interpret(screen, x)))); ok_flat(matches!(expr.head()?, Some("either")).then(||{ - either(state.namespace(expr.nth(1)?)?.unwrap(), thunk_a, thunk_b).draw(output) + either(state.namespace(&expr.nth(1)?)?.unwrap(), thunk_a, thunk_b).draw(output) })) }); /// Render one thing if a condition is true and another false. /// /// ``` -/// # use tengri::*; -/// # fn test () -> impl Draw { +/// # use ::tengri::*; fn test <'a> () -> impl Draw<'a, Tui> { /// either(true, "Yes", "No") /// # } /// ``` diff --git a/src/lib.rs b/src/lib.rs index ac7b155..6d5c745 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1797,19 +1797,19 @@ pub trait AsMutOpt { fn as_mut_opt (&mut self) -> Option<&mut T>; } -> UsuallyRef<'a, Self>; } - impl<'a, T: Language<'a> + 'a> ColorDsl<'a, T> for Color { + impl<'a, T: Language + 'a> ColorDsl<'a, T> for Color { fn new_g (expr: &'a T, try_to_u8: impl Fn(PerhapsRef<'a, &'a str>)->PerhapsRef<'a, u8>) -> Result> { - let n = try_to_u8(expr.tail().map_err(Into::into))?.ok_or(Domain("not gray"))?; + let n = try_to_u8(expr.tail().map_err(Into::into))?.ok_or(LanguageError::domain("not gray"))?; Ok(Self::Rgb(n, n, n)) } fn new_rgb (expr: &'a T, try_to_u8: impl Fn(PerhapsRef<'a, &str>)->PerhapsRef<'a, u8>) -> Result> { - let r = try_to_u8(expr.nth(1).map_err(Into::into))?.ok_or(Domain("not red"))?; - let g = try_to_u8(expr.nth(2).map_err(Into::into))?.ok_or(Domain("not green"))?; - let b = try_to_u8(expr.nth(3).map_err(Into::into))?.ok_or(Domain("not blue"))?; + let r = try_to_u8(expr.nth(1).map_err(Into::into))?.ok_or(LanguageError::domain("not red"))?; + let g = try_to_u8(expr.nth(2).map_err(Into::into))?.ok_or(LanguageError::domain("not green"))?; + let b = try_to_u8(expr.nth(3).map_err(Into::into))?.ok_or(LanguageError::domain("not blue"))?; Ok(Color::Rgb(r, g, b)) } } @@ -1935,8 +1935,8 @@ pub trait AsMutOpt { fn as_mut_opt (&mut self) -> Option<&mut T>; } /// # Ok(()) } /// ``` pub trait Keywords : 'static { - fn keywords () -> impl Iterator Perhaps>; - fn keyword <'a> (&self, to: &mut U, expr: &'a impl Language<'a>) -> PerhapsRef<'a, V> { + fn keywords <'a> () -> impl Iterator PerhapsRef<'a, V>>; + fn keyword <'a> (&self, to: &mut U, expr: &'a (impl Language + ?Sized)) -> PerhapsRef<'a, V> { if let Some(expr) = expr.src()? { for keyword in Self::keywords() { if let Some(result) = keyword(self, to, &expr)? { @@ -1951,7 +1951,7 @@ pub trait AsMutOpt { fn as_mut_opt (&mut self) -> Option<&mut T>; } #[macro_export] macro_rules! impl_keywords { ($T:ty, $U:ty, $V:ty [ $($kw:ident),* ]) => { impl Keywords<$T, $U> for $V { - fn keywords () -> impl Iterator Perhaps<$U>> { + fn keywords <'a> () -> impl Iterator PerhapsRef<'a, $U>> { [ $($kw),* ].into_iter() } } diff --git a/src/term/keys.rs b/src/term/keys.rs index ace0cf6..e7d05c2 100644 --- a/src/term/keys.rs +++ b/src/term/keys.rs @@ -70,7 +70,7 @@ impl TuiKey { } #[cfg(feature = "lang")] - pub fn from_dsl <'a> (dsl: &'a impl Language<'a>) -> UsuallyRef<'a, Self> { + pub fn from_dsl <'a> (dsl: &'a impl Language) -> UsuallyRef<'a, Self> { if let Some(word) = dsl.word()? { let word = word.trim(); Ok(if word == ":char" { diff --git a/src/term/modify.rs b/src/term/modify.rs index 0ba0c37..524179d 100644 --- a/src/term/modify.rs +++ b/src/term/modify.rs @@ -4,7 +4,7 @@ use Color::*; fn_kw_layout_tui!(kw_tui_fg |state, output, expr| { let thunk = draw(move|screen|ok_flat(expr.nth(2)?.map(|x: &'a str|state.interpret(screen, x)))); Ok(matches!(expr.head()?, Some("fg")).then(||{ - if let Some(color) = state.namespace(expr.nth(1)?.expect("fg: expected arg 0 (color)"))? { + if let Some(color) = state.namespace(&expr.nth(1)?.expect("fg: expected arg 0 (color)"))? { fg(color, thunk).draw(output) } else { return Err(format!("fg: {:?}: not a color", expr.nth(1)).into()) @@ -15,7 +15,7 @@ fn_kw_layout_tui!(kw_tui_fg |state, output, expr| { fn_kw_layout_tui!(kw_tui_bg |state, output, expr| { let thunk = draw(move|screen|ok_flat(expr.nth(2)?.map(|x: &'a str|state.interpret(screen, x)))); Ok(matches!(expr.head()?, Some("bg")).then(||{ - if let Some(color) = state.namespace(expr.nth(1)?.expect("bg: expected arg 0 (color)"))? { + if let Some(color) = state.namespace(&expr.nth(1)?.expect("bg: expected arg 0 (color)"))? { bg(color, thunk).draw(output) } else { return Err(format!("bg: {:?}: not a color", expr.nth(1)?).into()) @@ -24,23 +24,21 @@ fn_kw_layout_tui!(kw_tui_bg |state, output, expr| { }); impl Tui { - pub fn eval_color_expr <'a> (state: &impl Namespace, src: &'a impl Language<'a>) - -> Result, Box> - { + + pub fn eval_color_expr <'a> ( + state: &'a impl Namespace, + src: &'a impl Language + ) -> Result, Box> { if let Some(expr) = src.expr()? { match (expr.head()?, expr.tail()?) { (Some("g"), Some(tail)) => { - let n: u8 = state.namespace(tail.head().map_err(Into::into))? - .ok_or(LanguageError::Domain("not gray"))?; + let n: u8 = state.namespace(&tail.head()?)?.ok_or(LanguageError::domain("not gray"))?; Ok(Some(Color::Rgb(n, n, n))) }, (Some("rgb"), Some(tail)) => { - let r: u8 = state.namespace(tail.head().map_err(Into::into))? - .ok_or(LanguageError::Domain("not red"))?; - let g: u8 = state.namespace(tail.tail().head().map_err(Into::into))? - .ok_or(LanguageError::Domain("not green"))?; - let b: u8 = state.namespace(tail.tail().tail().head().map_err(Into::into))? - .ok_or(LanguageError::Domain("not blue"))?; + let r: u8 = state.namespace(&tail.nth(0)?)?.ok_or(LanguageError::domain("not red"))?; + let g: u8 = state.namespace(&tail.nth(1)?)?.ok_or(LanguageError::domain("not green"))?; + let b: u8 = state.namespace(&tail.nth(2)?)?.ok_or(LanguageError::domain("not blue"))?; Ok(Some(Color::Rgb(r, g, b))) }, (Some(_), _) => return Err( @@ -54,6 +52,7 @@ impl Tui { Ok(None) } } + } /// Apply foreground color.