1use crate::builder::IntoResettable;
2use crate::builder::Str;
3use crate::builder::StyledStr;
4use crate::util::eq_ignore_case;
5
6/// A possible value of an argument.
7///
8/// This is used for specifying [possible values] of [Args].
9///
10/// See also [`PossibleValuesParser`][crate::builder::PossibleValuesParser]
11///
12/// **NOTE:** Most likely you can use strings, rather than `PossibleValue` as it is only required
13/// to [hide] single values from help messages and shell completions or to attach [help] to
14/// possible values.
15///
16/// # Examples
17///
18/// ```rust
19/// # use clap::{Arg, builder::PossibleValue, ArgAction};
20/// let cfg = Arg::new("config")
21///     .action(ArgAction::Set)
22///     .value_name("FILE")
23///     .value_parser([
24///         PossibleValue::new("fast"),
25///         PossibleValue::new("slow").help("slower than fast"),
26///         PossibleValue::new("secret speed").hide(true)
27///     ]);
28/// ```
29///
30/// [Args]: crate::Arg
31/// [possible values]: crate::builder::ValueParser::possible_values
32/// [hide]: PossibleValue::hide()
33/// [help]: PossibleValue::help()
34#[derive(Debug, Default, Clone, PartialEq, Eq)]
35pub struct PossibleValue {
36    name: Str,
37    help: Option<StyledStr>,
38    aliases: Vec<Str>, // (name, visible)
39    hide: bool,
40}
41
42impl PossibleValue {
43    /// Create a [`PossibleValue`] with its name.
44    ///
45    /// The name will be used to decide whether this value was provided by the user to an argument.
46    ///
47    /// **NOTE:** In case it is not [hidden] it will also be shown in help messages for arguments
48    /// that use it as a [possible value] and have not hidden them through [`Arg::hide_possible_values(true)`].
49    ///
50    /// # Examples
51    ///
52    /// ```rust
53    /// # use clap::builder::PossibleValue;
54    /// PossibleValue::new("fast")
55    /// # ;
56    /// ```
57    /// [hidden]: PossibleValue::hide
58    /// [possible value]: crate::builder::PossibleValuesParser
59    /// [`Arg::hide_possible_values(true)`]: crate::Arg::hide_possible_values()
60    pub fn new(name: impl Into<Str>) -> Self {
61        PossibleValue {
62            name: name.into(),
63            ..Default::default()
64        }
65    }
66
67    /// Sets the help description of the value.
68    ///
69    /// This is typically displayed in completions (where supported) and should be a short, one-line
70    /// description.
71    ///
72    /// # Examples
73    ///
74    /// ```rust
75    /// # use clap::builder::PossibleValue;
76    /// PossibleValue::new("slow")
77    ///     .help("not fast")
78    /// # ;
79    /// ```
80    #[inline]
81    #[must_use]
82    pub fn help(mut self, help: impl IntoResettable<StyledStr>) -> Self {
83        self.help = help.into_resettable().into_option();
84        self
85    }
86
87    /// Hides this value from help and shell completions.
88    ///
89    /// This is an alternative to hiding through [`Arg::hide_possible_values(true)`], if you only
90    /// want to hide some values.
91    ///
92    /// # Examples
93    ///
94    /// ```rust
95    /// # use clap::builder::PossibleValue;
96    /// PossibleValue::new("secret")
97    ///     .hide(true)
98    /// # ;
99    /// ```
100    /// [`Arg::hide_possible_values(true)`]: crate::Arg::hide_possible_values()
101    #[inline]
102    #[must_use]
103    pub fn hide(mut self, yes: bool) -> Self {
104        self.hide = yes;
105        self
106    }
107
108    /// Sets a *hidden* alias for this argument value.
109    ///
110    /// # Examples
111    ///
112    /// ```rust
113    /// # use clap::builder::PossibleValue;
114    /// PossibleValue::new("slow")
115    ///     .alias("not-fast")
116    /// # ;
117    /// ```
118    #[must_use]
119    pub fn alias(mut self, name: impl IntoResettable<Str>) -> Self {
120        if let Some(name) = name.into_resettable().into_option() {
121            self.aliases.push(name);
122        } else {
123            self.aliases.clear();
124        }
125        self
126    }
127
128    /// Sets multiple *hidden* aliases for this argument value.
129    ///
130    /// # Examples
131    ///
132    /// ```rust
133    /// # use clap::builder::PossibleValue;
134    /// PossibleValue::new("slow")
135    ///     .aliases(["not-fast", "snake-like"])
136    /// # ;
137    /// ```
138    #[must_use]
139    pub fn aliases(mut self, names: impl IntoIterator<Item = impl Into<Str>>) -> Self {
140        self.aliases.extend(names.into_iter().map(|a| a.into()));
141        self
142    }
143}
144
145/// Reflection
146impl PossibleValue {
147    /// Get the name of the argument value
148    #[inline]
149    pub fn get_name(&self) -> &str {
150        self.name.as_str()
151    }
152
153    /// Get the help specified for this argument, if any
154    #[inline]
155    pub fn get_help(&self) -> Option<&StyledStr> {
156        self.help.as_ref()
157    }
158
159    /// Get the help specified for this argument, if any and the argument
160    /// value is not hidden
161    #[inline]
162    #[cfg(feature = "help")]
163    pub(crate) fn get_visible_help(&self) -> Option<&StyledStr> {
164        if !self.hide {
165            self.get_help()
166        } else {
167            None
168        }
169    }
170
171    /// Report if [`PossibleValue::hide`] is set
172    #[inline]
173    pub fn is_hide_set(&self) -> bool {
174        self.hide
175    }
176
177    /// Report if PossibleValue is not hidden and has a help message
178    pub(crate) fn should_show_help(&self) -> bool {
179        !self.hide && self.help.is_some()
180    }
181
182    /// Get the name if argument value is not hidden, `None` otherwise,
183    /// but wrapped in quotes if it contains whitespace
184    #[cfg(feature = "help")]
185    pub(crate) fn get_visible_quoted_name(&self) -> Option<std::borrow::Cow<'_, str>> {
186        if !self.hide {
187            Some(if self.name.contains(char::is_whitespace) {
188                format!("{:?}", self.name).into()
189            } else {
190                self.name.as_str().into()
191            })
192        } else {
193            None
194        }
195    }
196
197    /// Returns all valid values of the argument value.
198    ///
199    /// Namely the name and all aliases.
200    pub fn get_name_and_aliases(&self) -> impl Iterator<Item = &str> + '_ {
201        std::iter::once(self.get_name()).chain(self.aliases.iter().map(|s| s.as_str()))
202    }
203
204    /// Tests if the value is valid for this argument value
205    ///
206    /// The value is valid if it is either the name or one of the aliases.
207    ///
208    /// # Examples
209    ///
210    /// ```rust
211    /// # use clap::builder::PossibleValue;
212    /// let arg_value = PossibleValue::new("fast").alias("not-slow");
213    ///
214    /// assert!(arg_value.matches("fast", false));
215    /// assert!(arg_value.matches("not-slow", false));
216    ///
217    /// assert!(arg_value.matches("FAST", true));
218    /// assert!(!arg_value.matches("FAST", false));
219    /// ```
220    pub fn matches(&self, value: &str, ignore_case: bool) -> bool {
221        if ignore_case {
222            self.get_name_and_aliases()
223                .any(|name| eq_ignore_case(name, value))
224        } else {
225            self.get_name_and_aliases().any(|name| name == value)
226        }
227    }
228}
229
230impl<S: Into<Str>> From<S> for PossibleValue {
231    fn from(s: S) -> Self {
232        Self::new(s)
233    }
234}
235