From 2cd26bb4ca0dd35a0b588751fdbebc085bd7f40f Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 24 Mar 2023 23:22:23 -0500 Subject: [PATCH] feat: Allow defer initialization of subcommands This comes at the cost of 1.1 KiB of binary size Inspired by #4774 --- clap_builder/src/builder/command.rs | 30 +++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/clap_builder/src/builder/command.rs b/clap_builder/src/builder/command.rs index acbfae28cdd0..9df4e7e69e96 100644 --- a/clap_builder/src/builder/command.rs +++ b/clap_builder/src/builder/command.rs @@ -107,6 +107,7 @@ pub struct Command { subcommand_heading: Option, external_value_parser: Option, long_help_exists: bool, + deferred: Option Command>, } /// # Basic API @@ -431,6 +432,30 @@ impl Command { self } + /// Delay initialization for parts of the `Command` + /// + /// This is useful for large applications to delay definitions of subcommands until they are + /// being invoked. + /// + /// # Examples + /// + /// ```rust + /// # use clap_builder as clap; + /// # use clap::{Command, arg}; + /// Command::new("myprog") + /// .subcommand(Command::new("config") + /// .about("Controls configuration features") + /// .defer(|cmd| { + /// cmd.arg(arg!( "Required configuration file to use")) + /// }) + /// ) + /// # ; + /// ``` + pub fn defer(mut self, deferred: fn(Command) -> Command) -> Self { + self.deferred = Some(deferred); + self + } + /// Catch problems earlier in the development cycle. /// /// Most error states are handled as asserts under the assumption they are programming mistake @@ -3925,6 +3950,10 @@ impl Command { pub(crate) fn _build_self(&mut self, expand_help_tree: bool) { debug!("Command::_build: name={:?}", self.get_name()); if !self.settings.is_set(AppSettings::Built) { + if let Some(deferred) = self.deferred.take() { + *self = (deferred)(std::mem::take(self)); + } + // Make sure all the globally set flags apply to us as well self.settings = self.settings | self.g_settings; @@ -4759,6 +4788,7 @@ impl Default for Command { subcommand_heading: Default::default(), external_value_parser: Default::default(), long_help_exists: false, + deferred: None, } } }