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

error messages should textwrap like --help #4716

Open
2 tasks done
cbs228 opened this issue Feb 18, 2023 · 7 comments
Open
2 tasks done

error messages should textwrap like --help #4716

cbs228 opened this issue Feb 18, 2023 · 7 comments
Labels
A-help Area: documentation, including docs.rs, readme, examples, etc... C-enhancement Category: Raise on the bar on expectations S-waiting-on-decision Status: Waiting on a go/no-go before implementing

Comments

@cbs228
Copy link

cbs228 commented Feb 18, 2023

Please complete the following tasks

Clap Version

4.1.6

Describe your use case

I am attempting to use clap::Command::error() to harmonize my crate's startup error messages. In addition to normal argument-parsing errors, I also use clap to report "can't open file XXXX" and similar types of startup errors. This permits them to be printed with the red error: prefix provided by the color feature.

When built with the wrap_help feature, the output of --help is automatically wrapped to the terminal size (or to max_term_width). I would expect this text-wrapping to also be applied to errors, but it is not.

Describe the solution you'd like

The following minimal example reproduces one of my crate's error messages:

extern crate clap;

use clap::Command;

const ERR : &str = "cowardly refusing to read audio samples from a terminal.\n\nPipe a source of raw uncompressed audio from sox, parec, rtl_fm, or similar into this program.";

fn main() {
    Command::new("test")
        .max_term_width(91)
        .error(clap::error::ErrorKind::Io, ERR)
        .exit();
}

Playground link

On my terminal, which is 91-characters wide, this renders as:

error: cowardly refusing to read audio samples from a terminal.

Pipe a source of raw uncompressed audio from sox, parec, rtl_fm, or similar into this progr
am.

The naive line-wrapping of my terminal emulator splits a word, making it hard to read.

The output could be improved by applying the logic already used to wrap --help text to error messages as well. Then the output would wrap neatly at word boundaries, like this:

error: cowardly refusing to read audio samples from a terminal.

Pipe a source of raw uncompressed audio from sox, parec, rtl_fm, or similar into this
program.

Alternatives, if applicable

The wrapping behavior could be implemented in a custom ErrorFormatter. As far as I know, the logic for detecting terminal presence, terminal width, and for performing text wrapping appears to be internal to clap. Re-implementing this logic in the client crate would probably result in several more direct dependencies (like atty).

Additional Context

Rust has excellent error-handling and error tracing. When it comes to actually reporting the error to the CLI user, however, crates and their authors are mostly left to their own devices. I welcome other alternatives for performing this operation in a systematic, abstracted way.

EDIT: made example more concrete based on feedback in discussion.

@cbs228 cbs228 added the C-enhancement Category: Raise on the bar on expectations label Feb 18, 2023
@epage
Copy link
Member

epage commented Feb 19, 2023

Huh, doesn't look like this has come up before. I suspect its because most people are relying on the terminal width and just using wrapping for clean indentation for argument descriptions or if they care about max_term_width, their errors just aren't hitting that enough to notice.

How much of your example is artificaly (e.g. the text is)? Like, is that width artificial? What I'm interested in is ascertaining the impact of this problem. What would be helpful to know is what you are setting the term width to, why you are setting it to that, and what your errors look like with and without it.

@epage epage added S-waiting-on-decision Status: Waiting on a go/no-go before implementing A-help Area: documentation, including docs.rs, readme, examples, etc... labels Feb 19, 2023
@cbs228
Copy link
Author

cbs228 commented Feb 19, 2023

Like, is that width artificial?

Yes, the width in the example is artificial. It is merely to demonstrate on Playground that --help is wrapped but that errors are not. In reality, I would probably use a max_term_width of 100 or so.

The example output stderr is

error: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam pellentesque vehicula purus at lobortis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In porta facilisis commodo. Etiam consectetur dui vitae varius finibus. Nunc a urna urna. Nullam a porta tellus. Nulla eu ipsum vitae felis ornare pretium. Sed ornare, sem ac tempus vestibulum, est turpis congue lectus, nec vulputate est ipsum vitae ante.

Terminals will of course dutifully wrap long lines, but the wrapping is dumb and can split words.

The above example might be "better" as

error: Lorem ipsum dolor sit amet, 
consectetur adipiscing elit. Nullam 
pellentesque vehicula purus at 
lobortis. Class aptent taciti sociosqu 
ad litora torquent per conubia nostra, 
per inceptos himenaeos. In porta 
facilisis commodo. Etiam consectetur 
dui vitae varius finibus. Nunc a urna 
urna. Nullam a porta tellus. Nulla eu 
ipsum vitae felis ornare pretium. Sed 
ornare, sem ac tempus vestibulum, est 
turpis congue lectus, nec vulputate est 
ipsum vitae ante.

Here "better" is error text which is wrapped to the terminal width or the max_term_width.

Most error messages won't be long enough to need wrapping on reasonably-sized terminals (i.e., wider than half a punch-card). I'm not sure that any of clap's built-in errors get that long. In my actual use-case, my error message gets a bit long-winded because it provides advice on how to correct the error condition.

@epage
Copy link
Member

epage commented Feb 19, 2023

Lorem ipsum

FYI I'm looking for more concrete use cases. I brought up the artifical 40 but using lorem ipsum also keeps this conversation less concrete.

my error message gets a bit long-winded because it provides advice on how to correct the error condition.

Is there a reason you are putting the advice in the same paragraph? Seems like that would be best to split out. You also could format the error according to some only-documented-in-code rules and use clap's advice formatting.

Also, this is why I am looking for concrete examples, so we can look at the problem holistically and not just one narrow angle of it.

@cbs228
Copy link
Author

cbs228 commented Feb 19, 2023

Is there a reason you are putting the advice in the same paragraph?

It is split out into its own paragraph, but terminals do not break long lines of text neatly. The actual error message I am printing is:

const ERR : &str = "error: cowardly refusing to read audio samples from a terminal.\n\nPipe a source of raw uncompressed audio from sox, parec, rtl_fm, or similar into this program.";

The second line is 94 characters wide. My terminal's current width is 91 characters, which leads to ugly output:

Pipe a source of raw uncompressed audio from sox, parec, rtl_fm, or similar into this progr
am.

You also could format the error according to some only-documented-in-code rules

Can you point me in the right direction for these rules?

@epage
Copy link
Member

epage commented Feb 23, 2023

It is split out into its own paragraph, but terminals do not break long lines of text neatly. The actual error message I am printing is:

Thanks for the example!

Can you point me in the right direction for these rules?

Check out the source for RichFormatter as it reads the Error data structure and formats the text.

@cbs228
Copy link
Author

cbs228 commented Feb 25, 2023

I've seen the RichFormatter, but the existing functions for wrapping text are pub(crate). There doesn't appear to be any way to get at them or to express the "this should be wrapped" intent.

I could write a custom formatter which performs its own terminal queries and wrapping, without clap… but at that point it would probably be more efficient to not involve clap in my error-printing process at all.

@epage
Copy link
Member

epage commented Feb 26, 2023

StyledStr::wrap will remain private for now as we continue to work out what the StyledStr API will be. I've started back on improving StyledStr, so hopefully in the next couple of months we;'ll have a better idea of where it is at.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-help Area: documentation, including docs.rs, readme, examples, etc... C-enhancement Category: Raise on the bar on expectations S-waiting-on-decision Status: Waiting on a go/no-go before implementing
Projects
None yet
Development

No branches or pull requests

2 participants