From 933f1f88f81c79fc746446a5aa82cb8747fab96a Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 26 Sep 2022 11:35:18 -0500 Subject: [PATCH] fix(help)!: Wrapping is behind wrap_help If users don't want `wrap_help` feature, they can put newlines in where needed. Seems odd to support wrapping when the wrap size is fixed. For those hard coding the lines, this will save them a decent amount of size. --- CHANGELOG.md | 5 ++++- Cargo.toml | 2 +- src/builder/styled_str.rs | 5 ++++- src/output/help_template.rs | 9 +++++++-- src/output/textwrap/mod.rs | 9 +++++++++ tests/builder/help.rs | 31 ++++++++++++++++++++++++++++--- 6 files changed, 53 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf4f87a311da..f4a810e28fcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -125,7 +125,9 @@ Steps: 2. *If using Builder API*: Explicitly set the `arg.action(ArgAction::...)` on each argument (`StoreValue` for options and `IncOccurrences` for flags) 3. Run `cargo check --features clap/deprecated` and resolve all deprecation warnings 4. Upgrade to v4 -5. *If `default-features = false`*, run `cargo add clap -F help,usage,error-context` +5. Update feature flags + - *If `default-features = false`*, run `cargo add clap -F help,usage,error-context` + - Run `cargo add clap -F wrap_help` unless you want to hard code line wraps 6. Resolve compiler errors 7. Resolve behavior changes (see "subtle changes" under BREAKING CHANGES) 8. *At your leisure:* resolve new deprecation notices @@ -189,6 +191,7 @@ Subtle changes (i.e. compiler won't catch): - *(parser)* Always fill in `""` argument for external subcommands to make it easier to distinguish them from built-in commands (#3263) - *(parser)* Short flags now have higher precedence than hyphen values with `Arg::allow_hyphen_values`, to be consistent with `Command::allow_hyphen_values` (#4187) - *(parser)* `Arg::value_terminator` must be its own argument on the CLI rather than being in a delimited list (#4025) +- *(help)* Line wrapping of help is now behind the existing `wrap_help` feature flag, either enable it or hard code your wraps (#4258) - *(help)* Make `DeriveDisplayOrder` the default and removed the setting. To sort help, set `next_display_order(None)` (#2808) - *(help)* Subcommand display order respects `Command::next_display_order` instead of `DeriveDisplayOrder` and using its own initial display order value (#2808) - *(help)* Subcommands are now listed before arguments. To get the old behavior, see `Command::help_template` (#4132) diff --git a/Cargo.toml b/Cargo.toml index 771c5c96d57d..9c4ac31fda9c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,7 +77,7 @@ suggestions = ["dep:strsim", "error-context"] deprecated = ["clap_derive?/deprecated"] # Guided experience to prepare for next breaking release (at different stages of development, this may become default) derive = ["clap_derive", "dep:once_cell"] cargo = ["dep:once_cell"] # Disable if you're not using Cargo, enables Cargo-env-var-dependent macros -wrap_help = ["dep:terminal_size"] +wrap_help = ["help", "dep:terminal_size"] env = [] # Use environment variables during arg parsing unicode = ["dep:unicode-width", "dep:unicase"] # Support for unicode characters in arguments and help messages string = [] # Allow runtime generated strings diff --git a/src/builder/styled_str.rs b/src/builder/styled_str.rs index 01017e0f3817..8def36fde7d3 100644 --- a/src/builder/styled_str.rs +++ b/src/builder/styled_str.rs @@ -101,7 +101,10 @@ impl StyledStr { } } - #[cfg(feature = "help")] + #[cfg(not(feature = "wrap_help"))] + pub(crate) fn wrap(&mut self, _hard_width: usize) {} + + #[cfg(feature = "wrap_help")] pub(crate) fn wrap(&mut self, hard_width: usize) { let mut wrapper = crate::output::textwrap::wrap_algorithms::LineWrapper::new(hard_width); for (_, content) in self.iter_mut() { diff --git a/src/output/help_template.rs b/src/output/help_template.rs index da16f903fddf..00516bc50f74 100644 --- a/src/output/help_template.rs +++ b/src/output/help_template.rs @@ -1020,10 +1020,11 @@ fn longest_filter(arg: &Arg) -> bool { #[cfg(test)] mod test { - use super::*; - #[test] + #[cfg(feature = "wrap_help")] fn wrap_help_last_word() { + use super::*; + let help = String::from("foo bar baz"); assert_eq!(wrap(&help, 5), "foo\nbar\nbaz"); } @@ -1031,6 +1032,8 @@ mod test { #[test] #[cfg(feature = "unicode")] fn display_width_handles_non_ascii() { + use super::*; + // Popular Danish tongue-twister, the name of a fruit dessert. let text = "rødgrød med fløde"; assert_eq!(display_width(text), 17); @@ -1042,6 +1045,8 @@ mod test { #[test] #[cfg(feature = "unicode")] fn display_width_handles_emojis() { + use super::*; + let text = "😂"; // There is a single `char`... assert_eq!(text.chars().count(), 1); diff --git a/src/output/textwrap/mod.rs b/src/output/textwrap/mod.rs index c6e831f65cf5..d14d3fe7f16f 100644 --- a/src/output/textwrap/mod.rs +++ b/src/output/textwrap/mod.rs @@ -5,9 +5,12 @@ //! - `LineWrapper` is able to incrementally wrap which will help with `StyledStr pub(crate) mod core; +#[cfg(feature = "wrap_help")] pub(crate) mod word_separators; +#[cfg(feature = "wrap_help")] pub(crate) mod wrap_algorithms; +#[cfg(feature = "wrap_help")] pub(crate) fn wrap(content: &str, hard_width: usize) -> String { let mut wrapper = wrap_algorithms::LineWrapper::new(hard_width); let mut total = Vec::new(); @@ -19,7 +22,13 @@ pub(crate) fn wrap(content: &str, hard_width: usize) -> String { total.join("") } +#[cfg(not(feature = "wrap_help"))] +pub(crate) fn wrap(content: &str, _hard_width: usize) -> String { + content.to_owned() +} + #[cfg(test)] +#[cfg(feature = "wrap_help")] mod test { /// Compatibility shim to keep textwrap's tests fn wrap(content: &str, hard_width: usize) -> Vec { diff --git a/tests/builder/help.rs b/tests/builder/help.rs index 2255b0115a36..1bd8a2868e47 100644 --- a/tests/builder/help.rs +++ b/tests/builder/help.rs @@ -531,6 +531,7 @@ Options: } #[test] +#[cfg(feature = "wrap_help")] fn issue_626_unicode_cutoff() { static ISSUE_626_CUTOFF: &str = "\ Usage: ctest [OPTIONS] @@ -679,6 +680,7 @@ Options: } #[test] +#[cfg(feature = "wrap_help")] fn issue_626_panic() { static ISSUE_626_PANIC: &str = "\ Usage: ctest [OPTIONS] @@ -713,6 +715,7 @@ Options: } #[test] +#[cfg(feature = "wrap_help")] fn issue_626_variable_panic() { for i in 10..320 { let _ = Command::new("ctest") @@ -731,6 +734,7 @@ fn issue_626_variable_panic() { } #[test] +#[cfg(feature = "wrap_help")] fn final_word_wrapping() { static FINAL_WORD_WRAPPING: &str = "\ Usage: ctest @@ -748,7 +752,10 @@ Options: utils::assert_output(cmd, "ctest --help", FINAL_WORD_WRAPPING, false); } -static WRAPPING_NEWLINE_CHARS: &str = "\ +#[test] +#[cfg(feature = "wrap_help")] +fn wrapping_newline_chars() { + static WRAPPING_NEWLINE_CHARS: &str = "\ Usage: ctest [mode] Arguments: @@ -763,8 +770,6 @@ Options: -V, --version Print version information "; -#[test] -fn wrapping_newline_chars() { let cmd = Command::new("ctest") .version("0.1") .term_width(60) @@ -777,7 +782,23 @@ fn wrapping_newline_chars() { } #[test] +#[cfg(feature = "wrap_help")] fn wrapping_newline_variables() { + static WRAPPING_NEWLINE_CHARS: &str = "\ +Usage: ctest [mode] + +Arguments: + [mode] x, max, maximum 20 characters, contains symbols. + l, long Copy-friendly, 14 characters, + contains symbols. + m, med, medium Copy-friendly, 8 characters, + contains symbols. + +Options: + -h, --help Print help information + -V, --version Print version information +"; + let cmd = Command::new("ctest") .version("0.1") .term_width(60) @@ -790,6 +811,7 @@ fn wrapping_newline_variables() { } #[test] +#[cfg(feature = "wrap_help")] fn dont_wrap_urls() { let cmd = Command::new("Example") .term_width(30) @@ -849,6 +871,7 @@ fn old_newline_variables() { } #[test] +#[cfg(feature = "wrap_help")] fn issue_688_hide_pos_vals() { static ISSUE_688: &str = "\ Usage: ctest [OPTIONS] @@ -1147,6 +1170,7 @@ Options: } #[test] +#[cfg(feature = "wrap_help")] fn issue_777_wrap_all_things() { static ISSUE_777: &str = "A cmd with a crazy very long long long name hahaha 1.0 @@ -1423,6 +1447,7 @@ fn hide_default_val() { } #[test] +#[cfg(feature = "wrap_help")] fn escaped_whitespace_values() { static ESCAPED_DEFAULT_VAL: &str = "\ Usage: default [OPTIONS]