aboutsummaryrefslogtreecommitdiff
path: root/CHANGELOG.md
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-07-28 19:11:14 +0800
committer魏曹先生 <1992414357@qq.com>2026-07-28 19:11:14 +0800
commit2dff21cc78fd2d6a4fa4f227f6ad94e3f7baa943 (patch)
treede694a2d34a6dd60b08d6da31c4f27fcd5eec416 /CHANGELOG.md
parentbf35af6bbf30492bcd23eb6103fdac3382dd6d33 (diff)
feat(mingling_macros, mingling_pathf): add `#[command]` attribute macro
Add a new `#[command]` attribute macro (feature-gated behind `extra_macros`) that converts a plain function with a `Vec<String>` parameter into a fully wired Mingling command. The macro generates a `dispatcher!` call, a `#[chain]` wrapper, and a hidden module re-exporting all generated types. Also add `CommandPattern` to the pathf pattern analyzer to recognize `#[command]`-annotated functions and track their generated hidden modules.
Diffstat (limited to 'CHANGELOG.md')
-rw-r--r--CHANGELOG.md40
1 files changed, 40 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 15a5f7b..b53d3d6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -93,6 +93,46 @@ None
These methods provide ergonomic alternatives to `to_result()` + `unwrap()` / `unwrap_or_default()` / `unwrap_or_else()` / `expect()` chaining, reducing boilerplate when working with `PickArgParsed` tuples directly.
+3. **[`macros:command`]** Added the `#[command]` attribute macro (feature-gated behind `extra_macros`) that converts a plain function with a `Vec<String>` parameter into a fully wired Mingling command. The macro:
+
+ - Calls `dispatcher!("command_name")` to register the dispatcher entry.
+ - Generates a `#[chain]` wrapper that bridges the entry type (`Entry{Pascal}`) to the original function.
+ - Preserves the original function unchanged (including attributes, extensions, visibility, and asyncness).
+
+ **Syntax variants:**
+
+ ```rust,ignore
+ // Simple form — auto-derives names from function name
+ #[command]
+ fn greet(args: Vec<String>) -> Next { /* ... */ }
+ // → dispatcher!("greet"), CMDGreet, EntryGreet
+
+ // Explicit node path
+ #[command(node = "hello.world")]
+ fn greet(args: Vec<String>) -> Next { /* ... */ }
+ // → dispatcher!("hello.world", CMDGreet => EntryGreet)
+
+ // Explicit name/entry overrides
+ #[command(name = MyDispatcher, entry = MyEntry)]
+ fn greet(args: Vec<String>) -> Next { /* ... */ }
+ // → dispatcher!("greet", MyDispatcher => MyEntry)
+ ```
+
+ **Extension attributes** (e.g. `buffer`, `routeify`) passed as bare paths in `#[command(...)]` are applied as `#[ext]` attributes **on the original function**, not on the generated chain wrapper. The chain wrapper always uses bare `#[::mingling::macros::chain]`.
+
+ **Resource injection:** Parameters after the first are treated as resource injections and passed through to the generated `#[chain]` wrapper unchanged.
+
+ **Hidden module:** Each `#[command]` generates a `#[doc(hidden)]` module `__command_{fn_name}_module` that re-exports all generated types (`CMD*`, `Entry*`, chain struct, dispatcher static) for pathf / external access.
+
+ Internally, the implementation:
+ - Parses `#[command(...)]` arguments via `CommandArgs` supporting `node`, `name`, `entry` keys and extension paths.
+ - Validates function constraints (no `self`, at least one parameter).
+ - Handles async functions (rejected without the `async` feature).
+ - Resolves default names via `just_fmt::dot_case!` / `just_fmt::pascal_case!`.
+ - Builds a chain wrapper that calls the original function with `entry.into()` for the first argument.
+
+4. **[`pathf:patterns`]** Added `CommandPattern` to the `pathf` pattern analyzer, matching functions annotated with `#[command]`. The pattern tracks the generated hidden module (`__command_{fn}_module`) and marks it as a local module item via `AnalyzeItem::local_module()`. The build system generates a glob re-export `use path::__command_{fn}_module::*;` to bring all generated types (`Entry*`, `CMD*`, chain struct, dispatcher static) into scope.
+
#### **BREAKING CHANGES** (API CHANGES):
None