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