-
-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Use my textwrap crate for wrapping help texts #845
Conversation
Thanks for taking the time to do this, but I do have a few questions/concerns before this is merged:
To be clear, I'm not saying this unmergable, just we need to ensure all the bases are covered first 😄 |
Hi Kevin, thanks for the comments!
I'm very new to Rust so I didn't make any conscious choice about not supporting that version :-) Looking at this a bit indicates that it's the I've tested with
It probably isn't listed very clearly... :-) It is very simple currently: it splits the string on whitespace and proceeds to add each word into lines, one by one. So
is treated just like From your example, I think you might be talking about an initial/subsequent indentation, though -- the string of whitespace on the second to last line? That kind of formatting is not supported yet, but I would like to have it: mgeisler/textwrap#26. It doesn't seem to be necessary, though, since I'm just replacing the |
Because all whitespace (including tabs, newlines, etc) is treated as a single space, #617 will reintroduced if this PR were to be merged -- as mentioned, I added a test for the issue and the test passes before and fails after this PR. |
Ah ok, I understand now, I was under the impression
Perhaps. I have mixed feelings on hyphenation, it's subjective but I find it harder to read when not required. A good use for it, IMO would be when the terminal size is small, or there isn't much room for wrapping on whole word boundaries. I would be good with hyphenation happening in those cases, but I think enabling it wholesale would be a bit much. Also, if hyphenation isn't enabled, it'd nice to be able opt-out of pulling in related deps that aren't used. I don't know if this can be done in
I would like to maintain this abiltiy, so it'll be a blocker until One last thing I forgot ask beforehand, does |
Once this PR reaches a mergable state I'd like to do some comparison benchmarks too for reference |
Yeah, that makes a lot of sense! The user would have to tell clap which hyphenation patterns to use in any case, so I don't think it should be enabled unconditionally.
Nope, there's no support for this at the moment -- but I think you're right that it would make sense to add such a feature flag. The hyphenation dependency is rather large and pulls in many other dependencies.
Very well, I have some ideas for how this could be supported -- I'll let you know when it's there. Feel free to close/park the PR until then.
Yes, it should handle that fine -- mostly due to how it simply iterates over words from I saw that there is a The next version of |
☔ The latest upstream changes (presumably #867) made this pull request unmergeable. Please resolve the merge conflicts. |
I've fixed mgeisler/textwrap#36, so one can now use textwrap without the automatic hyphenation. I'll see about the indentation issue next and then resolve the merge conflicts here. |
3ff065d
to
2478090
Compare
Hi @kbknapp, I've finally updated this PR :-) With the newly released version 0.6.0 of textwrap, whitespace is new kept by default. This means the output in #617 is preserved. I've also added a benchmark which shows that the new code is faster -- generating the large and complicated help text for In my Travis, I have tested textwrap back to Rust 1.8.0 and it works there when the optional I've updated the PR description above to match the new state. I took out the old cleanup commits from this PR -- I hope to submit them afterwards if this gets merged. Please let me know if there's anything missing! |
I see a failed job in Travis -- the job that tests with Rust 1.11.0. I believe that is because of I think that build failure is unrelated to my change :-) The |
…r=kbknapp cargo: restrict unicode-segmentation to ~1.1.0 Version 1.2.0 of unicode-segmentation adds code that use the "?" operator, which in turn requires Rust 1.13.0. However, clap currently still works with Rust 1.11.0 and this caused build failures: https://travis-ci.org/kbknapp/clap-rs/jobs/235010822 The changes since 1.1.0 seem to be related cursors/iterators and I think clap can work fine without them. This was found as part of #845. See also unicode-rs/unicode-segmentation#26. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/kbknapp/clap-rs/967) <!-- Reviewable:end -->
☔ The latest upstream changes (presumably dd4c41e) made this pull request unmergeable. Please resolve the merge conflicts. |
The ripgrep benchmarks work with lots of options and have really long help texts. This makes them a good fit for judging the overall time it takes to construct and format the help text.
This adds a test for the issue clap-rs#617 about keeping whitespace intact in manually aligned text.
The textwrap crate uses a simpler linear-time algorithm for wrapping the text. The current algorithm in wrap_help uses several O(n) calls to String::insert and String::remove, which makes it potentially quadratic in complexity. Comparing the 05_ripgrep benchmark at commits textwrap~2 and textwrap gives this result on my machine: name before ns/iter after ns/iter diff ns/iter diff % build_app_long 22,101 21,099 -1,002 -4.53% build_app_short 22,138 21,205 -933 -4.21% build_help_long 514,265 284,467 -229,798 -44.68% build_help_short 85,720 85,693 -27 -0.03% parse_clean 23,471 22,859 -612 -2.61% parse_complex 29,535 28,919 -616 -2.09% parse_lots 422,815 414,577 -8,238 -1.95% As part of this commit, the wrapping_newline_chars test was updated. The old algorithm had a subtle bug where it would break lines too early. That is, it wrapped the text like ARGS: <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."; when it should really have wrapped it like ARGS: <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."; Notice how the word "14" was incorrectly moved to the next line. There is clearly room for the word on the line with the "l, long" option since there is room for "contains" just above it. I'm not sure why this is, but the algorithm in textwrap handles this case correctly.
Changes Unknown when pulling 12282e1 on mgeisler:textwrap into ** on kbknapp:master**. |
Yay, with the unicode-segmentation version fixed, the build passed. |
Nice! Thanks for sticking with this and putting in all the work 😄 ❤️ @homu r+ |
📌 Commit 12282e1 has been approved by |
Use my textwrap crate for wrapping help texts This PR replaces the `wrap_help` function with a call to my [textwrap][1] crate which does word wrapping using a simpler and faster algorithm. I've extended the `05_ripgrep` benchmarks with a benchmark that tests generating the help text -- I figured that ripgrep would be a good example since it has lots of long strings in the help output. Comparing before and after looks like this on my machine: ``` name before ns/iter after ns/iter diff ns/iter diff % speedup build_app_long 22,101 21,099 -1,002 -4.53% x 1.05 build_app_short 22,138 21,205 -933 -4.21% x 1.04 build_help_long 514,265 284,467 -229,798 -44.68% x 1.81 build_help_short 85,720 85,693 -27 -0.03% x 1.00 parse_clean 23,471 22,859 -612 -2.61% x 1.03 parse_complex 29,535 28,919 -616 -2.09% x 1.02 parse_lots 422,815 414,577 -8,238 -1.95% x 1.02 ``` I've also added a test for #617 to ensure that the output described there is kept unchanged. That is, textwrap will now by default keep horizontal whitespace when wrapping text and this allows you to do rudimentary formatting in the help text by manually inserting whitespace. [1]: https://crates.io/crates/textwrap <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/kbknapp/clap-rs/845) <!-- Reviewable:end -->
My pleasure, it's been a great learning experience! |
This PR replaces the
wrap_help
function with a call to my textwrap crate which does word wrapping using a simpler and faster algorithm. I've extended the05_ripgrep
benchmarks with a benchmark that tests generating the help text -- I figured that ripgrep would be a good example since it has lots of long strings in the help output. Comparing before and after looks like this on my machine:I've also added a test for #617 to ensure that the output described there is kept unchanged. That is, textwrap will now by default keep horizontal whitespace when wrapping text and this allows you to do rudimentary formatting in the help text by manually inserting whitespace.
This change is