aboutsummaryrefslogtreecommitdiff
path: root/mingling_macros/src
diff options
context:
space:
mode:
Diffstat (limited to 'mingling_macros/src')
-rw-r--r--mingling_macros/src/attr.rs4
-rw-r--r--mingling_macros/src/extensions.rs4
-rw-r--r--mingling_macros/src/func.rs16
-rw-r--r--mingling_macros/src/func/dispatcher.rs10
-rw-r--r--mingling_macros/src/func/suggest.rs43
-rw-r--r--mingling_macros/src/lib.rs50
6 files changed, 73 insertions, 54 deletions
diff --git a/mingling_macros/src/attr.rs b/mingling_macros/src/attr.rs
index 8c17878..54fe2f1 100644
--- a/mingling_macros/src/attr.rs
+++ b/mingling_macros/src/attr.rs
@@ -1,5 +1,5 @@
pub(crate) mod chain;
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
pub(crate) mod command;
#[cfg(feature = "comp")]
pub(crate) mod completion;
@@ -7,6 +7,6 @@ pub(crate) mod completion;
pub(crate) mod dispatcher_clap;
pub(crate) mod help;
pub(crate) mod mlint;
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
pub(crate) mod program_setup;
pub(crate) mod renderer;
diff --git a/mingling_macros/src/extensions.rs b/mingling_macros/src/extensions.rs
index c2fdb30..f4a6fde 100644
--- a/mingling_macros/src/extensions.rs
+++ b/mingling_macros/src/extensions.rs
@@ -10,11 +10,11 @@ use syn::parse::{Parse, ParseStream};
use syn::{Ident, Token};
/// Extension: `#[routeify]` — transforms `expr?` into `route!(expr)`.
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
pub(crate) mod routeify;
/// Extension: `#[renderify]` — transforms `expr?` into `render_route!(expr)`.
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
pub(crate) mod renderify;
/// Extension: `#[buffer]` — wraps a unit-returning function to return `RenderResult`.
diff --git a/mingling_macros/src/func.rs b/mingling_macros/src/func.rs
index d836b38..9e0e15f 100644
--- a/mingling_macros/src/func.rs
+++ b/mingling_macros/src/func.rs
@@ -1,18 +1,18 @@
pub(crate) mod dispatcher;
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
pub(crate) mod empty_result;
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
pub(crate) mod entry;
pub(crate) mod gen_program;
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
pub(crate) mod group;
-#[cfg(all(feature = "structural_renderer", feature = "extra_macros"))]
+#[cfg(all(feature = "structural_renderer", feature = "extras"))]
pub(crate) mod group_structural;
pub(crate) mod node;
pub(crate) mod pack;
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
pub(crate) mod pack_err;
-#[cfg(all(feature = "structural_renderer", feature = "extra_macros"))]
+#[cfg(all(feature = "structural_renderer", feature = "extras"))]
pub(crate) mod pack_err_structural;
#[cfg(feature = "structural_renderer")]
pub(crate) mod pack_structural;
@@ -30,9 +30,9 @@ pub(crate) mod register_dispatcher;
pub(crate) mod register_help;
pub(crate) mod register_renderer;
pub(crate) mod register_type;
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
pub(crate) mod render_route;
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
pub(crate) mod route;
#[cfg(feature = "comp")]
pub(crate) mod suggest;
diff --git a/mingling_macros/src/func/dispatcher.rs b/mingling_macros/src/func/dispatcher.rs
index ef02618..a9e2464 100644
--- a/mingling_macros/src/func/dispatcher.rs
+++ b/mingling_macros/src/func/dispatcher.rs
@@ -12,7 +12,7 @@ enum DispatcherChainInput {
command_struct: Ident,
pack: Ident,
},
- #[cfg(feature = "extra_macros")]
+ #[cfg(feature = "extras")]
Auto {
cmd_attrs: Vec<Attribute>,
command_name: syn::LitStr,
@@ -30,14 +30,14 @@ impl Parse for DispatcherChainInput {
// Check if this is the abbreviated form: just "command_name" without ", CMD => Entry"
if input.is_empty() {
- #[cfg(feature = "extra_macros")]
+ #[cfg(feature = "extras")]
{
return Ok(DispatcherChainInput::Auto {
cmd_attrs,
command_name,
});
}
- #[cfg(not(feature = "extra_macros"))]
+ #[cfg(not(feature = "extras"))]
{
return Err(syn::Error::new(
command_name.span(),
@@ -74,7 +74,7 @@ pub(crate) fn dispatcher(input: TokenStream) -> TokenStream {
// Parse the input
let dispatcher_input = syn::parse_macro_input!(input as DispatcherChainInput);
- #[cfg(not(feature = "extra_macros"))]
+ #[cfg(not(feature = "extras"))]
let (command_name, command_struct, pack, cmd_attrs, entry_attrs) = match dispatcher_input {
DispatcherChainInput::Default {
cmd_attrs,
@@ -85,7 +85,7 @@ pub(crate) fn dispatcher(input: TokenStream) -> TokenStream {
} => (command_name, command_struct, pack, cmd_attrs, entry_attrs),
};
- #[cfg(feature = "extra_macros")]
+ #[cfg(feature = "extras")]
let (command_name, command_struct, pack, cmd_attrs, entry_attrs) = match dispatcher_input {
DispatcherChainInput::Default {
cmd_attrs,
diff --git a/mingling_macros/src/func/suggest.rs b/mingling_macros/src/func/suggest.rs
index 85f1afe..6613a98 100644
--- a/mingling_macros/src/func/suggest.rs
+++ b/mingling_macros/src/func/suggest.rs
@@ -2,15 +2,15 @@ use proc_macro::TokenStream;
use quote::quote;
use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated;
-use syn::{Expr, LitStr, Token, parse_macro_input};
+use syn::{Expr, Token, parse_macro_input};
struct SuggestInput {
items: Punctuated<SuggestItem, Token![,]>,
}
enum SuggestItem {
- WithDesc(Box<(LitStr, Expr)>), // "-i" = "Insert something"
- Simple(LitStr), // "-I"
+ WithDesc(Box<(Expr, Expr)>), // "-i" = "Insert something"
+ Simple(Expr), // "-I"
}
impl Parse for SuggestInput {
@@ -22,7 +22,7 @@ impl Parse for SuggestInput {
impl Parse for SuggestItem {
fn parse(input: ParseStream) -> syn::Result<Self> {
- let key: LitStr = input.parse()?;
+ let key: Expr = input.parse()?;
if input.peek(Token![:]) {
let _colon: Token![:] = input.parse()?;
@@ -34,36 +34,55 @@ impl Parse for SuggestItem {
}
}
+/// 判断表达式是否是一个纯字符串字面量(仅由一对引号包裹)
+fn is_pure_lit_str(expr: &Expr) -> bool {
+ matches!(expr, Expr::Lit(lit) if matches!(lit.lit, syn::Lit::Str(_)))
+}
+
#[cfg(feature = "comp")]
pub(crate) fn suggest(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as SuggestInput);
let mut items = Vec::new();
+ let mut simple_items = Vec::new();
for item in input.items {
match item {
SuggestItem::WithDesc(boxed) => {
let (key, value) = *boxed;
- items.push(quote! {
- ::mingling::SuggestItem::new_with_desc(#key.to_string(), #value.to_string())
- });
+ if is_pure_lit_str(&key) {
+ items.push(quote! {
+ vec![#key .to_string()], #value
+ });
+ } else {
+ items.push(quote! {
+ #key, #value
+ });
+ }
}
SuggestItem::Simple(key) => {
- items.push(quote! {
- ::mingling::SuggestItem::new(#key.to_string())
- });
+ if is_pure_lit_str(&key) {
+ simple_items.push(quote! {
+ vec![#key .to_string()]
+ });
+ } else {
+ simple_items.push(quote! {
+ #key
+ });
+ }
}
}
}
- let expanded = if items.is_empty() {
+ let expanded = if items.is_empty() && simple_items.is_empty() {
quote! {
::mingling::Suggest::new()
}
} else {
quote! {{
let mut suggest = ::mingling::Suggest::new();
- #(suggest.insert(#items);)*
+ #(suggest.add_suggest_with_description(#items);)*
+ #(suggest.add_suggest(#simple_items);)*
suggest
}}
};
diff --git a/mingling_macros/src/lib.rs b/mingling_macros/src/lib.rs
index ae874af..b6656da 100644
--- a/mingling_macros/src/lib.rs
+++ b/mingling_macros/src/lib.rs
@@ -100,10 +100,10 @@
//! |---------|---------------|
//! | `clap` | `dispatcher_clap!` |
//! | `comp` | [`#[completion]`](attr.completion.html), `suggest!`, `suggest_enum!` |
-//! | `extra_macros` | `entry!`, `empty_result!`, `route!`, [`#[program_setup]`](attr.program_setup.html), `group!` |
+//! | `extras` | `entry!`, `empty_result!`, `route!`, [`#[program_setup]`](attr.program_setup.html), `group!` |
//! | `dispatch_tree` | `register_dispatcher!` (enables trie-based command dispatch) |
//! | `structural_renderer` | `#[derive(StructuralData)]`, `pack_structural!`, `pack_err_structural!`, `group_structural!` |
-//! | `structural_renderer` + `extra_macros` | `group_structural!`, `pack_err_structural!` |
+//! | `structural_renderer` + `extras` | `group_structural!`, `pack_err_structural!` |
//! | `async` | Enables async `#[chain]` functions |
//! | `repl` | Enables REPL execution loop |
//!
@@ -163,15 +163,15 @@ mod utils;
use attr::completion;
#[cfg(feature = "clap")]
use attr::dispatcher_clap;
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
use attr::program_setup;
use attr::{chain, help, renderer};
use derive::{enum_tag, grouped};
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
use func::entry;
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
pub(crate) use func::group as group_impl;
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
use func::pack_err;
#[cfg(feature = "comp")]
use func::suggest;
@@ -293,7 +293,7 @@ fn entry_has_variant(entry: &str, variant_name: &str) -> bool {
///
/// - The type must be accessible at the call site (imported or fully qualified).
/// - The alias name (if provided) must not conflict with existing types.
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
#[proc_macro]
pub fn group(input: TokenStream) -> TokenStream {
group_impl::group_macro(input)
@@ -309,8 +309,8 @@ pub fn group(input: TokenStream) -> TokenStream {
/// group_structural!(IoError = std::io::Error);
/// ```
///
-/// Requires the `structural_renderer` and `extra_macros` features.
-#[cfg(all(feature = "structural_renderer", feature = "extra_macros"))]
+/// Requires the `structural_renderer` and `extras` features.
+#[cfg(all(feature = "structural_renderer", feature = "extras"))]
#[proc_macro]
pub fn group_structural(input: TokenStream) -> TokenStream {
func::group_structural::group_structural(input)
@@ -490,8 +490,8 @@ pub fn pack_structural(input: TokenStream) -> TokenStream {
/// When the `structural_renderer` feature is enabled, the struct also gets
/// `#[derive(serde::Serialize)]`.
///
-/// This macro is only available with the `extra_macros` feature.
-#[cfg(feature = "extra_macros")]
+/// This macro is only available with the `extras` feature.
+#[cfg(feature = "extras")]
#[proc_macro]
pub fn pack_err(input: TokenStream) -> TokenStream {
pack_err::pack_err(input)
@@ -507,8 +507,8 @@ pub fn pack_err(input: TokenStream) -> TokenStream {
/// pack_err_structural!(ErrorNotDir = PathBuf);
/// ```
///
-/// Requires the `structural_renderer` and `extra_macros` features.
-#[cfg(all(feature = "structural_renderer", feature = "extra_macros"))]
+/// Requires the `structural_renderer` and `extras` features.
+#[cfg(all(feature = "structural_renderer", feature = "extras"))]
#[proc_macro]
pub fn pack_err_structural(input: TokenStream) -> TokenStream {
func::pack_err_structural::pack_err_structural(input)
@@ -568,7 +568,7 @@ pub fn pack_err_structural(input: TokenStream) -> TokenStream {
/// value.to_chain()
/// }
/// ```
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
#[proc_macro]
pub fn route(input: TokenStream) -> TokenStream {
func::route::route(input)
@@ -611,7 +611,7 @@ pub fn route(input: TokenStream) -> TokenStream {
/// Ok(RenderResult::new())
/// }
/// ```
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
#[proc_macro]
pub fn render_route(input: TokenStream) -> TokenStream {
func::render_route::render_route(input)
@@ -665,7 +665,7 @@ pub fn render_route(input: TokenStream) -> TokenStream {
///
/// [`ResultEmpty`]: https://docs.rs/mingling/latest/mingling/type.ResultEmpty.html
/// [`ChainProcess`]: https://docs.rs/mingling/latest/mingling/enum.ChainProcess.html
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
#[proc_macro]
pub fn empty_result(input: TokenStream) -> TokenStream {
func::empty_result::empty_result(input)
@@ -692,9 +692,9 @@ pub fn empty_result(input: TokenStream) -> TokenStream {
/// dispatcher!(MyProgram, "command.path", CommandStruct => EntryStruct);
/// ```
///
-/// ## Abbreviated syntax (requires `extra_macros` feature)
+/// ## Abbreviated syntax (requires `extras` feature)
///
-/// When the `extra_macros` feature is enabled, the `CommandStruct => EntryStruct`
+/// When the `extras` feature is enabled, the `CommandStruct => EntryStruct`
/// portion can be omitted. Struct names are auto-derived from the command path
/// using `PascalCase` conversion:
///
@@ -721,7 +721,7 @@ pub fn empty_result(input: TokenStream) -> TokenStream {
/// // With explicit program:
/// dispatcher!(MyApp, "status", StatusCommand => StatusEntry);
///
-/// // Abbreviated form (extra_macros required):
+/// // Abbreviated form (extras required):
/// // dispatcher!("remote.add"); // → CMDRemoteAdd, EntryRemoteAdd
/// ```
///
@@ -1094,7 +1094,7 @@ pub fn completion(attr: TokenStream, item: TokenStream) -> TokenStream {
/// - The function must have exactly one parameter of type `&mut Program<G>`.
/// - The function must return `()`.
/// - The function cannot be async.
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
#[proc_macro_attribute]
pub fn program_setup(attr: TokenStream, item: TokenStream) -> TokenStream {
program_setup::setup_attr(attr, item)
@@ -1102,7 +1102,7 @@ pub fn program_setup(attr: TokenStream, item: TokenStream) -> TokenStream {
/// Declares a command from a plain function.
///
-/// **This macro is only available with the `extra_macros` feature.**
+/// **This macro is only available with the `extras` feature.**
///
/// The `#[command]` attribute converts a function taking `Vec<String>` into a
/// Mingling command by:
@@ -1181,7 +1181,7 @@ pub fn program_setup(attr: TokenStream, item: TokenStream) -> TokenStream {
/// - The function must have at least one parameter (the `Vec<String>` entry argument).
/// - The function must not have a `self` parameter.
/// - Visibility (`pub` etc.) and `async` are preserved on the original function.
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
#[proc_macro_attribute]
pub fn command(attr: TokenStream, item: TokenStream) -> TokenStream {
attr::command::command_attr(attr, item)
@@ -1273,7 +1273,7 @@ pub fn dispatcher_clap(attr: TokenStream, item: TokenStream) -> TokenStream {
///
/// - `pack!` — For creating the wrapper types used with `entry!`.
/// - `dispatcher!` — Which implicitly creates entry types via `pack!`.
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
#[proc_macro]
pub fn entry(input: TokenStream) -> TokenStream {
entry::entry(input)
@@ -1438,7 +1438,7 @@ pub fn mlint(attr: TokenStream, item: TokenStream) -> TokenStream {
/// StateCalculate { number_a: a, operator: op, ... }.to_chain()
/// }
/// ```
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
#[proc_macro_attribute]
pub fn routeify(attr: TokenStream, item: TokenStream) -> TokenStream {
extensions::routeify::routeify_impl(attr, item)
@@ -1464,7 +1464,7 @@ pub fn routeify(attr: TokenStream, item: TokenStream) -> TokenStream {
/// Ok(RenderResult::new())
/// }
/// ```
-#[cfg(feature = "extra_macros")]
+#[cfg(feature = "extras")]
#[proc_macro_attribute]
pub fn renderify(attr: TokenStream, item: TokenStream) -> TokenStream {
extensions::renderify::renderify_impl(attr, item)