Repository: clap-rs/clap
Pull request #3231 (2021-12-30 17:45:09)

Revert "Remove {n} support"
This reverts commit 333b993481396d84197bd6e5b54c526a3b04e6a1.

PR #1810's motivation was effectively "this is redundant with `\n`".
That is a fine motivation.  Unfortunately, we don't have a way to force
a hard break in `clap_derive`.  #2389 should help with this eventually
but we shouldn't hold up 3.0 to get that ready.  So in the mean time, we
are restoring `{n}`.

We have #3230 for tracking the re-removal of it.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 813e95c8..00709c44 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -133,7 +133,6 @@ Subtle changes (i.e. compiler won't catch):
 - `Arg::env`, `Arg::env_os`, `Arg::last`, `Arg::require_equals`, `Arg::allow_hyphen_values`,
   `Arg::hide_possible_values`, `Arg::hide_default_value`, `Arg::hide_env_values`,
   `Arg::case_insensitive` and `Arg::multiple_values` no longer imply `ArgSettings::TakesValue` ([#2233](https://github.com/clap-rs/clap/issues/2233))
-- Removed support for `{n}` as a newline in help text ([#1810](https://github.com/clap-rs/clap/pull/1810))
 - `ArgMatches::is_present` no longer checks subcommand names
 - Some env variable values are now considered false for flags, not just "not-present" ([clap-rs/clap#2539](https://github.com/clap-rs/clap/issues/2539))
 - Changed `...`s meaning in usage parser.  Before, it always meant `multiple` which is still true for `--option [val]...`.  Now `[name]... --option [val]` results in `ArgSettings::MultipleOccurrences`.
diff --git a/src/build/usage_parser.rs b/src/build/usage_parser.rs
index ec868be3..1da76e24 100644
--- a/src/build/usage_parser.rs
+++ b/src/build/usage_parser.rs
@@ -1118,11 +1118,11 @@ mod test {
     #[test]
     fn pos_help_newline() {
         let a = Arg::from_usage(
-            "[pos]... 'some help\n\
+            "[pos]... 'some help{n}\
              info'",
         );
         assert_eq!(a.name, "pos");
-        assert_eq!(a.help.unwrap(), "some help\ninfo");
+        assert_eq!(a.help.unwrap(), "some help{n}info");
         assert!(a.is_set(ArgSettings::MultipleOccurrences));
         assert!(!a.is_set(ArgSettings::MultipleValues));
         assert!(!a.is_set(ArgSettings::Required));
@@ -1132,11 +1132,11 @@ mod test {
     #[test]
     fn pos_help_newline_lit_sq() {
         let a = Arg::from_usage(
-            "[pos]... 'some help\' stuff\n\
+            "[pos]... 'some help\' stuff{n}\
              info'",
         );
         assert_eq!(a.name, "pos");
-        assert_eq!(a.help.unwrap(), "some help' stuff\ninfo");
+        assert_eq!(a.help.unwrap(), "some help' stuff{n}info");
         assert!(a.is_set(ArgSettings::MultipleOccurrences));
         assert!(!a.is_set(ArgSettings::MultipleValues));
         assert!(!a.is_set(ArgSettings::Required));
diff --git a/src/output/help.rs b/src/output/help.rs
index ee667033..3bf777e6 100644
--- a/src/output/help.rs
+++ b/src/output/help.rs
@@ -351,7 +351,7 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
             self.parser.app.before_help
         };
         if let Some(output) = before_help {
-            self.none(text_wrapper(output, self.term_w))?;
+            self.none(text_wrapper(&output.replace("{n}", "\n"), self.term_w))?;
             self.none("\n\n")?;
         }
         Ok(())
@@ -369,7 +369,7 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
         };
         if let Some(output) = after_help {
             self.none("\n\n")?;
-            self.none(text_wrapper(output, self.term_w))?;
+            self.none(text_wrapper(&output.replace("{n}", "\n"), self.term_w))?;
         }
         Ok(())
     }
@@ -401,14 +401,14 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
         }
 
         debug!("Help::help: Too long...");
-        if too_long && spaces <= self.term_w {
+        if too_long && spaces <= self.term_w || help.contains("{n}") {
             debug!("Yes");
             debug!("Help::help: help...{}", help);
             debug!("Help::help: help width...{}", display_width(&help));
             // Determine how many newlines we need to insert
             let avail_chars = self.term_w - spaces;
             debug!("Help::help: Usable space...{}", avail_chars);
-            help = text_wrapper(&help, avail_chars);
+            help = text_wrapper(&help.replace("{n}", "\n"), avail_chars);
         } else {
             debug!("No");
         }
@@ -874,10 +874,10 @@ impl<'help, 'app, 'parser, 'writer> Help<'help, 'app, 'parser, 'writer> {
                 // In case we're dealing with subcommands i.e. git mv is translated to git-mv
                 bn.replace(" ", "-")
             } else {
-                text_wrapper(&self.parser.app.name, self.term_w)
+                text_wrapper(&self.parser.app.name.replace("{n}", "\n"), self.term_w)
             }
         } else {
-            text_wrapper(&self.parser.app.name, self.term_w)
+            text_wrapper(&self.parser.app.name.replace("{n}", "\n"), self.term_w)
         };
         self.good(&bin_name)?;
         Ok(())


Test patch:
diff --git a/tests/builder/help.rs b/tests/builder/help.rs
index c31b8542..52500c47 100644
--- a/tests/builder/help.rs
+++ b/tests/builder/help.rs
@@ -1125,6 +1125,24 @@ fn wrapping_newline_chars() {
     ));
 }
 
+#[test]
+fn wrapping_newline_variables() {
+    let app = App::new("ctest")
+        .version("0.1")
+        .term_width(60)
+        .arg(Arg::new("mode").help(
+            "x, max, maximum   20 characters, contains symbols.{n}\
+             l, long           Copy-friendly, 14 characters, contains symbols.{n}\
+             m, med, medium    Copy-friendly, 8 characters, contains symbols.{n}",
+        ));
+    assert!(utils::compare_output(
+        app,
+        "ctest --help",
+        WRAPPING_NEWLINE_CHARS,
+        false
+    ));
+}
+
 #[test]
 fn old_newline_chars() {
     let app = App::new("ctest").version("0.1").arg(
@@ -1140,6 +1158,21 @@ fn old_newline_chars() {
     ));
 }
 
+#[test]
+fn old_newline_variables() {
+    let app = App::new("ctest").version("0.1").arg(
+        Arg::new("mode")
+            .short('m')
+            .help("Some help with some wrapping{n}(Defaults to something)"),
+    );
+    assert!(utils::compare_output(
+        app,
+        "ctest --help",
+        OLD_NEWLINE_CHARS,
+        false
+    ));
+}
+
 #[test]
 fn issue_688_hide_pos_vals() {
     let filter_values = ["Nearest", "Linear", "Cubic", "Gaussian", "Lanczos3"];