diff --git a/Justfile b/Justfile index e17aef3..af61a41 100644 --- a/Justfile +++ b/Justfile @@ -1,8 +1,6 @@ covfig := "CARGO_INCREMENTAL=0 RUSTFLAGS='-Cinstrument-coverage' RUSTDOCFLAGS='-Cinstrument-coverage' 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/*'" -bacon: - {{covfig}} bacon -s cov: {{covfig}} time cargo test -j4 --workspace --profile coverage rm -rf target/coverage/html || true diff --git a/dsl/src/dsl_ast.rs b/dsl/src/dsl_ast.rs index c28d73a..24a0f6f 100644 --- a/dsl/src/dsl_ast.rs +++ b/dsl/src/dsl_ast.rs @@ -1,5 +1,6 @@ use crate::*; use std::sync::Arc; +use std::borrow::Cow; #[derive(Debug, Clone, Default, PartialEq)] pub struct Ast(pub Value, AstIter>); diff --git a/dsl/src/dsl_cst.rs b/dsl/src/dsl_cst.rs index cfae7e2..7757a70 100644 --- a/dsl/src/dsl_cst.rs +++ b/dsl/src/dsl_cst.rs @@ -3,10 +3,6 @@ use crate::*; /// CST stores strings as source references and expressions as new [SourceIter] instances. pub type CstValue<'source> = Value<&'source str, SourceIter<'source>>; -/// Token sharing memory with source reference. -#[derive(Debug, Copy, Clone, Default, PartialEq)] -pub struct CstToken<'source>(pub CstValue<'source>, pub CstMeta<'source>); - /// Reference to the source slice. #[derive(Debug, Copy, Clone, Default, PartialEq)] pub struct CstMeta<'source> { pub source: &'source str, @@ -14,6 +10,10 @@ pub struct CstToken<'source>(pub CstValue<'source>, pub CstMeta<'source>); pub length: usize, } +/// Token sharing memory with source reference. +#[derive(Debug, Copy, Clone, Default, PartialEq)] +pub struct CstToken<'source>(pub CstValue<'source>, pub CstMeta<'source>); + impl<'source> CstToken<'source> { pub const fn new ( source: &'source str, start: usize, length: usize, value: CstValue<'source> diff --git a/dsl/src/dsl_display.rs b/dsl/src/dsl_display.rs index f86b4be..aaae8c7 100644 --- a/dsl/src/dsl_display.rs +++ b/dsl/src/dsl_display.rs @@ -1,5 +1,5 @@ use crate::*; -use std::fmt::{Display, Formatter, Error as FormatError}; +use std::fmt::{Debug, Display, Formatter, Error as FormatError}; impl Display for Ast { fn fmt (&self, out: &mut Formatter) -> Result<(), FormatError> { use Value::*; diff --git a/dsl/src/dsl_iter.rs b/dsl/src/dsl_iter.rs index 2e0e47a..07cfdd7 100644 --- a/dsl/src/dsl_iter.rs +++ b/dsl/src/dsl_iter.rs @@ -7,32 +7,25 @@ pub trait DslIter { fn rest (self) -> Vec; } -/// Implement the const iterator pattern. -#[macro_export] macro_rules! const_iter { - ($(<$l:lifetime>)?|$self:ident: $Struct:ty| => $Item:ty => $expr:expr) => { - impl$(<$l>)? Iterator for $Struct { - type Item = $Item; - fn next (&mut $self) -> Option<$Item> { $expr } - } - impl$(<$l>)? ConstIntoIter for $Struct { - type Kind = IsIteratorKind; - type Item = $Item; - type IntoIter = Self; - } +#[derive(Debug, Clone, Default, PartialEq)] +pub struct AstIter(std::collections::VecDeque); + +impl DslIter for AstIter { + type Token = Ast; + fn peek (&self) -> Option { + self.0.get(0).cloned() + } + fn next (&mut self) -> Option { + self.0.pop_front() + } + fn rest (self) -> Vec { + self.0.into() } } -/// Owns a reference to the source text. -/// [SourceConstIter::next] emits subsequent pairs of: -/// * a [CstToken] and -/// * the source text remaining -/// * [ ] TODO: maybe [SourceConstIter::next] should wrap the remaining source in `Self` ? -#[derive(Copy, Clone, Debug, Default, PartialEq)] -pub struct SourceConstIter<'source>(pub &'source str); - -impl<'source> From> for SourceIter<'source> { - fn from (source: SourceConstIter<'source>) -> Self{ - Self(source) +impl<'source> From> for AstIter { + fn from (source: SourceIter<'source>) -> Self { + Self(source.map(Into::into).collect()) } } @@ -78,6 +71,35 @@ impl<'source> Into> for SourceIter<'source> { } } +/// Implement the const iterator pattern. +#[macro_export] macro_rules! const_iter { + ($(<$l:lifetime>)?|$self:ident: $Struct:ty| => $Item:ty => $expr:expr) => { + impl$(<$l>)? Iterator for $Struct { + type Item = $Item; + fn next (&mut $self) -> Option<$Item> { $expr } + } + impl$(<$l>)? ConstIntoIter for $Struct { + type Kind = IsIteratorKind; + type Item = $Item; + type IntoIter = Self; + } + } +} + +/// Owns a reference to the source text. +/// [SourceConstIter::next] emits subsequent pairs of: +/// * a [CstToken] and +/// * the source text remaining +/// * [ ] TODO: maybe [SourceConstIter::next] should wrap the remaining source in `Self` ? +#[derive(Copy, Clone, Debug, Default, PartialEq)] +pub struct SourceConstIter<'source>(pub &'source str); + +impl<'source> From> for SourceIter<'source> { + fn from (source: SourceConstIter<'source>) -> Self{ + Self(source) + } +} + impl<'source> From<&'source str> for SourceConstIter<'source> { fn from (source: &'source str) -> Self{ Self::new(source) @@ -106,25 +128,3 @@ impl<'source> SourceConstIter<'source> { } const_iter!(<'source>|self: SourceConstIter<'source>| => CstToken<'source> => self.next_mut().map(|(result, _)|result)); - -#[derive(Debug, Clone, Default, PartialEq)] -pub struct AstIter(std::collections::VecDeque); - -impl DslIter for AstIter { - type Token = Ast; - fn peek (&self) -> Option { - self.0.get(0).cloned() - } - fn next (&mut self) -> Option { - self.0.pop_front() - } - fn rest (self) -> Vec { - self.0.into() - } -} - -impl<'source> From> for AstIter { - fn from (source: SourceIter<'source>) -> Self { - Self(source.map(Into::into).collect()) - } -} diff --git a/dsl/src/dsl_test.rs b/dsl/src/dsl_test.rs index 2f5ce15..4f7c4b2 100644 --- a/dsl/src/dsl_test.rs +++ b/dsl/src/dsl_test.rs @@ -1,21 +1,21 @@ -use crate::*; - #[cfg(test)] mod test_token_iter { use crate::*; //use proptest::prelude::*; #[test] fn test_iters () { let mut iter = crate::SourceIter::new(&":foo :bar"); let _ = iter.next(); + let mut iter = crate::TokenIter::new(&":foo :bar"); + let _ = iter.next(); } #[test] const fn test_const_iters () { - let iter = crate::SourceConstIter::new(&":foo :bar"); + let mut iter = crate::SourceIter::new(&":foo :bar"); let _ = iter.next(); } #[test] fn test_num () { - let _digit = to_digit('0'); - let _digit = to_digit('x'); - let _number = to_number(&"123"); - let _number = to_number(&"12asdf3"); + let digit = to_digit('0'); + let digit = to_digit('x'); + let number = to_number(&"123"); + let number = to_number(&"12asdf3"); } //proptest! { //#[test] fn proptest_source_iter ( @@ -33,54 +33,67 @@ use crate::*; //} } -//#[cfg(test)] mod test_token_prop { - //use crate::{CstToken, CstMeta, Value::*}; - //use proptest::prelude::*; - //proptest! { - //#[test] fn test_token_prop ( - //source in "\\PC*", - //start in usize::MIN..usize::MAX, - //length in usize::MIN..usize::MAX, - //) { - //let token = CstToken(Nil, CstMeta { source: &source, start, length }); - //let _ = token.slice(); - //} - //} -//} +#[cfg(test)] mod test_token_prop { + use proptest::prelude::*; + proptest! { + #[test] fn test_token_prop ( + source in "\\PC*", + start in usize::MIN..usize::MAX, + length in usize::MIN..usize::MAX, + ) { + let token = crate::Token { + source: &source, + start, + length, + value: crate::Value::Nil + }; + let _ = token.slice(); + } + } +} #[cfg(test)] #[test] fn test_token () -> Result<(), Box> { - use crate::Value::*; let source = ":f00"; - let mut token = CstToken(Sym(":"), CstMeta { source, start: 0, length: 1 }); + let mut token = Token { source, start: 0, length: 1, value: Sym(":") }; token = token.grow_sym(); - assert_eq!(token, CstToken(Sym(":f"), CstMeta { source, start: 0, length: 2, })); + assert_eq!(token, Token { source, start: 0, length: 2, value: Sym(":f") }); token = token.grow_sym(); - assert_eq!(token, CstToken(Sym(":f0"), CstMeta { source, start: 0, length: 3, })); + assert_eq!(token, Token { source, start: 0, length: 3, value: Sym(":f0") }); token = token.grow_sym(); - assert_eq!(token, CstToken(Sym(":f00"), CstMeta { source, start: 0, length: 4, })); + assert_eq!(token, Token { source, start: 0, length: 4, value: Sym(":f00") }); - assert_eq!(None, - SourceIter::new("").next()); - assert_eq!(None, - SourceIter::new(" \n \r \t ").next()); - assert_eq!(&Num(7), - SourceIter::new("7").next().unwrap().0.value()); - assert_eq!(&Num(100), - SourceIter::new(" 100 ").next().unwrap().0.value()); - assert_eq!(&Err(Unexpected('a')), - SourceIter::new(" 9a ").next().unwrap().0.value()); - assert_eq!(&Sym(":123foo"), - SourceIter::new(" :123foo ").next().unwrap().0.value()); - assert_eq!(&Sym("@bar456"), - SourceIter::new(" \r\r\r\n\n\n@bar456\t\t\t\t\t\t").next().unwrap().0.value()); - assert_eq!(&Key("foo123"), - SourceIter::new("foo123").next().unwrap().0.value()); - assert_eq!(&Key("foo/bar"), - SourceIter::new("foo/bar").next().unwrap().0.value()); - assert_eq!(&Str("foo/bar"), - SourceIter::new("\"foo/bar\"").next().unwrap().0.value()); - assert_eq!(&Str("foo/bar"), - SourceIter::new(" \"foo/bar\" ").next().unwrap().0.value()); + let src = ""; + assert_eq!(None, SourceIter(src).next()); + + let src = " \n \r \t "; + assert_eq!(None, SourceIter(src).next()); + + let src = "7"; + assert_eq!(Num(7), SourceIter(src).next().unwrap().0.value); + + let src = " 100 "; + assert_eq!(Num(100), SourceIter(src).next().unwrap().0.value); + + let src = " 9a "; + assert_eq!(Err(Unexpected('a')), SourceIter(src).next().unwrap().0.value); + + let src = " :123foo "; + assert_eq!(Sym(":123foo"), SourceIter(src).next().unwrap().0.value); + + let src = " \r\r\r\n\n\n@bar456\t\t\t\t\t\t"; + assert_eq!(Sym("@bar456"), SourceIter(src).next().unwrap().0.value); + + let src = "foo123"; + assert_eq!(Key("foo123"), SourceIter(src).next().unwrap().0.value); + + let src = "foo/bar"; + assert_eq!(Key("foo/bar"), SourceIter(src).next().unwrap().0.value); + + let src = "\"foo/bar\""; + assert_eq!(Str("foo/bar"), SourceIter(src).next().unwrap().0.value); + + let src = " \"foo/bar\" "; + assert_eq!(Str("foo/bar"), SourceIter(src).next().unwrap().0.value); Ok(()) } @@ -95,7 +108,7 @@ use crate::*; //let mut expr = view.peek(); //assert_eq!(view.0.0, source); //assert_eq!(expr, Some(Token { - //source, start: 0, length: source.len() - 1, value: Exp(0, SourceIter::new(&source[1..])) + //source, start: 0, length: source.len() - 1, value: Exp(0, SourceIter(&source[1..])) //})); ////panic!("{view:?}"); ////panic!("{:#?}", expr); diff --git a/dsl/src/dsl_value.rs b/dsl/src/dsl_value.rs index f06cf84..45b586f 100644 --- a/dsl/src/dsl_value.rs +++ b/dsl/src/dsl_value.rs @@ -73,12 +73,12 @@ impl Clone for Value { } impl Copy for Value {} impl Debug for Value { - fn fmt (&self, _f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + fn fmt (&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { todo!() } } impl Display for Value { - fn fmt (&self, _f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + fn fmt (&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { todo!() } } diff --git a/dsl/src/lib.rs b/dsl/src/lib.rs index 24a5ee0..7e990c8 100644 --- a/dsl/src/lib.rs +++ b/dsl/src/lib.rs @@ -42,7 +42,7 @@ pub(crate) use thiserror::Error; pub(crate) use self::DslError::*; mod dsl_ast; pub use self::dsl_ast::*; mod dsl_cst; pub use self::dsl_cst::*; -mod dsl_display; //pub use self::dsl_display::*; +mod dsl_display; pub use self::dsl_display::*; mod dsl_domain; pub use self::dsl_domain::*; mod dsl_error; pub use self::dsl_error::*; mod dsl_iter; pub use self::dsl_iter::*; diff --git a/input/src/input_dsl.rs b/input/src/input_dsl.rs index d34a8f7..a91453f 100644 --- a/input/src/input_dsl.rs +++ b/input/src/input_dsl.rs @@ -1,5 +1,5 @@ use crate::*; -//use std::marker::PhantomData; +use std::marker::PhantomData; use std::fmt::Debug; #[derive(Default, Debug)] pub struct InputLayers(Vec); diff --git a/input/src/lib.rs b/input/src/lib.rs index 1324e15..4f27011 100644 --- a/input/src/lib.rs +++ b/input/src/lib.rs @@ -33,6 +33,6 @@ mod input_handle; pub use self::input_handle::*; } #[cfg(all(test, feature = "dsl"))] #[test] fn test_dsl_keymap () -> Usually<()> { - let _keymap = SourceIter::new(""); + let keymap = SourceIter::new(""); Ok(()) } diff --git a/output/src/lib.rs b/output/src/lib.rs index 5407df5..30e8fff 100644 --- a/output/src/lib.rs +++ b/output/src/lib.rs @@ -16,4 +16,3 @@ mod ops; pub use self::ops::*; mod output; pub use self::output::*; #[cfg(test)] mod test; -#[cfg(test)] pub use proptest_derive::Arbitrary; diff --git a/output/src/ops.rs b/output/src/ops.rs index 88a2ccb..cfeb23e 100644 --- a/output/src/ops.rs +++ b/output/src/ops.rs @@ -53,7 +53,7 @@ mod map; pub use self::map::*; mod memo; pub use self::memo::*; mod stack; pub use self::stack::*; mod thunk; pub use self::thunk::*; -mod transform; //pub use self::transform::*; +mod transform; pub use self::transform::*; /// Renders multiple things on top of each other, #[macro_export] macro_rules! lay { diff --git a/output/src/ops/memo.rs b/output/src/ops/memo.rs index 8168f2d..07e2d93 100644 --- a/output/src/ops/memo.rs +++ b/output/src/ops/memo.rs @@ -1,4 +1,4 @@ -//use crate::*; +use crate::*; use std::sync::{Arc, RwLock}; #[derive(Debug, Default)] pub struct Memo { diff --git a/output/src/ops/stack.rs b/output/src/ops/stack.rs index 59930ce..6498ab0 100644 --- a/output/src/ops/stack.rs +++ b/output/src/ops/stack.rs @@ -24,7 +24,7 @@ impl Stack { } } impl)->())->()> Content for Stack { - fn layout (&self, to: E::Area) -> E::Area { + fn layout (&self, mut to: E::Area) -> E::Area { let mut x = to.x(); let mut y = to.y(); let (mut w_used, mut w_remaining) = (E::Unit::zero(), to.w()); diff --git a/output/src/ops_dsl.rs b/output/src/ops_dsl.rs index 5d131bb..196f693 100644 --- a/output/src/ops_dsl.rs +++ b/output/src/ops_dsl.rs @@ -3,7 +3,7 @@ use Value::*; impl Dsl for When where S: Eval + Eval { fn try_provide (state: &S, source: Ast) -> Perhaps { - if let Exp(_, mut exp) = source.0 && let Some(Ast(Key(id))) = exp.peek() && *id == *"when" { + if let Exp(_, exp) = source.0 && let Some(Ast(Key(id))) = exp.peek() && *id == *"when" { let _ = exp.next(); return Ok(Some(Self( state.eval(exp.next().unwrap(), ||"when: expected condition")?, @@ -16,7 +16,7 @@ impl Dsl for When where S: Eval + Eval { impl Dsl for Either where S: Eval + Eval + Eval { fn try_provide (state: &S, source: Ast) -> Perhaps { - if let Exp(_, mut exp) = source.0 && let Some(Ast(Key(id))) = exp.peek() && *id == *"either" { + if let Exp(_, exp) = source.0 && let Some(Ast(Key(id))) = exp.peek() && *id == *"either" { let _ = exp.next(); return Ok(Some(Self( state.eval(exp.next().unwrap(), ||"either: expected condition")?, @@ -32,7 +32,7 @@ impl Dsl for Align where S: Eval, A> { fn try_provide (state: &S, source: Ast) -> Perhaps { if let Exp(_, source) = source.0 { let mut rest = source.clone(); - return Ok(Some(match rest.next().as_ref().and_then(|x|x.key()) { + return Ok(Some(match rest.next().and_then(|x|x.key()) { Some("align/c") => Self::c(state.eval(rest.next(), ||"align/c: expected content")?), Some("align/x") => Self::x(state.eval(rest.next(), ||"align/x: expected content")?), Some("align/y") => Self::y(state.eval(rest.next(), ||"align/y: expected content")?), @@ -55,7 +55,7 @@ impl Dsl for Bsp where S: Eval, A> + Eval Perhaps { if let Exp(_, exp) = source.0 { let mut rest = exp.clone(); - return Ok(Some(match rest.next().as_ref().and_then(|x|x.key()) { + return Ok(Some(match rest.next().and_then(|x|x.key()) { Some("bsp/n") => Self::n( state.eval(rest.next(), ||"bsp/n: expected content 1")?, state.eval(rest.next(), ||"bsp/n: expected content 2")?, diff --git a/output/src/test.rs b/output/src/test.rs index d324664..517aa64 100644 --- a/output/src/test.rs +++ b/output/src/test.rs @@ -1,5 +1,5 @@ -use crate::{*, Direction::*}; -//use proptest_derive::Arbitrary; +use crate::*; +use proptest_derive::Arbitrary; use proptest::{prelude::*, option::of}; proptest! { @@ -86,7 +86,7 @@ macro_rules! test_op_transform { if let Some(op) = match (op_x, op_y) { (Some(x), Some(y)) => Some($Op::xy(x, y, content)), (Some(x), None) => Some($Op::x(x, content)), - (None, Some(y)) => Some($Op::y(y, content)), + (Some(y), None) => Some($Op::y(y, content)), _ => None } { assert_eq!(Content::layout(&op, [x, y, w, h]), @@ -142,7 +142,7 @@ proptest! { fn area_mut (&mut self) -> &mut [u16;4] { &mut self.0 } - fn place + ?Sized> (&mut self, _: [u16;4], _: &T) { + fn place (&mut self, _: [u16;4], _: &impl Render) { () } } @@ -162,9 +162,9 @@ proptest! { #[test] fn test_iter_map () { struct Foo; impl Content for Foo {} - fn _make_map + Send + Sync> (data: &Vec) -> impl Content { - Map::new(||data.iter(), |_foo, _index|{}) + fn make_map + Send + Sync> (data: &Vec) -> impl Content { + Map::new(||data.iter(), |foo, index|{}) } - let _data = vec![Foo, Foo, Foo]; + let data = vec![Foo, Foo, Foo]; //let map = make_map(&data); } diff --git a/proc/src/lib.rs b/proc/src/lib.rs index bc39ee5..02ba5de 100644 --- a/proc/src/lib.rs +++ b/proc/src/lib.rs @@ -76,7 +76,7 @@ pub(crate) fn write_quote_to (out: &mut TokenStream2, quote: TokenStream2) { assert_eq!(x.output, output); // TODO - let _x: crate::proc_view::ViewImpl = pq! { + let x: crate::proc_view::ViewImpl = pq! { impl Foo { /// docstring1 #[tengri::view(":view1")] #[bar] fn a_view () {} @@ -86,7 +86,7 @@ pub(crate) fn write_quote_to (out: &mut TokenStream2, quote: TokenStream2) { #[baz] fn is_not_view () {} } }; - let _expected_target: Ident = pq! { Foo }; + let expected_target: Ident = pq! { Foo }; //assert_eq!(x.target, expected_target); //assert_eq!(x.items.len(), 2); //assert_eq!(x.items[0].item, pq! { diff --git a/proc/src/proc_command.rs b/proc/src/proc_command.rs index 078e794..b4ab9d7 100644 --- a/proc/src/proc_command.rs +++ b/proc/src/proc_command.rs @@ -73,18 +73,18 @@ impl ToTokens for CommandDef { out }); - let _matchers = exposed.values().map(|arm|{ + let matchers = exposed.values().map(|arm|{ let key = LitStr::new(&arm.to_key(), Span::call_site()); let variant = { let mut out = TokenStream2::new(); out.append(arm.to_enum_variant_ident()); - let _ident = &arm.0; + let ident = &arm.0; if arm.has_args() { out.append(Group::new(Delimiter::Brace, { let mut out = TokenStream2::new(); - for (arg, _ty) in arm.args() { + for (arg, ty) in arm.args() { write_quote_to(&mut out, quote! { - #arg: Dsl::try_provide(self, words)?, + #arg: Take::take_or_fail(self, words)?, }); } out @@ -149,8 +149,8 @@ impl ToTokens for CommandDef { } } /// Generated by [tengri_proc::command]. - impl ::tengri::dsl::Dsl<#state> for #command_enum { - fn try_provide (state: &#state, mut words: ::tengri::dsl::Ast) -> Perhaps { + impl ::tengri::dsl::Take<#state> for #command_enum { + fn take (state: &#state, mut words: ::tengri::dsl::Cst) -> Perhaps { let mut words = words.clone(); let token = words.next(); todo!()//Ok(match token { #(#matchers)* _ => None }) @@ -193,7 +193,7 @@ impl CommandArm { unreachable!("only typed args should be present at this position"); }) } - fn _to_enum_variant_def (&self) -> TokenStream2 { + fn to_enum_variant_def (&self) -> TokenStream2 { let mut out = TokenStream2::new(); out.append(self.to_enum_variant_ident()); //let ident = &self.0; diff --git a/proc/src/proc_expose.rs b/proc/src/proc_expose.rs index 2b64d1a..873b639 100644 --- a/proc/src/proc_expose.rs +++ b/proc/src/proc_expose.rs @@ -85,8 +85,8 @@ impl ToTokens for ExposeImpl { }); write_quote_to(out, quote! { /// Generated by [tengri_proc::expose]. - impl ::tengri::dsl::Dsl<#state> for #t { - fn try_provide (state: &#state, mut words: ::tengri::dsl::Ast) -> Perhaps { + impl ::tengri::dsl::Take<#state> for #t { + fn take (state: &#state, mut words: ::tengri::dsl::Cst) -> Perhaps { Ok(Some(match words.next().map(|x|x.value) { #predefined #(#values)* diff --git a/proc/src/proc_view.rs b/proc/src/proc_view.rs index ef5aa49..9815c34 100644 --- a/proc/src/proc_view.rs +++ b/proc/src/proc_view.rs @@ -45,7 +45,7 @@ impl ToTokens for ViewDef { // that operate over constants and symbols. let builtin = builtins_with_boxes_output(quote! { #output }).map(|builtin|quote! { ::tengri::dsl::Value::Exp(_, expr) => return Ok(Some( - #builtin::try_provide(state, expr, ||"failed to load builtin")?.boxed() + #builtin::take_or_fail(state, expr, ||"failed to load builtin")?.boxed() )), }); // Symbols are handled by user-taked functions @@ -63,8 +63,11 @@ impl ToTokens for ViewDef { /// Makes [#self_ty] able to construct the [Render]able /// which might correspond to a given [TokenStream], /// while taking [#self_ty]'s state into consideration. - impl<'state> ::tengri::dsl::Dsl + 'state>> for #self_ty { - fn try_provide (state: &'state #self_ty, mut words: ::tengri::dsl::Ast) -> Perhaps + 'state>> { + impl<'source, 'state: 'source> + Take<'state, 'source, #self_ty> + for Box + 'state> + { + fn take (state: &'state #self_ty, mut words: Cst<'source>) -> Perhaps { Ok(if let Some(::tengri::dsl::Token { value, .. }) = words.peek() { match value { #(#builtin)* #(#exposed)* _ => None } } else { @@ -76,11 +79,11 @@ impl ToTokens for ViewDef { } } -fn _builtins_with_holes () -> impl Iterator { +fn builtins_with_holes () -> impl Iterator { builtins_with(quote! { _ }, quote! { _ }) } -fn _builtins_with_boxes () -> impl Iterator { +fn builtins_with_boxes () -> impl Iterator { builtins_with(quote! { _ }, quote! { Box> }) } diff --git a/tengri/src/lib.rs b/tengri/src/lib.rs index 972a702..d451e70 100644 --- a/tengri/src/lib.rs +++ b/tengri/src/lib.rs @@ -5,4 +5,96 @@ pub use ::tengri_core::*; #[cfg(feature="tui")] pub use ::tengri_tui as tui; #[cfg(test)] extern crate tengri_proc; -#[cfg(test)] mod test; +#[cfg(test)] #[test] fn test_subcommand () -> Usually<()> { + use crate::input::{Command, InputMap, KeyMap, Handle, handle}; + use crate::dsl::TokenIter; + use crate::tui::TuiIn; + use crossterm::event::{Event, KeyEvent, KeyCode, KeyModifiers, KeyEventKind, KeyEventState}; + //use crate::input::*; + //use crate::dsl::*; + struct Test { + keys: InputMap<'static, Test, TestCommand, TuiIn, TokenIter<'static>> + } + handle!(TuiIn: |self: Test, input|if let Some(command) = self.keys.command(self, input) { + Ok(Some(true)) + } else { + Ok(None) + }); + #[tengri_proc::command(Test)] impl TestCommand { + fn do_thing (state: &mut Test) -> Perhaps { + Ok(None) + } + fn do_thing_arg (state: &mut Test, arg: usize) -> Perhaps { + Ok(None) + } + fn do_sub (state: &mut Test, command: TestSubcommand) -> Perhaps { + Ok(command.execute(state)?.map(|command|Self::DoSub { command })) + } + } + #[tengri_proc::command(Test)] impl TestSubcommand { + fn do_other_thing (state: &mut Test) -> Perhaps { + Ok(None) + } + fn do_other_thing_arg (state: &mut Test, arg: usize) -> Perhaps { + Ok(None) + } + } + let mut test = Test { + keys: InputMap::new(" + (@a do-thing) + (@b do-thing-arg 0) + (@c do-sub do-other-thing) + (@d do-sub do-other-thing-arg 0) + ".into()) + }; + assert_eq!(Some(true), test.handle(&TuiIn(Default::default(), Event::Key(KeyEvent { + kind: KeyEventKind::Press, + code: KeyCode::Char('a'), + modifiers: KeyModifiers::NONE, + state: KeyEventState::NONE, + })))?); + assert_eq!(Some(true), test.handle(&TuiIn(Default::default(), Event::Key(KeyEvent { + kind: KeyEventKind::Press, + code: KeyCode::Char('b'), + modifiers: KeyModifiers::NONE, + state: KeyEventState::NONE, + })))?); + assert_eq!(Some(true), test.handle(&TuiIn(Default::default(), Event::Key(KeyEvent { + kind: KeyEventKind::Press, + code: KeyCode::Char('c'), + modifiers: KeyModifiers::NONE, + state: KeyEventState::NONE, + })))?); + assert_eq!(Some(true), test.handle(&TuiIn(Default::default(), Event::Key(KeyEvent { + kind: KeyEventKind::Press, + code: KeyCode::Char('d'), + modifiers: KeyModifiers::NONE, + state: KeyEventState::NONE, + })))?); + assert_eq!(None, test.handle(&TuiIn(Default::default(), Event::Key(KeyEvent { + kind: KeyEventKind::Press, + code: KeyCode::Char('z'), + modifiers: KeyModifiers::NONE, + state: KeyEventState::NONE, + })))?); + Ok(()) +} + +//FIXME: +//#[cfg(test)] #[test] fn test_dsl_context () { + //use crate::dsl::{Dsl, Value}; + + //struct Test; + //#[tengri_proc::expose] + //impl Test { + //fn some_bool (&self) -> bool { + //true + //} + //} + //assert_eq!(Dsl::get(&Test, &Value::Sym(":false")), Some(false)); + //assert_eq!(Dsl::get(&Test, &Value::Sym(":true")), Some(true)); + //assert_eq!(Dsl::get(&Test, &Value::Sym(":some-bool")), Some(true)); + //assert_eq!(Dsl::get(&Test, &Value::Sym(":missing-bool")), None); + //assert_eq!(Dsl::get(&Test, &Value::Num(0)), Some(false)); + //assert_eq!(Dsl::get(&Test, &Value::Num(1)), Some(true)); +//} diff --git a/tengri/src/test.rs b/tengri/src/test.rs deleted file mode 100644 index 817c11b..0000000 --- a/tengri/src/test.rs +++ /dev/null @@ -1,97 +0,0 @@ -use crate::*; - -#[test] fn test_subcommand () -> Usually<()> { - use crate::input::{Command, Handle, handle}; - //use crate::dsl::TokenIter; - use crate::tui::TuiIn; - use crossterm::event::{Event, KeyEvent, KeyCode, KeyModifiers, KeyEventKind, KeyEventState}; - //use crate::input::*; - //use crate::dsl::*; - struct Test { - //keys: InputMap<'static, Test, TestCommand, TuiIn, TokenIter<'static>> - } - handle!(TuiIn: |self: Test, input|if let Some(command) = self.keys.command(self, input) { - Ok(Some(true)) - } else { - Ok(None) - }); - #[tengri_proc::command(Test)] - impl TestCommand { - fn do_thing (_state: &mut Test) -> Perhaps { - Ok(None) - } - fn do_thing_arg (_state: &mut Test, _arg: usize) -> Perhaps { - Ok(None) - } - fn do_sub (state: &mut Test, command: TestSubcommand) -> Perhaps { - Ok(command.execute(state)?.map(|command|Self::DoSub { command })) - } - } - #[tengri_proc::command(Test)] - impl TestSubcommand { - fn do_other_thing (_state: &mut Test) -> Perhaps { - Ok(None) - } - fn do_other_thing_arg (_state: &mut Test, _arg: usize) -> Perhaps { - Ok(None) - } - } - let mut test = Test { - keys: InputMap::new(" - (@a do-thing) - (@b do-thing-arg 0) - (@c do-sub do-other-thing) - (@d do-sub do-other-thing-arg 0) - ".into()) - }; - assert_eq!(Some(true), test.handle(&TuiIn(Default::default(), Event::Key(KeyEvent { - kind: KeyEventKind::Press, - code: KeyCode::Char('a'), - modifiers: KeyModifiers::NONE, - state: KeyEventState::NONE, - })))?); - assert_eq!(Some(true), test.handle(&TuiIn(Default::default(), Event::Key(KeyEvent { - kind: KeyEventKind::Press, - code: KeyCode::Char('b'), - modifiers: KeyModifiers::NONE, - state: KeyEventState::NONE, - })))?); - assert_eq!(Some(true), test.handle(&TuiIn(Default::default(), Event::Key(KeyEvent { - kind: KeyEventKind::Press, - code: KeyCode::Char('c'), - modifiers: KeyModifiers::NONE, - state: KeyEventState::NONE, - })))?); - assert_eq!(Some(true), test.handle(&TuiIn(Default::default(), Event::Key(KeyEvent { - kind: KeyEventKind::Press, - code: KeyCode::Char('d'), - modifiers: KeyModifiers::NONE, - state: KeyEventState::NONE, - })))?); - assert_eq!(None, test.handle(&TuiIn(Default::default(), Event::Key(KeyEvent { - kind: KeyEventKind::Press, - code: KeyCode::Char('z'), - modifiers: KeyModifiers::NONE, - state: KeyEventState::NONE, - })))?); - Ok(()) -} - -//FIXME: -//#[cfg(test)] #[test] fn test_dsl_context () { - //use crate::dsl::{Dsl, Value}; - - //struct Test; - //#[tengri_proc::expose] - //impl Test { - //fn some_bool (&self) -> bool { - //true - //} - //} - //assert_eq!(Dsl::get(&Test, &Value::Sym(":false")), Some(false)); - //assert_eq!(Dsl::get(&Test, &Value::Sym(":true")), Some(true)); - //assert_eq!(Dsl::get(&Test, &Value::Sym(":some-bool")), Some(true)); - //assert_eq!(Dsl::get(&Test, &Value::Sym(":missing-bool")), None); - //assert_eq!(Dsl::get(&Test, &Value::Num(0)), Some(false)); - //assert_eq!(Dsl::get(&Test, &Value::Num(1)), Some(true)); -//} diff --git a/tui/examples/edn/edn01.edn b/tui/examples/edn01.edn similarity index 100% rename from tui/examples/edn/edn01.edn rename to tui/examples/edn01.edn diff --git a/tui/examples/edn/edn02.edn b/tui/examples/edn02.edn similarity index 100% rename from tui/examples/edn/edn02.edn rename to tui/examples/edn02.edn diff --git a/tui/examples/edn/edn03.edn b/tui/examples/edn03.edn similarity index 100% rename from tui/examples/edn/edn03.edn rename to tui/examples/edn03.edn diff --git a/tui/examples/edn/edn04.edn b/tui/examples/edn04.edn similarity index 100% rename from tui/examples/edn/edn04.edn rename to tui/examples/edn04.edn diff --git a/tui/examples/edn/edn05.edn b/tui/examples/edn05.edn similarity index 100% rename from tui/examples/edn/edn05.edn rename to tui/examples/edn05.edn diff --git a/tui/examples/edn/edn06.edn b/tui/examples/edn06.edn similarity index 100% rename from tui/examples/edn/edn06.edn rename to tui/examples/edn06.edn diff --git a/tui/examples/edn/edn07.edn b/tui/examples/edn07.edn similarity index 100% rename from tui/examples/edn/edn07.edn rename to tui/examples/edn07.edn diff --git a/tui/examples/edn/edn08.edn b/tui/examples/edn08.edn similarity index 100% rename from tui/examples/edn/edn08.edn rename to tui/examples/edn08.edn diff --git a/tui/examples/edn/edn09.edn b/tui/examples/edn09.edn similarity index 100% rename from tui/examples/edn/edn09.edn rename to tui/examples/edn09.edn diff --git a/tui/examples/edn/edn10.edn b/tui/examples/edn10.edn similarity index 100% rename from tui/examples/edn/edn10.edn rename to tui/examples/edn10.edn diff --git a/tui/examples/edn/edn11.edn b/tui/examples/edn11.edn similarity index 100% rename from tui/examples/edn/edn11.edn rename to tui/examples/edn11.edn diff --git a/tui/examples/edn/edn12.edn b/tui/examples/edn12.edn similarity index 100% rename from tui/examples/edn/edn12.edn rename to tui/examples/edn12.edn diff --git a/tui/examples/edn/edn13.edn b/tui/examples/edn13.edn similarity index 100% rename from tui/examples/edn/edn13.edn rename to tui/examples/edn13.edn diff --git a/tui/examples/edn/edn14.edn b/tui/examples/edn14.edn similarity index 100% rename from tui/examples/edn/edn14.edn rename to tui/examples/edn14.edn diff --git a/tui/examples/edn/edn15.edn b/tui/examples/edn15.edn similarity index 100% rename from tui/examples/edn/edn15.edn rename to tui/examples/edn15.edn diff --git a/tui/examples/edn/edn16.edn b/tui/examples/edn16.edn similarity index 100% rename from tui/examples/edn/edn16.edn rename to tui/examples/edn16.edn diff --git a/tui/examples/edn/edn17.edn b/tui/examples/edn17.edn similarity index 100% rename from tui/examples/edn/edn17.edn rename to tui/examples/edn17.edn diff --git a/tui/examples/edn/edn99.edn b/tui/examples/edn99.edn similarity index 100% rename from tui/examples/edn/edn99.edn rename to tui/examples/edn99.edn diff --git a/tui/examples/tui.rs b/tui/examples/tui.rs index 63312e8..066ab20 100644 --- a/tui/examples/tui.rs +++ b/tui/examples/tui.rs @@ -1,6 +1,6 @@ use tengri::{self, Usually, Perhaps, input::*, output::*, tui::*, dsl::*}; use std::sync::{Arc, RwLock}; -//use crossterm::event::{*, KeyCode::*}; +use crossterm::event::{*, KeyCode::*}; use crate::ratatui::style::Color; fn main () -> Usually<()> { @@ -13,23 +13,23 @@ fn main () -> Usually<()> { const KEYMAP: &str = "(@left prev) (@right next)"; const EXAMPLES: &'static [&'static str] = &[ - include_str!("edn/edn01.edn"), - include_str!("edn/edn02.edn"), - include_str!("edn/edn03.edn"), - include_str!("edn/edn04.edn"), - include_str!("edn/edn05.edn"), - include_str!("edn/edn06.edn"), - include_str!("edn/edn07.edn"), - include_str!("edn/edn08.edn"), - include_str!("edn/edn09.edn"), - include_str!("edn/edn10.edn"), - include_str!("edn/edn11.edn"), - include_str!("edn/edn12.edn"), - //include_str!("edn/edn13.edn"), - include_str!("edn/edn14.edn"), - include_str!("edn/edn15.edn"), - include_str!("edn/edn16.edn"), - include_str!("edn/edn17.edn"), + include_str!("edn01.edn"), + include_str!("edn02.edn"), + include_str!("edn03.edn"), + include_str!("edn04.edn"), + include_str!("edn05.edn"), + include_str!("edn06.edn"), + include_str!("edn07.edn"), + include_str!("edn08.edn"), + include_str!("edn09.edn"), + include_str!("edn10.edn"), + include_str!("edn11.edn"), + include_str!("edn12.edn"), + //include_str!("edn13.edn"), + include_str!("edn14.edn"), + include_str!("edn15.edn"), + include_str!("edn16.edn"), + include_str!("edn17.edn"), ]; handle!(TuiIn: |self: Example, input|{ @@ -63,7 +63,7 @@ impl ExampleCommand { } } -content!(TuiOut: |self: Example|{ +view!(TuiOut: |self: Example|{ let index = self.0 + 1; let wh = self.1.wh(); let src = EXAMPLES.get(self.0).unwrap_or(&""); @@ -72,29 +72,12 @@ content!(TuiOut: |self: Example|{ let code = Tui::bg(Color::Rgb(10, 60, 10), Push::y(2, Align::n(format!("{}", src)))); let content = Tui::bg(Color::Rgb(10, 10, 60), View(self, TokenIter::new(src))); self.1.of(Bsp::s(title, Bsp::n(""/*code*/, content))) +}; { + ":title" => Tui::bg(Color::Rgb(60, 10, 10), Push::y(1, Align::n(format!("Example {}/{}:", self.0 + 1, EXAMPLES.len())))).boxed(), + ":code" => Tui::bg(Color::Rgb(10, 60, 10), Push::y(2, Align::n(format!("{}", EXAMPLES[self.0])))).boxed(), + ":hello" => Tui::bg(Color::Rgb(10, 100, 10), "Hello").boxed(), + ":world" => Tui::bg(Color::Rgb(100, 10, 10), "world").boxed(), + ":hello-world" => "Hello world!".boxed(), + ":map-e" => Map::east(5u16, ||0..5u16, |n, i|format!("{n}")).boxed(), + ":map-s" => Map::south(5u16, ||0..5u16, |n, i|format!("{n}")).boxed(), }); - -#[tengri_proc::view(TuiOut)] -impl Example { - pub fn title (&self) -> impl Content + use<'_> { - Tui::bg(Color::Rgb(60, 10, 10), Push::y(1, Align::n(format!("Example {}/{}:", self.0 + 1, EXAMPLES.len())))).boxed() - } - pub fn code (&self) -> impl Content + use<'_> { - Tui::bg(Color::Rgb(10, 60, 10), Push::y(2, Align::n(format!("{}", EXAMPLES[self.0])))).boxed() - } - pub fn hello (&self) -> impl Content + use<'_> { - Tui::bg(Color::Rgb(10, 100, 10), "Hello").boxed() - } - pub fn world (&self) -> impl Content + use<'_> { - Tui::bg(Color::Rgb(100, 10, 10), "world").boxed() - } - pub fn hello_world (&self) -> impl Content + use<'_> { - "Hello world!".boxed() - } - pub fn map_e (&self) -> impl Content + use<'_> { - Map::east(5u16, ||0..5u16, |n, _i|format!("{n}")).boxed() - } - pub fn map_s (&self) -> impl Content + use<'_> { - Map::south(5u16, ||0..5u16, |n, _i|format!("{n}")).boxed() - } -} diff --git a/tui/src/lib.rs b/tui/src/lib.rs index e3792f1..79648b9 100644 --- a/tui/src/lib.rs +++ b/tui/src/lib.rs @@ -36,7 +36,7 @@ pub(crate) use std::io::{stdout, Stdout}; #[cfg(test)] #[test] fn test_tui_engine () -> Usually<()> { use crate::*; - //use std::sync::{Arc, RwLock}; + use std::sync::{Arc, RwLock}; struct TestComponent(String); impl Content for TestComponent { fn content (&self) -> impl Render { @@ -44,21 +44,21 @@ pub(crate) use std::io::{stdout, Stdout}; } } impl Handle for TestComponent { - fn handle (&mut self, _from: &TuiIn) -> Perhaps { + fn handle (&mut self, from: &TuiIn) -> Perhaps { Ok(None) } } let engine = Tui::new()?; engine.read().unwrap().exited.store(true, std::sync::atomic::Ordering::Relaxed); let state = TestComponent("hello world".into()); - let _state = std::sync::Arc::new(std::sync::RwLock::new(state)); + let state = std::sync::Arc::new(std::sync::RwLock::new(state)); //engine.run(&state)?; Ok(()) } #[cfg(test)] #[test] fn test_parse_key () { - //use KeyModifiers as Mods; - let _test = |x: &str, y|assert_eq!(KeyMatcher::new(x).build(), Some(Event::Key(y))); + use KeyModifiers as Mods; + let test = |x: &str, y|assert_eq!(KeyMatcher::new(x).build(), Some(Event::Key(y))); //test(":x", //KeyEvent::new(KeyCode::Char('x'), Mods::NONE)); //test(":ctrl-x", diff --git a/tui/src/tui_content.rs b/tui/src/tui_content.rs index 108d0b2..1b9cc1b 100644 --- a/tui/src/tui_content.rs +++ b/tui/src/tui_content.rs @@ -13,12 +13,12 @@ macro_rules! impl_content_layout_render { } mod tui_border; pub use self::tui_border::*; -mod tui_button; //pub use self::tui_button::*; +mod tui_button; pub use self::tui_button::*; mod tui_color; pub use self::tui_color::*; mod tui_field; pub use self::tui_field::*; mod tui_phat; pub use self::tui_phat::*; mod tui_repeat; pub use self::tui_repeat::*; -mod tui_number; //pub use self::tui_number::*; +mod tui_number; pub use self::tui_number::*; mod tui_scroll; pub use self::tui_scroll::*; mod tui_string; pub use self::tui_string::*; mod tui_style; pub use self::tui_style::*; diff --git a/tui/src/tui_content/tui_button.rs b/tui/src/tui_content/tui_button.rs index 53e546e..ec58935 100644 --- a/tui/src/tui_content/tui_button.rs +++ b/tui/src/tui_content/tui_button.rs @@ -1 +1 @@ -//use crate::{*, Color::*}; +use crate::{*, Color::*}; diff --git a/tui/src/tui_content/tui_field.rs b/tui/src/tui_content/tui_field.rs index 3e47e9f..3823182 100644 --- a/tui/src/tui_content/tui_field.rs +++ b/tui/src/tui_content/tui_field.rs @@ -3,7 +3,7 @@ use crate::*; pub struct FieldH(pub ItemTheme, pub T, pub U); impl, U: Content> Content for FieldH { fn content (&self) -> impl Render { - let Self(ItemTheme { darkest, dark, lightest, .. }, title, value) = self; + let Self(ItemTheme { darkest, dark, lighter, lightest, .. }, title, value) = self; row!( Tui::fg_bg(dark.rgb, darkest.rgb, "▐"), Tui::fg_bg(lightest.rgb, dark.rgb, title), @@ -16,7 +16,7 @@ impl, U: Content> Content for FieldH { pub struct FieldV(pub ItemTheme, pub T, pub U); impl, U: Content> Content for FieldV { fn content (&self) -> impl Render { - let Self(ItemTheme { darkest, dark, lightest, .. }, title, value) = self; + let Self(ItemTheme { darkest, dark, lighter, lightest, .. }, title, value) = self; Bsp::n( Align::w(Tui::bg(darkest.rgb, Tui::fg(lightest.rgb, Tui::bold(true, value)))), Fill::x(Align::w(row!( @@ -60,7 +60,7 @@ impl Field { value_align: None, } } - pub fn label ( + fn label ( self, label: Option, align: Option, @@ -75,7 +75,7 @@ impl Field { ..self } } - pub fn value ( + fn value ( self, value: Option, align: Option, diff --git a/tui/src/tui_content/tui_number.rs b/tui/src/tui_content/tui_number.rs index 46c4ef1..8e283ce 100644 --- a/tui/src/tui_content/tui_number.rs +++ b/tui/src/tui_content/tui_number.rs @@ -1,5 +1,5 @@ use crate::*; -render!(TuiOut: |self: u64, _to|todo!()); +render!(TuiOut: |self: u64, to|todo!()); -render!(TuiOut: |self: f64, _to|todo!()); +render!(TuiOut: |self: f64, to|todo!()); diff --git a/tui/src/tui_engine/tui_input.rs b/tui/src/tui_engine/tui_input.rs index 3bf7791..c9cd788 100644 --- a/tui/src/tui_engine/tui_input.rs +++ b/tui/src/tui_engine/tui_input.rs @@ -56,13 +56,13 @@ impl TuiIn { } } -//#[cfg(feature = "dsl")] -//impl DslInput for TuiIn { - //fn matches_dsl (&self, token: &str) -> bool { - //if let Some(event) = KeyMatcher::new(token).build() { - //&event == self.event() - //} else { - //false - //} - //} -//} +#[cfg(feature = "dsl")] +impl DslInput for TuiIn { + fn matches_dsl (&self, token: &str) -> bool { + if let Some(event) = KeyMatcher::new(token).build() { + &event == self.event() + } else { + false + } + } +}