aboutsummaryrefslogtreecommitdiff
path: root/mingling
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-08-17 02:29:30 +0800
committer魏曹先生 <1992414357@qq.com>2026-08-17 02:39:56 +0800
commit6980fbf2f9fb4c599d8dc6ff549a8b3288eb24e9 (patch)
treebc7049698955d7a40706ea691fd5bab526a6b5e5 /mingling
parent4c191b2b46a67a0dda6e9a867b40f45156af4f9c (diff)
refactor!: remove dynamic dispatcher registration API
Dispatchers are now always registered at compile time, removing the `with_dispatcher` / `with_dispatchers` methods and the `PathfinderConfig` API. The `dispatch_tree` feature now only controls the matching strategy (trie vs linear list).
Diffstat (limited to 'mingling')
-rw-r--r--mingling/Cargo.toml2
-rw-r--r--mingling/src/docs/lib.md3
-rw-r--r--mingling/src/example_docs.rs183
-rw-r--r--mingling/src/gen_program.rs13
4 files changed, 89 insertions, 112 deletions
diff --git a/mingling/Cargo.toml b/mingling/Cargo.toml
index 1148f2a..1de0f57 100644
--- a/mingling/Cargo.toml
+++ b/mingling/Cargo.toml
@@ -60,7 +60,7 @@ docs_rs = []
# Features
clap = ["mingling_core/clap", "mingling_macros/clap"]
-dispatch_tree = ["mingling_core/dispatch_tree", "mingling_macros/dispatch_tree"]
+dispatch_tree = ["mingling_macros/dispatch_tree"]
repl = ["mingling_core/repl", "mingling_macros/repl"]
comp = ["mingling_core/comp", "mingling_macros/comp"]
parser = ["dep:size"]
diff --git a/mingling/src/docs/lib.md b/mingling/src/docs/lib.md
index 697f6c5..993358b 100644
--- a/mingling/src/docs/lib.md
+++ b/mingling/src/docs/lib.md
@@ -25,8 +25,7 @@ use mingling::prelude::*;
dispatcher!("greet", CMDGreet => EntryGreet);
fn main() {
- let mut program = ThisProgram::new();
- program.with_dispatcher(CMDGreet);
+ let program = ThisProgram::new();
program.exec_and_exit();
}
diff --git a/mingling/src/example_docs.rs b/mingling/src/example_docs.rs
index c292598..5e4df1b 100644
--- a/mingling/src/example_docs.rs
+++ b/mingling/src/example_docs.rs
@@ -117,9 +117,7 @@
/// gen_program!();
///
/// fn main() {
-/// let mut program = ThisProgram::new();
-/// program.with_dispatcher(CMDTransfer);
-/// program.with_dispatcher(CMDStrictTransfer);
+/// let program = ThisProgram::new();
/// program.exec_and_exit();
/// }
/// ```
@@ -269,7 +267,6 @@ pub mod example_argument_parse {}
/// program.with_resource(ResNumberDisplaySetting { round: *round });
/// // --------- IMPORTANT ---------
///
-/// program.with_dispatcher(CMDCalculate);
/// program.exec_and_exit();
/// }
///
@@ -424,8 +421,6 @@ pub mod example_argument_picker {}
/// async fn main() {
/// let mut program = ThisProgram::new();
///
-/// program.with_dispatcher(CMDDownload);
-///
/// // Add a hook to display when the download begins
/// program.with_hook(ProgramHook::empty().on_begin::<_, ()>(|_| println!("Download begin")));
///
@@ -508,10 +503,7 @@ pub mod example_async_support {}
///
/// fn main() {
/// // Create a new ThisProgram
-/// let mut program = ThisProgram::new();
-///
-/// // Add the CMDGreet dispatcher
-/// program.with_dispatcher(CMDGreet);
+/// let program = ThisProgram::new();
///
/// // Run the program, then exit the process
/// program.exec_and_exit();
@@ -645,7 +637,6 @@ pub mod example_basic {}
/// // Capture Clap's help information and write to RenderResult
/// // --------- IMPORTANT ---------
///
-/// program.with_dispatcher(CMDGreet);
/// program.exec_and_exit();
/// }
///
@@ -824,10 +815,7 @@ pub mod example_combine_pathf_dispatch_tree {}
/// use mingling::prelude::*;
///
/// fn main() {
-/// let mut program = ThisProgram::new();
-/// program.with_dispatcher(sub::CMDHello);
-/// program.with_dispatcher(sub::CMDDescription);
-/// program.exec_and_exit();
+/// ThisProgram::new().exec_and_exit();
/// }
///
/// gen_program!();
@@ -876,14 +864,7 @@ pub mod example_combine_pathf_metadata {}
/// use mingling::{macros::buffer, picker::IntoPicker, prelude::*};
///
/// fn main() {
-/// let mut program = ThisProgram::new();
-///
-/// // Import the dispatchers generated by the `#[command]` macro
-/// program.with_dispatcher(CMDHelloWorld);
-/// program.with_dispatcher(CMDGreetSomeone);
-/// program.with_dispatcher(CMDGoodBye);
-///
-/// program.exec_and_exit();
+/// ThisProgram::new().exec_and_exit();
/// }
///
/// pack!(ResultGreeting = String);
@@ -1002,19 +983,11 @@ pub mod example_command_macro {}
///
/// Source code (./src/main.rs)
/// ```ignore
-/// use mingling::{macros::suggest, prelude::*, ShellContext, Suggest};
+/// use mingling::{ShellContext, Suggest, macros::suggest, prelude::*};
/// use std::io::Write;
///
/// fn main() {
-/// let mut program = ThisProgram::new();
-///
-/// program.with_dispatcher(CMDGreet);
-///
-/// // --------- IMPORTANT ---------
-/// // The `comp` feature makes `gen_program!()` generate a CMDCompletion automatically
-/// // It adds a hidden `__comp` subcommand for communication with the completion script
-/// program.with_dispatcher(crate::CMDCompletion);
-/// // --------- IMPORTANT ---------
+/// let program = ThisProgram::new();
///
/// // TIP: Note that the completion script reads stdout,
/// // so make sure no output is produced before the CMDCompletion is dispatched.
@@ -1180,9 +1153,7 @@ pub mod example_completion {}
/// gen_program!();
///
/// fn main() {
-/// let mut program = ThisProgram::new();
-/// program.with_dispatcher(CMDConnect);
-/// program.exec_and_exit();
+/// ThisProgram::new().exec_and_exit();
/// }
///
/// // Address conversion
@@ -1247,11 +1218,9 @@ pub mod example_custom_pickable {}
/// > This example will introduce how to use `dispatch_tree`
/// > to optimize your command line lookup efficiency
///
-/// When the number of commands in your project increases, you can use `dispatch_tree` to complete command registration at compile time.
-/// It will generate a trie for quickly finding related commands by prefix.
-///
-/// Therefore, after enabling this feature,
-/// `Program` will no longer store a Dispatcher list internally, and the `with_dispatcher` function will not be compiled.
+/// When the number of commands in your project increases, you can enable
+/// `dispatch_tree` to switch command matching from a linear scan to a
+/// character-level trie.
///
/// Run:
/// ```bash
@@ -1305,12 +1274,6 @@ pub mod example_custom_pickable {}
///
/// fn main() {
/// let program = ThisProgram::new();
-///
-/// // --------- IMPORTANT ---------
-/// // // You no longer need to use `with_dispatcher` anymore;
-/// // // it'll be collected automatically once the `dispatch_tree` feature is enabled
-/// // program.with_dispatcher(...);
-///
/// program.exec_and_exit();
/// }
///
@@ -1447,10 +1410,7 @@ pub mod example_dispatch_tree {}
/// gen_program!();
///
/// fn main() {
-/// let mut program = ThisProgram::new();
-/// program.with_dispatcher(CMDCompletion);
-/// program.with_dispatcher(CMDLanguageSelection);
-/// program.exec_and_exit();
+/// ThisProgram::new().exec_and_exit();
/// }
/// ```
pub mod example_enum_tag {}
@@ -1579,9 +1539,7 @@ pub mod example_enum_tag {}
/// gen_program!();
///
/// fn main() {
-/// let mut program = ThisProgram::new();
-/// program.with_dispatcher(CMDHello);
-/// program.exec_and_exit();
+/// ThisProgram::new().exec_and_exit();
/// }
/// ```
pub mod example_error_handling {}
@@ -1633,7 +1591,6 @@ pub mod example_error_handling {}
/// program.with_setup(ExitCodeSetup::default());
/// // --------- IMPORTANT ---------
///
-/// program.with_dispatcher(CMDHello);
/// program.exec_and_exit();
/// }
///
@@ -1739,8 +1696,6 @@ pub mod example_exitcode {}
/// program.with_setup(BasicProgramSetup);
/// // --------- IMPORTANT ---------
///
-/// program.with_dispatcher(CMDGreet);
-///
/// program.exec_and_exit();
/// }
///
@@ -1814,7 +1769,6 @@ pub mod example_help {}
/// );
/// // --------- IMPORTANT ---------
///
-/// program.with_dispatcher(CMDGreet);
/// program.exec_and_exit();
/// }
///
@@ -1870,15 +1824,7 @@ pub mod example_hook {}
/// dispatcher!("remote.remove", CMDRemoteRemove => EntryRemoteRemove);
///
/// fn main() {
-/// let mut program = ThisProgram::new();
-///
-/// // --------- IMPORTANT ---------
-/// program.with_dispatcher(CMDRemoteAdd);
-/// // ^^^^^^^^^^^^\_ CMDRemoteAdd is implicitly created
-/// // --------- IMPORTANT ---------
-///
-/// program.with_dispatcher(CMDRemoteRemove);
-/// program.exec_and_exit();
+/// ThisProgram::new().exec_and_exit();
/// }
///
/// gen_program!();
@@ -1966,7 +1912,6 @@ pub mod example_implicit_dispatcher {}
/// program.with_resource(ResLargeData::lazy_init(init_res_large_data));
/// // --------- IMPORTANT ---------
///
-/// program.with_dispatcher(CMDShow).with_dispatcher(CMDNone);
/// program.exec_and_exit();
/// }
///
@@ -2051,11 +1996,7 @@ pub mod example_lazy_resources {}
/// dispatcher!("nodoc", CMDNoDescription => EntryNoDescription);
///
/// fn main() {
-/// let mut program = ThisProgram::new();
-/// program.with_dispatcher(CMDGreet);
-/// program.with_dispatcher(CMDDescription);
-/// program.with_dispatcher(CMDNoDescription);
-/// program.exec_and_exit();
+/// ThisProgram::new().exec_and_exit();
/// }
///
/// /// The metadata type attached to an entry.
@@ -2247,10 +2188,7 @@ pub mod example_metadata {}
/// }
///
/// fn main() {
-/// let mut program = ThisProgram::new();
-/// program.with_dispatcher(CMDParse);
-/// program.with_dispatcher(CMDError);
-/// program.exec_and_exit();
+/// ThisProgram::new().exec_and_exit();
/// }
///
/// gen_program!();
@@ -2423,10 +2361,10 @@ pub mod example_outside_type {}
///
/// fn main() {
/// let mut program = ThisProgram::new();
+///
/// // Add StructuralRendererSetup to support --json / --yaml flags
/// program.with_setup(StructuralRendererSetup);
-/// program.with_dispatcher(CMDFind);
-/// program.with_dispatcher(CMDFindStructural);
+///
/// let _ = program.exec();
/// }
/// ```
@@ -2481,7 +2419,6 @@ pub mod example_pack_err {}
///
/// fn main() {
/// let mut program = ThisProgram::new();
-/// program.with_dispatcher(CMDPanic);
///
/// // --------- IMPORTANT ---------
/// // Enable silence_panic to suppress automatic Panic output
@@ -2572,12 +2509,9 @@ pub mod example_panic_unwind {}
/// mod sub;
///
/// use mingling::macros::gen_program;
-/// use crate::sub::CMDGreet;
///
/// fn main() {
-/// let mut program = ThisProgram::new();
-/// program.with_dispatcher(CMDGreet);
-/// program.exec_and_exit();
+/// ThisProgram::new().exec_and_exit();
/// }
///
/// gen_program!();
@@ -2641,12 +2575,6 @@ pub mod example_pathfinder {}
/// // Resource
/// program.with_resource(ResCurrentDir::default());
///
-/// // Dispatchers
-/// program.with_dispatcher(CMDCd);
-/// program.with_dispatcher(CMDLs);
-/// program.with_dispatcher(CMDExit);
-/// program.with_dispatcher(CMDClear);
-///
/// // Setups
/// // Enable basic std::io::stdin().read_line(&mut input)
/// program.with_setup(BasicREPLReadlineSetup);
@@ -2846,9 +2774,6 @@ pub mod example_repl_basic {}
/// });
/// // --------- IMPORTANT ---------
///
-/// program
-/// .with_dispatcher(CMDCurrent)
-/// .with_dispatcher(CMDModifyCurrent);
/// program.exec_and_exit();
/// }
///
@@ -2885,7 +2810,8 @@ pub mod example_repl_basic {}
pub mod example_resources {}
/// Example Setup
///
-/// > This example demonstrates how to build a custom Setup for modular management of project components
+/// > This example demonstrates how to build a custom Setup that encapsulates a
+/// > group of related resources and registers them with `with_resource`.
///
/// Source code (./Cargo.toml)
/// ```toml
@@ -2903,6 +2829,25 @@ pub mod example_resources {}
/// Source code (./src/main.rs)
/// ```ignore
/// use mingling::{Program, macros::program_setup, prelude::*};
+/// use std::io::Write;
+///
+/// // A group of related resources — here, the demo app's identity.
+/// // Resource types are plain structs: any `Default + Clone + Send + Sync` type
+/// // can be used as a resource, and it is identified by its type.
+/// #[derive(Default, Clone)]
+/// struct ResAppName {
+/// name: String,
+/// }
+///
+/// #[derive(Default, Clone)]
+/// struct ResAppVersion {
+/// version: String,
+/// }
+///
+/// #[derive(Default, Clone)]
+/// struct ResGreetingPrefix {
+/// prefix: String,
+/// }
///
/// fn main() {
/// let mut program = ThisProgram::new();
@@ -2917,22 +2862,45 @@ pub mod example_resources {}
///
/// // --------- IMPORTANT ---------
/// // Define `CustomSetup` (inferred from `custom_setup`)
-/// // Package part of the program construction logic into this type for modular management
+/// // Package part of the program construction logic into this type for modular
+/// // management — e.g. register a group of related resources here.
/// #[program_setup]
/// fn custom_setup(program: &mut Program<ThisProgram>) {
-/// program.with_dispatcher(CMD1);
-/// program.with_dispatcher(CMD2);
-/// program.with_dispatcher(CMD3);
-/// program.with_dispatcher(CMD4);
-/// program.with_dispatcher(CMD5);
+/// program.with_resource(ResAppName {
+/// name: "mingling".to_string(),
+/// });
+/// program.with_resource(ResAppVersion {
+/// version: "0.5.0".to_string(),
+/// });
+/// program.with_resource(ResGreetingPrefix {
+/// prefix: "Hello".to_string(),
+/// });
/// }
/// // --------- IMPORTANT ---------
///
-/// dispatcher!("1", CMD1 => Entry1);
-/// dispatcher!("2", CMD2 => Entry2);
-/// dispatcher!("3", CMD3 => Entry3);
-/// dispatcher!("4", CMD4 => Entry4);
-/// dispatcher!("5", CMD5 => Entry5);
+/// dispatcher!("greet", CMDGreet => EntryGreet);
+///
+/// pack!(ResultGreeting = String);
+///
+/// /// Chain: reads the `ResAppName` and `ResAppVersion` resources.
+/// #[chain]
+/// fn handle_greet(args: EntryGreet, app: &ResAppName, version: &ResAppVersion) -> Next {
+/// let who = args
+/// .inner
+/// .first()
+/// .cloned()
+/// .unwrap_or_else(|| "World".to_string());
+/// let greeting: ResultGreeting = format!("{} from {} v{}", who, app.name, version.version).into();
+/// greeting.into()
+/// }
+///
+/// /// Renderer: injects the `ResGreetingPrefix` resource to decorate the output.
+/// #[renderer]
+/// fn render_greet(greeting: ResultGreeting, prefix: &ResGreetingPrefix) -> RenderResult {
+/// let mut render_result = RenderResult::new();
+/// writeln!(render_result, "{}, {}!", prefix.prefix, *greeting).ok();
+/// render_result
+/// }
///
/// gen_program!();
/// ```
@@ -2990,7 +2958,6 @@ pub mod example_setup {}
/// let mut program = ThisProgram::new();
/// // Add `StructuralRendererSetup` to receive user input `--json` `--yaml` parameters
/// program.with_setup(StructuralRendererSetup);
-/// program.with_dispatcher(CMDRender);
/// let _ = program.exec();
/// }
///
@@ -3193,9 +3160,7 @@ pub mod example_structural_renderer {}
/// gen_program!();
///
/// fn main() {
-/// let mut program = ThisProgram::new();
-/// program.with_dispatcher(CMDHello);
-/// program.exec_and_exit();
+/// ThisProgram::new().exec_and_exit();
/// }
/// ```
pub mod example_unit_test {}
diff --git a/mingling/src/gen_program.rs b/mingling/src/gen_program.rs
index 6a0b144..b1fa118 100644
--- a/mingling/src/gen_program.rs
+++ b/mingling/src/gen_program.rs
@@ -193,6 +193,19 @@ impl ProgramCollect for ThisProgram {
type ResultEmpty = ResultEmpty;
+ fn dispatch_args(
+ _raw: &[String],
+ ) -> Result<
+ mingling_core::AnyOutput<Self::Enum>,
+ mingling_core::error::ProgramInternalExecuteError,
+ > {
+ todo!()
+ }
+
+ fn get_nodes() -> Vec<(String, &'static (dyn Dispatcher<Self::Enum> + Send + Sync))> {
+ todo!()
+ }
+
fn build_renderer_not_found(_member_id: Self::Enum) -> mingling_core::AnyOutput<Self::Enum> {
todo!()
}