119625d8cSopenharmony_ci// Internal 219625d8cSopenharmony_ciuse crate::builder::IntoResettable; 319625d8cSopenharmony_ciuse crate::util::Id; 419625d8cSopenharmony_ci 519625d8cSopenharmony_ci/// Family of related [arguments]. 619625d8cSopenharmony_ci/// 719625d8cSopenharmony_ci/// By placing arguments in a logical group, you can create easier requirement and 819625d8cSopenharmony_ci/// exclusion rules instead of having to list each argument individually, or when you want a rule 919625d8cSopenharmony_ci/// to apply "any but not all" arguments. 1019625d8cSopenharmony_ci/// 1119625d8cSopenharmony_ci/// For instance, you can make an entire `ArgGroup` required. If [`ArgGroup::multiple(true)`] is 1219625d8cSopenharmony_ci/// set, this means that at least one argument from that group must be present. If 1319625d8cSopenharmony_ci/// [`ArgGroup::multiple(false)`] is set (the default), one and *only* one must be present. 1419625d8cSopenharmony_ci/// 1519625d8cSopenharmony_ci/// You can also do things such as name an entire `ArgGroup` as a [conflict] or [requirement] for 1619625d8cSopenharmony_ci/// another argument, meaning any of the arguments that belong to that group will cause a failure 1719625d8cSopenharmony_ci/// if present, or must be present respectively. 1819625d8cSopenharmony_ci/// 1919625d8cSopenharmony_ci/// Perhaps the most common use of `ArgGroup`s is to require one and *only* one argument to be 2019625d8cSopenharmony_ci/// present out of a given set. Imagine that you had multiple arguments, and you want one of them 2119625d8cSopenharmony_ci/// to be required, but making all of them required isn't feasible because perhaps they conflict 2219625d8cSopenharmony_ci/// with each other. For example, lets say that you were building an application where one could 2319625d8cSopenharmony_ci/// set a given version number by supplying a string with an option argument, i.e. 2419625d8cSopenharmony_ci/// `--set-ver v1.2.3`, you also wanted to support automatically using a previous version number 2519625d8cSopenharmony_ci/// and simply incrementing one of the three numbers. So you create three flags `--major`, 2619625d8cSopenharmony_ci/// `--minor`, and `--patch`. All of these arguments shouldn't be used at one time but you want to 2719625d8cSopenharmony_ci/// specify that *at least one* of them is used. For this, you can create a group. 2819625d8cSopenharmony_ci/// 2919625d8cSopenharmony_ci/// Finally, you may use `ArgGroup`s to pull a value from a group of arguments when you don't care 3019625d8cSopenharmony_ci/// exactly which argument was actually used at runtime. 3119625d8cSopenharmony_ci/// 3219625d8cSopenharmony_ci/// # Examples 3319625d8cSopenharmony_ci/// 3419625d8cSopenharmony_ci/// The following example demonstrates using an `ArgGroup` to ensure that one, and only one, of 3519625d8cSopenharmony_ci/// the arguments from the specified group is present at runtime. 3619625d8cSopenharmony_ci/// 3719625d8cSopenharmony_ci/// ```rust 3819625d8cSopenharmony_ci/// # use clap::{Command, arg, ArgGroup, error::ErrorKind}; 3919625d8cSopenharmony_ci/// let result = Command::new("cmd") 4019625d8cSopenharmony_ci/// .arg(arg!(--"set-ver" <ver> "set the version manually")) 4119625d8cSopenharmony_ci/// .arg(arg!(--major "auto increase major")) 4219625d8cSopenharmony_ci/// .arg(arg!(--minor "auto increase minor")) 4319625d8cSopenharmony_ci/// .arg(arg!(--patch "auto increase patch")) 4419625d8cSopenharmony_ci/// .group(ArgGroup::new("vers") 4519625d8cSopenharmony_ci/// .args(["set-ver", "major", "minor", "patch"]) 4619625d8cSopenharmony_ci/// .required(true)) 4719625d8cSopenharmony_ci/// .try_get_matches_from(vec!["cmd", "--major", "--patch"]); 4819625d8cSopenharmony_ci/// // Because we used two args in the group it's an error 4919625d8cSopenharmony_ci/// assert!(result.is_err()); 5019625d8cSopenharmony_ci/// let err = result.unwrap_err(); 5119625d8cSopenharmony_ci/// assert_eq!(err.kind(), ErrorKind::ArgumentConflict); 5219625d8cSopenharmony_ci/// ``` 5319625d8cSopenharmony_ci/// 5419625d8cSopenharmony_ci/// This next example shows a passing parse of the same scenario 5519625d8cSopenharmony_ci/// ```rust 5619625d8cSopenharmony_ci/// # use clap::{Command, arg, ArgGroup, Id}; 5719625d8cSopenharmony_ci/// let result = Command::new("cmd") 5819625d8cSopenharmony_ci/// .arg(arg!(--"set-ver" <ver> "set the version manually")) 5919625d8cSopenharmony_ci/// .arg(arg!(--major "auto increase major")) 6019625d8cSopenharmony_ci/// .arg(arg!(--minor "auto increase minor")) 6119625d8cSopenharmony_ci/// .arg(arg!(--patch "auto increase patch")) 6219625d8cSopenharmony_ci/// .group(ArgGroup::new("vers") 6319625d8cSopenharmony_ci/// .args(["set-ver", "major", "minor","patch"]) 6419625d8cSopenharmony_ci/// .required(true)) 6519625d8cSopenharmony_ci/// .try_get_matches_from(vec!["cmd", "--major"]); 6619625d8cSopenharmony_ci/// assert!(result.is_ok()); 6719625d8cSopenharmony_ci/// let matches = result.unwrap(); 6819625d8cSopenharmony_ci/// // We may not know which of the args was used, so we can test for the group... 6919625d8cSopenharmony_ci/// assert!(matches.contains_id("vers")); 7019625d8cSopenharmony_ci/// // We can also ask the group which arg was used 7119625d8cSopenharmony_ci/// assert_eq!(matches 7219625d8cSopenharmony_ci/// .get_one::<Id>("vers") 7319625d8cSopenharmony_ci/// .expect("`vers` is required") 7419625d8cSopenharmony_ci/// .as_str(), 7519625d8cSopenharmony_ci/// "major" 7619625d8cSopenharmony_ci/// ); 7719625d8cSopenharmony_ci/// // we could also alternatively check each arg individually (not shown here) 7819625d8cSopenharmony_ci/// ``` 7919625d8cSopenharmony_ci/// [`ArgGroup::multiple(true)`]: ArgGroup::multiple() 8019625d8cSopenharmony_ci/// 8119625d8cSopenharmony_ci/// [`ArgGroup::multiple(false)`]: ArgGroup::multiple() 8219625d8cSopenharmony_ci/// [arguments]: crate::Arg 8319625d8cSopenharmony_ci/// [conflict]: crate::Arg::conflicts_with() 8419625d8cSopenharmony_ci/// [requirement]: crate::Arg::requires() 8519625d8cSopenharmony_ci#[derive(Default, Clone, Debug, PartialEq, Eq)] 8619625d8cSopenharmony_cipub struct ArgGroup { 8719625d8cSopenharmony_ci pub(crate) id: Id, 8819625d8cSopenharmony_ci pub(crate) args: Vec<Id>, 8919625d8cSopenharmony_ci pub(crate) required: bool, 9019625d8cSopenharmony_ci pub(crate) requires: Vec<Id>, 9119625d8cSopenharmony_ci pub(crate) conflicts: Vec<Id>, 9219625d8cSopenharmony_ci pub(crate) multiple: bool, 9319625d8cSopenharmony_ci} 9419625d8cSopenharmony_ci 9519625d8cSopenharmony_ci/// # Builder 9619625d8cSopenharmony_ciimpl ArgGroup { 9719625d8cSopenharmony_ci /// Create a `ArgGroup` using a unique name. 9819625d8cSopenharmony_ci /// 9919625d8cSopenharmony_ci /// The name will be used to get values from the group or refer to the group inside of conflict 10019625d8cSopenharmony_ci /// and requirement rules. 10119625d8cSopenharmony_ci /// 10219625d8cSopenharmony_ci /// # Examples 10319625d8cSopenharmony_ci /// 10419625d8cSopenharmony_ci /// ```rust 10519625d8cSopenharmony_ci /// # use clap::{Command, ArgGroup}; 10619625d8cSopenharmony_ci /// ArgGroup::new("config") 10719625d8cSopenharmony_ci /// # ; 10819625d8cSopenharmony_ci /// ``` 10919625d8cSopenharmony_ci pub fn new(id: impl Into<Id>) -> Self { 11019625d8cSopenharmony_ci ArgGroup::default().id(id) 11119625d8cSopenharmony_ci } 11219625d8cSopenharmony_ci 11319625d8cSopenharmony_ci /// Sets the group name. 11419625d8cSopenharmony_ci /// 11519625d8cSopenharmony_ci /// # Examples 11619625d8cSopenharmony_ci /// 11719625d8cSopenharmony_ci /// ```rust 11819625d8cSopenharmony_ci /// # use clap::{Command, ArgGroup}; 11919625d8cSopenharmony_ci /// ArgGroup::default().id("config") 12019625d8cSopenharmony_ci /// # ; 12119625d8cSopenharmony_ci /// ``` 12219625d8cSopenharmony_ci #[must_use] 12319625d8cSopenharmony_ci pub fn id(mut self, id: impl Into<Id>) -> Self { 12419625d8cSopenharmony_ci self.id = id.into(); 12519625d8cSopenharmony_ci self 12619625d8cSopenharmony_ci } 12719625d8cSopenharmony_ci 12819625d8cSopenharmony_ci /// Adds an [argument] to this group by name 12919625d8cSopenharmony_ci /// 13019625d8cSopenharmony_ci /// # Examples 13119625d8cSopenharmony_ci /// 13219625d8cSopenharmony_ci /// ```rust 13319625d8cSopenharmony_ci /// # use clap::{Command, Arg, ArgGroup, ArgAction}; 13419625d8cSopenharmony_ci /// let m = Command::new("myprog") 13519625d8cSopenharmony_ci /// .arg(Arg::new("flag") 13619625d8cSopenharmony_ci /// .short('f') 13719625d8cSopenharmony_ci /// .action(ArgAction::SetTrue)) 13819625d8cSopenharmony_ci /// .arg(Arg::new("color") 13919625d8cSopenharmony_ci /// .short('c') 14019625d8cSopenharmony_ci /// .action(ArgAction::SetTrue)) 14119625d8cSopenharmony_ci /// .group(ArgGroup::new("req_flags") 14219625d8cSopenharmony_ci /// .arg("flag") 14319625d8cSopenharmony_ci /// .arg("color")) 14419625d8cSopenharmony_ci /// .get_matches_from(vec!["myprog", "-f"]); 14519625d8cSopenharmony_ci /// // maybe we don't know which of the two flags was used... 14619625d8cSopenharmony_ci /// assert!(m.contains_id("req_flags")); 14719625d8cSopenharmony_ci /// // but we can also check individually if needed 14819625d8cSopenharmony_ci /// assert!(m.contains_id("flag")); 14919625d8cSopenharmony_ci /// ``` 15019625d8cSopenharmony_ci /// [argument]: crate::Arg 15119625d8cSopenharmony_ci #[must_use] 15219625d8cSopenharmony_ci pub fn arg(mut self, arg_id: impl IntoResettable<Id>) -> Self { 15319625d8cSopenharmony_ci if let Some(arg_id) = arg_id.into_resettable().into_option() { 15419625d8cSopenharmony_ci self.args.push(arg_id); 15519625d8cSopenharmony_ci } else { 15619625d8cSopenharmony_ci self.args.clear(); 15719625d8cSopenharmony_ci } 15819625d8cSopenharmony_ci self 15919625d8cSopenharmony_ci } 16019625d8cSopenharmony_ci 16119625d8cSopenharmony_ci /// Adds multiple [arguments] to this group by name 16219625d8cSopenharmony_ci /// 16319625d8cSopenharmony_ci /// # Examples 16419625d8cSopenharmony_ci /// 16519625d8cSopenharmony_ci /// ```rust 16619625d8cSopenharmony_ci /// # use clap::{Command, Arg, ArgGroup, ArgAction}; 16719625d8cSopenharmony_ci /// let m = Command::new("myprog") 16819625d8cSopenharmony_ci /// .arg(Arg::new("flag") 16919625d8cSopenharmony_ci /// .short('f') 17019625d8cSopenharmony_ci /// .action(ArgAction::SetTrue)) 17119625d8cSopenharmony_ci /// .arg(Arg::new("color") 17219625d8cSopenharmony_ci /// .short('c') 17319625d8cSopenharmony_ci /// .action(ArgAction::SetTrue)) 17419625d8cSopenharmony_ci /// .group(ArgGroup::new("req_flags") 17519625d8cSopenharmony_ci /// .args(["flag", "color"])) 17619625d8cSopenharmony_ci /// .get_matches_from(vec!["myprog", "-f"]); 17719625d8cSopenharmony_ci /// // maybe we don't know which of the two flags was used... 17819625d8cSopenharmony_ci /// assert!(m.contains_id("req_flags")); 17919625d8cSopenharmony_ci /// // but we can also check individually if needed 18019625d8cSopenharmony_ci /// assert!(m.contains_id("flag")); 18119625d8cSopenharmony_ci /// ``` 18219625d8cSopenharmony_ci /// [arguments]: crate::Arg 18319625d8cSopenharmony_ci #[must_use] 18419625d8cSopenharmony_ci pub fn args(mut self, ns: impl IntoIterator<Item = impl Into<Id>>) -> Self { 18519625d8cSopenharmony_ci for n in ns { 18619625d8cSopenharmony_ci self = self.arg(n); 18719625d8cSopenharmony_ci } 18819625d8cSopenharmony_ci self 18919625d8cSopenharmony_ci } 19019625d8cSopenharmony_ci 19119625d8cSopenharmony_ci /// Getters for all args. It will return a vector of `Id` 19219625d8cSopenharmony_ci /// 19319625d8cSopenharmony_ci /// # Example 19419625d8cSopenharmony_ci /// 19519625d8cSopenharmony_ci /// ```rust 19619625d8cSopenharmony_ci /// # use clap::{ArgGroup}; 19719625d8cSopenharmony_ci /// let args: Vec<&str> = vec!["a1".into(), "a4".into()]; 19819625d8cSopenharmony_ci /// let grp = ArgGroup::new("program").args(&args); 19919625d8cSopenharmony_ci /// 20019625d8cSopenharmony_ci /// for (pos, arg) in grp.get_args().enumerate() { 20119625d8cSopenharmony_ci /// assert_eq!(*arg, args[pos]); 20219625d8cSopenharmony_ci /// } 20319625d8cSopenharmony_ci /// ``` 20419625d8cSopenharmony_ci pub fn get_args(&self) -> impl Iterator<Item = &Id> { 20519625d8cSopenharmony_ci self.args.iter() 20619625d8cSopenharmony_ci } 20719625d8cSopenharmony_ci 20819625d8cSopenharmony_ci /// Allows more than one of the [`Arg`]s in this group to be used. (Default: `false`) 20919625d8cSopenharmony_ci /// 21019625d8cSopenharmony_ci /// # Examples 21119625d8cSopenharmony_ci /// 21219625d8cSopenharmony_ci /// Notice in this example we use *both* the `-f` and `-c` flags which are both part of the 21319625d8cSopenharmony_ci /// group 21419625d8cSopenharmony_ci /// 21519625d8cSopenharmony_ci /// ```rust 21619625d8cSopenharmony_ci /// # use clap::{Command, Arg, ArgGroup, ArgAction}; 21719625d8cSopenharmony_ci /// let m = Command::new("myprog") 21819625d8cSopenharmony_ci /// .arg(Arg::new("flag") 21919625d8cSopenharmony_ci /// .short('f') 22019625d8cSopenharmony_ci /// .action(ArgAction::SetTrue)) 22119625d8cSopenharmony_ci /// .arg(Arg::new("color") 22219625d8cSopenharmony_ci /// .short('c') 22319625d8cSopenharmony_ci /// .action(ArgAction::SetTrue)) 22419625d8cSopenharmony_ci /// .group(ArgGroup::new("req_flags") 22519625d8cSopenharmony_ci /// .args(["flag", "color"]) 22619625d8cSopenharmony_ci /// .multiple(true)) 22719625d8cSopenharmony_ci /// .get_matches_from(vec!["myprog", "-f", "-c"]); 22819625d8cSopenharmony_ci /// // maybe we don't know which of the two flags was used... 22919625d8cSopenharmony_ci /// assert!(m.contains_id("req_flags")); 23019625d8cSopenharmony_ci /// ``` 23119625d8cSopenharmony_ci /// In this next example, we show the default behavior (i.e. `multiple(false)) which will throw 23219625d8cSopenharmony_ci /// an error if more than one of the args in the group was used. 23319625d8cSopenharmony_ci /// 23419625d8cSopenharmony_ci /// ```rust 23519625d8cSopenharmony_ci /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction}; 23619625d8cSopenharmony_ci /// let result = Command::new("myprog") 23719625d8cSopenharmony_ci /// .arg(Arg::new("flag") 23819625d8cSopenharmony_ci /// .short('f') 23919625d8cSopenharmony_ci /// .action(ArgAction::SetTrue)) 24019625d8cSopenharmony_ci /// .arg(Arg::new("color") 24119625d8cSopenharmony_ci /// .short('c') 24219625d8cSopenharmony_ci /// .action(ArgAction::SetTrue)) 24319625d8cSopenharmony_ci /// .group(ArgGroup::new("req_flags") 24419625d8cSopenharmony_ci /// .args(["flag", "color"])) 24519625d8cSopenharmony_ci /// .try_get_matches_from(vec!["myprog", "-f", "-c"]); 24619625d8cSopenharmony_ci /// // Because we used both args in the group it's an error 24719625d8cSopenharmony_ci /// assert!(result.is_err()); 24819625d8cSopenharmony_ci /// let err = result.unwrap_err(); 24919625d8cSopenharmony_ci /// assert_eq!(err.kind(), ErrorKind::ArgumentConflict); 25019625d8cSopenharmony_ci /// ``` 25119625d8cSopenharmony_ci /// 25219625d8cSopenharmony_ci /// [`Arg`]: crate::Arg 25319625d8cSopenharmony_ci #[inline] 25419625d8cSopenharmony_ci #[must_use] 25519625d8cSopenharmony_ci pub fn multiple(mut self, yes: bool) -> Self { 25619625d8cSopenharmony_ci self.multiple = yes; 25719625d8cSopenharmony_ci self 25819625d8cSopenharmony_ci } 25919625d8cSopenharmony_ci 26019625d8cSopenharmony_ci /// Return true if the group allows more than one of the arguments 26119625d8cSopenharmony_ci /// in this group to be used. (Default: `false`) 26219625d8cSopenharmony_ci /// 26319625d8cSopenharmony_ci /// # Example 26419625d8cSopenharmony_ci /// 26519625d8cSopenharmony_ci /// ```rust 26619625d8cSopenharmony_ci /// # use clap::{ArgGroup}; 26719625d8cSopenharmony_ci /// let mut group = ArgGroup::new("myprog") 26819625d8cSopenharmony_ci /// .args(["f", "c"]) 26919625d8cSopenharmony_ci /// .multiple(true); 27019625d8cSopenharmony_ci /// 27119625d8cSopenharmony_ci /// assert!(group.is_multiple()); 27219625d8cSopenharmony_ci /// ``` 27319625d8cSopenharmony_ci pub fn is_multiple(&mut self) -> bool { 27419625d8cSopenharmony_ci self.multiple 27519625d8cSopenharmony_ci } 27619625d8cSopenharmony_ci 27719625d8cSopenharmony_ci /// Require an argument from the group to be present when parsing. 27819625d8cSopenharmony_ci /// 27919625d8cSopenharmony_ci /// This is unless conflicting with another argument. A required group will be displayed in 28019625d8cSopenharmony_ci /// the usage string of the application in the format `<arg|arg2|arg3>`. 28119625d8cSopenharmony_ci /// 28219625d8cSopenharmony_ci /// **NOTE:** This setting only applies to the current [`Command`] / [`Subcommand`]s, and not 28319625d8cSopenharmony_ci /// globally. 28419625d8cSopenharmony_ci /// 28519625d8cSopenharmony_ci /// **NOTE:** By default, [`ArgGroup::multiple`] is set to `false` which when combined with 28619625d8cSopenharmony_ci /// `ArgGroup::required(true)` states, "One and *only one* arg must be used from this group. 28719625d8cSopenharmony_ci /// Use of more than one arg is an error." Vice setting `ArgGroup::multiple(true)` which 28819625d8cSopenharmony_ci /// states, '*At least* one arg from this group must be used. Using multiple is OK." 28919625d8cSopenharmony_ci /// 29019625d8cSopenharmony_ci /// # Examples 29119625d8cSopenharmony_ci /// 29219625d8cSopenharmony_ci /// ```rust 29319625d8cSopenharmony_ci /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction}; 29419625d8cSopenharmony_ci /// let result = Command::new("myprog") 29519625d8cSopenharmony_ci /// .arg(Arg::new("flag") 29619625d8cSopenharmony_ci /// .short('f') 29719625d8cSopenharmony_ci /// .action(ArgAction::SetTrue)) 29819625d8cSopenharmony_ci /// .arg(Arg::new("color") 29919625d8cSopenharmony_ci /// .short('c') 30019625d8cSopenharmony_ci /// .action(ArgAction::SetTrue)) 30119625d8cSopenharmony_ci /// .group(ArgGroup::new("req_flags") 30219625d8cSopenharmony_ci /// .args(["flag", "color"]) 30319625d8cSopenharmony_ci /// .required(true)) 30419625d8cSopenharmony_ci /// .try_get_matches_from(vec!["myprog"]); 30519625d8cSopenharmony_ci /// // Because we didn't use any of the args in the group, it's an error 30619625d8cSopenharmony_ci /// assert!(result.is_err()); 30719625d8cSopenharmony_ci /// let err = result.unwrap_err(); 30819625d8cSopenharmony_ci /// assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument); 30919625d8cSopenharmony_ci /// ``` 31019625d8cSopenharmony_ci /// 31119625d8cSopenharmony_ci /// [`Subcommand`]: crate::Subcommand 31219625d8cSopenharmony_ci /// [`ArgGroup::multiple`]: ArgGroup::multiple() 31319625d8cSopenharmony_ci /// [`Command`]: crate::Command 31419625d8cSopenharmony_ci #[inline] 31519625d8cSopenharmony_ci #[must_use] 31619625d8cSopenharmony_ci pub fn required(mut self, yes: bool) -> Self { 31719625d8cSopenharmony_ci self.required = yes; 31819625d8cSopenharmony_ci self 31919625d8cSopenharmony_ci } 32019625d8cSopenharmony_ci 32119625d8cSopenharmony_ci /// Specify an argument or group that must be present when this group is. 32219625d8cSopenharmony_ci /// 32319625d8cSopenharmony_ci /// This is not to be confused with a [required group]. Requirement rules function just like 32419625d8cSopenharmony_ci /// [argument requirement rules], you can name other arguments or groups that must be present 32519625d8cSopenharmony_ci /// when any one of the arguments from this group is used. 32619625d8cSopenharmony_ci /// 32719625d8cSopenharmony_ci /// **NOTE:** The name provided may be an argument or group name 32819625d8cSopenharmony_ci /// 32919625d8cSopenharmony_ci /// # Examples 33019625d8cSopenharmony_ci /// 33119625d8cSopenharmony_ci /// ```rust 33219625d8cSopenharmony_ci /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction}; 33319625d8cSopenharmony_ci /// let result = Command::new("myprog") 33419625d8cSopenharmony_ci /// .arg(Arg::new("flag") 33519625d8cSopenharmony_ci /// .short('f') 33619625d8cSopenharmony_ci /// .action(ArgAction::SetTrue)) 33719625d8cSopenharmony_ci /// .arg(Arg::new("color") 33819625d8cSopenharmony_ci /// .short('c') 33919625d8cSopenharmony_ci /// .action(ArgAction::SetTrue)) 34019625d8cSopenharmony_ci /// .arg(Arg::new("debug") 34119625d8cSopenharmony_ci /// .short('d') 34219625d8cSopenharmony_ci /// .action(ArgAction::SetTrue)) 34319625d8cSopenharmony_ci /// .group(ArgGroup::new("req_flags") 34419625d8cSopenharmony_ci /// .args(["flag", "color"]) 34519625d8cSopenharmony_ci /// .requires("debug")) 34619625d8cSopenharmony_ci /// .try_get_matches_from(vec!["myprog", "-c"]); 34719625d8cSopenharmony_ci /// // because we used an arg from the group, and the group requires "-d" to be used, it's an 34819625d8cSopenharmony_ci /// // error 34919625d8cSopenharmony_ci /// assert!(result.is_err()); 35019625d8cSopenharmony_ci /// let err = result.unwrap_err(); 35119625d8cSopenharmony_ci /// assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument); 35219625d8cSopenharmony_ci /// ``` 35319625d8cSopenharmony_ci /// [required group]: ArgGroup::required() 35419625d8cSopenharmony_ci /// [argument requirement rules]: crate::Arg::requires() 35519625d8cSopenharmony_ci #[must_use] 35619625d8cSopenharmony_ci pub fn requires(mut self, id: impl IntoResettable<Id>) -> Self { 35719625d8cSopenharmony_ci if let Some(id) = id.into_resettable().into_option() { 35819625d8cSopenharmony_ci self.requires.push(id); 35919625d8cSopenharmony_ci } else { 36019625d8cSopenharmony_ci self.requires.clear(); 36119625d8cSopenharmony_ci } 36219625d8cSopenharmony_ci self 36319625d8cSopenharmony_ci } 36419625d8cSopenharmony_ci 36519625d8cSopenharmony_ci /// Specify arguments or groups that must be present when this group is. 36619625d8cSopenharmony_ci /// 36719625d8cSopenharmony_ci /// This is not to be confused with a [required group]. Requirement rules function just like 36819625d8cSopenharmony_ci /// [argument requirement rules], you can name other arguments or groups that must be present 36919625d8cSopenharmony_ci /// when one of the arguments from this group is used. 37019625d8cSopenharmony_ci /// 37119625d8cSopenharmony_ci /// **NOTE:** The names provided may be an argument or group name 37219625d8cSopenharmony_ci /// 37319625d8cSopenharmony_ci /// # Examples 37419625d8cSopenharmony_ci /// 37519625d8cSopenharmony_ci /// ```rust 37619625d8cSopenharmony_ci /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction}; 37719625d8cSopenharmony_ci /// let result = Command::new("myprog") 37819625d8cSopenharmony_ci /// .arg(Arg::new("flag") 37919625d8cSopenharmony_ci /// .short('f') 38019625d8cSopenharmony_ci /// .action(ArgAction::SetTrue)) 38119625d8cSopenharmony_ci /// .arg(Arg::new("color") 38219625d8cSopenharmony_ci /// .short('c') 38319625d8cSopenharmony_ci /// .action(ArgAction::SetTrue)) 38419625d8cSopenharmony_ci /// .arg(Arg::new("debug") 38519625d8cSopenharmony_ci /// .short('d') 38619625d8cSopenharmony_ci /// .action(ArgAction::SetTrue)) 38719625d8cSopenharmony_ci /// .arg(Arg::new("verb") 38819625d8cSopenharmony_ci /// .short('v') 38919625d8cSopenharmony_ci /// .action(ArgAction::SetTrue)) 39019625d8cSopenharmony_ci /// .group(ArgGroup::new("req_flags") 39119625d8cSopenharmony_ci /// .args(["flag", "color"]) 39219625d8cSopenharmony_ci /// .requires_all(["debug", "verb"])) 39319625d8cSopenharmony_ci /// .try_get_matches_from(vec!["myprog", "-c", "-d"]); 39419625d8cSopenharmony_ci /// // because we used an arg from the group, and the group requires "-d" and "-v" to be used, 39519625d8cSopenharmony_ci /// // yet we only used "-d" it's an error 39619625d8cSopenharmony_ci /// assert!(result.is_err()); 39719625d8cSopenharmony_ci /// let err = result.unwrap_err(); 39819625d8cSopenharmony_ci /// assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument); 39919625d8cSopenharmony_ci /// ``` 40019625d8cSopenharmony_ci /// [required group]: ArgGroup::required() 40119625d8cSopenharmony_ci /// [argument requirement rules]: crate::Arg::requires_ifs() 40219625d8cSopenharmony_ci #[must_use] 40319625d8cSopenharmony_ci pub fn requires_all(mut self, ns: impl IntoIterator<Item = impl Into<Id>>) -> Self { 40419625d8cSopenharmony_ci for n in ns { 40519625d8cSopenharmony_ci self = self.requires(n); 40619625d8cSopenharmony_ci } 40719625d8cSopenharmony_ci self 40819625d8cSopenharmony_ci } 40919625d8cSopenharmony_ci 41019625d8cSopenharmony_ci /// Specify an argument or group that must **not** be present when this group is. 41119625d8cSopenharmony_ci /// 41219625d8cSopenharmony_ci /// Exclusion (aka conflict) rules function just like [argument exclusion rules], you can name 41319625d8cSopenharmony_ci /// other arguments or groups that must *not* be present when one of the arguments from this 41419625d8cSopenharmony_ci /// group are used. 41519625d8cSopenharmony_ci /// 41619625d8cSopenharmony_ci /// **NOTE:** The name provided may be an argument, or group name 41719625d8cSopenharmony_ci /// 41819625d8cSopenharmony_ci /// # Examples 41919625d8cSopenharmony_ci /// 42019625d8cSopenharmony_ci /// ```rust 42119625d8cSopenharmony_ci /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction}; 42219625d8cSopenharmony_ci /// let result = Command::new("myprog") 42319625d8cSopenharmony_ci /// .arg(Arg::new("flag") 42419625d8cSopenharmony_ci /// .short('f') 42519625d8cSopenharmony_ci /// .action(ArgAction::SetTrue)) 42619625d8cSopenharmony_ci /// .arg(Arg::new("color") 42719625d8cSopenharmony_ci /// .short('c') 42819625d8cSopenharmony_ci /// .action(ArgAction::SetTrue)) 42919625d8cSopenharmony_ci /// .arg(Arg::new("debug") 43019625d8cSopenharmony_ci /// .short('d') 43119625d8cSopenharmony_ci /// .action(ArgAction::SetTrue)) 43219625d8cSopenharmony_ci /// .group(ArgGroup::new("req_flags") 43319625d8cSopenharmony_ci /// .args(["flag", "color"]) 43419625d8cSopenharmony_ci /// .conflicts_with("debug")) 43519625d8cSopenharmony_ci /// .try_get_matches_from(vec!["myprog", "-c", "-d"]); 43619625d8cSopenharmony_ci /// // because we used an arg from the group, and the group conflicts with "-d", it's an error 43719625d8cSopenharmony_ci /// assert!(result.is_err()); 43819625d8cSopenharmony_ci /// let err = result.unwrap_err(); 43919625d8cSopenharmony_ci /// assert_eq!(err.kind(), ErrorKind::ArgumentConflict); 44019625d8cSopenharmony_ci /// ``` 44119625d8cSopenharmony_ci /// [argument exclusion rules]: crate::Arg::conflicts_with() 44219625d8cSopenharmony_ci #[must_use] 44319625d8cSopenharmony_ci pub fn conflicts_with(mut self, id: impl IntoResettable<Id>) -> Self { 44419625d8cSopenharmony_ci if let Some(id) = id.into_resettable().into_option() { 44519625d8cSopenharmony_ci self.conflicts.push(id); 44619625d8cSopenharmony_ci } else { 44719625d8cSopenharmony_ci self.conflicts.clear(); 44819625d8cSopenharmony_ci } 44919625d8cSopenharmony_ci self 45019625d8cSopenharmony_ci } 45119625d8cSopenharmony_ci 45219625d8cSopenharmony_ci /// Specify arguments or groups that must **not** be present when this group is. 45319625d8cSopenharmony_ci /// 45419625d8cSopenharmony_ci /// Exclusion rules function just like [argument exclusion rules], you can name other arguments 45519625d8cSopenharmony_ci /// or groups that must *not* be present when one of the arguments from this group are used. 45619625d8cSopenharmony_ci /// 45719625d8cSopenharmony_ci /// **NOTE:** The names provided may be an argument, or group name 45819625d8cSopenharmony_ci /// 45919625d8cSopenharmony_ci /// # Examples 46019625d8cSopenharmony_ci /// 46119625d8cSopenharmony_ci /// ```rust 46219625d8cSopenharmony_ci /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction}; 46319625d8cSopenharmony_ci /// let result = Command::new("myprog") 46419625d8cSopenharmony_ci /// .arg(Arg::new("flag") 46519625d8cSopenharmony_ci /// .short('f') 46619625d8cSopenharmony_ci /// .action(ArgAction::SetTrue)) 46719625d8cSopenharmony_ci /// .arg(Arg::new("color") 46819625d8cSopenharmony_ci /// .short('c') 46919625d8cSopenharmony_ci /// .action(ArgAction::SetTrue)) 47019625d8cSopenharmony_ci /// .arg(Arg::new("debug") 47119625d8cSopenharmony_ci /// .short('d') 47219625d8cSopenharmony_ci /// .action(ArgAction::SetTrue)) 47319625d8cSopenharmony_ci /// .arg(Arg::new("verb") 47419625d8cSopenharmony_ci /// .short('v') 47519625d8cSopenharmony_ci /// .action(ArgAction::SetTrue)) 47619625d8cSopenharmony_ci /// .group(ArgGroup::new("req_flags") 47719625d8cSopenharmony_ci /// .args(["flag", "color"]) 47819625d8cSopenharmony_ci /// .conflicts_with_all(["debug", "verb"])) 47919625d8cSopenharmony_ci /// .try_get_matches_from(vec!["myprog", "-c", "-v"]); 48019625d8cSopenharmony_ci /// // because we used an arg from the group, and the group conflicts with either "-v" or "-d" 48119625d8cSopenharmony_ci /// // it's an error 48219625d8cSopenharmony_ci /// assert!(result.is_err()); 48319625d8cSopenharmony_ci /// let err = result.unwrap_err(); 48419625d8cSopenharmony_ci /// assert_eq!(err.kind(), ErrorKind::ArgumentConflict); 48519625d8cSopenharmony_ci /// ``` 48619625d8cSopenharmony_ci /// 48719625d8cSopenharmony_ci /// [argument exclusion rules]: crate::Arg::conflicts_with_all() 48819625d8cSopenharmony_ci #[must_use] 48919625d8cSopenharmony_ci pub fn conflicts_with_all(mut self, ns: impl IntoIterator<Item = impl Into<Id>>) -> Self { 49019625d8cSopenharmony_ci for n in ns { 49119625d8cSopenharmony_ci self = self.conflicts_with(n); 49219625d8cSopenharmony_ci } 49319625d8cSopenharmony_ci self 49419625d8cSopenharmony_ci } 49519625d8cSopenharmony_ci} 49619625d8cSopenharmony_ci 49719625d8cSopenharmony_ci/// # Reflection 49819625d8cSopenharmony_ciimpl ArgGroup { 49919625d8cSopenharmony_ci /// Get the name of the group 50019625d8cSopenharmony_ci #[inline] 50119625d8cSopenharmony_ci pub fn get_id(&self) -> &Id { 50219625d8cSopenharmony_ci &self.id 50319625d8cSopenharmony_ci } 50419625d8cSopenharmony_ci 50519625d8cSopenharmony_ci /// Reports whether [`ArgGroup::required`] is set 50619625d8cSopenharmony_ci #[inline] 50719625d8cSopenharmony_ci pub fn is_required_set(&self) -> bool { 50819625d8cSopenharmony_ci self.required 50919625d8cSopenharmony_ci } 51019625d8cSopenharmony_ci} 51119625d8cSopenharmony_ci 51219625d8cSopenharmony_ciimpl From<&'_ ArgGroup> for ArgGroup { 51319625d8cSopenharmony_ci fn from(g: &ArgGroup) -> Self { 51419625d8cSopenharmony_ci g.clone() 51519625d8cSopenharmony_ci } 51619625d8cSopenharmony_ci} 51719625d8cSopenharmony_ci 51819625d8cSopenharmony_ci#[cfg(test)] 51919625d8cSopenharmony_cimod test { 52019625d8cSopenharmony_ci use super::*; 52119625d8cSopenharmony_ci 52219625d8cSopenharmony_ci #[test] 52319625d8cSopenharmony_ci fn groups() { 52419625d8cSopenharmony_ci let g = ArgGroup::new("test") 52519625d8cSopenharmony_ci .arg("a1") 52619625d8cSopenharmony_ci .arg("a4") 52719625d8cSopenharmony_ci .args(["a2", "a3"]) 52819625d8cSopenharmony_ci .required(true) 52919625d8cSopenharmony_ci .conflicts_with("c1") 53019625d8cSopenharmony_ci .conflicts_with_all(["c2", "c3"]) 53119625d8cSopenharmony_ci .conflicts_with("c4") 53219625d8cSopenharmony_ci .requires("r1") 53319625d8cSopenharmony_ci .requires_all(["r2", "r3"]) 53419625d8cSopenharmony_ci .requires("r4"); 53519625d8cSopenharmony_ci 53619625d8cSopenharmony_ci let args: Vec<Id> = vec!["a1".into(), "a4".into(), "a2".into(), "a3".into()]; 53719625d8cSopenharmony_ci let reqs: Vec<Id> = vec!["r1".into(), "r2".into(), "r3".into(), "r4".into()]; 53819625d8cSopenharmony_ci let confs: Vec<Id> = vec!["c1".into(), "c2".into(), "c3".into(), "c4".into()]; 53919625d8cSopenharmony_ci 54019625d8cSopenharmony_ci assert_eq!(g.args, args); 54119625d8cSopenharmony_ci assert_eq!(g.requires, reqs); 54219625d8cSopenharmony_ci assert_eq!(g.conflicts, confs); 54319625d8cSopenharmony_ci } 54419625d8cSopenharmony_ci 54519625d8cSopenharmony_ci #[test] 54619625d8cSopenharmony_ci fn test_from() { 54719625d8cSopenharmony_ci let g = ArgGroup::new("test") 54819625d8cSopenharmony_ci .arg("a1") 54919625d8cSopenharmony_ci .arg("a4") 55019625d8cSopenharmony_ci .args(["a2", "a3"]) 55119625d8cSopenharmony_ci .required(true) 55219625d8cSopenharmony_ci .conflicts_with("c1") 55319625d8cSopenharmony_ci .conflicts_with_all(["c2", "c3"]) 55419625d8cSopenharmony_ci .conflicts_with("c4") 55519625d8cSopenharmony_ci .requires("r1") 55619625d8cSopenharmony_ci .requires_all(["r2", "r3"]) 55719625d8cSopenharmony_ci .requires("r4"); 55819625d8cSopenharmony_ci 55919625d8cSopenharmony_ci let args: Vec<Id> = vec!["a1".into(), "a4".into(), "a2".into(), "a3".into()]; 56019625d8cSopenharmony_ci let reqs: Vec<Id> = vec!["r1".into(), "r2".into(), "r3".into(), "r4".into()]; 56119625d8cSopenharmony_ci let confs: Vec<Id> = vec!["c1".into(), "c2".into(), "c3".into(), "c4".into()]; 56219625d8cSopenharmony_ci 56319625d8cSopenharmony_ci let g2 = ArgGroup::from(&g); 56419625d8cSopenharmony_ci assert_eq!(g2.args, args); 56519625d8cSopenharmony_ci assert_eq!(g2.requires, reqs); 56619625d8cSopenharmony_ci assert_eq!(g2.conflicts, confs); 56719625d8cSopenharmony_ci } 56819625d8cSopenharmony_ci 56919625d8cSopenharmony_ci // This test will *fail to compile* if ArgGroup is not Send + Sync 57019625d8cSopenharmony_ci #[test] 57119625d8cSopenharmony_ci fn arg_group_send_sync() { 57219625d8cSopenharmony_ci fn foo<T: Send + Sync>(_: T) {} 57319625d8cSopenharmony_ci foo(ArgGroup::new("test")) 57419625d8cSopenharmony_ci } 57519625d8cSopenharmony_ci 57619625d8cSopenharmony_ci #[test] 57719625d8cSopenharmony_ci fn arg_group_expose_is_multiple_helper() { 57819625d8cSopenharmony_ci let args: Vec<Id> = vec!["a1".into(), "a4".into()]; 57919625d8cSopenharmony_ci 58019625d8cSopenharmony_ci let mut grp_multiple = ArgGroup::new("test_multiple").args(&args).multiple(true); 58119625d8cSopenharmony_ci assert!(grp_multiple.is_multiple()); 58219625d8cSopenharmony_ci 58319625d8cSopenharmony_ci let mut grp_not_multiple = ArgGroup::new("test_multiple").args(&args).multiple(false); 58419625d8cSopenharmony_ci assert!(!grp_not_multiple.is_multiple()); 58519625d8cSopenharmony_ci } 58619625d8cSopenharmony_ci 58719625d8cSopenharmony_ci #[test] 58819625d8cSopenharmony_ci fn arg_group_expose_get_args_helper() { 58919625d8cSopenharmony_ci let args: Vec<Id> = vec!["a1".into(), "a4".into()]; 59019625d8cSopenharmony_ci let grp = ArgGroup::new("program").args(&args); 59119625d8cSopenharmony_ci 59219625d8cSopenharmony_ci for (pos, arg) in grp.get_args().enumerate() { 59319625d8cSopenharmony_ci assert_eq!(*arg, args[pos]); 59419625d8cSopenharmony_ci } 59519625d8cSopenharmony_ci } 59619625d8cSopenharmony_ci} 597