aboutsummaryrefslogtreecommitdiff
path: root/mingling_pathf/src/patterns/dispatcher_clap.rs
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-08-17 03:27:46 +0800
committer魏曹先生 <1992414357@qq.com>2026-08-17 03:27:46 +0800
commitc23c590330af83afb6e146bcd9b0a274b3689d22 (patch)
tree34599cf2737ce4de22653c9ccae2d60a38a15842 /mingling_pathf/src/patterns/dispatcher_clap.rs
parent6980fbf2f9fb4c599d8dc6ff549a8b3288eb24e9 (diff)
refactor!: remove Node type and simplify dispatcher macro syntax
The `dispatcher!` macro no longer requires a `CMD*` dispatcher type argument; the dispatcher struct is now generated internally as `__Dispatcher{Pascal}`. The `Node` type, `node!` macro, and `Dispatcher::node()` / `clone_dispatcher()` methods are removed.
Diffstat (limited to 'mingling_pathf/src/patterns/dispatcher_clap.rs')
-rw-r--r--mingling_pathf/src/patterns/dispatcher_clap.rs56
1 files changed, 31 insertions, 25 deletions
diff --git a/mingling_pathf/src/patterns/dispatcher_clap.rs b/mingling_pathf/src/patterns/dispatcher_clap.rs
index da9da3e..cd7bf67 100644
--- a/mingling_pathf/src/patterns/dispatcher_clap.rs
+++ b/mingling_pathf/src/patterns/dispatcher_clap.rs
@@ -2,16 +2,16 @@
//! The `DispatcherClapPattern` matches structs annotated with `#[dispatcher_clap(...)]` and
//! extracts key items for code generation or analysis:
//! - The entry struct name (always)
-//! - The dispatcher command struct (`CMD*`, always)
+//! - The hidden dispatcher struct (`__Dispatcher*`, always)
//! - The error type, if `error = ErrorType` is specified
//! - The help internal struct, if `help = true` is specified
//! - The `__internal_dispatcher_*` compile-time collected static (always)
//!
//! Supported 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 { ... }`
+//! - `#[dispatcher_clap("greet")] struct EntryGreet { ... }`
+//! - `#[dispatcher_clap("greet", error = ErrorGreet)] struct EntryGreet { ... }`
+//! - `#[dispatcher_clap("greet", help = true)] struct EntryGreet { ... }`
+//! - `#[dispatcher_clap("greet", error = ErrorGreet, help = true)] struct EntryGreet { ... }`
use syn::Item;
@@ -19,16 +19,16 @@ use crate::pattern_analyzer::{AnalyzeItem, AnalyzePattern};
/// Match structs annotated with `#[dispatcher_clap(...)]`, extracting:
/// - The entry type (struct name, always)
-/// - The dispatcher struct (`CMD*`, always)
+/// - The hidden dispatcher struct (`__Dispatcher*`, always)
/// - The error type, if `error = ErrorType` is specified
/// - The help internal struct, if `help = true` is specified
/// - `__internal_dispatcher_*` — compile-time collected static (always)
///
/// 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 { ... }`
+/// - `#[dispatcher_clap("greet")] struct EntryGreet { ... }`
+/// - `#[dispatcher_clap("greet", error = ErrorGreet)] struct EntryGreet { ... }`
+/// - `#[dispatcher_clap("greet", help = true)] struct EntryGreet { ... }`
+/// - `#[dispatcher_clap("greet", error = ErrorGreet, help = true)] struct EntryGreet { ... }`
#[derive(Default)]
pub struct DispatcherClapPattern;
@@ -95,9 +95,10 @@ impl DispatcherClapPattern {
let args_str = args.map(|l| l.tokens.to_string()).unwrap_or_default();
let parsed = parse_dispatcher_clap_args(&args_str);
- // CMD type — always
- if let Some(ref cmd) = parsed.cmd_type {
- items.push(AnalyzeItem::local(module.to_string(), cmd.clone()));
+ // Hidden dispatcher struct — always (if the command name is given)
+ if let Some(ref cmd_name) = parsed.cmd_name {
+ let hidden_name = format!("__Dispatcher{}", to_pascal_case(cmd_name));
+ items.push(AnalyzeItem::local(module.to_string(), hidden_name));
}
// Error type — if error = TypeName
@@ -107,9 +108,9 @@ impl DispatcherClapPattern {
// Help internal struct — if help = true
if parsed.help_enabled
- && let Some(ref cmd) = parsed.cmd_type
+ && let Some(ref cmd_name) = parsed.cmd_name
{
- let help_fn = format!("__{}_help", just_fmt::snake_case!(cmd));
+ let help_fn = format!("__{}_help", just_fmt::snake_case!(cmd_name));
let help_struct = format!("__internal_help_{}", just_fmt::snake_case!(&help_fn));
items.push(AnalyzeItem::local(module.to_string(), help_struct));
}
@@ -128,15 +129,13 @@ impl DispatcherClapPattern {
struct ParsedClapArgs {
cmd_name: Option<String>,
- cmd_type: Option<String>,
error_type: Option<String>,
help_enabled: bool,
}
-/// Parse `#[dispatcher_clap("cmd", CMDType, error = ErrorType, help = true)]` arguments.
+/// Parse `#[dispatcher_clap("cmd", 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;
@@ -178,23 +177,30 @@ fn parse_dispatcher_clap_args(args: &str) -> ParsedClapArgs {
}
_ => {}
}
- } else {
- // Bare ident — the CMD type
- let clean = part.trim_end_matches([')', ']']).trim();
- if !clean.is_empty() && cmd_type.is_none() {
- cmd_type = Some(clean.to_string());
- }
}
+ // Bare idents (e.g. the old CMD struct argument) are ignored.
}
ParsedClapArgs {
cmd_name,
- cmd_type,
error_type,
help_enabled,
}
}
+/// Simple `pascal_case` conversion for deriving the hidden dispatcher name.
+fn to_pascal_case(s: &str) -> String {
+ s.split(['-', '_', '.'])
+ .filter(|s| !s.is_empty())
+ .map(|s| {
+ let mut c = s.chars();
+ c.next().map_or_else(String::new, |f| {
+ f.to_uppercase().collect::<String>() + c.as_str()
+ })
+ })
+ .collect()
+}
+
fn has_attr(attrs: &[syn::Attribute], name: &str) -> bool {
attrs
.iter()