diff options
Diffstat (limited to 'mingling_pathf')
| -rw-r--r-- | mingling_pathf/src/pattern_analyzer.rs | 2 | ||||
| -rw-r--r-- | mingling_pathf/src/patterns/dispatcher_clap.rs | 51 | ||||
| -rw-r--r-- | mingling_pathf/src/patterns/groupped_derive.rs | 53 | ||||
| -rw-r--r-- | mingling_pathf/test/src/lib.rs | 30 | ||||
| -rw-r--r-- | mingling_pathf/test/src/test_files/test_groupped_derive.rs | 17 |
5 files changed, 119 insertions, 34 deletions
diff --git a/mingling_pathf/src/pattern_analyzer.rs b/mingling_pathf/src/pattern_analyzer.rs index bfc2dc3..c4b1971 100644 --- a/mingling_pathf/src/pattern_analyzer.rs +++ b/mingling_pathf/src/pattern_analyzer.rs @@ -23,7 +23,7 @@ pub fn init_with_config(config: PathfinderConfig) -> PatternAnalyzer { analyzer.add_pattern(HelpPattern); analyzer.add_pattern(CompletionPattern); analyzer.add_pattern(DispatcherPattern::new(config.use_dispatch_tree)); - analyzer.add_pattern(DispatcherClapPattern); + analyzer.add_pattern(DispatcherClapPattern::new(config.use_dispatch_tree)); analyzer } diff --git a/mingling_pathf/src/patterns/dispatcher_clap.rs b/mingling_pathf/src/patterns/dispatcher_clap.rs index aed96e5..2e1ec6c 100644 --- a/mingling_pathf/src/patterns/dispatcher_clap.rs +++ b/mingling_pathf/src/patterns/dispatcher_clap.rs @@ -7,13 +7,22 @@ use crate::pattern_analyzer::{AnalyzeItem, AnalyzePattern}; /// - The dispatcher struct (`CMD*`, always) /// - The error type, if `error = ErrorType` is specified /// - The help internal struct, if `help = true` is specified +/// - `__internal_dispatcher_*` — dispatch tree static (when `use_dispatch_tree` is true) /// /// Covers forms: /// - `#[dispatcher_clap("greet", CMDGreet)] struct EntryGreet { ... }` /// - `#[dispatcher_clap("greet", CMDGreet, error = ErrorGreet)] struct EntryGreet { ... }` /// - `#[dispatcher_clap("greet", CMDGreet, help = true)] struct EntryGreet { ... }` /// - `#[dispatcher_clap("greet", CMDGreet, error = ErrorGreet, help = true)] struct EntryGreet { ... }` -pub struct DispatcherClapPattern; +pub struct DispatcherClapPattern { + pub use_dispatch_tree: bool, +} + +impl DispatcherClapPattern { + pub fn new(use_dispatch_tree: bool) -> Self { + Self { use_dispatch_tree } + } +} impl AnalyzePattern for DispatcherClapPattern { fn contains(&self, content: &str) -> bool { @@ -65,11 +74,6 @@ impl AnalyzePattern for DispatcherClapPattern { } // Help internal struct — if help = true - // The dispatcher_clap macro generates: - // __{cmd_snake}_help (via `format!("__{}_help", snake_case(dispatcher_struct))`) - // The `#[help]` macro then generates: - // __internal_help_{fn_snake} (via `format!("__internal_help_{}", snake_case(fn_name))`) - // Final name: __internal_help_{snake_case("__{cmd_snake}_help")} if parsed.help_enabled && let Some(ref cmd) = parsed.cmd_type { @@ -81,6 +85,20 @@ impl AnalyzePattern for DispatcherClapPattern { item_name: help_struct, }); } + + // __internal_dispatcher_* — when configured + if self.use_dispatch_tree + && let Some(ref cmd_name) = parsed.cmd_name + { + let internal_name = format!( + "__internal_dispatcher_{}", + just_fmt::snake_case!(cmd_name) + ); + items.push(AnalyzeItem { + module: String::new(), + item_name: internal_name, + }); + } } } Item::Mod(item_mod) => { @@ -135,6 +153,20 @@ impl AnalyzePattern for DispatcherClapPattern { item_name: help_struct, }); } + + // __internal_dispatcher_* — when configured + if self.use_dispatch_tree + && let Some(ref cmd_name) = parsed.cmd_name + { + let internal_name = format!( + "__internal_dispatcher_{}", + just_fmt::snake_case!(cmd_name) + ); + items.push(AnalyzeItem { + module: item_mod.ident.to_string(), + item_name: internal_name, + }); + } } } } @@ -149,6 +181,7 @@ impl AnalyzePattern for DispatcherClapPattern { } struct ParsedClapArgs { + cmd_name: Option<String>, cmd_type: Option<String>, error_type: Option<String>, help_enabled: bool, @@ -156,17 +189,18 @@ struct ParsedClapArgs { /// Parse `#[dispatcher_clap("cmd", CMDType, error = ErrorType, help = true)]` arguments. fn parse_dispatcher_clap_args(args: &str) -> ParsedClapArgs { + let mut cmd_name = None; let mut cmd_type = None; let mut error_type = None; let mut help_enabled = false; let args = args.trim(); - // Find the first quoted string (the command name) and skip it - // After that, look for ident-like tokens separated by commas + // Extract the first quoted string (the command name) let after_cmd = if let Some(start) = args.find('"') { let after_open = &args[start + 1..]; if let Some(end) = after_open.find('"') { + cmd_name = Some(after_open[..end].to_string()); after_open[end + 1..].trim() } else { args @@ -212,6 +246,7 @@ fn parse_dispatcher_clap_args(args: &str) -> ParsedClapArgs { } ParsedClapArgs { + cmd_name, cmd_type, error_type, help_enabled, diff --git a/mingling_pathf/src/patterns/groupped_derive.rs b/mingling_pathf/src/patterns/groupped_derive.rs index 44e7731..8491121 100644 --- a/mingling_pathf/src/patterns/groupped_derive.rs +++ b/mingling_pathf/src/patterns/groupped_derive.rs @@ -24,27 +24,24 @@ impl AnalyzePattern for GrouppedDerivePattern { for item in &syntax.items { match item { - Item::Struct(s) - if has_groupped_derive(&s.attrs) => { - items.push(AnalyzeItem { - module: String::new(), - item_name: s.ident.to_string(), - }); - } - Item::Enum(e) - if has_groupped_derive(&e.attrs) => { - items.push(AnalyzeItem { - module: String::new(), - item_name: e.ident.to_string(), - }); - } - Item::Union(u) - if has_groupped_derive(&u.attrs) => { - items.push(AnalyzeItem { - module: String::new(), - item_name: u.ident.to_string(), - }); - } + Item::Struct(s) if has_groupped_derive(&s.attrs) => { + items.push(AnalyzeItem { + module: String::new(), + item_name: s.ident.to_string(), + }); + } + Item::Enum(e) if has_groupped_derive(&e.attrs) => { + items.push(AnalyzeItem { + module: String::new(), + item_name: e.ident.to_string(), + }); + } + Item::Union(u) if has_groupped_derive(&u.attrs) => { + items.push(AnalyzeItem { + module: String::new(), + item_name: u.ident.to_string(), + }); + } Item::Mod(item_mod) => { if let Some((_, nested)) = &item_mod.content { for n in nested { @@ -77,12 +74,18 @@ impl AnalyzePattern for GrouppedDerivePattern { fn has_groupped_derive(attrs: &[syn::Attribute]) -> bool { attrs.iter().any(|attr| { if attr.path().is_ident("derive") { - attr.parse_args::<syn::MetaList>().ok().is_some_and(|meta| { - meta.path.segments.iter().any(|seg| { - let name = seg.ident.to_string(); + // Correctly parse comma-separated paths in #[derive(Groupped, Debug, ...)] + attr.parse_args_with(|input: syn::parse::ParseStream| { + let paths = + syn::punctuated::Punctuated::<syn::Path, syn::Token![,]>::parse_terminated( + input, + )?; + Ok(paths.iter().any(|p| { + let name = p.segments.last().unwrap().ident.to_string(); name == "Groupped" || name == "GrouppedSerialize" - }) + })) }) + .unwrap_or(false) } else { false } diff --git a/mingling_pathf/test/src/lib.rs b/mingling_pathf/test/src/lib.rs index 6fce3b2..824cbbf 100644 --- a/mingling_pathf/test/src/lib.rs +++ b/mingling_pathf/test/src/lib.rs @@ -233,8 +233,11 @@ fn test_groupped_derive_analyze() { "::Derived1", "::Derived2", "::Derived3", + "::EnumDerived1", + "::EnumDerived2", "::sub::Derived1", "::sub::Derived3", + "::sub::EnumDerived1", ]; assert_eq!(r.len(), required.len()); @@ -357,3 +360,30 @@ fn test_dispatcher_clap_analyze() { assert!(r.contains(*entry), "Result should contain: {}", entry); } } + +#[test] +fn test_dispatcher_clap_dispatch_tree() { + use mingling_pathf::config::PathfinderConfig; + use mingling_pathf::pattern_analyzer; + + let file = current_dir() + .unwrap() + .join("src/test_files/test_dispatcher_clap.rs"); + + // Without dispatch_tree: 26 items (same set as test_dispatcher_clap_analyze) + let r1 = pattern_analyzer::init().analyze_file(&file).unwrap(); + assert_eq!(r1.len(), 26); + + // With dispatch_tree: 26 + 4 __internal (root) + 3 __internal (sub, no "full") = 33 + let r2 = pattern_analyzer::init_with_config(PathfinderConfig::with_dispatch_tree()) + .analyze_file(&file) + .unwrap(); + assert_eq!(r2.len(), 33); + assert!(r2.contains("::__internal_dispatcher_greet")); + assert!(r2.contains("::__internal_dispatcher_delete")); + assert!(r2.contains("::__internal_dispatcher_helpcmd")); + assert!(r2.contains("::__internal_dispatcher_full")); + assert!(r2.contains("::sub::__internal_dispatcher_greet")); + assert!(r2.contains("::sub::__internal_dispatcher_delete")); + assert!(r2.contains("::sub::__internal_dispatcher_helpcmd")); +} diff --git a/mingling_pathf/test/src/test_files/test_groupped_derive.rs b/mingling_pathf/test/src/test_files/test_groupped_derive.rs index f6c6fa9..913587c 100644 --- a/mingling_pathf/test/src/test_files/test_groupped_derive.rs +++ b/mingling_pathf/test/src/test_files/test_groupped_derive.rs @@ -13,6 +13,18 @@ struct Derived3 { value: bool, } +#[derive(Groupped)] +enum EnumDerived1 { + A, + B, +} + +#[derive(GrouppedSerialize)] +enum EnumDerived2 { + X(String), + Y(i32), +} + pub mod sub { #[derive(Groupped)] struct Derived1 { @@ -23,4 +35,9 @@ pub mod sub { struct Derived3 { value: bool, } + + #[derive(Groupped)] + enum EnumDerived1 { + A, + } } |
