• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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