Skip to content

Commit 5c6f832

Browse files
committed
feat: Add Visible Aliases for PossibleValue
Before this change, it was not possible to have *visible* aliases for PossibleValues, all aliases were hidden in help output. This change adds a new API for adding visible aliases and modifies the help generation scheme to display these visible aliases.
1 parent 43efde9 commit 5c6f832

File tree

2 files changed

+74
-27
lines changed

2 files changed

+74
-27
lines changed

clap_builder/src/builder/possible_value.rs

+62-16
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use anstyle::Style;
2+
13
use crate::builder::IntoResettable;
24
use crate::builder::Str;
35
use crate::builder::StyledStr;
@@ -37,6 +39,7 @@ pub struct PossibleValue {
3739
name: Str,
3840
help: Option<StyledStr>,
3941
aliases: Vec<Str>, // (name, visible)
42+
visible_aliases: Vec<Str>,
4043
hide: bool,
4144
}
4245

@@ -130,6 +133,20 @@ impl PossibleValue {
130133
self
131134
}
132135

136+
/// Add a _visible_ alias to this [PossibleValue].
137+
///
138+
/// Unlike [PossibleValue::alias], these aliases will show in help output.
139+
#[must_use]
140+
pub fn visible_alias(mut self, name: impl IntoResettable<Str>) -> Self {
141+
if let Some(name) = name.into_resettable().into_option() {
142+
self.visible_aliases.push(name);
143+
} else {
144+
self.visible_aliases.clear();
145+
}
146+
147+
self
148+
}
149+
133150
/// Sets multiple *hidden* aliases for this argument value.
134151
///
135152
/// # Examples
@@ -146,6 +163,16 @@ impl PossibleValue {
146163
self.aliases.extend(names.into_iter().map(|a| a.into()));
147164
self
148165
}
166+
167+
/// Add multiple _visible_ aliases to this [PossibleValue].
168+
///
169+
/// Unlike [PossibleValue::aliases], these aliases will show in help output.
170+
#[must_use]
171+
pub fn visible_aliases(mut self, names: impl IntoIterator<Item = impl Into<Str>>) -> Self {
172+
self.visible_aliases
173+
.extend(names.into_iter().map(|a| a.into()));
174+
self
175+
}
149176
}
150177

151178
/// Reflection
@@ -156,6 +183,38 @@ impl PossibleValue {
156183
self.name.as_str()
157184
}
158185

186+
/// Get the visible aliases for this argument
187+
pub fn get_visible_aliases(&self) -> &Vec<Str> {
188+
&self.visible_aliases
189+
}
190+
191+
/// Render help text for this [PossibleValue] with all of its visible aliases included.
192+
///
193+
/// If there are no visible aliases, this will simply emit the formatted name, if there are visible aliases, these
194+
/// will be appended like this: `name [aliases: a, b, c]`.
195+
pub fn render_help_prefix_long(&self, literal: &Style) -> String {
196+
let name = self.get_name();
197+
let aliases = if self.get_visible_aliases().is_empty() {
198+
"".to_string()
199+
} else {
200+
// [aliases: a, b, c]
201+
format!(
202+
"[aliases: {}]",
203+
self.get_visible_aliases()
204+
.iter()
205+
.map(|s| { format!("{}{s}{}", literal.render(), literal.render_reset()) })
206+
.collect::<Vec<_>>()
207+
.join(", ")
208+
)
209+
};
210+
211+
format!(
212+
"{}{name}{}{aliases}",
213+
literal.render(),
214+
literal.render_reset()
215+
)
216+
}
217+
159218
/// Get the help specified for this argument, if any
160219
#[inline]
161220
pub fn get_help(&self) -> Option<&StyledStr> {
@@ -173,26 +232,13 @@ impl PossibleValue {
173232
!self.hide && self.help.is_some()
174233
}
175234

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-
191235
/// Returns all valid values of the argument value.
192236
///
193237
/// Namely the name and all aliases.
194238
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()))
239+
std::iter::once(self.get_name())
240+
.chain(self.aliases.iter().map(|s| s.as_str()))
241+
.chain(self.visible_aliases.iter().map(|s| s.as_str()))
196242
}
197243

198244
/// Tests if the value is valid for this argument value

clap_builder/src/output/help_template.rs

+12-11
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ use std::borrow::Cow;
88
use std::cmp;
99
use std::usize;
1010

11+
use crate::builder::{Arg, Command};
1112
// Internal
1213
use crate::builder::PossibleValue;
1314
use crate::builder::Str;
1415
use crate::builder::StyledStr;
1516
use crate::builder::Styles;
16-
use crate::builder::{Arg, Command};
1717
use crate::output::display_width;
1818
use crate::output::wrap;
1919
use crate::output::Usage;
@@ -689,10 +689,11 @@ impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
689689
let possible_vals = arg.get_possible_values();
690690
if !possible_vals.is_empty() {
691691
debug!("HelpTemplate::help: Found possible vals...{possible_vals:?}");
692+
692693
let longest = possible_vals
693694
.iter()
694695
.filter(|f| !f.is_hide_set())
695-
.map(|f| display_width(f.get_name()))
696+
.map(|f| display_width(f.render_help_prefix_long(literal).as_str()))
696697
.max()
697698
.expect("Only called with possible value");
698699

@@ -705,19 +706,15 @@ impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
705706
}
706707
self.writer.push_str("Possible values:");
707708
for pv in possible_vals.iter().filter(|pv| !pv.is_hide_set()) {
708-
let name = pv.get_name();
709+
let prefix = pv.render_help_prefix_long(literal);
709710

710711
let mut descr = StyledStr::new();
711-
let _ = write!(
712-
&mut descr,
713-
"{}{name}{}",
714-
literal.render(),
715-
literal.render_reset()
716-
);
712+
713+
let _ = write!(&mut descr, "{prefix}",);
717714
if let Some(help) = pv.get_help() {
718715
debug!("HelpTemplate::help: Possible Value help");
719716
// To align help messages
720-
let padding = longest - display_width(name);
717+
let padding = longest - display_width(prefix.as_str());
721718
let _ = write!(&mut descr, ": {:padding$}", "");
722719
descr.push_styled(help);
723720
}
@@ -850,7 +847,11 @@ impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
850847

851848
let pvs = possible_vals
852849
.iter()
853-
.filter_map(PossibleValue::get_visible_quoted_name)
850+
.filter(|v| !v.is_hide_set())
851+
.flat_map(|v| {
852+
std::iter::once(v.get_name())
853+
.chain(v.get_visible_aliases().iter().map(|s| s.as_str()))
854+
})
854855
.collect::<Vec<_>>()
855856
.join(", ");
856857

0 commit comments

Comments
 (0)