1# Changelog 2 3This file lists the most important changes made in each release of 4`textwrap`. 5 6## Version 0.15.0 (2022-02-27) 7 8This is a major feature release with two main changes: 9 10* [#421](https://github.com/mgeisler/textwrap/pull/421): Use `f64` 11 instead of `usize` for fragment widths. 12 13 This fixes problems with overflows in the internal computations of 14 `wrap_optimal_fit` when fragments (words) or line lenghts had 15 extreme values, such as `usize::MAX`. 16 17* [#438](https://github.com/mgeisler/textwrap/pull/438): Simplify 18 `Options` by removing generic type parameters. 19 20 This change removes the new generic parameters introduced in version 21 0.14, as well as the original `WrapSplitter` parameter which has 22 been present since very early versions. 23 24 The result is a simplification of function and struct signatures 25 across the board. So what used to be 26 27 ```rust 28 let options: Options< 29 wrap_algorithms::FirstFit, 30 word_separators::AsciiSpace, 31 word_splitters::HyphenSplitter, 32 > = Options::new(80); 33 ``` 34 35 if types are fully written out, is now simply 36 37 ```rust 38 let options: Options<'_> = Options::new(80); 39 ``` 40 41 The anonymous lifetime represent the lifetime of the 42 `initial_indent` and `subsequent_indent` strings. The change is 43 nearly performance neutral (a 1-2% regression). 44 45Smaller improvements and changes: 46 47* [#404](https://github.com/mgeisler/textwrap/pull/404): Make 48 documentation for short last-line penalty more precise. 49* [#405](https://github.com/mgeisler/textwrap/pull/405): Cleanup and 50 simplify `Options` docstring. 51* [#411](https://github.com/mgeisler/textwrap/pull/411): Default to 52 `OptimalFit` in interactive example. 53* [#415](https://github.com/mgeisler/textwrap/pull/415): Add demo 54 program to help compute binary sizes. 55* [#423](https://github.com/mgeisler/textwrap/pull/423): Add fuzz 56 tests with fully arbitrary fragments. 57* [#424](https://github.com/mgeisler/textwrap/pull/424): Change 58 `wrap_optimal_fit` penalties to non-negative numbers. 59* [#430](https://github.com/mgeisler/textwrap/pull/430): Add 60 `debug-words` example. 61* [#432](https://github.com/mgeisler/textwrap/pull/432): Use precise 62 dependency versions in Cargo.toml. 63 64## Version 0.14.2 (2021-06-27) 65 66The 0.14.1 release included more changes than intended and has been 67yanked. The change intended for 0.14.1 is now included in 0.14.2. 68 69## Version 0.14.1 (2021-06-26) 70 71This release fixes a panic reported by @Makoto, thanks! 72 73* [#391](https://github.com/mgeisler/textwrap/pull/391): Fix panic in 74 `find_words` due to string access outside of a character boundary. 75 76## Version 0.14.0 (2021-06-05) 77 78This is a major feature release which makes Textwrap more configurable 79and flexible. The high-level API of `textwrap::wrap` and 80`textwrap::fill` remains unchanged, but low-level structs have moved 81around. 82 83The biggest change is the introduction of new generic type parameters 84to the `Options` struct. These parameters lets you statically 85configure the wrapping algorithm, the word separator, and the word 86splitter. If you previously spelled out the full type for `Options`, 87you now need to take the extra type parameters into account. This 88means that 89 90```rust 91let options: Options<HyphenSplitter> = Options::new(80); 92``` 93 94changes to 95 96```rust 97let options: Options< 98 wrap_algorithms::FirstFit, 99 word_separators::AsciiSpace, 100 word_splitters::HyphenSplitter, 101> = Options::new(80); 102``` 103 104This is quite a mouthful, so we suggest using type inferrence where 105possible. You won’t see any chance if you call `wrap` directly with a 106width or with an `Options` value constructed on the fly. Please open 107an issue if this causes problems for you! 108 109### New `WordSeparator` Trait 110 111* [#332](https://github.com/mgeisler/textwrap/pull/332): Add 112 `WordSeparator` trait to allow customizing how words are found in a 113 line of text. Until now, Textwrap would always assume that words are 114 separated by ASCII space characters. You can now customize this as 115 needed. 116 117* [#313](https://github.com/mgeisler/textwrap/pull/313): Add support 118 for using the Unicode line breaking algorithm to find words. This is 119 done by adding a second implementation of the new `WordSeparator` 120 trait. The implementation uses the unicode-linebreak crate, which is 121 a new optional dependency. 122 123 With this, Textwrap can be used with East-Asian languages such as 124 Chinese or Japanese where there are no spaces between words. 125 Breaking a long sequence of emojis is another example where line 126 breaks might be wanted even if there are no whitespace to be found. 127 Feedback would be appreciated for this feature. 128 129 130### Indent 131 132* [#353](https://github.com/mgeisler/textwrap/pull/353): Trim trailing 133 whitespace from `prefix` in `indent`. 134 135 Before, empty lines would get no prefix added. Now, empty lines have 136 a trimmed prefix added. This little trick makes `indent` much more 137 useful since you can now safely indent with `"# "` without creating 138 trailing whitespace in the output due to the trailing whitespace in 139 your prefix. 140 141* [#354](https://github.com/mgeisler/textwrap/pull/354): Make `indent` 142 about 20% faster by preallocating the output string. 143 144 145### Documentation 146 147* [#308](https://github.com/mgeisler/textwrap/pull/308): Document 148 handling of leading and trailing whitespace when wrapping text. 149 150### WebAssembly Demo 151 152* [#310](https://github.com/mgeisler/textwrap/pull/310): Thanks to 153 WebAssembly, you can now try out Textwrap directly in your browser. 154 Please try it out: https://mgeisler.github.io/textwrap/. 155 156### New Generic Parameters 157 158* [#331](https://github.com/mgeisler/textwrap/pull/331): Remove outer 159 boxing from `Options`. 160 161* [#357](https://github.com/mgeisler/textwrap/pull/357): Replace 162 `core::WrapAlgorithm` enum with a `wrap_algorithms::WrapAlgorithm` 163 trait. This allows for arbitrary wrapping algorithms to be plugged 164 into the library. 165 166* [#358](https://github.com/mgeisler/textwrap/pull/358): Switch 167 wrapping functions to use a slice for `line_widths`. 168 169* [#368](https://github.com/mgeisler/textwrap/pull/368): Move 170 `WordSeparator` and `WordSplitter` traits to separate modules. 171 Before, Textwrap had several top-level structs such as 172 `NoHyphenation` and `HyphenSplitter`. These implementations of 173 `WordSplitter` now lives in a dedicated `word_splitters` module. 174 Similarly, we have a new `word_separators` module for 175 implementations of `WordSeparator`. 176 177* [#369](https://github.com/mgeisler/textwrap/pull/369): Rename 178 `Options::splitter` to `Options::word_splitter` for consistency with 179 the other fields backed by traits. 180 181## Version 0.13.4 (2021-02-23) 182 183This release removes `println!` statements which was left behind in 184`unfill` by mistake. 185 186* [#296](https://github.com/mgeisler/textwrap/pull/296): Improve house 187 building example with more comments. 188* [#297](https://github.com/mgeisler/textwrap/pull/297): Remove debug 189 prints in the new `unfill` function. 190 191## Version 0.13.3 (2021-02-20) 192 193This release contains a bugfix for `indent` and improved handling of 194emojis. We’ve also added a new function for formatting text in columns 195and functions for reformatting already wrapped text. 196 197* [#276](https://github.com/mgeisler/textwrap/pull/276): Extend 198 `core::display_width` to handle emojis when the unicode-width Cargo 199 feature is disabled. 200* [#279](https://github.com/mgeisler/textwrap/pull/279): Make `indent` 201 preserve existing newlines in the input string. Before, 202 `indent("foo", "")` would return `"foo\n"` by mistake. It now 203 returns `"foo"` instead. 204* [#281](https://github.com/mgeisler/textwrap/pull/281): Ensure all 205 `Options` fields have examples. 206* [#282](https://github.com/mgeisler/textwrap/pull/282): Add a 207 `wrap_columns` function. 208* [#294](https://github.com/mgeisler/textwrap/pull/294): Add new 209 `unfill` and `refill` functions. 210 211## Version 0.13.2 (2020-12-30) 212 213This release primarily makes all dependencies optional. This makes it 214possible to slim down textwrap as needed. 215 216* [#254](https://github.com/mgeisler/textwrap/pull/254): `impl 217 WordSplitter` for `Box<T> where T: WordSplitter`. 218* [#255](https://github.com/mgeisler/textwrap/pull/255): Use command 219 line arguments as initial text in interactive example. 220* [#256](https://github.com/mgeisler/textwrap/pull/256): Introduce 221 fuzz tests for `wrap_optimal_fit` and `wrap_first_fit`. 222* [#260](https://github.com/mgeisler/textwrap/pull/260): Make the 223 unicode-width dependency optional. 224* [#261](https://github.com/mgeisler/textwrap/pull/261): Make the 225 smawk dependency optional. 226 227## Version 0.13.1 (2020-12-10) 228 229This is a bugfix release which fixes a regression in 0.13.0. The bug 230meant that colored text was wrapped incorrectly. 231 232* [#245](https://github.com/mgeisler/textwrap/pull/245): Support 233 deleting a word with Ctrl-Backspace in the interactive demo. 234* [#246](https://github.com/mgeisler/textwrap/pull/246): Show build 235 type (debug/release) in interactive demo. 236* [#249](https://github.com/mgeisler/textwrap/pull/249): Correctly 237 compute width while skipping over ANSI escape sequences. 238 239## Version 0.13.0 (2020-12-05) 240 241This is a major release which rewrites the core logic, adds many new 242features, and fixes a couple of bugs. Most programs which use 243`textwrap` stays the same, incompatibilities and upgrade notes are 244given below. 245 246Clone the repository and run the following to explore the new features 247in an interactive demo (Linux only): 248 249```sh 250$ cargo run --example interactive --all-features 251``` 252 253### Bug Fixes 254 255#### Rewritten core wrapping algorithm 256 257* [#221](https://github.com/mgeisler/textwrap/pull/221): Reformulate 258 wrapping in terms of words with whitespace and penalties. 259 260The core wrapping algorithm has been completely rewritten. This fixed 261bugs and simplified the code, while also making it possible to use 262`textwrap` outside the context of the terminal. 263 264As part of this, trailing whitespace is now discarded consistently 265from wrapped lines. Before we would inconsistently remove whitespace 266at the end of wrapped lines, except for the last. Leading whitespace 267is still preserved. 268 269### New Features 270 271#### Optimal-fit wrapping 272 273* [#234](https://github.com/mgeisler/textwrap/pull/234): Introduce 274 wrapping using an optimal-fit algorithm. 275 276This release adds support for new wrapping algorithm which finds a 277globally optimal set of line breaks, taking certain penalties into 278account. As an example, the old algorithm would produce 279 280 "To be, or" 281 "not to be:" 282 "that is" 283 "the" 284 "question" 285 286Notice how the fourth line with “the” is very short. The new algorithm 287shortens the previous lines slightly to produce fewer short lines: 288 289 "To be," 290 "or not to" 291 "be: that" 292 "is the" 293 "question" 294 295Use the new `textwrap::core::WrapAlgorithm` enum to select between the 296new and old algorithm. By default, the new algorithm is used. 297 298The optimal-fit algorithm is inspired by the line breaking algorithm 299used in TeX, described in the 1981 article [_Breaking Paragraphs into 300Lines_](http://www.eprg.org/G53DOC/pdfs/knuth-plass-breaking.pdf) by 301Knuth and Plass. 302 303#### In-place wrapping 304 305* [#226](https://github.com/mgeisler/textwrap/pull/226): Add a 306 `fill_inplace` function. 307 308When the text you want to fill is already a temporary `String`, you 309can now mutate it in-place with `fill_inplace`: 310 311```rust 312let mut greeting = format!("Greetings {}, welcome to the game! You have {} lives left.", 313 player.name, player.lives); 314fill_inplace(&mut greeting, line_width); 315``` 316 317This is faster than calling `fill` and it will reuse the memory 318already allocated for the string. 319 320### Changed Features 321 322#### `Wrapper` is replaced with `Options` 323 324* [#213](https://github.com/mgeisler/textwrap/pull/213): Simplify API 325 with only top-level functions. 326* [#215](https://github.com/mgeisler/textwrap/pull/215): Reintroducing 327 the type parameter on `Options` (previously known as `Wrapper`). 328* [#219](https://github.com/mgeisler/textwrap/pull/219): Allow using 329 trait objects with `fill` & `wrap`. 330* [#227](https://github.com/mgeisler/textwrap/pull/227): Replace 331 `WrapOptions` with `Into<Options>`. 332 333The `Wrapper` struct held the options (line width, indentation, etc) 334for wrapping text. It was also the entry point for actually wrapping 335the text via its methods such as `wrap`, `wrap_iter`, 336`into_wrap_iter`, and `fill` methods. 337 338The struct has been replaced by a simpler `Options` struct which only 339holds options. The `Wrapper` methods are gone, their job has been 340taken over by the top-level `wrap` and `fill` functions. The signature 341of these functions have changed from 342 343```rust 344fn fill(s: &str, width: usize) -> String; 345 346fn wrap(s: &str, width: usize) -> Vec<Cow<'_, str>>; 347``` 348 349to the more general 350 351```rust 352fn fill<'a, S, Opt>(text: &str, options: Opt) -> String 353where 354 S: WordSplitter, 355 Opt: Into<Options<'a, S>>; 356 357fn wrap<'a, S, Opt>(text: &str, options: Opt) -> Vec<Cow<'_, str>> 358where 359 S: WordSplitter, 360 Opt: Into<Options<'a, S>>; 361``` 362 363The `Into<Options<'a, S>` bound allows you to pass an `usize` (which 364is interpreted as the line width) *and* a full `Options` object. This 365allows the new functions to work like the old, plus you can now fully 366customize the behavior of the wrapping via `Options` when needed. 367 368Code that call `textwrap::wrap` or `textwrap::fill` can remain 369unchanged. Code that calls into `Wrapper::wrap` or `Wrapper::fill` 370will need to be update. This is a mechanical change, please see 371[#213](https://github.com/mgeisler/textwrap/pull/213) for examples. 372 373Thanks to @CryptJar and @Koxiat for their support in the PRs above! 374 375### Removed Features 376 377* The `wrap_iter` and `into_wrap_iter` methods are gone. This means 378 that lazy iteration is no longer supported: you always get all 379 wrapped lines back as a `Vec`. This was done to simplify the code 380 and to support the optimal-fit algorithm. 381 382 The first-fit algorithm could still be implemented in an incremental 383 fashion. Please let us know if this is important to you. 384 385### Other Changes 386 387* [#206](https://github.com/mgeisler/textwrap/pull/206): Change 388 `Wrapper.splitter` from `T: WordSplitter` to `Box<dyn 389 WordSplitter>`. 390* [#216](https://github.com/mgeisler/textwrap/pull/216): Forbid the 391 use of unsafe code. 392 393## Version 0.12.1 (2020-07-03) 394 395This is a bugfix release. 396 397* Fixed [#176][issue-176]: Mention compile-time wrapping by linking to 398 the [`textwrap-macros` crate]. 399* Fixed [#193][issue-193]: Wrapping with `break_words(false)` was 400 broken and would cause extra whitespace to be inserted when words 401 were longer than the line width. 402 403## Version 0.12.0 (2020-06-26) 404 405The code has been updated to the [Rust 2018 edition][rust-2018] and 406each new release of `textwrap` will only support the latest stable 407version of Rust. Trying to support older Rust versions is a fool's 408errand: our dependencies keep releasing new patch versions that 409require newer and newer versions of Rust. 410 411The `term_size` feature has been replaced by `terminal_size`. The API 412is unchanged, it is just the name of the Cargo feature that changed. 413 414The `hyphenation` feature now only embeds the hyphenation patterns for 415US-English. This slims down the dependency. 416 417* Fixed [#140][issue-140]: Ignore ANSI escape sequences. 418* Fixed [#158][issue-158]: Unintended wrapping when using external splitter. 419* Fixed [#177][issue-177]: Update examples to the 2018 edition. 420 421## Version 0.11.0 (2018-12-09) 422 423Due to our dependencies bumping their minimum supported version of 424Rust, the minimum version of Rust we test against is now 1.22.0. 425 426* Merged [#141][issue-141]: Fix `dedent` handling of empty lines and 427 trailing newlines. Thanks @bbqsrc! 428* Fixed [#151][issue-151]: Release of version with hyphenation 0.7. 429 430## Version 0.10.0 (2018-04-28) 431 432Due to our dependencies bumping their minimum supported version of 433Rust, the minimum version of Rust we test against is now 1.17.0. 434 435* Fixed [#99][issue-99]: Word broken even though it would fit on line. 436* Fixed [#107][issue-107]: Automatic hyphenation is off by one. 437* Fixed [#122][issue-122]: Take newlines into account when wrapping. 438* Fixed [#129][issue-129]: Panic on string with em-dash. 439 440## Version 0.9.0 (2017-10-05) 441 442The dependency on `term_size` is now optional, and by default this 443feature is not enabled. This is a *breaking change* for users of 444`Wrapper::with_termwidth`. Enable the `term_size` feature to restore 445the old functionality. 446 447Added a regression test for the case where `width` is set to 448`usize::MAX`, thanks @Fraser999! All public structs now implement 449`Debug`, thanks @hcpl! 450 451* Fixed [#101][issue-101]: Make `term_size` an optional dependency. 452 453## Version 0.8.0 (2017-09-04) 454 455The `Wrapper` stuct is now generic over the type of word splitter 456being used. This means less boxing and a nicer API. The 457`Wrapper::word_splitter` method has been removed. This is a *breaking 458API change* if you used the method to change the word splitter. 459 460The `Wrapper` struct has two new methods that will wrap the input text 461lazily: `Wrapper::wrap_iter` and `Wrapper::into_wrap_iter`. Use those 462if you will be iterating over the wrapped lines one by one. 463 464* Fixed [#59][issue-59]: `wrap` could return an iterator. Thanks 465 @hcpl! 466* Fixed [#81][issue-81]: Set `html_root_url`. 467 468## Version 0.7.0 (2017-07-20) 469 470Version 0.7.0 changes the return type of `Wrapper::wrap` from 471`Vec<String>` to `Vec<Cow<'a, str>>`. This means that the output lines 472borrow data from the input string. This is a *breaking API change* if 473you relied on the exact return type of `Wrapper::wrap`. Callers of the 474`textwrap::fill` convenience function will see no breakage. 475 476The above change and other optimizations makes version 0.7.0 roughly 47715-30% faster than version 0.6.0. 478 479The `squeeze_whitespace` option has been removed since it was 480complicating the above optimization. Let us know if this option is 481important for you so we can provide a work around. 482 483* Fixed [#58][issue-58]: Add a "fast_wrap" function. 484* Fixed [#61][issue-61]: Documentation errors. 485 486## Version 0.6.0 (2017-05-22) 487 488Version 0.6.0 adds builder methods to `Wrapper` for easy one-line 489initialization and configuration: 490 491```rust 492let wrapper = Wrapper::new(60).break_words(false); 493``` 494 495It also add a new `NoHyphenation` word splitter that will never split 496words, not even at existing hyphens. 497 498* Fixed [#28][issue-28]: Support not squeezing whitespace. 499 500## Version 0.5.0 (2017-05-15) 501 502Version 0.5.0 has *breaking API changes*. However, this only affects 503code using the hyphenation feature. The feature is now optional, so 504you will first need to enable the `hyphenation` feature as described 505above. Afterwards, please change your code from 506```rust 507wrapper.corpus = Some(&corpus); 508``` 509to 510```rust 511wrapper.splitter = Box::new(corpus); 512``` 513 514Other changes include optimizations, so version 0.5.0 is roughly 51510-15% faster than version 0.4.0. 516 517* Fixed [#19][issue-19]: Add support for finding terminal size. 518* Fixed [#25][issue-25]: Handle words longer than `self.width`. 519* Fixed [#26][issue-26]: Support custom indentation. 520* Fixed [#36][issue-36]: Support building without `hyphenation`. 521* Fixed [#39][issue-39]: Respect non-breaking spaces. 522 523## Version 0.4.0 (2017-01-24) 524 525Documented complexities and tested these via `cargo bench`. 526 527* Fixed [#13][issue-13]: Immediatedly add word if it fits. 528* Fixed [#14][issue-14]: Avoid splitting on initial hyphens. 529 530## Version 0.3.0 (2017-01-07) 531 532Added support for automatic hyphenation. 533 534## Version 0.2.0 (2016-12-28) 535 536Introduced `Wrapper` struct. Added support for wrapping on hyphens. 537 538## Version 0.1.0 (2016-12-17) 539 540First public release with support for wrapping strings on whitespace. 541 542[rust-2018]: https://doc.rust-lang.org/edition-guide/rust-2018/ 543[`textwrap-macros` crate]: https://crates.io/crates/textwrap-macros 544 545[issue-13]: https://github.com/mgeisler/textwrap/issues/13 546[issue-14]: https://github.com/mgeisler/textwrap/issues/14 547[issue-19]: https://github.com/mgeisler/textwrap/issues/19 548[issue-25]: https://github.com/mgeisler/textwrap/issues/25 549[issue-26]: https://github.com/mgeisler/textwrap/issues/26 550[issue-28]: https://github.com/mgeisler/textwrap/issues/28 551[issue-36]: https://github.com/mgeisler/textwrap/issues/36 552[issue-39]: https://github.com/mgeisler/textwrap/issues/39 553[issue-58]: https://github.com/mgeisler/textwrap/issues/58 554[issue-59]: https://github.com/mgeisler/textwrap/issues/59 555[issue-61]: https://github.com/mgeisler/textwrap/issues/61 556[issue-81]: https://github.com/mgeisler/textwrap/issues/81 557[issue-99]: https://github.com/mgeisler/textwrap/issues/99 558[issue-101]: https://github.com/mgeisler/textwrap/issues/101 559[issue-107]: https://github.com/mgeisler/textwrap/issues/107 560[issue-122]: https://github.com/mgeisler/textwrap/issues/122 561[issue-129]: https://github.com/mgeisler/textwrap/issues/129 562[issue-140]: https://github.com/mgeisler/textwrap/issues/140 563[issue-141]: https://github.com/mgeisler/textwrap/issues/141 564[issue-151]: https://github.com/mgeisler/textwrap/issues/151 565[issue-158]: https://github.com/mgeisler/textwrap/issues/158 566[issue-176]: https://github.com/mgeisler/textwrap/issues/176 567[issue-177]: https://github.com/mgeisler/textwrap/issues/177 568[issue-193]: https://github.com/mgeisler/textwrap/issues/193 569