Skip to content

Commit f984aa5

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 f984aa5

File tree

2 files changed

+81
-12
lines changed

2 files changed

+81
-12
lines changed

clap_builder/src/builder/possible_value.rs

+66-1
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,42 @@ 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+
const ALIASES_PREFIX: &str = " [aliases: ";
197+
const ALIASES_POSTFIX: &str = "]";
198+
const ALIASES_JOINER: &str = ", ";
199+
200+
let name = self.get_name();
201+
let aliases = if self.get_visible_aliases().is_empty() {
202+
"".to_string()
203+
} else {
204+
// [aliases: a, b, c]
205+
format!(
206+
"{ALIASES_PREFIX}{}{ALIASES_POSTFIX}",
207+
self.get_visible_aliases()
208+
.iter()
209+
.map(|s| { format!("{}{s}{}", literal.render(), literal.render_reset()) })
210+
.collect::<Vec<_>>()
211+
.join(ALIASES_JOINER)
212+
)
213+
};
214+
215+
format!(
216+
"{}{name}{}{aliases}",
217+
literal.render(),
218+
literal.render_reset()
219+
)
220+
}
221+
159222
/// Get the help specified for this argument, if any
160223
#[inline]
161224
pub fn get_help(&self) -> Option<&StyledStr> {
@@ -192,7 +255,9 @@ impl PossibleValue {
192255
///
193256
/// Namely the name and all aliases.
194257
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()))
258+
std::iter::once(self.get_name())
259+
.chain(self.aliases.iter().map(|s| s.as_str()))
260+
.chain(self.visible_aliases.iter().map(|s| s.as_str()))
196261
}
197262

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

clap_builder/src/output/help_template.rs

+15-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,12 @@ 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+
693+
// FIXME
692694
let longest = possible_vals
693695
.iter()
694696
.filter(|f| !f.is_hide_set())
695-
.map(|f| display_width(f.get_name()))
697+
.map(|f| display_width(f.render_help_prefix_long(literal).as_str()))
696698
.max()
697699
.expect("Only called with possible value");
698700

@@ -705,19 +707,15 @@ impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
705707
}
706708
self.writer.push_str("Possible values:");
707709
for pv in possible_vals.iter().filter(|pv| !pv.is_hide_set()) {
708-
let name = pv.get_name();
710+
let prefix = pv.render_help_prefix_long(literal);
709711

710712
let mut descr = StyledStr::new();
711-
let _ = write!(
712-
&mut descr,
713-
"{}{name}{}",
714-
literal.render(),
715-
literal.render_reset()
716-
);
713+
714+
let _ = write!(&mut descr, "{prefix}",);
717715
if let Some(help) = pv.get_help() {
718716
debug!("HelpTemplate::help: Possible Value help");
719717
// To align help messages
720-
let padding = longest - display_width(name);
718+
let padding = longest - display_width(prefix.as_str());
721719
let _ = write!(&mut descr, ": {:padding$}", "");
722720
descr.push_styled(help);
723721
}
@@ -848,9 +846,15 @@ impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
848846
if !possible_vals.is_empty() {
849847
debug!("HelpTemplate::spec_vals: Found possible vals...{possible_vals:?}");
850848

849+
// FIXME here is where possible values are formatted in short form, should be a list with no difference
850+
// between possible value names and visible aliases
851851
let pvs = possible_vals
852852
.iter()
853-
.filter_map(PossibleValue::get_visible_quoted_name)
853+
.filter(|v| !v.is_hide_set())
854+
.flat_map(|v| {
855+
std::iter::once(v.get_name())
856+
.chain(v.get_visible_aliases().iter().map(|s| s.as_str()))
857+
})
854858
.collect::<Vec<_>>()
855859
.join(", ");
856860

0 commit comments

Comments
 (0)