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