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