Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(help)!: Wrapping is behind wrap_help #4258

Merged
merged 3 commits into from Sep 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 9 additions & 5 deletions CHANGELOG.md
Expand Up @@ -125,9 +125,12 @@ 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. Resolve compiler errors
6. Resolve behavior changes (see "subtle changes" under BREAKING CHANGES)
7. *At your leisure:* resolve new deprecation notices
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

Example test (derive):
```rust
Expand Down Expand Up @@ -155,7 +158,7 @@ fn verify_cli() {
}
```

Note: the idomatic / recommended way of specifying different types of args in the Builder API has changed:
Note: the idiomatic / recommended way of specifying different types of args in the Builder API has changed:

Before
```rust
Expand Down Expand Up @@ -184,10 +187,11 @@ Subtle changes (i.e. compiler won't catch):
- `mut_arg` can no longer be used to customize help and version arguments, instead disable them (`Command::disable_help_flag`, `Command::disable_version_flag`) and provide your own (#4056)
- Removed lifetimes from `Command`, `Arg`, `ArgGroup`, and `PossibleValue`, assuming `'static`. `string` feature flag will enable support for `String`s (#1041, #2150, #4223)
- `arg!(--flag <value>)` is now optional, instead of required. Add `.required(true)` at the end to restore the original behavior (#4206)
- Added default feature flags, `help`, `usage` and `error-context` (#4236)
- Added default feature flags, `help`, `usage` and `error-context`, requiring adding them back in if `default-features = false` (#4236)
- *(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)
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/_features.rs
Expand Up @@ -19,7 +19,7 @@
//! * **env**: Turns on the usage of environment variables during parsing.
//! * **unicode**: Turns on support for unicode characters (including emoji) in arguments and help messages.
//! * **wrap_help**: Turns on the help text wrapping feature, based on the terminal size.
//! * **string**: Allow runtime generated strings
//! * **string**: Allow runtime generated strings (e.g. with [`Str`][crate::builder::Str]).
//!
//! #### Experimental features
//!
Expand Down
3 changes: 3 additions & 0 deletions src/builder/os_str.rs
@@ -1,6 +1,9 @@
use crate::builder::Str;

/// A UTF-8-encoded fixed string
///
/// **NOTE:** To support dynamic values (i.e. `OsString`), enable the [`string`
/// feature][crate::_features]
#[derive(Default, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
pub struct OsStr {
name: Inner,
Expand Down
3 changes: 3 additions & 0 deletions src/builder/str.rs
@@ -1,4 +1,7 @@
/// A UTF-8-encoded fixed string
///
/// **NOTE:** To support dynamic values (i.e. `String`), enable the [`string`
/// feature][crate::_features]
#[derive(Default, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
pub struct Str {
name: Inner,
Expand Down
5 changes: 4 additions & 1 deletion src/builder/styled_str.rs
Expand Up @@ -101,7 +101,10 @@ impl StyledStr {
}
}

#[cfg(feature = "help")]
#[cfg(all(not(feature = "wrap_help"), feature = "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() {
Expand Down
9 changes: 7 additions & 2 deletions src/output/help_template.rs
Expand Up @@ -1020,17 +1020,20 @@ 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");
}

#[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);
Expand All @@ -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);
Expand Down
9 changes: 9 additions & 0 deletions src/output/textwrap/mod.rs
Expand Up @@ -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();
Expand All @@ -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<String> {
Expand Down
31 changes: 28 additions & 3 deletions tests/builder/help.rs
Expand Up @@ -531,6 +531,7 @@ Options:
}

#[test]
#[cfg(feature = "wrap_help")]
fn issue_626_unicode_cutoff() {
static ISSUE_626_CUTOFF: &str = "\
Usage: ctest [OPTIONS]
Expand Down Expand Up @@ -679,6 +680,7 @@ Options:
}

#[test]
#[cfg(feature = "wrap_help")]
fn issue_626_panic() {
static ISSUE_626_PANIC: &str = "\
Usage: ctest [OPTIONS]
Expand Down Expand Up @@ -713,6 +715,7 @@ Options:
}

#[test]
#[cfg(feature = "wrap_help")]
fn issue_626_variable_panic() {
for i in 10..320 {
let _ = Command::new("ctest")
Expand All @@ -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
Expand All @@ -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:
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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]
Expand Down