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