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

HelpWriter: panic wrapping text containing unicode symbol chars in subcommand help #456

Closed
mroth opened this issue Mar 22, 2016 · 6 comments
Assignees
Labels
A-help Area: documentation, including docs.rs, readme, examples, etc... C-bug Category: Updating dependencies

Comments

@mroth
Copy link

mroth commented Mar 22, 2016

Subcommand help text which contains more complex Unicode characters can cause the help command to panic.

See below for a stacktrace. Adjusting the width of the CLI terminal can cause the problem to occur/not occur consistently based on the current width, so it's likely caused by the wrapping trying to split in the middle of a unicode character codepoint.

I believe this was introduced in 813d75d along with subcommand help text wrapping (which is really awesome otherwise!).

thread '<main>' panicked at 'index 0 and/or 60 in `Display the short emoji representation for your termagotchi™` do not lie on character boundary', ../src/libcore/str/mod.rs:1598
stack backtrace:
   1:        0x10fa3c9e8 - sys::backtrace::tracing::imp::write::h7add7fdda97786a1s4u
   2:        0x10fa3e525 - panicking::default_handler::_$u7b$$u7b$closure$u7d$$u7d$::closure.44030
   3:        0x10fa3e148 - panicking::default_handler::h72a4f6df9637bc80Rvz
   4:        0x10fa33196 - sys_common::unwind::begin_unwind_inner::hf798769ad97c097fe3t
   5:        0x10fa3360e - sys_common::unwind::begin_unwind_fmt::hb2ee19b4aa59ba8ak2t
   6:        0x10fa3bf07 - rust_begin_unwind
   7:        0x10fa60ac0 - panicking::panic_fmt::h9d9cbf48c6ff6310ycM
   8:        0x10fa624f0 - str::slice_error_fail::h97aedef563a2dfabPmT
   9:        0x10f97c373 - str::traits::str.ops..Index<ops..RangeTo<usize>>::index::h1e69d08957082f93sbT
  10:        0x10f8b879f - args::help_writer::find_idx_of_space::he879ddbadecf1e4ffFi
  11:        0x10f90851a - args::help_writer::HelpWriter<'a, A>::help::h2240499278455361512
  12:        0x10f903d6f - args::help_writer::HelpWriter<'a, A>::write_to::h9530559573826397999
  13:        0x10f9037c3 - app::App<'a, 'b>::write_self_help::h8722768814391291797
  14:        0x10f89b097 - app::parser::Parser<'a, 'b>::write_help::h9220252229631760033
  15:        0x10f98456e - app::parser::Parser<'a, 'b>::print_help::h15c368c98a1c10deite
  16:        0x10f930f3f - app::parser::Parser<'a, 'b>::_help::hbdceb0fc7d8f1341bBc
  17:        0x10f90f350 - app::parser::Parser<'a, 'b>::get_matches_with::h2081742809601178753
  18:        0x10f90ce9b - app::App<'a, 'b>::get_matches_from_safe_borrow::h7370758756097233278
  19:        0x10f90ac7f - app::App<'a, 'b>::get_matches_from::h18159698238090864155
  20:        0x10f90ab7d - app::App<'a, 'b>::get_matches::h88cd2dd2f328b008OBf
  21:        0x10f8775a2 - main::h3dfae617a6cf0b5bmaa
  22:        0x10fa3dd52 - sys_common::unwind::try::try_fn::h14432562570411141333
  23:        0x10fa3be9b - __rust_try
  24:        0x10fa3dc10 - rt::lang_start::h34152b86eed7986bXnz
  25:        0x10f8877b9 - main

In general, I'd guess this is likely due to using a byte-based index somewhere instead of a unicode character iterator, but not certain where in the code I would address this.

@kbknapp
Copy link
Member

kbknapp commented Mar 22, 2016

Thanks for filing this! I'll update soon 👍

@kbknapp kbknapp added C-bug Category: Updating dependencies P2: need to have A-help Area: documentation, including docs.rs, readme, examples, etc... labels Mar 22, 2016
@kbknapp
Copy link
Member

kbknapp commented Mar 23, 2016

I've looked into this a little but I'm having trouble re-producing the panic. Do you have a code sample which causes it, and know what your term width is when it panics?

If you'd like, you can compile clap with the "debug" cargo feature which will spit out a ton of output that could be helpful in pinning this down.

[dependencies]
clap = { version = "2.2.1", features = ["debug"]}

@mroth
Copy link
Author

mroth commented Mar 24, 2016

Here is the actual CLI menu I currently have in my code, but with all functionality and imports removed (as you can see, it's from quite a silly project, oh well!).
https://gist.github.com/mroth/646c9b85cf2c3475c00b

This particular configuration generates the panic with a terminal width of 80 chars.

And here is the debug output:

$ cargo run -- --help
     Running `target/debug/termagotchi --help`
**DEBUG** fn=from_usage;
**DEBUG** exec=new; usage="[NAME] \'Optional name to use for your termagotchi\u{2122} (autogenerated otherwise)\'"
**DEBUG** fn=parse;
**DEBUG** iter; pos=0;
**DEBUG** fn=stop_at;
**DEBUG** fn=name;
**DEBUG** fn=stop_at;
**DEBUG** setting name: NAME
**DEBUG** explicit name set...
**DEBUG** iter; pos=5;
**DEBUG** fn=stop_at;
**DEBUG** fn=help;
**DEBUG** fn=stop_at;
**DEBUG** setting help: Optional name to use for your termagotchi™ (autogenerated otherwise)
**DEBUG** iter; pos=79;
**DEBUG** fn=stop_at;
**DEBUG** vals: None
**DEBUG** fn=from_usage;
**DEBUG** exec=new; usage="-f, --force \'Do not prompt before overwriting existing termagotchi\u{2122}\'"
**DEBUG** fn=parse;
**DEBUG** iter; pos=0;
**DEBUG** fn=stop_at;
**DEBUG** fn=short_or_long;
**DEBUG** fn=short;
**DEBUG** setting short: f
**DEBUG** setting name: f
**DEBUG** iter; pos=1;
**DEBUG** fn=stop_at;
**DEBUG** fn=short_or_long;
**DEBUG** fn=long;
**DEBUG** fn=stop_at;
**DEBUG** setting name: force
**DEBUG** setting long: force
**DEBUG** iter; pos=11;
**DEBUG** fn=stop_at;
**DEBUG** fn=help;
**DEBUG** fn=stop_at;
**DEBUG** setting help: Do not prompt before overwriting existing termagotchi™
**DEBUG** iter; pos=70;
**DEBUG** fn=stop_at;
**DEBUG** vals: None
**DEBUG** fn=Parser::add_subcommand;
**DEBUG** Is help...No
**DEBUG** Using Setting VersionlessSubcommands...Yes
**DEBUG** Using Setting GlobalVersion...No
**DEBUG** fn=from_usage;
**DEBUG** exec=new; usage="-f, --force \'Do not prompt before abandoning existing termagotchi\'"
**DEBUG** fn=parse;
**DEBUG** iter; pos=0;
**DEBUG** fn=stop_at;
**DEBUG** fn=short_or_long;
**DEBUG** fn=short;
**DEBUG** setting short: f
**DEBUG** setting name: f
**DEBUG** iter; pos=1;
**DEBUG** fn=stop_at;
**DEBUG** fn=short_or_long;
**DEBUG** fn=long;
**DEBUG** fn=stop_at;
**DEBUG** setting name: force
**DEBUG** setting long: force
**DEBUG** iter; pos=11;
**DEBUG** fn=stop_at;
**DEBUG** fn=help;
**DEBUG** fn=stop_at;
**DEBUG** setting help: Do not prompt before abandoning existing termagotchi
**DEBUG** iter; pos=66;
**DEBUG** fn=stop_at;
**DEBUG** vals: None
**DEBUG** fn=Parser::add_subcommand;
**DEBUG** Is help...No
**DEBUG** Using Setting VersionlessSubcommands...Yes
**DEBUG** Using Setting GlobalVersion...No
**DEBUG** fn=Parser::add_subcommand;
**DEBUG** Is help...No
**DEBUG** Using Setting VersionlessSubcommands...Yes
**DEBUG** Using Setting GlobalVersion...No
**DEBUG** fn=Parser::add_subcommand;
**DEBUG** Is help...No
**DEBUG** Using Setting VersionlessSubcommands...Yes
**DEBUG** Using Setting GlobalVersion...No
**DEBUG** fn=Parser::add_subcommand;
**DEBUG** Is help...No
**DEBUG** Using Setting VersionlessSubcommands...Yes
**DEBUG** Using Setting GlobalVersion...No
**DEBUG** fn=Parser::add_subcommand;
**DEBUG** Is help...No
**DEBUG** Using Setting VersionlessSubcommands...Yes
**DEBUG** Using Setting GlobalVersion...No
**DEBUG** fn=Parser::add_subcommand;
**DEBUG** Is help...No
**DEBUG** Using Setting VersionlessSubcommands...Yes
**DEBUG** Using Setting GlobalVersion...No
**DEBUG** fn=get_matches_with;
**DEBUG** fn=create_help_and_version;
**DEBUG** Building --help
**DEBUG** Building --version
**DEBUG** Building help
**DEBUG** Begin parsing '"--help"' ([45, 45, 104, 101, 108, 112])
**DEBUG** Starts new arg...Yes
**DEBUG** fn=parse_long_arg;
**DEBUG** Does it contain '='...No
**DEBUG** Found valid flag '--help'
**DEBUG** Checking if --help is help or version...**DEBUG** fn=create_usage;
**DEBUG** fn=write_to;
**DEBUG** fn=short;
**DEBUG** fn=long;
**DEBUG** macro=write_spaces!;
**DEBUG** fn=val;
**DEBUG** fn=help;
**DEBUG** fn=spec_vals;
**DEBUG** Writing values
**DEBUG** Term width...80
**DEBUG** Too long...false
**DEBUG** Too long...No
**DEBUG** fn=write_to;
**DEBUG** fn=short;
**DEBUG** fn=long;
**DEBUG** macro=write_spaces!;
**DEBUG** fn=val;
**DEBUG** fn=help;
**DEBUG** fn=spec_vals;
**DEBUG** Writing values
**DEBUG** Term width...80
**DEBUG** Too long...false
**DEBUG** Too long...No
**DEBUG** fn=write_to;
**DEBUG** fn=short;
**DEBUG** fn=long;
**DEBUG** fn=val;
**DEBUG** macro=write_spaces!;
**DEBUG** fn=help;
**DEBUG** fn=spec_vals;
**DEBUG** Writing values
**DEBUG** Term width...80
**DEBUG** Too long...false
**DEBUG** Too long...No
**DEBUG** fn=write_to;
**DEBUG** fn=short;
**DEBUG** fn=long;
**DEBUG** fn=val;
**DEBUG** macro=write_spaces!;
**DEBUG** fn=help;
**DEBUG** fn=spec_vals;
**DEBUG** Writing values
**DEBUG** Term width...80
**DEBUG** Too long...false
**DEBUG** Too long...No
**DEBUG** fn=write_to;
**DEBUG** fn=short;
**DEBUG** fn=long;
**DEBUG** fn=val;
**DEBUG** macro=write_spaces!;
**DEBUG** fn=help;
**DEBUG** fn=spec_vals;
**DEBUG** Writing values
**DEBUG** Term width...80
**DEBUG** Too long...false
**DEBUG** Too long...No
**DEBUG** fn=write_to;
**DEBUG** fn=short;
**DEBUG** fn=long;
**DEBUG** fn=val;
**DEBUG** macro=write_spaces!;
**DEBUG** fn=help;
**DEBUG** fn=spec_vals;
**DEBUG** Writing values
**DEBUG** Term width...80
**DEBUG** Too long...false
**DEBUG** Too long...No
**DEBUG** fn=write_to;
**DEBUG** fn=short;
**DEBUG** fn=long;
**DEBUG** fn=val;
**DEBUG** macro=write_spaces!;
**DEBUG** fn=help;
**DEBUG** fn=spec_vals;
**DEBUG** Writing values
**DEBUG** Term width...80
**DEBUG** Too long...true
**DEBUG** Too long...Yes
**DEBUG** help: Prints this message or the help message of the given subcommand(s)
**DEBUG** help len: 66
**DEBUG** Usable space: 61
**DEBUG** Longest word...13
**DEBUG** Enough space...Yes
**DEBUG** fn=find_idx_of_space;
**DEBUG** haystack: Prints this message or the help message of the given subcomm
**DEBUG** iter;c=m,i=0
**DEBUG** iter;c=m,i=1
**DEBUG** iter;c=o,i=2
**DEBUG** iter;c=c,i=3
**DEBUG** iter;c=b,i=4
**DEBUG** iter;c=u,i=5
**DEBUG** iter;c=s,i=6
**DEBUG** iter;c= ,i=7
**DEBUG** Found space returning start-i...52
**DEBUG** Adding idx: 52
**DEBUG** At 52: Some(' ')
**DEBUG** iter;i=0,idx=52
**DEBUG** removing: 52
**DEBUG** at 52: Some(' ')
**DEBUG** macro=write_spaces!;
**DEBUG** fn=write_to;
**DEBUG** fn=short;
**DEBUG** fn=long;
**DEBUG** fn=val;
**DEBUG** macro=write_spaces!;
**DEBUG** fn=help;
**DEBUG** fn=spec_vals;
**DEBUG** Writing values
**DEBUG** Term width...80
**DEBUG** Too long...false
**DEBUG** Too long...No
**DEBUG** fn=write_to;
**DEBUG** fn=short;
**DEBUG** fn=long;
**DEBUG** fn=val;
**DEBUG** macro=write_spaces!;
**DEBUG** fn=help;
**DEBUG** fn=spec_vals;
**DEBUG** Writing values
**DEBUG** Term width...80
**DEBUG** Too long...true
**DEBUG** Too long...Yes
**DEBUG** help: Display the short emoji representation for your termagotchi™
**DEBUG** help len: 62
**DEBUG** Usable space: 61
**DEBUG** Longest word...14
**DEBUG** Enough space...Yes
**DEBUG** fn=find_idx_of_space;
thread '<main>' panicked at 'index 0 and/or 60 in `Display the short emoji representation for your termagotchi™` do not lie on character boundary', ../src/libcore/str/mod.rs:1598
note: Run with `RUST_BACKTRACE=1` for a backtrace.
termagotchi 0.1.0
A virtual terminal pet.

USAGE:
    termagotchi [FLAGS] [SUBCOMMAND]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    abandon    Abandons your existing termagotchi™!
    adopt      Adopt a new termagotchi™ 🐣
    clean      Clean up any poops 💩
    feed       Feed your termagotchi™ 🍼
    help       Prints this message or the help message of the given
               subcommand(s)
    play       Play with your termagotchi™
    prompt     Process didn't exit successfully: `target/debug/termagotchi --help` (exit code: 101)

@kbknapp
Copy link
Member

kbknapp commented Mar 26, 2016

Ah ok, thanks! Let me test this out with some solutions over the next few days and I should have this solved pretty quick.

@kbknapp kbknapp self-assigned this Mar 27, 2016
@kbknapp
Copy link
Member

kbknapp commented Mar 27, 2016

v2.2.2 on crates.io should have this fixed!

@mroth
Copy link
Author

mroth commented Mar 27, 2016

Can confirm this appears to have fixed for me as well! 👍

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-bug Category: Updating dependencies
Projects
None yet
Development

No branches or pull requests

2 participants