diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-08-17 02:29:30 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-08-17 02:39:56 +0800 |
| commit | 6980fbf2f9fb4c599d8dc6ff549a8b3288eb24e9 (patch) | |
| tree | bc7049698955d7a40706ea691fd5bab526a6b5e5 /mingling | |
| parent | 4c191b2b46a67a0dda6e9a867b40f45156af4f9c (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.toml | 2 | ||||
| -rw-r--r-- | mingling/src/docs/lib.md | 3 | ||||
| -rw-r--r-- | mingling/src/example_docs.rs | 183 | ||||
| -rw-r--r-- | mingling/src/gen_program.rs | 13 |
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!() } |
