| 1 | // Internal | 
| 2 | use crate::builder::IntoResettable; | 
|---|
| 3 | use crate::util::Id; | 
|---|
| 4 |  | 
|---|
| 5 | /// Family of related [arguments]. | 
|---|
| 6 | /// | 
|---|
| 7 | /// By placing arguments in a logical group, you can create easier requirement and | 
|---|
| 8 | /// exclusion rules instead of having to list each argument individually, or when you want a rule | 
|---|
| 9 | /// to apply "any but not all" arguments. | 
|---|
| 10 | /// | 
|---|
| 11 | /// For instance, you can make an entire `ArgGroup` required. If [`ArgGroup::multiple(true)`] is | 
|---|
| 12 | /// set, this means that at least one argument from that group must be present. If | 
|---|
| 13 | /// [`ArgGroup::multiple(false)`] is set (the default), one and *only* one must be present. | 
|---|
| 14 | /// | 
|---|
| 15 | /// You can also do things such as name an entire `ArgGroup` as a [conflict] or [requirement] for | 
|---|
| 16 | /// another argument, meaning any of the arguments that belong to that group will cause a failure | 
|---|
| 17 | /// if present, or must be present respectively. | 
|---|
| 18 | /// | 
|---|
| 19 | /// Perhaps the most common use of `ArgGroup`s is to require one and *only* one argument to be | 
|---|
| 20 | /// present out of a given set. Imagine that you had multiple arguments, and you want one of them | 
|---|
| 21 | /// to be required, but making all of them required isn't feasible because perhaps they conflict | 
|---|
| 22 | /// with each other. For example, lets say that you were building an application where one could | 
|---|
| 23 | /// set a given version number by supplying a string with an option argument, i.e. | 
|---|
| 24 | /// `--set-ver v1.2.3`, you also wanted to support automatically using a previous version number | 
|---|
| 25 | /// and simply incrementing one of the three numbers. So you create three flags `--major`, | 
|---|
| 26 | /// `--minor`, and `--patch`. All of these arguments shouldn't be used at one time but you want to | 
|---|
| 27 | /// specify that *at least one* of them is used. For this, you can create a group. | 
|---|
| 28 | /// | 
|---|
| 29 | /// Finally, you may use `ArgGroup`s to pull a value from a group of arguments when you don't care | 
|---|
| 30 | /// exactly which argument was actually used at runtime. | 
|---|
| 31 | /// | 
|---|
| 32 | /// # Examples | 
|---|
| 33 | /// | 
|---|
| 34 | /// The following example demonstrates using an `ArgGroup` to ensure that one, and only one, of | 
|---|
| 35 | /// the arguments from the specified group is present at runtime. | 
|---|
| 36 | /// | 
|---|
| 37 | /// ```rust | 
|---|
| 38 | /// # use clap_builder as clap; | 
|---|
| 39 | /// # use clap::{Command, arg, ArgGroup, error::ErrorKind}; | 
|---|
| 40 | /// let result = Command::new( "cmd") | 
|---|
| 41 | ///     .arg(arg!(-- "set-ver"<ver> "set the version manually")) | 
|---|
| 42 | ///     .arg(arg!(--major "auto increase major")) | 
|---|
| 43 | ///     .arg(arg!(--minor "auto increase minor")) | 
|---|
| 44 | ///     .arg(arg!(--patch "auto increase patch")) | 
|---|
| 45 | ///     .group(ArgGroup::new( "vers") | 
|---|
| 46 | ///          .args([ "set-ver", "major", "minor", "patch"]) | 
|---|
| 47 | ///          .required(true)) | 
|---|
| 48 | ///     .try_get_matches_from(vec![ "cmd", "--major", "--patch"]); | 
|---|
| 49 | /// // Because we used two args in the group it's an error | 
|---|
| 50 | /// assert!(result.is_err()); | 
|---|
| 51 | /// let err = result.unwrap_err(); | 
|---|
| 52 | /// assert_eq!(err.kind(), ErrorKind::ArgumentConflict); | 
|---|
| 53 | /// ``` | 
|---|
| 54 | /// | 
|---|
| 55 | /// This next example shows a passing parse of the same scenario | 
|---|
| 56 | /// ```rust | 
|---|
| 57 | /// # use clap_builder as clap; | 
|---|
| 58 | /// # use clap::{Command, arg, ArgGroup, Id}; | 
|---|
| 59 | /// let result = Command::new( "cmd") | 
|---|
| 60 | ///     .arg(arg!(-- "set-ver"<ver> "set the version manually")) | 
|---|
| 61 | ///     .arg(arg!(--major "auto increase major")) | 
|---|
| 62 | ///     .arg(arg!(--minor "auto increase minor")) | 
|---|
| 63 | ///     .arg(arg!(--patch "auto increase patch")) | 
|---|
| 64 | ///     .group(ArgGroup::new( "vers") | 
|---|
| 65 | ///          .args([ "set-ver", "major", "minor", "patch"]) | 
|---|
| 66 | ///          .required(true)) | 
|---|
| 67 | ///     .try_get_matches_from(vec![ "cmd", "--major"]); | 
|---|
| 68 | /// assert!(result.is_ok()); | 
|---|
| 69 | /// let matches = result.unwrap(); | 
|---|
| 70 | /// // We may not know which of the args was used, so we can test for the group... | 
|---|
| 71 | /// assert!(matches.contains_id( "vers")); | 
|---|
| 72 | /// // We can also ask the group which arg was used | 
|---|
| 73 | /// assert_eq!(matches | 
|---|
| 74 | ///     .get_one::<Id>( "vers") | 
|---|
| 75 | ///     .expect( "`vers` is required") | 
|---|
| 76 | ///     .as_str(), | 
|---|
| 77 | /// "major" | 
|---|
| 78 | /// ); | 
|---|
| 79 | /// // we could also alternatively check each arg individually (not shown here) | 
|---|
| 80 | /// ``` | 
|---|
| 81 | /// [`ArgGroup::multiple(true)`]: ArgGroup::multiple() | 
|---|
| 82 | /// | 
|---|
| 83 | /// [`ArgGroup::multiple(false)`]: ArgGroup::multiple() | 
|---|
| 84 | /// [arguments]: crate::Arg | 
|---|
| 85 | /// [conflict]: crate::Arg::conflicts_with() | 
|---|
| 86 | /// [requirement]: crate::Arg::requires() | 
|---|
| 87 | #[ derive(Default, Clone, Debug, PartialEq, Eq)] | 
|---|
| 88 | pub struct ArgGroup { | 
|---|
| 89 | pub(crate) id: Id, | 
|---|
| 90 | pub(crate) args: Vec<Id>, | 
|---|
| 91 | pub(crate) required: bool, | 
|---|
| 92 | pub(crate) requires: Vec<Id>, | 
|---|
| 93 | pub(crate) conflicts: Vec<Id>, | 
|---|
| 94 | pub(crate) multiple: bool, | 
|---|
| 95 | } | 
|---|
| 96 |  | 
|---|
| 97 | /// # Builder | 
|---|
| 98 | impl ArgGroup { | 
|---|
| 99 | /// Create a `ArgGroup` using a unique name. | 
|---|
| 100 | /// | 
|---|
| 101 | /// The name will be used to get values from the group or refer to the group inside of conflict | 
|---|
| 102 | /// and requirement rules. | 
|---|
| 103 | /// | 
|---|
| 104 | /// # Examples | 
|---|
| 105 | /// | 
|---|
| 106 | /// ```rust | 
|---|
| 107 | /// # use clap_builder as clap; | 
|---|
| 108 | /// # use clap::{Command, ArgGroup}; | 
|---|
| 109 | /// ArgGroup::new( "config") | 
|---|
| 110 | /// # ; | 
|---|
| 111 | /// ``` | 
|---|
| 112 | pub fn new(id: impl Into<Id>) -> Self { | 
|---|
| 113 | ArgGroup::default().id(id) | 
|---|
| 114 | } | 
|---|
| 115 |  | 
|---|
| 116 | /// Sets the group name. | 
|---|
| 117 | /// | 
|---|
| 118 | /// # Examples | 
|---|
| 119 | /// | 
|---|
| 120 | /// ```rust | 
|---|
| 121 | /// # use clap_builder as clap; | 
|---|
| 122 | /// # use clap::{Command, ArgGroup}; | 
|---|
| 123 | /// ArgGroup::default().id( "config") | 
|---|
| 124 | /// # ; | 
|---|
| 125 | /// ``` | 
|---|
| 126 | #[ must_use] | 
|---|
| 127 | pub fn id(mut self, id: impl Into<Id>) -> Self { | 
|---|
| 128 | self.id = id.into(); | 
|---|
| 129 | self | 
|---|
| 130 | } | 
|---|
| 131 |  | 
|---|
| 132 | /// Adds an [argument] to this group by name | 
|---|
| 133 | /// | 
|---|
| 134 | /// # Examples | 
|---|
| 135 | /// | 
|---|
| 136 | /// ```rust | 
|---|
| 137 | /// # use clap_builder as clap; | 
|---|
| 138 | /// # use clap::{Command, Arg, ArgGroup, ArgAction}; | 
|---|
| 139 | /// let m = Command::new( "myprog") | 
|---|
| 140 | ///     .arg(Arg::new( "flag") | 
|---|
| 141 | ///         .short( 'f') | 
|---|
| 142 | ///         .action(ArgAction::SetTrue)) | 
|---|
| 143 | ///     .arg(Arg::new( "color") | 
|---|
| 144 | ///         .short( 'c') | 
|---|
| 145 | ///         .action(ArgAction::SetTrue)) | 
|---|
| 146 | ///     .group(ArgGroup::new( "req_flags") | 
|---|
| 147 | ///         .arg( "flag") | 
|---|
| 148 | ///         .arg( "color")) | 
|---|
| 149 | ///     .get_matches_from(vec![ "myprog", "-f"]); | 
|---|
| 150 | /// // maybe we don't know which of the two flags was used... | 
|---|
| 151 | /// assert!(m.contains_id( "req_flags")); | 
|---|
| 152 | /// // but we can also check individually if needed | 
|---|
| 153 | /// assert!(m.contains_id( "flag")); | 
|---|
| 154 | /// ``` | 
|---|
| 155 | /// [argument]: crate::Arg | 
|---|
| 156 | #[ must_use] | 
|---|
| 157 | pub fn arg(mut self, arg_id: impl IntoResettable<Id>) -> Self { | 
|---|
| 158 | if let Some(arg_id) = arg_id.into_resettable().into_option() { | 
|---|
| 159 | self.args.push(arg_id); | 
|---|
| 160 | } else { | 
|---|
| 161 | self.args.clear(); | 
|---|
| 162 | } | 
|---|
| 163 | self | 
|---|
| 164 | } | 
|---|
| 165 |  | 
|---|
| 166 | /// Adds multiple [arguments] to this group by name | 
|---|
| 167 | /// | 
|---|
| 168 | /// # Examples | 
|---|
| 169 | /// | 
|---|
| 170 | /// ```rust | 
|---|
| 171 | /// # use clap_builder as clap; | 
|---|
| 172 | /// # use clap::{Command, Arg, ArgGroup, ArgAction}; | 
|---|
| 173 | /// let m = Command::new( "myprog") | 
|---|
| 174 | ///     .arg(Arg::new( "flag") | 
|---|
| 175 | ///         .short( 'f') | 
|---|
| 176 | ///         .action(ArgAction::SetTrue)) | 
|---|
| 177 | ///     .arg(Arg::new( "color") | 
|---|
| 178 | ///         .short( 'c') | 
|---|
| 179 | ///         .action(ArgAction::SetTrue)) | 
|---|
| 180 | ///     .group(ArgGroup::new( "req_flags") | 
|---|
| 181 | ///         .args([ "flag", "color"])) | 
|---|
| 182 | ///     .get_matches_from(vec![ "myprog", "-f"]); | 
|---|
| 183 | /// // maybe we don't know which of the two flags was used... | 
|---|
| 184 | /// assert!(m.contains_id( "req_flags")); | 
|---|
| 185 | /// // but we can also check individually if needed | 
|---|
| 186 | /// assert!(m.contains_id( "flag")); | 
|---|
| 187 | /// ``` | 
|---|
| 188 | /// [arguments]: crate::Arg | 
|---|
| 189 | #[ must_use] | 
|---|
| 190 | pub fn args(mut self, ns: impl IntoIterator<Item = impl Into<Id>>) -> Self { | 
|---|
| 191 | for n in ns { | 
|---|
| 192 | self = self.arg(n); | 
|---|
| 193 | } | 
|---|
| 194 | self | 
|---|
| 195 | } | 
|---|
| 196 |  | 
|---|
| 197 | /// Getters for all args. It will return a vector of `Id` | 
|---|
| 198 | /// | 
|---|
| 199 | /// # Example | 
|---|
| 200 | /// | 
|---|
| 201 | /// ```rust | 
|---|
| 202 | /// # use clap_builder as clap; | 
|---|
| 203 | /// # use clap::{ArgGroup}; | 
|---|
| 204 | /// let args: Vec<&str> = vec![ "a1".into(), "a4".into()]; | 
|---|
| 205 | /// let grp = ArgGroup::new( "program").args(&args); | 
|---|
| 206 | /// | 
|---|
| 207 | /// for (pos, arg) in grp.get_args().enumerate() { | 
|---|
| 208 | ///     assert_eq!(*arg, args[pos]); | 
|---|
| 209 | /// } | 
|---|
| 210 | /// ``` | 
|---|
| 211 | pub fn get_args(&self) -> impl Iterator<Item = &Id> { | 
|---|
| 212 | self.args.iter() | 
|---|
| 213 | } | 
|---|
| 214 |  | 
|---|
| 215 | /// Allows more than one of the [`Arg`]s in this group to be used. (Default: `false`) | 
|---|
| 216 | /// | 
|---|
| 217 | /// # Examples | 
|---|
| 218 | /// | 
|---|
| 219 | /// Notice in this example we use *both* the `-f` and `-c` flags which are both part of the | 
|---|
| 220 | /// group | 
|---|
| 221 | /// | 
|---|
| 222 | /// ```rust | 
|---|
| 223 | /// # use clap_builder as clap; | 
|---|
| 224 | /// # use clap::{Command, Arg, ArgGroup, ArgAction}; | 
|---|
| 225 | /// let m = Command::new( "myprog") | 
|---|
| 226 | ///     .arg(Arg::new( "flag") | 
|---|
| 227 | ///         .short( 'f') | 
|---|
| 228 | ///         .action(ArgAction::SetTrue)) | 
|---|
| 229 | ///     .arg(Arg::new( "color") | 
|---|
| 230 | ///         .short( 'c') | 
|---|
| 231 | ///         .action(ArgAction::SetTrue)) | 
|---|
| 232 | ///     .group(ArgGroup::new( "req_flags") | 
|---|
| 233 | ///         .args([ "flag", "color"]) | 
|---|
| 234 | ///         .multiple(true)) | 
|---|
| 235 | ///     .get_matches_from(vec![ "myprog", "-f", "-c"]); | 
|---|
| 236 | /// // maybe we don't know which of the two flags was used... | 
|---|
| 237 | /// assert!(m.contains_id( "req_flags")); | 
|---|
| 238 | /// ``` | 
|---|
| 239 | /// In this next example, we show the default behavior (i.e. `multiple(false)`) which will throw | 
|---|
| 240 | /// an error if more than one of the args in the group was used. | 
|---|
| 241 | /// | 
|---|
| 242 | /// ```rust | 
|---|
| 243 | /// # use clap_builder as clap; | 
|---|
| 244 | /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction}; | 
|---|
| 245 | /// let result = Command::new( "myprog") | 
|---|
| 246 | ///     .arg(Arg::new( "flag") | 
|---|
| 247 | ///         .short( 'f') | 
|---|
| 248 | ///         .action(ArgAction::SetTrue)) | 
|---|
| 249 | ///     .arg(Arg::new( "color") | 
|---|
| 250 | ///         .short( 'c') | 
|---|
| 251 | ///         .action(ArgAction::SetTrue)) | 
|---|
| 252 | ///     .group(ArgGroup::new( "req_flags") | 
|---|
| 253 | ///         .args([ "flag", "color"])) | 
|---|
| 254 | ///     .try_get_matches_from(vec![ "myprog", "-f", "-c"]); | 
|---|
| 255 | /// // Because we used both args in the group it's an error | 
|---|
| 256 | /// assert!(result.is_err()); | 
|---|
| 257 | /// let err = result.unwrap_err(); | 
|---|
| 258 | /// assert_eq!(err.kind(), ErrorKind::ArgumentConflict); | 
|---|
| 259 | /// ``` | 
|---|
| 260 | /// | 
|---|
| 261 | /// [`Arg`]: crate::Arg | 
|---|
| 262 | #[ inline] | 
|---|
| 263 | #[ must_use] | 
|---|
| 264 | pub fn multiple(mut self, yes: bool) -> Self { | 
|---|
| 265 | self.multiple = yes; | 
|---|
| 266 | self | 
|---|
| 267 | } | 
|---|
| 268 |  | 
|---|
| 269 | /// Return true if the group allows more than one of the arguments | 
|---|
| 270 | /// in this group to be used. (Default: `false`) | 
|---|
| 271 | /// | 
|---|
| 272 | /// # Example | 
|---|
| 273 | /// | 
|---|
| 274 | /// ```rust | 
|---|
| 275 | /// # use clap_builder as clap; | 
|---|
| 276 | /// # use clap::{ArgGroup}; | 
|---|
| 277 | /// let mut group = ArgGroup::new( "myprog") | 
|---|
| 278 | ///     .args([ "f", "c"]) | 
|---|
| 279 | ///     .multiple(true); | 
|---|
| 280 | /// | 
|---|
| 281 | /// assert!(group.is_multiple()); | 
|---|
| 282 | /// ``` | 
|---|
| 283 | pub fn is_multiple(&mut self) -> bool { | 
|---|
| 284 | self.multiple | 
|---|
| 285 | } | 
|---|
| 286 |  | 
|---|
| 287 | /// Require an argument from the group to be present when parsing. | 
|---|
| 288 | /// | 
|---|
| 289 | /// This is unless conflicting with another argument.  A required group will be displayed in | 
|---|
| 290 | /// the usage string of the application in the format `<arg|arg2|arg3>`. | 
|---|
| 291 | /// | 
|---|
| 292 | /// <div class="warning"> | 
|---|
| 293 | /// | 
|---|
| 294 | /// **NOTE:** This setting only applies to the current [`Command`] / [`Subcommand`]s, and not | 
|---|
| 295 | /// globally. | 
|---|
| 296 | /// | 
|---|
| 297 | /// </div> | 
|---|
| 298 | /// | 
|---|
| 299 | /// <div class="warning"> | 
|---|
| 300 | /// | 
|---|
| 301 | /// **NOTE:** By default, [`ArgGroup::multiple`] is set to `false` which when combined with | 
|---|
| 302 | /// `ArgGroup::required(true)` states, "One and *only one* arg must be used from this group. | 
|---|
| 303 | /// Use of more than one arg is an error." Vice setting `ArgGroup::multiple(true)` which | 
|---|
| 304 | /// states, '*At least* one arg from this group must be used. Using multiple is OK." | 
|---|
| 305 | /// | 
|---|
| 306 | /// </div> | 
|---|
| 307 | /// | 
|---|
| 308 | /// # Examples | 
|---|
| 309 | /// | 
|---|
| 310 | /// ```rust | 
|---|
| 311 | /// # use clap_builder as clap; | 
|---|
| 312 | /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction}; | 
|---|
| 313 | /// let result = Command::new( "myprog") | 
|---|
| 314 | ///     .arg(Arg::new( "flag") | 
|---|
| 315 | ///         .short( 'f') | 
|---|
| 316 | ///         .action(ArgAction::SetTrue)) | 
|---|
| 317 | ///     .arg(Arg::new( "color") | 
|---|
| 318 | ///         .short( 'c') | 
|---|
| 319 | ///         .action(ArgAction::SetTrue)) | 
|---|
| 320 | ///     .group(ArgGroup::new( "req_flags") | 
|---|
| 321 | ///         .args([ "flag", "color"]) | 
|---|
| 322 | ///         .required(true)) | 
|---|
| 323 | ///     .try_get_matches_from(vec![ "myprog"]); | 
|---|
| 324 | /// // Because we didn't use any of the args in the group, it's an error | 
|---|
| 325 | /// assert!(result.is_err()); | 
|---|
| 326 | /// let err = result.unwrap_err(); | 
|---|
| 327 | /// assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument); | 
|---|
| 328 | /// ``` | 
|---|
| 329 | /// | 
|---|
| 330 | /// [`Subcommand`]: crate::Subcommand | 
|---|
| 331 | /// [`ArgGroup::multiple`]: ArgGroup::multiple() | 
|---|
| 332 | /// [`Command`]: crate::Command | 
|---|
| 333 | #[ inline] | 
|---|
| 334 | #[ must_use] | 
|---|
| 335 | pub fn required(mut self, yes: bool) -> Self { | 
|---|
| 336 | self.required = yes; | 
|---|
| 337 | self | 
|---|
| 338 | } | 
|---|
| 339 |  | 
|---|
| 340 | /// Specify an argument or group that must be present when this group is. | 
|---|
| 341 | /// | 
|---|
| 342 | /// This is not to be confused with a [required group]. Requirement rules function just like | 
|---|
| 343 | /// [argument requirement rules], you can name other arguments or groups that must be present | 
|---|
| 344 | /// when any one of the arguments from this group is used. | 
|---|
| 345 | /// | 
|---|
| 346 | /// <div class="warning"> | 
|---|
| 347 | /// | 
|---|
| 348 | /// **NOTE:** The name provided may be an argument or group name | 
|---|
| 349 | /// | 
|---|
| 350 | /// </div> | 
|---|
| 351 | /// | 
|---|
| 352 | /// # Examples | 
|---|
| 353 | /// | 
|---|
| 354 | /// ```rust | 
|---|
| 355 | /// # use clap_builder as clap; | 
|---|
| 356 | /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction}; | 
|---|
| 357 | /// let result = Command::new( "myprog") | 
|---|
| 358 | ///     .arg(Arg::new( "flag") | 
|---|
| 359 | ///         .short( 'f') | 
|---|
| 360 | ///         .action(ArgAction::SetTrue)) | 
|---|
| 361 | ///     .arg(Arg::new( "color") | 
|---|
| 362 | ///         .short( 'c') | 
|---|
| 363 | ///         .action(ArgAction::SetTrue)) | 
|---|
| 364 | ///     .arg(Arg::new( "debug") | 
|---|
| 365 | ///         .short( 'd') | 
|---|
| 366 | ///         .action(ArgAction::SetTrue)) | 
|---|
| 367 | ///     .group(ArgGroup::new( "req_flags") | 
|---|
| 368 | ///         .args([ "flag", "color"]) | 
|---|
| 369 | ///         .requires( "debug")) | 
|---|
| 370 | ///     .try_get_matches_from(vec![ "myprog", "-c"]); | 
|---|
| 371 | /// // because we used an arg from the group, and the group requires "-d" to be used, it's an | 
|---|
| 372 | /// // error | 
|---|
| 373 | /// assert!(result.is_err()); | 
|---|
| 374 | /// let err = result.unwrap_err(); | 
|---|
| 375 | /// assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument); | 
|---|
| 376 | /// ``` | 
|---|
| 377 | /// [required group]: ArgGroup::required() | 
|---|
| 378 | /// [argument requirement rules]: crate::Arg::requires() | 
|---|
| 379 | #[ must_use] | 
|---|
| 380 | pub fn requires(mut self, id: impl IntoResettable<Id>) -> Self { | 
|---|
| 381 | if let Some(id) = id.into_resettable().into_option() { | 
|---|
| 382 | self.requires.push(id); | 
|---|
| 383 | } else { | 
|---|
| 384 | self.requires.clear(); | 
|---|
| 385 | } | 
|---|
| 386 | self | 
|---|
| 387 | } | 
|---|
| 388 |  | 
|---|
| 389 | /// Specify arguments or groups that must be present when this group is. | 
|---|
| 390 | /// | 
|---|
| 391 | /// This is not to be confused with a [required group]. Requirement rules function just like | 
|---|
| 392 | /// [argument requirement rules], you can name other arguments or groups that must be present | 
|---|
| 393 | /// when one of the arguments from this group is used. | 
|---|
| 394 | /// | 
|---|
| 395 | /// <div class="warning"> | 
|---|
| 396 | /// | 
|---|
| 397 | /// **NOTE:** The names provided may be an argument or group name | 
|---|
| 398 | /// | 
|---|
| 399 | /// </div> | 
|---|
| 400 | /// | 
|---|
| 401 | /// # Examples | 
|---|
| 402 | /// | 
|---|
| 403 | /// ```rust | 
|---|
| 404 | /// # use clap_builder as clap; | 
|---|
| 405 | /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction}; | 
|---|
| 406 | /// let result = Command::new( "myprog") | 
|---|
| 407 | ///     .arg(Arg::new( "flag") | 
|---|
| 408 | ///         .short( 'f') | 
|---|
| 409 | ///         .action(ArgAction::SetTrue)) | 
|---|
| 410 | ///     .arg(Arg::new( "color") | 
|---|
| 411 | ///         .short( 'c') | 
|---|
| 412 | ///         .action(ArgAction::SetTrue)) | 
|---|
| 413 | ///     .arg(Arg::new( "debug") | 
|---|
| 414 | ///         .short( 'd') | 
|---|
| 415 | ///         .action(ArgAction::SetTrue)) | 
|---|
| 416 | ///     .arg(Arg::new( "verb") | 
|---|
| 417 | ///         .short( 'v') | 
|---|
| 418 | ///         .action(ArgAction::SetTrue)) | 
|---|
| 419 | ///     .group(ArgGroup::new( "req_flags") | 
|---|
| 420 | ///         .args([ "flag", "color"]) | 
|---|
| 421 | ///         .requires_all([ "debug", "verb"])) | 
|---|
| 422 | ///     .try_get_matches_from(vec![ "myprog", "-c", "-d"]); | 
|---|
| 423 | /// // because we used an arg from the group, and the group requires "-d" and "-v" to be used, | 
|---|
| 424 | /// // yet we only used "-d" it's an error | 
|---|
| 425 | /// assert!(result.is_err()); | 
|---|
| 426 | /// let err = result.unwrap_err(); | 
|---|
| 427 | /// assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument); | 
|---|
| 428 | /// ``` | 
|---|
| 429 | /// [required group]: ArgGroup::required() | 
|---|
| 430 | /// [argument requirement rules]: crate::Arg::requires_ifs() | 
|---|
| 431 | #[ must_use] | 
|---|
| 432 | pub fn requires_all(mut self, ns: impl IntoIterator<Item = impl Into<Id>>) -> Self { | 
|---|
| 433 | for n in ns { | 
|---|
| 434 | self = self.requires(n); | 
|---|
| 435 | } | 
|---|
| 436 | self | 
|---|
| 437 | } | 
|---|
| 438 |  | 
|---|
| 439 | /// Specify an argument or group that must **not** be present when this group is. | 
|---|
| 440 | /// | 
|---|
| 441 | /// Exclusion (aka conflict) rules function just like [argument exclusion rules], you can name | 
|---|
| 442 | /// other arguments or groups that must *not* be present when one of the arguments from this | 
|---|
| 443 | /// group are used. | 
|---|
| 444 | /// | 
|---|
| 445 | /// <div class="warning"> | 
|---|
| 446 | /// | 
|---|
| 447 | /// **NOTE:** The name provided may be an argument, or group name | 
|---|
| 448 | /// | 
|---|
| 449 | /// </div> | 
|---|
| 450 | /// | 
|---|
| 451 | /// # Examples | 
|---|
| 452 | /// | 
|---|
| 453 | /// ```rust | 
|---|
| 454 | /// # use clap_builder as clap; | 
|---|
| 455 | /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction}; | 
|---|
| 456 | /// let result = Command::new( "myprog") | 
|---|
| 457 | ///     .arg(Arg::new( "flag") | 
|---|
| 458 | ///         .short( 'f') | 
|---|
| 459 | ///         .action(ArgAction::SetTrue)) | 
|---|
| 460 | ///     .arg(Arg::new( "color") | 
|---|
| 461 | ///         .short( 'c') | 
|---|
| 462 | ///         .action(ArgAction::SetTrue)) | 
|---|
| 463 | ///     .arg(Arg::new( "debug") | 
|---|
| 464 | ///         .short( 'd') | 
|---|
| 465 | ///         .action(ArgAction::SetTrue)) | 
|---|
| 466 | ///     .group(ArgGroup::new( "req_flags") | 
|---|
| 467 | ///         .args([ "flag", "color"]) | 
|---|
| 468 | ///         .conflicts_with( "debug")) | 
|---|
| 469 | ///     .try_get_matches_from(vec![ "myprog", "-c", "-d"]); | 
|---|
| 470 | /// // because we used an arg from the group, and the group conflicts with "-d", it's an error | 
|---|
| 471 | /// assert!(result.is_err()); | 
|---|
| 472 | /// let err = result.unwrap_err(); | 
|---|
| 473 | /// assert_eq!(err.kind(), ErrorKind::ArgumentConflict); | 
|---|
| 474 | /// ``` | 
|---|
| 475 | /// [argument exclusion rules]: crate::Arg::conflicts_with() | 
|---|
| 476 | #[ must_use] | 
|---|
| 477 | pub fn conflicts_with(mut self, id: impl IntoResettable<Id>) -> Self { | 
|---|
| 478 | if let Some(id) = id.into_resettable().into_option() { | 
|---|
| 479 | self.conflicts.push(id); | 
|---|
| 480 | } else { | 
|---|
| 481 | self.conflicts.clear(); | 
|---|
| 482 | } | 
|---|
| 483 | self | 
|---|
| 484 | } | 
|---|
| 485 |  | 
|---|
| 486 | /// Specify arguments or groups that must **not** be present when this group is. | 
|---|
| 487 | /// | 
|---|
| 488 | /// Exclusion rules function just like [argument exclusion rules], you can name other arguments | 
|---|
| 489 | /// or groups that must *not* be present when one of the arguments from this group are used. | 
|---|
| 490 | /// | 
|---|
| 491 | /// <div class="warning"> | 
|---|
| 492 | /// | 
|---|
| 493 | /// **NOTE:** The names provided may be an argument, or group name | 
|---|
| 494 | /// | 
|---|
| 495 | /// </div> | 
|---|
| 496 | /// | 
|---|
| 497 | /// # Examples | 
|---|
| 498 | /// | 
|---|
| 499 | /// ```rust | 
|---|
| 500 | /// # use clap_builder as clap; | 
|---|
| 501 | /// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction}; | 
|---|
| 502 | /// let result = Command::new( "myprog") | 
|---|
| 503 | ///     .arg(Arg::new( "flag") | 
|---|
| 504 | ///         .short( 'f') | 
|---|
| 505 | ///         .action(ArgAction::SetTrue)) | 
|---|
| 506 | ///     .arg(Arg::new( "color") | 
|---|
| 507 | ///         .short( 'c') | 
|---|
| 508 | ///         .action(ArgAction::SetTrue)) | 
|---|
| 509 | ///     .arg(Arg::new( "debug") | 
|---|
| 510 | ///         .short( 'd') | 
|---|
| 511 | ///         .action(ArgAction::SetTrue)) | 
|---|
| 512 | ///     .arg(Arg::new( "verb") | 
|---|
| 513 | ///         .short( 'v') | 
|---|
| 514 | ///         .action(ArgAction::SetTrue)) | 
|---|
| 515 | ///     .group(ArgGroup::new( "req_flags") | 
|---|
| 516 | ///         .args([ "flag", "color"]) | 
|---|
| 517 | ///         .conflicts_with_all([ "debug", "verb"])) | 
|---|
| 518 | ///     .try_get_matches_from(vec![ "myprog", "-c", "-v"]); | 
|---|
| 519 | /// // because we used an arg from the group, and the group conflicts with either "-v" or "-d" | 
|---|
| 520 | /// // it's an error | 
|---|
| 521 | /// assert!(result.is_err()); | 
|---|
| 522 | /// let err = result.unwrap_err(); | 
|---|
| 523 | /// assert_eq!(err.kind(), ErrorKind::ArgumentConflict); | 
|---|
| 524 | /// ``` | 
|---|
| 525 | /// | 
|---|
| 526 | /// [argument exclusion rules]: crate::Arg::conflicts_with_all() | 
|---|
| 527 | #[ must_use] | 
|---|
| 528 | pub fn conflicts_with_all(mut self, ns: impl IntoIterator<Item = impl Into<Id>>) -> Self { | 
|---|
| 529 | for n in ns { | 
|---|
| 530 | self = self.conflicts_with(n); | 
|---|
| 531 | } | 
|---|
| 532 | self | 
|---|
| 533 | } | 
|---|
| 534 | } | 
|---|
| 535 |  | 
|---|
| 536 | /// # Reflection | 
|---|
| 537 | impl ArgGroup { | 
|---|
| 538 | /// Get the name of the group | 
|---|
| 539 | #[ inline] | 
|---|
| 540 | pub fn get_id(&self) -> &Id { | 
|---|
| 541 | &self.id | 
|---|
| 542 | } | 
|---|
| 543 |  | 
|---|
| 544 | /// Reports whether [`ArgGroup::required`] is set | 
|---|
| 545 | #[ inline] | 
|---|
| 546 | pub fn is_required_set(&self) -> bool { | 
|---|
| 547 | self.required | 
|---|
| 548 | } | 
|---|
| 549 | } | 
|---|
| 550 |  | 
|---|
| 551 | impl From<&'_ ArgGroup> for ArgGroup { | 
|---|
| 552 | fn from(g: &ArgGroup) -> Self { | 
|---|
| 553 | g.clone() | 
|---|
| 554 | } | 
|---|
| 555 | } | 
|---|
| 556 |  | 
|---|
| 557 | #[ cfg(test)] | 
|---|
| 558 | mod test { | 
|---|
| 559 | use super::*; | 
|---|
| 560 |  | 
|---|
| 561 | #[ test] | 
|---|
| 562 | fn groups() { | 
|---|
| 563 | let g = ArgGroup::new( "test") | 
|---|
| 564 | .arg( "a1") | 
|---|
| 565 | .arg( "a4") | 
|---|
| 566 | .args([ "a2", "a3"]) | 
|---|
| 567 | .required(true) | 
|---|
| 568 | .conflicts_with( "c1") | 
|---|
| 569 | .conflicts_with_all([ "c2", "c3"]) | 
|---|
| 570 | .conflicts_with( "c4") | 
|---|
| 571 | .requires( "r1") | 
|---|
| 572 | .requires_all([ "r2", "r3"]) | 
|---|
| 573 | .requires( "r4"); | 
|---|
| 574 |  | 
|---|
| 575 | let args: Vec<Id> = vec![ "a1".into(), "a4".into(), "a2".into(), "a3".into()]; | 
|---|
| 576 | let reqs: Vec<Id> = vec![ "r1".into(), "r2".into(), "r3".into(), "r4".into()]; | 
|---|
| 577 | let confs: Vec<Id> = vec![ "c1".into(), "c2".into(), "c3".into(), "c4".into()]; | 
|---|
| 578 |  | 
|---|
| 579 | assert_eq!(g.args, args); | 
|---|
| 580 | assert_eq!(g.requires, reqs); | 
|---|
| 581 | assert_eq!(g.conflicts, confs); | 
|---|
| 582 | } | 
|---|
| 583 |  | 
|---|
| 584 | #[ test] | 
|---|
| 585 | fn test_from() { | 
|---|
| 586 | let g = ArgGroup::new( "test") | 
|---|
| 587 | .arg( "a1") | 
|---|
| 588 | .arg( "a4") | 
|---|
| 589 | .args([ "a2", "a3"]) | 
|---|
| 590 | .required(true) | 
|---|
| 591 | .conflicts_with( "c1") | 
|---|
| 592 | .conflicts_with_all([ "c2", "c3"]) | 
|---|
| 593 | .conflicts_with( "c4") | 
|---|
| 594 | .requires( "r1") | 
|---|
| 595 | .requires_all([ "r2", "r3"]) | 
|---|
| 596 | .requires( "r4"); | 
|---|
| 597 |  | 
|---|
| 598 | let args: Vec<Id> = vec![ "a1".into(), "a4".into(), "a2".into(), "a3".into()]; | 
|---|
| 599 | let reqs: Vec<Id> = vec![ "r1".into(), "r2".into(), "r3".into(), "r4".into()]; | 
|---|
| 600 | let confs: Vec<Id> = vec![ "c1".into(), "c2".into(), "c3".into(), "c4".into()]; | 
|---|
| 601 |  | 
|---|
| 602 | let g2 = ArgGroup::from(&g); | 
|---|
| 603 | assert_eq!(g2.args, args); | 
|---|
| 604 | assert_eq!(g2.requires, reqs); | 
|---|
| 605 | assert_eq!(g2.conflicts, confs); | 
|---|
| 606 | } | 
|---|
| 607 |  | 
|---|
| 608 | // This test will *fail to compile* if ArgGroup is not Send + Sync | 
|---|
| 609 | #[ test] | 
|---|
| 610 | fn arg_group_send_sync() { | 
|---|
| 611 | fn foo<T: Send + Sync>(_: T) {} | 
|---|
| 612 | foo(ArgGroup::new( "test")); | 
|---|
| 613 | } | 
|---|
| 614 |  | 
|---|
| 615 | #[ test] | 
|---|
| 616 | fn arg_group_expose_is_multiple_helper() { | 
|---|
| 617 | let args: Vec<Id> = vec![ "a1".into(), "a4".into()]; | 
|---|
| 618 |  | 
|---|
| 619 | let mut grp_multiple = ArgGroup::new( "test_multiple").args(&args).multiple(true); | 
|---|
| 620 | assert!(grp_multiple.is_multiple()); | 
|---|
| 621 |  | 
|---|
| 622 | let mut grp_not_multiple = ArgGroup::new( "test_multiple").args(&args).multiple(false); | 
|---|
| 623 | assert!(!grp_not_multiple.is_multiple()); | 
|---|
| 624 | } | 
|---|
| 625 |  | 
|---|
| 626 | #[ test] | 
|---|
| 627 | fn arg_group_expose_get_args_helper() { | 
|---|
| 628 | let args: Vec<Id> = vec![ "a1".into(), "a4".into()]; | 
|---|
| 629 | let grp = ArgGroup::new( "program").args(&args); | 
|---|
| 630 |  | 
|---|
| 631 | for (pos, arg) in grp.get_args().enumerate() { | 
|---|
| 632 | assert_eq!(*arg, args[pos]); | 
|---|
| 633 | } | 
|---|
| 634 | } | 
|---|
| 635 | } | 
|---|
| 636 |  | 
|---|