Reformulate wrapping in terms of words with whitespace and penalties #221
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This is a complete rewrite of the core word wrapping functionality. The user-visible change is that
wrap
now returns aVec<Cow<'_, str>>
instead ofimpl Iterator<Item = Cow<'_, str>>
. In other words, you now get all lines returned to you at once instead of getting an iterator back. Code that simply iterated over the old return value simply need to add.iter()
, code that already collected the lines into a vector can now do away with this code. I looked around GitHub for code that usestextwrap
and most code simply calls
fill
orwrap
. An example is theclap
crate.New algorithm: Before, we would step though the input string and (attempt to) keep track of all aspects of the state. This didn't always work (see at least #122, #158, #158, and #193) and it's inflexible.
This commit replaces the old algorithm with a new one which works on a more abstract level. We now first
First split the input string into "words". A word is a substring of the original string, including any trailing whitespace.
We split each word according to the
WordSplitter
.Optional, if
break_words
istrue
: further spit each word so that it is no longer than the line width.We then simply put the words into lines based on the display width.
This is slower than the previous algorithm. The
fill/1600
benchmark shows that is now takes ~19 microseconds to wrap a 1600 character long string (about 20 lines of terminal text). That is ~8 microseconds longer than before. I think this is still plenty fast, and the new structure makes it easier to reason about the logic.This is a step towards #126: the
wrap_fragments
function could now in principle be used to wrap any kind of opaque "box", and this box could carry formatting information as needed. We can work on abstracting more functionality going forward, probably by making theFragment
trait more powerful, e.g., by moving thebreak_apart
method fromWord
toFragment
.