diff --git a/input/input.rs b/input/input.rs index b251232..aa72db1 100644 --- a/input/input.rs +++ b/input/input.rs @@ -19,6 +19,37 @@ pub trait Input: Sized { fn done (&self); } +/// Define a trait an implement it for various mutation-enabled wrapper types. */ +#[macro_export] macro_rules! flex_trait_mut ( + ($Trait:ident $(<$($A:ident:$T:ident),+>)? { + $(fn $fn:ident (&mut $self:ident $(, $arg:ident:$ty:ty)*) -> $ret:ty $body:block)* + })=>{ + pub trait $Trait $(<$($A: $T),+>)? { + $(fn $fn (&mut $self $(,$arg:$ty)*) -> $ret $body)* + } + impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for &mut _T_ { + $(fn $fn (&mut $self $(,$arg:$ty)*) -> $ret { (*$self).$fn($($arg),*) })* + } + impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for Option<_T_> { + $(fn $fn (&mut $self $(,$arg:$ty)*) -> $ret { + if let Some(this) = $self { this.$fn($($arg),*) } else { Ok(None) } + })* + } + impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for ::std::sync::Mutex<_T_> { + $(fn $fn (&mut $self $(,$arg:$ty)*) -> $ret { $self.get_mut().unwrap().$fn($($arg),*) })* + } + impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for ::std::sync::Arc<::std::sync::Mutex<_T_>> { + $(fn $fn (&mut $self $(,$arg:$ty)*) -> $ret { $self.lock().unwrap().$fn($($arg),*) })* + } + impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for ::std::sync::RwLock<_T_> { + $(fn $fn (&mut $self $(,$arg:$ty)*) -> $ret { $self.write().unwrap().$fn($($arg),*) })* + } + impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for ::std::sync::Arc<::std::sync::RwLock<_T_>> { + $(fn $fn (&mut $self $(,$arg:$ty)*) -> $ret { $self.write().unwrap().$fn($($arg),*) })* + } + }; +); + flex_trait_mut!(Handle { fn handle (&mut self, _input: &E) -> Perhaps { Ok(None) diff --git a/output/src/view.rs b/output/src/view.rs index 8e62c91..fc6411a 100644 --- a/output/src/view.rs +++ b/output/src/view.rs @@ -1,30 +1,30 @@ use crate::*; -use ::dizzle::{Dsl, DslExpr, DslWord, DslNs}; +use ::dizzle::{Language, Expression, Symbol, Namespace}; pub trait View { - fn view_expr <'a> (&'a self, output: &mut O, expr: &'a impl DslExpr) -> Usually { + fn view_expr <'a> (&'a self, _output: &mut O, expr: &'a impl Expression) -> Usually { Err(format!("View::view_expr: no exprs defined: {expr:?}").into()) } - fn view_word <'a> (&'a self, output: &mut O, word: &'a impl DslWord) -> Usually { + fn view_word <'a> (&'a self, _output: &mut O, word: &'a impl Symbol) -> Usually { Err(format!("View::view_word: no words defined: {word:?}").into()) } - fn view <'a> (&'a self, output: &mut O, dsl: &'a impl Dsl) -> Usually { + fn view <'a> (&'a self, output: &mut O, dsl: &'a impl Language) -> Usually { if let Ok(Some(expr)) = dsl.expr() { self.view_expr(output, &expr) } else if let Ok(Some(word)) = dsl.word() { self.view_word(output, &word) } else { - panic!("{dsl:?}: invalid") + Err(format!("{dsl:?}: invalid").into()) } } } pub fn evaluate_output_expression <'a, O: Out + 'a, S> ( - state: &S, output: &mut O, expr: &'a impl DslExpr + state: &S, output: &mut O, expr: &'a impl Expression ) -> Usually where S: View - + for<'b>DslNs<'b, bool> - + for<'b>DslNs<'b, O::Unit> + + 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 @@ -43,12 +43,12 @@ pub fn evaluate_output_expression <'a, O: Out + 'a, S> ( match frags.next() { Some("when") => output.place(&When::new( - state.from(arg0?)?.unwrap(), + state.resolve(arg0?)?.unwrap(), Thunk::new(move|output: &mut O|state.view(output, &arg1).unwrap()) )), Some("either") => output.place(&Either::new( - state.from(arg0?)?.unwrap(), + state.resolve(arg0?)?.unwrap(), Thunk::new(move|output: &mut O|state.view(output, &arg1).unwrap()), Thunk::new(move|output: &mut O|state.view(output, &arg2).unwrap()) )), @@ -96,9 +96,9 @@ pub fn evaluate_output_expression <'a, O: Out + 'a, S> ( let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("fixed: unsupported axis {axis:?}") }; let cb = Thunk::new(move|output: &mut O|state.view(output, &arg).unwrap()); match axis { - Some("xy") | None => Fixed::XY(state.from(arg0?)?.unwrap(), state.from(arg1?)?.unwrap(), cb), - Some("x") => Fixed::X(state.from(arg0?)?.unwrap(), cb), - Some("y") => Fixed::Y(state.from(arg0?)?.unwrap(), cb), + Some("xy") | None => Fixed::XY(state.resolve(arg0?)?.unwrap(), state.resolve(arg1?)?.unwrap(), cb), + Some("x") => Fixed::X(state.resolve(arg0?)?.unwrap(), cb), + Some("y") => Fixed::Y(state.resolve(arg0?)?.unwrap(), cb), frag => unimplemented!("fixed/{frag:?} ({expr:?}) ({head:?}) ({:?})", head.src()?.unwrap_or_default().split("/").next()) } @@ -109,9 +109,9 @@ pub fn evaluate_output_expression <'a, O: Out + 'a, S> ( let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("fixed: unsupported axis {axis:?}") }; let cb = Thunk::new(move|output: &mut O|state.view(output, &arg).unwrap()); match axis { - Some("xy") | None => Min::XY(state.from(arg0?)?.unwrap(), state.from(arg1?)?.unwrap(), cb), - Some("x") => Min::X(state.from(arg0?)?.unwrap(), cb), - Some("y") => Min::Y(state.from(arg0?)?.unwrap(), cb), + Some("xy") | None => Min::XY(state.resolve(arg0?)?.unwrap(), state.resolve(arg1?)?.unwrap(), cb), + Some("x") => Min::X(state.resolve(arg0?)?.unwrap(), cb), + Some("y") => Min::Y(state.resolve(arg0?)?.unwrap(), cb), frag => unimplemented!("min/{frag:?}") } }), @@ -121,9 +121,9 @@ pub fn evaluate_output_expression <'a, O: Out + 'a, S> ( let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("fixed: unsupported axis {axis:?}") }; let cb = Thunk::new(move|output: &mut O|state.view(output, &arg).unwrap()); match axis { - Some("xy") | None => Max::XY(state.from(arg0?)?.unwrap(), state.from(arg1?)?.unwrap(), cb), - Some("x") => Max::X(state.from(arg0?)?.unwrap(), cb), - Some("y") => Max::Y(state.from(arg0?)?.unwrap(), cb), + Some("xy") | None => Max::XY(state.resolve(arg0?)?.unwrap(), state.resolve(arg1?)?.unwrap(), cb), + Some("x") => Max::X(state.resolve(arg0?)?.unwrap(), cb), + Some("y") => Max::Y(state.resolve(arg0?)?.unwrap(), cb), frag => unimplemented!("max/{frag:?}") } }), @@ -133,9 +133,9 @@ pub fn evaluate_output_expression <'a, O: Out + 'a, S> ( let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("fixed: unsupported axis {axis:?}") }; let cb = Thunk::new(move|output: &mut O|state.view(output, &arg).unwrap()); match axis { - Some("xy") | None => Push::XY(state.from(arg0?)?.unwrap(), state.from(arg1?)?.unwrap(), cb), - Some("x") => Push::X(state.from(arg0?)?.unwrap(), cb), - Some("y") => Push::Y(state.from(arg0?)?.unwrap(), cb), + Some("xy") | None => Push::XY(state.resolve(arg0?)?.unwrap(), state.resolve(arg1?)?.unwrap(), cb), + Some("x") => Push::X(state.resolve(arg0?)?.unwrap(), cb), + Some("y") => Push::Y(state.resolve(arg0?)?.unwrap(), cb), frag => unimplemented!("push/{frag:?}") } }), diff --git a/tui/src/tui_engine.rs b/tui/src/tui_engine.rs index 52a84a0..1c53261 100644 --- a/tui/src/tui_engine.rs +++ b/tui/src/tui_engine.rs @@ -88,7 +88,7 @@ impl TuiRun for Arc> { fn run (&self, state: &Arc>) -> Usually<()> { let _input_thread = TuiIn::run_input(self, state, Duration::from_millis(100)); self.write().unwrap().setup()?; - let render_thread = TuiOut::run_output(self, state, Duration::from_millis(10)); + let render_thread = TuiOut::run_output(self, state, Duration::from_millis(10))?; match render_thread.join() { Ok(result) => { self.write().unwrap().teardown()?; @@ -96,7 +96,7 @@ impl TuiRun for Arc> { }, Err(error) => { self.write().unwrap().teardown()?; - panic!("\n\rDraw thread failed: {error:?}.\n\r") + panic!("\n\rDraw thread failed: error={error:?}.\n\r") }, } Ok(()) @@ -105,22 +105,22 @@ impl TuiRun for Arc> { #[cfg(feature = "dsl")] pub fn evaluate_output_expression_tui <'a, S> ( - state: &S, mut output: &mut TuiOut, expr: impl DslExpr + 'a + state: &S, output: &mut TuiOut, expr: impl Expression + 'a ) -> Usually where S: View - + for<'b>DslNs<'b, bool> - + for<'b>DslNs<'b, u16> - + for<'b>DslNs<'b, Color> + + for<'b>Namespace<'b, bool> + + for<'b>Namespace<'b, u16> + + for<'b>Namespace<'b, Color> { // See `tengri_output::evaluate_output_expression` let head = expr.head()?; let mut frags = head.src()?.unwrap_or_default().split("/"); - let args = expr.tail(); - let arg0 = args.head(); + let args = expr.tail(); + let arg0 = args.head(); let tail0 = args.tail(); - let arg1 = tail0.head(); + let arg1 = tail0.head(); let tail1 = tail0.tail(); - let arg2 = tail1.head(); + let _arg2 = tail1.head(); match frags.next() { Some("text") => if let Some(src) = args?.src()? { output.place(&src) }, @@ -128,7 +128,7 @@ pub fn evaluate_output_expression_tui <'a, S> ( Some("fg") => { let arg0 = arg0?.expect("fg: expected arg 0 (color)"); output.place(&Tui::fg( - DslNs::::from(state, arg0)?.unwrap_or_else(||panic!("fg: {arg0:?}: not a color")), + Namespace::::resolve(state, arg0)?.unwrap_or_else(||panic!("fg: {arg0:?}: not a color")), Thunk::new(move|output: &mut TuiOut|state.view(output, &arg1).unwrap()), )) }, @@ -136,7 +136,7 @@ pub fn evaluate_output_expression_tui <'a, S> ( Some("bg") => { let arg0 = arg0?.expect("bg: expected arg 0 (color)"); output.place(&Tui::bg( - DslNs::::from(state, arg0)?.unwrap_or_else(||panic!("bg: {arg0:?}: not a color")), + Namespace::::resolve(state, arg0)?.unwrap_or_else(||panic!("bg: {arg0:?}: not a color")), Thunk::new(move|output: &mut TuiOut|state.view(output, &arg1).unwrap()), )) }, diff --git a/tui/src/tui_engine/tui_event.rs b/tui/src/tui_engine/tui_event.rs index 1245a30..ead67fc 100644 --- a/tui/src/tui_engine/tui_event.rs +++ b/tui/src/tui_engine/tui_event.rs @@ -11,7 +11,7 @@ impl TuiEvent { Self(event) } #[cfg(feature = "dsl")] - pub fn from_dsl (dsl: impl Dsl) -> Perhaps { + pub fn from_dsl (dsl: impl Language) -> Perhaps { Ok(TuiKey::from_dsl(dsl)?.to_crossterm().map(Self)) } } @@ -19,7 +19,7 @@ pub struct TuiKey(Option, KeyModifiers); impl TuiKey { const SPLIT: char = '/'; #[cfg(feature = "dsl")] - pub fn from_dsl (dsl: impl Dsl) -> Usually { + pub fn from_dsl (dsl: impl Language) -> Usually { if let Some(word) = dsl.word()? { let word = word.trim(); Ok(if word == ":char" {