From a16603fbc88a41c0cb4a315383cb647b0f9bb2b5 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Thu, 8 May 2025 18:37:42 +0300 Subject: [PATCH 1/4] proc: command: associated fns instead of methods --- proc/src/proc_command.rs | 113 ++++++++++++++------------------------- 1 file changed, 39 insertions(+), 74 deletions(-) diff --git a/proc/src/proc_command.rs b/proc/src/proc_command.rs index d3d2ec4..9d1d9ad 100644 --- a/proc/src/proc_command.rs +++ b/proc/src/proc_command.rs @@ -109,21 +109,28 @@ impl CommandArm { fn ident_to_enum_variant (ident: &Ident) -> Arc { format!("{}", AsUpperCamelCase(format!("{ident}"))).into() } + fn has_args (&self) -> bool { + self.1.len() > 1 + } + fn args (&self) -> impl Iterator)> { + self.1.iter().skip(1).filter_map(|arg|if let FnArg::Typed(PatType { + ty, pat: box Pat::Ident(PatIdent { ident: arg, .. }), .. + }) = arg { + Some((arg, ty)) + } else { + unreachable!("only typed args should be present at this position"); + None + }) + } fn to_enum_variant_def (&self) -> TokenStream2 { let mut out = TokenStream2::new(); out.append(self.to_enum_variant_ident()); let ident = &self.0; - if self.1.len() > 2 { + if self.has_args() { out.append(Group::new(Delimiter::Brace, { let mut out = TokenStream2::new(); - for arg in self.1.iter().skip(2) { - if let FnArg::Typed(PatType { - ty, pat: box Pat::Ident(PatIdent { ident, .. }), .. - }) = arg { - write_quote_to(&mut out, quote! { #ident : #ty , }); - } else { - unreachable!("only typed args should be present at this position") - } + for (arg, ty) in self.args() { + write_quote_to(&mut out, quote! { #arg : #ty , }); } out })); @@ -135,24 +142,18 @@ impl CommandArm { let mut out = TokenStream2::new(); out.append(self.to_enum_variant_ident()); let ident = &self.0; - if self.1.len() > 2 { + if self.has_args() { out.append(Group::new(Delimiter::Brace, { let mut out = TokenStream2::new(); - for arg in self.1.iter().skip(2) { - if let FnArg::Typed(PatType { - ty, pat: box Pat::Ident(PatIdent { ident: arg, .. }), .. - }) = arg { - let take_err = LitStr::new(&format!("{}: missing argument \"{}\" ({})", - quote!{#ident}, quote!{#arg}, quote!{#ty}), Span::call_site()); - let give_err = LitStr::new(&format!("{}: missing value \"{}\" ({})", - quote!{#ident}, quote!{#arg}, quote!{#ty}), Span::call_site()); - write_quote_to(&mut out, quote! { - #arg : Context::get(state, &iter.next().expect(#take_err).value) - .expect(#give_err) , - }); - } else { - unreachable!("only typed args should be present at this position") - } + for (arg, ty) in self.args() { + let take_err = LitStr::new(&format!("{}: missing argument \"{}\" ({})", + quote!{#ident}, quote!{#arg}, quote!{#ty}), Span::call_site()); + let give_err = LitStr::new(&format!("{}: missing value \"{}\" ({})", + quote!{#ident}, quote!{#arg}, quote!{#ty}), Span::call_site()); + write_quote_to(&mut out, quote! { + #arg : Context::get(state, &iter.next().expect(#take_err).value) + .expect(#give_err) , + }); } out })); @@ -163,17 +164,11 @@ impl CommandArm { let mut out = TokenStream2::new(); out.append(self.to_enum_variant_ident()); let ident = &self.0; - if self.1.len() > 2 { + if self.has_args() { out.append(Group::new(Delimiter::Brace, { let mut out = TokenStream2::new(); - for arg in self.1.iter().skip(2) { - if let FnArg::Typed(PatType { - ty, pat: box Pat::Ident(PatIdent { ident: arg, .. }), .. - }) = arg { - write_quote_to(&mut out, quote! { #arg , }); - } else { - unreachable!("only typed args should be present at this position") - } + for (arg, ty) in self.args() { + write_quote_to(&mut out, quote! { #arg , }); } out })); @@ -181,52 +176,21 @@ impl CommandArm { out } fn to_matcher (&self) -> TokenStream2 { - let mut out = TokenStream2::new(); - let key = LitStr::new(&self.to_key(), Span::call_site()); - let ident = &self.0; - let take_args = self.1.iter().skip(2).map(|arg|{ - if let FnArg::Typed(PatType { - ty, pat: box Pat::Ident(PatIdent { ident: arg, .. }), .. - }) = arg { - let take_err = LitStr::new(&format!("{}: missing argument \"{}\" ({})", - quote!{#ident}, quote!{#arg}, quote!{#ty}), Span::call_site()); - write_quote(quote! { - let #ident: #ty = Context::<#ty>::get( - state, - &iter.next().expect(#take_err).value - ); - }) - } else { - unreachable!("only typed args should be present at this position") - } - }).collect::>(); - let variant = Self::ident_to_enum_variant(&self.0); + let key = LitStr::new(&self.to_key(), Span::call_site()); let variant = self.to_enum_variant_bind(); + let pattern = quote! { + Some(::tengri::dsl::Token { value: ::tengri::dsl::Value::Key(#key), .. }) + }; write_quote(quote! { - Some(::tengri::dsl::Token { value: ::tengri::dsl::Value::Key(#key), .. }) => { - let mut iter = iter.clone(); - //#(#take_args)* - //let rest = iter; // TODO - Some(Self::#variant) - }, + #pattern => { let mut iter = iter.clone(); Some(Self::#variant) }, }) } fn to_implementation (&self) -> TokenStream2 { let ident = &self.0; let variant = self.to_enum_variant_unbind(); let mut give_rest = write_quote(quote! { /*TODO*/ }); - let give_args = self.1.iter().skip(2).map(|arg|{ - if let FnArg::Typed(PatType { - ty, pat: box Pat::Ident(PatIdent { ident: arg, .. }), .. - }) = arg { - //let give_err = LitStr::new(&format!("{}: missing value \"{}\" ({})", - //quote!{#ident}, quote!{#pat}, quote!{#ty}), Span::call_site()); - write_quote(quote! { #arg, }) - } else { - unreachable!("only typed args should be present at this position") - } - }).collect::>(); - write_quote(quote! { Self::#variant => self.#ident(state, #(#give_args)* #give_rest), }) + let give_args = self.args().map(|(arg, ty)|write_quote(quote! { #arg, })).collect::>(); + write_quote(quote! { Self::#variant => Self::#ident(state, #(#give_args)* #give_rest), }) } } @@ -269,8 +233,9 @@ impl ToTokens for CommandArm { })); out.append(Punct::new('=', Joint)); out.append(Punct::new('>', Alone)); - out.append(Ident::new("self", Span::call_site())); - out.append(Punct::new('.', Alone)); + out.append(Ident::new("Self", Span::call_site())); + out.append(Punct::new(':', Joint)); + out.append(Punct::new(':', Alone)); out.append(ident.clone()); out.append(Group::new(Delimiter::Parenthesis, { let mut out = TokenStream2::new(); From bcbcc387a27f424b2199a3cdf16b78b0653b6592 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Thu, 8 May 2025 20:18:07 +0300 Subject: [PATCH 2/4] proc: cleanup --- proc/src/proc_command.rs | 2 +- proc/src/proc_expose.rs | 65 +++++++++++++--------------------------- 2 files changed, 21 insertions(+), 46 deletions(-) diff --git a/proc/src/proc_command.rs b/proc/src/proc_command.rs index 9d1d9ad..7102fd8 100644 --- a/proc/src/proc_command.rs +++ b/proc/src/proc_command.rs @@ -202,7 +202,7 @@ impl ToTokens for CommandVariant { out.append(Group::new(Delimiter::Parenthesis, { let mut out = TokenStream2::new(); for arg in args.iter() { - if let FnArg::Typed(PatType { attrs, pat, colon_token, ty }) = arg { + if let FnArg::Typed(PatType { ty, .. }) = arg { out.append(LitStr::new( &format!("{}", quote! { #ty }), Span::call_site() diff --git a/proc/src/proc_expose.rs b/proc/src/proc_expose.rs index 0303509..f3bb235 100644 --- a/proc/src/proc_expose.rs +++ b/proc/src/proc_expose.rs @@ -7,10 +7,7 @@ pub(crate) struct ExposeDef(pub(crate) ExposeMeta, pub(crate) ExposeImpl); pub(crate) struct ExposeMeta; #[derive(Debug, Clone)] -pub(crate) struct ExposeImpl { - block: ItemImpl, - exposed: BTreeMap>, -} +pub(crate) struct ExposeImpl(ItemImpl, BTreeMap>); #[derive(Debug, Clone)] struct ExposeArm(String, Ident); @@ -49,26 +46,22 @@ impl Parse for ExposeImpl { } } } - Ok(Self { block, exposed }) + Ok(Self(block, exposed)) } } impl ToTokens for ExposeDef { fn to_tokens (&self, out: &mut TokenStream2) { - let Self(meta, data) = self; - for token in quote! { #data } { - out.append(token) - } + let Self(_meta, data) = self; + write_quote_to(out, quote! { #data }); } } impl ToTokens for ExposeImpl { fn to_tokens (&self, out: &mut TokenStream2) { - let Self { block, exposed } = self; - let target = &self.block.self_ty; - for token in quote! { #block } { - out.append(token); - } + let Self(block, exposed) = self; + let target = &block.self_ty; + write_quote_to(out, quote! { #block }); for (t, variants) in exposed.iter() { let formatted_type = format!("{}", quote! { #t }); let predefined = match formatted_type.as_str() { @@ -89,8 +82,8 @@ impl ToTokens for ExposeImpl { }, _ => quote! {}, }; - let values = variants.iter().map(|(k, v)|ExposeArm(k.clone(), v.clone())); - let trait_impl = quote! { + let values = variants.iter().map(ExposeArm::from); + write_quote_to(out, quote! { impl ::tengri::dsl::Context<#t> for #target { fn get (&self, dsl: &::tengri::dsl::Value) -> Option<#t> { Some(match dsl { @@ -100,10 +93,7 @@ impl ToTokens for ExposeImpl { }) } } - }; - for token in trait_impl { - out.append(token); - } + }); } if exposed.len() > 0 { //panic!("{}", quote! {#out}); @@ -111,34 +101,19 @@ impl ToTokens for ExposeImpl { } } +impl From<(&String, &Ident)> for ExposeArm { + fn from ((a, b): (&String, &Ident)) -> Self { + Self(a.clone(), b.clone()) + } +} + impl ToTokens for ExposeArm { fn to_tokens (&self, out: &mut TokenStream2) { let Self(key, value) = self; - out.append(Punct::new(':', Joint)); - out.append(Punct::new(':', Alone)); - out.append(Ident::new("tengri", Span::call_site())); - out.append(Punct::new(':', Joint)); - out.append(Punct::new(':', Alone)); - out.append(Ident::new("dsl", Span::call_site())); - out.append(Punct::new(':', Joint)); - out.append(Punct::new(':', Alone)); - out.append(Ident::new("Value", Span::call_site())); - out.append(Punct::new(':', Joint)); - out.append(Punct::new(':', Alone)); - out.append(Ident::new("Sym", Span::call_site())); - out.append(Group::new(Delimiter::Parenthesis, { - let mut out = TokenStream2::new(); - out.append(LitStr::new(&key, Span::call_site()).token()); - out - })); - out.append(Punct::new('=', Joint)); - out.append(Punct::new('>', Alone)); - out.append(Ident::new("self", Span::call_site())); - out.append(Punct::new('.', Alone)); - for token in quote! { #value } { - out.append(token); - } - out.append(Group::new(Delimiter::Parenthesis, TokenStream2::new())); + let key = LitStr::new(&key, Span::call_site()); + write_quote_to(out, quote! { + ::tengri::dsl::Value::Sym(#key) => self.#value() + }) } } From b7bb6119aac975632969719c7ec5b71d97dbe356 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Thu, 8 May 2025 22:07:10 +0300 Subject: [PATCH 3/4] remove old declarative macros --- Cargo.lock | 1 + dsl/src/dsl_macros.rs | 121 ----------------------------------- dsl/src/lib.rs | 22 ++++--- input/src/input_macros.rs | 119 ---------------------------------- proc/src/proc_command.rs | 2 - proc/src/proc_expose.rs | 1 + tui/Cargo.toml | 5 +- tui/examples/demo.rs.old | 131 -------------------------------------- tui/examples/tui.rs | 39 +++++------- 9 files changed, 33 insertions(+), 408 deletions(-) delete mode 100644 tui/examples/demo.rs.old diff --git a/Cargo.lock b/Cargo.lock index 0df7fbe..d9ccc29 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -998,6 +998,7 @@ dependencies = [ "tengri_dsl", "tengri_input", "tengri_output", + "tengri_proc", "unicode-width 0.2.0", ] diff --git a/dsl/src/dsl_macros.rs b/dsl/src/dsl_macros.rs index 338583f..93b2cea 100644 --- a/dsl/src/dsl_macros.rs +++ b/dsl/src/dsl_macros.rs @@ -24,127 +24,6 @@ } } -/// Implement `Context` for one or more base structs, types, and keys. */ -#[macro_export] macro_rules! expose { - ($([$self:ident:$State:ty] $(([$($Type:tt)*] $(($pat:literal $expr:expr))*))*)*) => { - $(expose!(@impl [$self: $State] { $([$($Type)*] => { $($pat => $expr),* })* });)* - }; - ($([$self:ident:$State:ty] { $([$($Type:tt)*] => { $($pat:pat => $expr:expr),* $(,)? })* })*) => { - $(expose!(@impl [$self: $State] { $([$($Type)*] => { $($pat => $expr),* })* });)* - }; - (@impl [$self:ident:$State:ty] { $([$($Type:tt)*] => { $($pat:pat => $expr:expr),* $(,)? })* }) => { - $(expose!(@type [$($Type)*] [$self: $State] => { $($pat => $expr),* });)* - }; - (@type [bool] [$self:ident: $State:ty] => { $($pat:pat => $expr:expr),* $(,)? }) => { - provide_bool!(bool: |$self: $State| { $($pat => $expr),* }); - }; - (@type [u16] [$self:ident: $State:ty] => { $($pat:pat => $expr:expr),* $(,)? }) => { - provide_num!(u16: |$self: $State| { $($pat => $expr),* }); - }; - (@type [usize] [$self:ident: $State:ty] => { $($pat:pat => $expr:expr),* $(,)? }) => { - provide_num!(usize: |$self: $State| { $($pat => $expr),* }); - }; - (@type [isize] [$self:ident: $State:ty] => { $($pat:pat => $expr:expr),* $(,)? }) => { - provide_num!(isize: |$self: $State| { $($pat => $expr),* }); - }; - (@type [$Type:ty] [$self:ident: $State:ty] => { $($pat:pat => $expr:expr),* $(,)? }) => { - provide!($Type: |$self: $State| { $($pat => $expr),* }); - }; -} - -/// Implement `Context` for a context and type. -#[macro_export] macro_rules! provide { - // Provide a value to the EDN template - ($type:ty:|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => { - impl Context<$type> for $State { - #[allow(unreachable_code)] - fn get (&$self, dsl: &Value) -> Option<$type> { - use Value::*; - Some(match dsl { $(Sym($pat) => $expr,)* _ => return None }) - } - } - }; - // Provide a value more generically - ($lt:lifetime: $type:ty:|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => { - impl<$lt> Context<$lt, $type> for $State { - #[allow(unreachable_code)] - fn get (&$lt $self, dsl: &Value) -> Option<$type> { - use Value::*; - Some(match dsl { $(Sym($pat) => $expr,)* _ => return None }) - } - } - }; -} - -/// Implement `Context` for a context and numeric type. -/// -/// This enables support for numeric literals. -#[macro_export] macro_rules! provide_num { - // Provide a value that may also be a numeric literal in the EDN, to a generic implementation. - ($type:ty:|$self:ident:<$T:ident:$Trait:path>|{ $($pat:pat => $expr:expr),* $(,)? }) => { - impl<$T: $Trait> Context<$type> for $T { - fn get (&$self, dsl: &Value) -> Option<$type> { - use Value::*; - Some(match dsl { $(Sym($pat) => $expr,)* Num(n) => *n as $type, _ => return None }) - } - } - }; - // Provide a value that may also be a numeric literal in the EDN, to a concrete implementation. - ($type:ty:|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => { - impl Context<$type> for $State { - fn get (&$self, dsl: &Value) -> Option<$type> { - use Value::*; - Some(match dsl { $(Sym($pat) => $expr,)* Num(n) => *n as $type, _ => return None }) - } - } - }; -} - -/// Implement `Context` for a context and the boolean type. -/// -/// This enables support for boolean literals. -#[macro_export] macro_rules! provide_bool { - // Provide a value that may also be a numeric literal in the EDN, to a generic implementation. - ($type:ty:|$self:ident:<$T:ident:$Trait:path>|{ $($pat:pat => $expr:expr),* $(,)? }) => { - impl<$T: $Trait> Context<$type> for $T { - fn get (&$self, dsl: &Value) -> Option<$type> { - use Value::*; - Some(match dsl { - Num(n) => match *n { 0 => false, _ => true }, - Sym(":false") | Sym(":f") => false, - Sym(":true") | Sym(":t") => true, - $(Sym($pat) => $expr,)* - _ => return Context::get(self, dsl) - }) - } - } - }; - // Provide a value that may also be a numeric literal in the EDN, to a concrete implementation. - ($type:ty:|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => { - impl Context<$type> for $State { - fn get (&$self, dsl: &Value) -> Option<$type> { - use Value::*; - Some(match dsl { - Num(n) => match *n { 0 => false, _ => true }, - Sym(":false") | Sym(":f") => false, - Sym(":true") | Sym(":t") => true, - $(Sym($pat) => $expr,)* - _ => return None - }) - } - } - }; -} - -#[macro_export] macro_rules! impose { - ([$self:ident:$Struct:ty] $(($Command:ty : $(($cmd:literal $args:tt $result:expr))*))*) => { - $(atom_command!($Command: |$self: $Struct| { $(($cmd $args $result))* });)* - }; - ([$self:ident:$Struct:ty] { $($Command:ty => $variants:tt)* }) => { - $(atom_command!($Command: |$self: $Struct| $variants);)* - }; -} - #[macro_export] macro_rules! get_value { ($state:expr => $token:expr) => { if let Some(value) = $state.get(&$token.value) { diff --git a/dsl/src/lib.rs b/dsl/src/lib.rs index 994fc80..411974a 100644 --- a/dsl/src/lib.rs +++ b/dsl/src/lib.rs @@ -116,16 +116,18 @@ mod dsl_macros; #[cfg(test)] #[test] fn test_dsl_context () { struct Test; - provide_bool!(bool: |self: Test|{ - ":provide-bool" => true - }); - let test = Test; - assert_eq!(test.get(&Value::Sym(":false")), Some(false)); - assert_eq!(test.get(&Value::Sym(":true")), Some(true)); - assert_eq!(test.get(&Value::Sym(":provide-bool")), Some(true)); - assert_eq!(test.get(&Value::Sym(":missing-bool")), None); - assert_eq!(test.get(&Value::Num(0)), Some(false)); - assert_eq!(test.get(&Value::Num(1)), Some(true)); + #[tengri_proc::expose] + impl Test { + fn some_bool (&self) -> bool { + true + } + } + assert_eq!(Test.get(&Value::Sym(":false")), Some(false)); + assert_eq!(Test.get(&Value::Sym(":true")), Some(true)); + assert_eq!(Test.get(&Value::Sym(":some-bool")), Some(true)); + assert_eq!(Test.get(&Value::Sym(":missing-bool")), None); + assert_eq!(Test.get(&Value::Num(0)), Some(false)); + assert_eq!(Test.get(&Value::Num(1)), Some(true)); } //#[cfg(test)] #[test] fn test_examples () -> Result<(), ParseError> { diff --git a/input/src/input_macros.rs b/input/src/input_macros.rs index c3e13e9..689c94e 100644 --- a/input/src/input_macros.rs +++ b/input/src/input_macros.rs @@ -1,30 +1,5 @@ use crate::*; -/** Implement `Command` for given `State` and collection - * of `Variant` to `handler` mappings. */ -#[macro_export] macro_rules! defcom { - ([$self:ident, $state:ident:$State:ty] $(($Command:ident $(( - $Variant:ident [$($($param:ident: $Param:ty),+)?] $expr:expr - ))*))*) => { - $(#[derive(Clone, Debug)] pub enum $Command { - $($Variant $(($($Param),+))?),* - })* - $(command!(|$self: $Command, $state: $State|match $self { - $($Command::$Variant $(($($param),+))? => $expr),* - });)* - }; - (|$self:ident, $state:ident:$State:ty| $($Command:ident { $( - $Variant:ident $(($($param:ident: $Param:ty),+))? => $expr:expr - )* $(,)? })*) => { - $(#[derive(Clone, Debug)] pub enum $Command { - $($Variant $(($($Param),+))?),* - })* - $(command!(|$self: $Command, $state: $State|match $self { - $($Command::$Variant $(($($param),+))? => $expr),* - });)* - }; -} - /** Implement `Command` for given `State` and `handler` */ #[macro_export] macro_rules! command { ($(<$($l:lifetime),+>)?|$self:ident:$Command:ty,$state:ident:$State:ty|$handler:expr) => { @@ -35,97 +10,3 @@ use crate::*; } }; } - -/** Implement `DslCommand` for given `State` and `Command` */ -#[cfg(feature = "dsl")] -#[macro_export] macro_rules! atom_command { - ($Command:ty : |$state:ident:<$State:ident: $Trait:path>| { $(( - // identifier - $key:literal [ - // named parameters - $( - // argument name - $arg:ident - // if type is not provided defaults to Dsl - $( - // type:name separator - : - // argument type - $type:ty - )? - ),* - // rest of parameters - $(, ..$rest:ident)? - ] - // bound command: - $command:expr - ))* }) => { - impl<'a, $State: $Trait> TryFromDsl<'a, $State> for $Command { - fn try_from_expr ($state: &$State, iter: TokenIter) -> Option { - let iter = iter.clone(); - match iter.next() { - $(Some(Token { value: Value::Key($key), .. }) => { - let iter = iter.clone(); - $( - let next = iter.next(); - if next.is_none() { panic!("no argument: {}", stringify!($arg)); } - let $arg = next.unwrap(); - $(let $arg: Option<$type> = Context::<$type>::get($state, &$arg.value);)? - )* - $(let $rest = iter.clone();)? - return $command - },)* - _ => None - } - None - } - } - }; - ($Command:ty : |$state:ident:$State:ty| { $(( - // identifier - $key:literal [ - // named parameters - $( - // argument name - $arg:ident - // if type is not provided defaults to Dsl - $( - // type:name separator - : - // argument type - $type:ty - )? - ),* - // rest of parameters - $(, ..$rest:ident)? - ] - // bound command: - $command:expr - ))* }) => { - impl<'a> TryFromDsl<'a, $State> for $Command { - fn try_from_expr ($state: &$State, iter: TokenIter) -> Option { - let mut iter = iter.clone(); - match iter.next() { - $(Some(Token { value: Value::Key($key), .. }) => { - let mut iter = iter.clone(); - $( - let next = iter.next(); - if next.is_none() { panic!("no argument: {}", stringify!($arg)); } - let $arg = next.unwrap(); - $(let $arg: Option<$type> = Context::<$type>::get($state, &$arg.value);)? - )* - $(let $rest = iter.clone();)? - return $command - }),* - _ => None - } - } - } - }; - (@bind $state:ident =>$arg:ident ? : $type:ty) => { - let $arg: Option<$type> = Context::<$type>::get($state, $arg); - }; - (@bind $state:ident => $arg:ident : $type:ty) => { - let $arg: $type = Context::<$type>::get_or_fail($state, $arg); - }; -} diff --git a/proc/src/proc_command.rs b/proc/src/proc_command.rs index 7102fd8..b9ececc 100644 --- a/proc/src/proc_command.rs +++ b/proc/src/proc_command.rs @@ -227,8 +227,6 @@ impl ToTokens for CommandArm { out.append(Group::new(Delimiter::Parenthesis, { let mut out = TokenStream2::new(); out.append(self.to_enum_variant_ident()); - for arg in args.iter() { - } out })); out.append(Punct::new('=', Joint)); diff --git a/proc/src/proc_expose.rs b/proc/src/proc_expose.rs index f3bb235..affb192 100644 --- a/proc/src/proc_expose.rs +++ b/proc/src/proc_expose.rs @@ -84,6 +84,7 @@ impl ToTokens for ExposeImpl { }; let values = variants.iter().map(ExposeArm::from); write_quote_to(out, quote! { + /// Generated by [tengri_proc]. impl ::tengri::dsl::Context<#t> for #target { fn get (&self, dsl: &::tengri::dsl::Value) -> Option<#t> { Some(match dsl { diff --git a/tui/Cargo.toml b/tui/Cargo.toml index 5bf0dc2..a9eb4d9 100644 --- a/tui/Cargo.toml +++ b/tui/Cargo.toml @@ -20,8 +20,9 @@ tengri_output = { path = "../output" } tengri_dsl = { optional = true, path = "../dsl" } [dev-dependencies] -tengri = { path = "../tengri", features = [ "dsl" ] } -tengri_dsl = { path = "../dsl" } +tengri = { path = "../tengri", features = [ "dsl" ] } +tengri_dsl = { path = "../dsl" } +tengri_proc = { path = "../proc" } [features] dsl = [ "tengri_dsl", "tengri_input/dsl", "tengri_output/dsl" ] diff --git a/tui/examples/demo.rs.old b/tui/examples/demo.rs.old deleted file mode 100644 index ba013de..0000000 --- a/tui/examples/demo.rs.old +++ /dev/null @@ -1,131 +0,0 @@ -use tek::*; - -fn main () -> Usually<()> { - Tui::run(Arc::new(RwLock::new(Demo::new())))?; - Ok(()) -} - -pub struct Demo { - index: usize, - items: Vec>> -} - -impl Demo { - fn new () -> Self { - Self { - index: 0, - items: vec![] - } - } -} - -impl Content for Demo { - type Engine = Tui; - fn content (&self) -> dyn Render { - let border_style = Style::default().fg(Color::Rgb(0,0,0)); - Align::Center(Layers::new(move|add|{ - - add(&Background(Color::Rgb(0,128,128)))?; - - add(&Margin::XY(1, 1, Stack::down(|add|{ - - add(&Layers::new(|add|{ - add(&Background(Color::Rgb(128,96,0)))?; - add(&Border(Square(border_style)))?; - add(&Margin::XY(2, 1, "..."))?; - Ok(()) - }).debug())?; - - add(&Layers::new(|add|{ - add(&Background(Color::Rgb(128,64,0)))?; - add(&Border(Lozenge(border_style)))?; - add(&Margin::XY(4, 2, "---"))?; - Ok(()) - }).debug())?; - - add(&Layers::new(|add|{ - add(&Background(Color::Rgb(96,64,0)))?; - add(&Border(SquareBold(border_style)))?; - add(&Margin::XY(6, 3, "~~~"))?; - Ok(()) - }).debug())?; - - Ok(()) - })).debug())?; - - Ok(()) - - })) - //Align::Center(Margin::X(1, Layers::new(|add|{ - //add(&Background(Color::Rgb(128,0,0)))?; - //add(&Stack::down(|add|{ - //add(&Margin::Y(1, Layers::new(|add|{ - //add(&Background(Color::Rgb(0,128,0)))?; - //add(&Align::Center("12345"))?; - //add(&Align::Center("FOO")) - //})))?; - //add(&Margin::XY(1, 1, Layers::new(|add|{ - //add(&Align::Center("1234567"))?; - //add(&Align::Center("BAR"))?; - //add(&Background(Color::Rgb(0,0,128))) - //}))) - //})) - //}))) - - //Align::Y(Layers::new(|add|{ - //add(&Background(Color::Rgb(128,0,0)))?; - //add(&Margin::X(1, Align::Center(Stack::down(|add|{ - //add(&Align::X(Margin::Y(1, Layers::new(|add|{ - //add(&Background(Color::Rgb(0,128,0)))?; - //add(&Align::Center("12345"))?; - //add(&Align::Center("FOO")) - //})))?; - //add(&Margin::XY(1, 1, Layers::new(|add|{ - //add(&Align::Center("1234567"))?; - //add(&Align::Center("BAR"))?; - //add(&Background(Color::Rgb(0,0,128))) - //})))?; - //Ok(()) - //}))))) - //})) - } -} - -impl Handle for Demo { - fn handle (&mut self, from: &TuiIn) -> Perhaps { - use KeyCode::{PageUp, PageDown}; - match from.event() { - kexp!(PageUp) => { - self.index = (self.index + 1) % self.items.len(); - }, - kexp!(PageDown) => { - self.index = if self.index > 1 { - self.index - 1 - } else { - self.items.len() - 1 - }; - }, - _ => return Ok(None) - } - Ok(Some(true)) - } -} - -//lisp!(CONTENT Demo (LET - //(BORDER-STYLE (STYLE (FG (RGB 0 0 0)))) - //(BG-COLOR-0 (RGB 0 128 128)) - //(BG-COLOR-1 (RGB 128 96 0)) - //(BG-COLOR-2 (RGB 128 64 0)) - //(BG-COLOR-3 (RGB 96 64 0)) - //(CENTER (LAYERS - //(BACKGROUND BG-COLOR-0) - //(OUTSET-XY 1 1 (SPLIT-DOWN - //(LAYERS (BACKGROUND BG-COLOR-1) - //(BORDER SQUARE BORDER-STYLE) - //(OUTSET-XY 2 1 "...")) - //(LAYERS (BACKGROUND BG-COLOR-2) - //(BORDER LOZENGE BORDER-STYLE) - //(OUTSET-XY 4 2 "---")) - //(LAYERS (BACKGROUND BG-COLOR-3) - //(BORDER SQUARE-BOLD BORDER-STYLE) - //(OUTSET-XY 2 1 "~~~")))))))) diff --git a/tui/examples/tui.rs b/tui/examples/tui.rs index 7d9f9d7..3869a8e 100644 --- a/tui/examples/tui.rs +++ b/tui/examples/tui.rs @@ -41,23 +41,24 @@ handle!(TuiIn: |self: Example, input|{ }) }); -defcom! { |self, state: Example| - ExampleCommand { - Next => { - state.0 = (state.0 + 1) % EXAMPLES.len(); - None - } - Prev => { - state.0 = if state.0 > 0 { state.0 - 1 } else { EXAMPLES.len() - 1 }; - None - } - } +#[tengri_proc::expose] +impl Example { + //[bool] => {} + //[u16] => {} + //[usize] => {} } -atom_command!(ExampleCommand: |app: Example| { - ("prev" [] Some(Self::Prev)) - ("next" [] Some(Self::Next)) -}); +#[tengri_proc::command(Example)] +impl ExampleCommand { + fn next (state: &mut Example) -> Perhaps { + state.0 = (state.0 + 1) % EXAMPLES.len(); + Ok(None) + } + fn prev (state: &mut Example) -> Perhaps { + state.0 = if state.0 > 0 { state.0 - 1 } else { EXAMPLES.len() - 1 }; + Ok(None) + } +} view!(TuiOut: |self: Example|{ let index = self.0 + 1; @@ -77,11 +78,3 @@ view!(TuiOut: |self: Example|{ ":map-e" => Map::east(5u16, ||0..5u16, |n, i|format!("{n}")).boxed(), ":map-s" => Map::south(5u16, ||0..5u16, |n, i|format!("{n}")).boxed(), }); - -expose! { - [self: Example] { - [bool] => {} - [u16] => {} - [usize] => {} - } -} From 22d63eed9c9cb5bed5016d851f90773e0f60280d Mon Sep 17 00:00:00 2001 From: unspeaker Date: Fri, 9 May 2025 01:38:18 +0300 Subject: [PATCH 4/4] input, dsl: cleanup --- dsl/src/dsl_iter.rs | 2 +- input/src/_input.rs | 36 ----------------- input/src/_input_event_map.rs | 73 ----------------------------------- input/src/input_macros.rs | 2 - 4 files changed, 1 insertion(+), 112 deletions(-) delete mode 100644 input/src/_input.rs delete mode 100644 input/src/_input_event_map.rs diff --git a/dsl/src/dsl_iter.rs b/dsl/src/dsl_iter.rs index 269bc55..acdbe4b 100644 --- a/dsl/src/dsl_iter.rs +++ b/dsl/src/dsl_iter.rs @@ -105,7 +105,7 @@ pub const fn peek_src <'a> (source: &'a str) -> Option> { }), _ => token.error(Unexpected(c)) }, - Str(s) => match c { + Str(_) => match c { '"' => return Some(token), _ => token.grow_str(), }, diff --git a/input/src/_input.rs b/input/src/_input.rs deleted file mode 100644 index 24dd927..0000000 --- a/input/src/_input.rs +++ /dev/null @@ -1,36 +0,0 @@ -use crate::*; -use std::time::Duration; -use std::thread::JoinHandle; - -/// Event source -pub trait Input: Send + Sync + Sized { - /// Type of input event - type Event; - /// Result of handling input - type Handled; // TODO: make this an Option> containing the undo - /// Currently handled event - fn event (&self) -> &Self::Event; - /// Whether component should exit - fn is_done (&self) -> bool; - /// Mark component as done - fn done (&self); -} - -/// Input thread entrypoint. -pub trait InputRun { - fn run_input (engine: T, state: Self, timer: Duration) -> JoinHandle<()>; -} - -/// Handle input through a mutable reference. -pub trait Handle: Send + Sync { - fn handle (&mut self, _input: &E) -> Perhaps { - Ok(None) - } -} - -/// Handle input through an immutable reference (e.g. [Arc] or [Arc]) -pub trait HandleRef: Send + Sync { - fn handle (&self, _input: &E) -> Perhaps { - Ok(None) - } -} diff --git a/input/src/_input_event_map.rs b/input/src/_input_event_map.rs deleted file mode 100644 index fc9644d..0000000 --- a/input/src/_input_event_map.rs +++ /dev/null @@ -1,73 +0,0 @@ -use crate::*; - -pub struct EventMap<'a, S, I: PartialEq, C> { - pub bindings: &'a [(I, &'a dyn Fn(&S) -> Option)], - pub fallback: Option<&'a dyn Fn(&S, &I) -> Option> -} - -impl<'a, S, I: PartialEq, C> EventMap<'a, S, I, C> { - pub fn handle (&self, state: &S, input: &I) -> Option { - for (binding, handler) in self.bindings.iter() { - if input == binding { - return handler(state) - } - } - if let Some(fallback) = self.fallback { - fallback(state, input) - } else { - None - } - } -} - -#[macro_export] macro_rules! keymap { - ( - $(<$lt:lifetime>)? $KEYS:ident = |$state:ident: $State:ty, $input:ident: $Input:ty| $Command:ty - { $($key:expr => $handler:expr),* $(,)? } $(,)? - ) => { - pub const $KEYS: EventMap<'static, $State, $Input, $Command> = EventMap { - fallback: None, - bindings: &[ $(($key, &|$state|Some($handler)),)* ] - }; - input_to_command!($(<$lt>)? $Command: |$state: $State, input: $Input|$KEYS.handle($state, input)?); - }; - ( - $(<$lt:lifetime>)? $KEYS:ident = |$state:ident: $State:ty, $input:ident: $Input:ty| $Command:ty - { $($key:expr => $handler:expr),* $(,)? }, $default:expr - ) => { - pub const $KEYS: EventMap<'static, $State, $Input, $Command> = EventMap { - fallback: Some(&|$state, $input|Some($default)), - bindings: &[ $(($key, &|$state|Some($handler)),)* ] - }; - input_to_command!($(<$lt>)? $Command: |$state: $State, input: $Input|$KEYS.handle($state, input)?); - }; -} - -#[macro_export] macro_rules! input_to_command { - (<$($l:lifetime),+> $Command:ty: |$state:ident:$State:ty, $input:ident:$Input:ty| $handler:expr) => { - impl<$($l),+> InputToCommand<$Input, $State> for $Command { - fn input_to_command ($state: &$State, $input: &$Input) -> Option { - Some($handler) - } - } - }; - ($Command:ty: |$state:ident:$State:ty, $input:ident:$Input:ty| $handler:expr) => { - impl InputToCommand<$Input, $State> for $Command { - fn input_to_command ($state: &$State, $input: &$Input) -> Option { - Some($handler) - } - } - } -} - -pub trait InputToCommand: Command + Sized { - fn input_to_command (state: &S, input: &I) -> Option; - fn execute_with_state (state: &mut S, input: &I) -> Perhaps { - Ok(if let Some(command) = Self::input_to_command(state, input) { - let _undo = command.execute(state)?; - Some(true) - } else { - None - }) - } -} diff --git a/input/src/input_macros.rs b/input/src/input_macros.rs index 689c94e..ae5758c 100644 --- a/input/src/input_macros.rs +++ b/input/src/input_macros.rs @@ -1,5 +1,3 @@ -use crate::*; - /** Implement `Command` for given `State` and `handler` */ #[macro_export] macro_rules! command { ($(<$($l:lifetime),+>)?|$self:ident:$Command:ty,$state:ident:$State:ty|$handler:expr) => {