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