Repository: clap-rs/clap
Pull request #5999 (2025-05-11 10:35:38)

feat(help): Merge lists of short and long aliases
Short aliases are displayed before long aliases, consistent with the order of the short and long argument variants at the start of each line.

Based on [this suggestion][1] from @epage.

[1]: https://github.com/clap-rs/clap/pull/5996#discussion_r2083363726


Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e501191d..02dfaa1a 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -164,7 +164,7 @@ jobs:
     - name: Install Rust
       uses: dtolnay/rust-toolchain@stable
       with:
-        toolchain: "1.87"  # STABLE
+        toolchain: "1.86"  # STABLE
     - uses: Swatinem/rust-cache@v2
     - name: UI Tests
       run: make test-ui-${{ matrix.features }}
@@ -207,7 +207,7 @@ jobs:
     - name: Install Rust
       uses: dtolnay/rust-toolchain@stable
       with:
-        toolchain: "1.87"  # STABLE
+        toolchain: "1.86"  # STABLE
     - uses: Swatinem/rust-cache@v2
     - name: Check documentation
       env:
@@ -222,7 +222,7 @@ jobs:
     - name: Install Rust
       uses: dtolnay/rust-toolchain@stable
       with:
-        toolchain: "1.87"  # STABLE
+        toolchain: "1.86"  # STABLE
         components: rustfmt
     - uses: Swatinem/rust-cache@v2
     - name: Check formatting
@@ -236,7 +236,7 @@ jobs:
     - name: Install Rust
       uses: dtolnay/rust-toolchain@stable
       with:
-        toolchain: "1.87"  # STABLE
+        toolchain: "1.86"  # STABLE
         components: clippy
     - uses: Swatinem/rust-cache@v2
     - name: Lint (ultra-minimal)
diff --git a/Makefile b/Makefile
index 5e62de8c..378ee772 100644
--- a/Makefile
+++ b/Makefile
@@ -10,7 +10,7 @@ ifneq (${TOOLCHAIN_TARGET},)
   ARGS+=--target ${TOOLCHAIN_TARGET}
 endif
 
-STABLE?=1.87
+STABLE?=1.86
 
 _FEATURES = minimal default wasm full debug release
 _FEATURES_minimal = --no-default-features --features "std"
diff --git a/clap_builder/src/builder/command.rs b/clap_builder/src/builder/command.rs
index d0e7d482..8ecd484e 100644
--- a/clap_builder/src/builder/command.rs
+++ b/clap_builder/src/builder/command.rs
@@ -2113,6 +2113,8 @@ impl Command {
     ///     )
     /// # ;
     /// ```
+    ///
+    /// [`ArgMatches::usage`]: ArgMatches::usage()
     #[must_use]
     pub fn override_usage(mut self, usage: impl IntoResettable<StyledStr>) -> Self {
         self.usage_str = usage.into_resettable().into_option();
@@ -3744,6 +3746,8 @@ impl Command {
     }
 
     /// Get the custom section heading specified via [`Command::next_help_heading`].
+    ///
+    /// [`Command::help_heading`]: Command::help_heading()
     #[inline]
     pub fn get_next_help_heading(&self) -> Option<&str> {
         self.current_help_heading.as_deref()
diff --git a/clap_builder/src/error/kind.rs b/clap_builder/src/error/kind.rs
index 298a4fd3..a9d576c6 100644
--- a/clap_builder/src/error/kind.rs
+++ b/clap_builder/src/error/kind.rs
@@ -252,6 +252,7 @@ pub enum ErrorKind {
     /// # }
     /// ```
     ///
+    /// [`Arg::allow_invalid_utf8`]: crate::Arg::allow_invalid_utf8
     /// [`Command::external_subcommand_value_parser`]: crate::Command::external_subcommand_value_parser
     InvalidUtf8,
 
diff --git a/clap_builder/src/output/help_template.rs b/clap_builder/src/output/help_template.rs
index 801fcbfa..51f98f03 100644
--- a/clap_builder/src/output/help_template.rs
+++ b/clap_builder/src/output/help_template.rs
@@ -785,31 +785,29 @@ impl HelpTemplate<'_, '_> {
             spec_vals.push(format!("[default: {pvs}]"));
         }
 
-        let als = a
-            .aliases
+        let mut als = Vec::new();
+
+        let short_als = a
+            .short_aliases
             .iter()
             .filter(|&als| als.1) // visible
-            .map(|als| format!("--{}", als.0)) // name
-            .collect::<Vec<_>>()
-            .join(", ");
-        if !als.is_empty() {
-            debug!("HelpTemplate::spec_vals: Found aliases...{:?}", a.aliases);
-            spec_vals.push(format!("[aliases: {als}]"));
-        }
+            .map(|als| format!("-{}", als.0)); // name
+        debug!(
+            "HelpTemplate::spec_vals: Found short aliases...{:?}",
+            a.short_aliases
+        );
+        als.extend(short_als);
 
-        let als = a
-            .short_aliases
+        let long_als = a
+            .aliases
             .iter()
             .filter(|&als| als.1) // visible
-            .map(|&als| format!("-{}", als.0)) // name
-            .collect::<Vec<_>>()
-            .join(", ");
+            .map(|als| format!("--{}", als.0)); // name
+        debug!("HelpTemplate::spec_vals: Found aliases...{:?}", a.aliases);
+        als.extend(long_als);
+
         if !als.is_empty() {
-            debug!(
-                "HelpTemplate::spec_vals: Found short aliases...{:?}",
-                a.short_aliases
-            );
-            spec_vals.push(format!("[short aliases: {als}]"));
+            spec_vals.push(format!("[aliases: {}]", als.join(", ")));
         }
 
         if !a.is_hide_possible_values_set() && !self.use_long_pv(a) {
diff --git a/clap_builder/src/parser/matches/arg_matches.rs b/clap_builder/src/parser/matches/arg_matches.rs
index 056f521a..2d53e2b9 100644
--- a/clap_builder/src/parser/matches/arg_matches.rs
+++ b/clap_builder/src/parser/matches/arg_matches.rs
@@ -308,6 +308,7 @@ impl ArgMatches {
     /// ```
     /// [`Iterator`]: std::iter::Iterator
     /// [`OsSt`]: std::ffi::OsStr
+    /// [values]: OsValues
     /// [`String`]: std::string::String
     #[cfg_attr(debug_assertions, track_caller)]
     pub fn get_raw(&self, id: &str) -> Option<RawValues<'_>> {
@@ -362,6 +363,7 @@ impl ArgMatches {
     /// ```
     /// [`Iterator`]: std::iter::Iterator
     /// [`OsStr`]: std::ffi::OsStr
+    /// [values]: OsValues
     /// [`String`]: std::string::String
     #[cfg_attr(debug_assertions, track_caller)]
     pub fn get_raw_occurrences(&self, id: &str) -> Option<RawOccurrences<'_>> {
@@ -851,6 +853,7 @@ impl ArgMatches {
     /// assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2]);
     /// ```
     /// [`ArgMatches::index_of`]: ArgMatches::index_of()
+    /// [delimiter]: Arg::value_delimiter()
     #[cfg_attr(debug_assertions, track_caller)]
     pub fn indices_of(&self, id: &str) -> Option<Indices<'_>> {
         let arg = some!(self.get_arg(id));
diff --git a/examples/tutorial_builder/03_04_subcommands.md b/examples/tutorial_builder/03_04_subcommands.md
index 24d44889..a32b7768 100644
--- a/examples/tutorial_builder/03_04_subcommands.md
+++ b/examples/tutorial_builder/03_04_subcommands.md
@@ -29,10 +29,7 @@ $ 03_04_subcommands add bob
 
 ```
 
-We set
-[`Command::arg_required_else_help`][crate::Command::arg_required_else_help] to
-show the help, rather than an error, when the
-[required subcommand][crate::Command::subcommand_required] is missing:
+Because we set [`Command::arg_required_else_help`][crate::Command::arg_required_else_help]:
 ```console
 $ 03_04_subcommands
 ? failed
diff --git a/examples/tutorial_derive/03_04_subcommands.md b/examples/tutorial_derive/03_04_subcommands.md
index 3ae06774..4d57dfee 100644
--- a/examples/tutorial_derive/03_04_subcommands.md
+++ b/examples/tutorial_derive/03_04_subcommands.md
@@ -29,8 +29,8 @@ $ 03_04_subcommands_derive add bob
 
 ```
 
-When specifying commands with `command: Commands`, they are [required][crate::Command::subcommand_required].
-By default, a missing subcommand will [show help rather than error][crate::Command::arg_required_else_help].
+When specifying commands with `command: Commands`, they are required.
+Alternatively, you could do `command: Option<Commands>` to make it optional.
 ```console
 $ 03_04_subcommands_derive
 ? failed
@@ -47,7 +47,6 @@ Options:
   -V, --version  Print version
 
 ```
-To make a subcommand optional, wrap it in an `Option` (e.g. `command: Option<Commands>`).
 
 Since we specified [`#[command(propagate_version = true)]`][crate::Command::propagate_version],
 the `--version` flag is available in all subcommands:
diff --git a/src/_derive/mod.rs b/src/_derive/mod.rs
index b49d0dbd..b9091d2a 100644
--- a/src/_derive/mod.rs
+++ b/src/_derive/mod.rs
@@ -8,7 +8,7 @@
 //!     3. [Arg Attributes](#arg-attributes)
 //!     4. [ValueEnum Attributes](#valueenum-attributes)
 //!     5. [Possible Value Attributes](#possible-value-attributes)
-//! 3. [Field Types](#field-types)
+//! 3. [Arg Types](#arg-types)
 //! 4. [Doc Comments](#doc-comments)
 //! 5. [Mixing Builder and Derive APIs](#mixing-builder-and-derive-apis)
 //! 6. [Tips](#tips)
@@ -294,18 +294,9 @@
 //!   - When not present: [Doc comment summary](#doc-comments)
 //! - `skip`: Ignore this variant
 //!
-//! ## Field Types
+//! ## Arg Types
 //!
-//! `clap` assumes some intent based on the type used.
-//!
-//! ### Subcommand Types
-//!
-//! | Type                  | Effect              | Implies                                                   |
-//! |-----------------------|---------------------|-----------------------------------------------------------|
-//! | `Option<T>`           | optional subcommand |                                                           |
-//! | `T`                   | required subcommand | `.subcommand_required(true).arg_required_else_help(true)` |
-//!
-//! ### Arg Types
+//! `clap` assumes some intent based on the type used:
 //!
 //! | Type                  | Effect                                               | Implies                                                     | Notes |
 //! |-----------------------|------------------------------------------------------|-------------------------------------------------------------|-------|


Test patch:
diff --git a/tests/builder/arg_aliases_short.rs b/tests/builder/arg_aliases_short.rs
index 60a84305..c0feda50 100644
--- a/tests/builder/arg_aliases_short.rs
+++ b/tests/builder/arg_aliases_short.rs
@@ -193,8 +193,8 @@ Some help
 Usage: ct test [OPTIONS]
 
 Options:
-  -o, --opt <opt>  [short aliases: -v]
-  -f, --flag       [aliases: --flag1] [short aliases: -a, -b, -🦆]
+  -o, --opt <opt>  [aliases: -v]
+  -f, --flag       [aliases: -a, -b, -🦆, --flag1]
   -h, --help       Print help
   -V, --version    Print version
 ";
diff --git a/tests/derive_ui.rs b/tests/derive_ui.rs
index d06f69fb..9652bd5b 100644
--- a/tests/derive_ui.rs
+++ b/tests/derive_ui.rs
@@ -8,7 +8,7 @@
 #![cfg(feature = "unstable-derive-ui-tests")]
 
 #[cfg(feature = "derive")]
-#[rustversion::attr(not(stable(1.87)), ignore)] // STABLE
+#[rustversion::attr(not(stable(1.86)), ignore)] // STABLE
 #[test]
 fn ui() {
     let t = trybuild::TestCases::new();