README.md
1# Textwrap
2
3[![](https://img.shields.io/crates/v/textwrap.svg)][crates-io]
4[![](https://docs.rs/textwrap/badge.svg)][api-docs]
5[![](https://travis-ci.org/mgeisler/textwrap.svg?branch=master)][travis-ci]
6[![](https://ci.appveyor.com/api/projects/status/github/mgeisler/textwrap?branch=master&svg=true)][appveyor]
7[![](https://codecov.io/gh/mgeisler/textwrap/branch/master/graph/badge.svg)][codecov]
8
9Textwrap is a small Rust crate for word wrapping text. You can use it
10to format strings for display in commandline applications. The crate
11name and interface is inspired by
12the [Python textwrap module][py-textwrap].
13
14## Usage
15
16Add this to your `Cargo.toml`:
17```toml
18[dependencies]
19textwrap = "0.11"
20```
21
22and this to your crate root:
23```rust
24extern crate textwrap;
25```
26
27If you would like to have automatic hyphenation, specify the
28dependency as:
29```toml
30[dependencies]
31textwrap = { version = "0.11", features = ["hyphenation"] }
32```
33
34To conveniently wrap text at the current terminal width, enable the
35`term_size` feature:
36
37```toml
38[dependencies]
39textwrap = { version = "0.11", features = ["term_size"] }
40```
41
42## Documentation
43
44**[API documentation][api-docs]**
45
46## Getting Started
47
48Word wrapping single strings is easy using the `fill` function:
49```rust
50extern crate textwrap;
51use textwrap::fill;
52
53fn main() {
54 let text = "textwrap: a small library for wrapping text.";
55 println!("{}", fill(text, 18));
56}
57```
58The output is
59```
60textwrap: a small
61library for
62wrapping text.
63```
64
65With the `hyphenation` feature, you can get automatic hyphenation
66for [about 70 languages][patterns]. Your program must load and
67configure the hyphenation patterns to use:
68```rust
69extern crate hyphenation;
70extern crate textwrap;
71
72use hyphenation::{Language, Load, Standard};
73use textwrap::Wrapper;
74
75fn main() {
76 let hyphenator = Standard::from_embedded(Language::EnglishUS).unwrap();
77 let wrapper = Wrapper::with_splitter(18, hyphenator);
78 let text = "textwrap: a small library for wrapping text.";
79 println!("{}", wrapper.fill(text))
80}
81```
82
83The output now looks like this:
84```
85textwrap: a small
86library for wrap-
87ping text.
88```
89
90The hyphenation uses high-quality TeX hyphenation patterns.
91
92## Examples
93
94The library comes with some small example programs that shows various
95features.
96
97### Layout Example
98
99The `layout` example shows how a fixed example string is wrapped at
100different widths. Run the example with:
101
102```shell
103$ cargo run --features hyphenation --example layout
104```
105
106The program will use the following string:
107
108> Memory safety without garbage collection. Concurrency without data
109> races. Zero-cost abstractions.
110
111The string is wrapped at all widths between 15 and 60 columns. With
112narrow columns the output looks like this:
113
114```
115.--- Width: 15 ---.
116| Memory safety |
117| without garbage |
118| collection. |
119| Concurrency |
120| without data |
121| races. Zero- |
122| cost abstrac- |
123| tions. |
124.--- Width: 16 ----.
125| Memory safety |
126| without garbage |
127| collection. Con- |
128| currency without |
129| data races. Ze- |
130| ro-cost abstrac- |
131| tions. |
132```
133
134Later, longer lines are used and the output now looks like this:
135
136```
137.-------------------- Width: 49 --------------------.
138| Memory safety without garbage collection. Concur- |
139| rency without data races. Zero-cost abstractions. |
140.---------------------- Width: 53 ----------------------.
141| Memory safety without garbage collection. Concurrency |
142| without data races. Zero-cost abstractions. |
143.------------------------- Width: 59 -------------------------.
144| Memory safety without garbage collection. Concurrency with- |
145| out data races. Zero-cost abstractions. |
146```
147
148Notice how words are split at hyphens (such as "zero-cost") but also
149how words are hyphenated using automatic/machine hyphenation.
150
151### Terminal Width Example
152
153The `termwidth` example simply shows how the width can be set
154automatically to the current terminal width. Run it with this command:
155
156```
157$ cargo run --example termwidth
158```
159
160If you run it in a narrow terminal, you'll see output like this:
161```
162Formatted in within 60 columns:
163----
164Memory safety without garbage collection. Concurrency
165without data races. Zero-cost abstractions.
166----
167```
168
169If `stdout` is not connected to the terminal, the program will use a
170default of 80 columns for the width:
171
172```
173$ cargo run --example termwidth | cat
174Formatted in within 80 columns:
175----
176Memory safety without garbage collection. Concurrency without data races. Zero-
177cost abstractions.
178----
179```
180
181## Release History
182
183This section lists the largest changes per release.
184
185### Version 0.11.0 — December 9th, 2018
186
187Due to our dependencies bumping their minimum supported version of
188Rust, the minimum version of Rust we test against is now 1.22.0.
189
190* Merged [#141][issue-141]: Fix `dedent` handling of empty lines and
191 trailing newlines. Thanks @bbqsrc!
192* Fixed [#151][issue-151]: Release of version with hyphenation 0.7.
193
194### Version 0.10.0 — April 28th, 2018
195
196Due to our dependencies bumping their minimum supported version of
197Rust, the minimum version of Rust we test against is now 1.17.0.
198
199* Fixed [#99][issue-99]: Word broken even though it would fit on line.
200* Fixed [#107][issue-107]: Automatic hyphenation is off by one.
201* Fixed [#122][issue-122]: Take newlines into account when wrapping.
202* Fixed [#129][issue-129]: Panic on string with em-dash.
203
204### Version 0.9.0 — October 5th, 2017
205
206The dependency on `term_size` is now optional, and by default this
207feature is not enabled. This is a *breaking change* for users of
208`Wrapper::with_termwidth`. Enable the `term_size` feature to restore
209the old functionality.
210
211Added a regression test for the case where `width` is set to
212`usize::MAX`, thanks @Fraser999! All public structs now implement
213`Debug`, thanks @hcpl!
214
215* Fixed [#101][issue-101]: Make `term_size` an optional dependency.
216
217### Version 0.8.0 — September 4th, 2017
218
219The `Wrapper` stuct is now generic over the type of word splitter
220being used. This means less boxing and a nicer API. The
221`Wrapper::word_splitter` method has been removed. This is a *breaking
222API change* if you used the method to change the word splitter.
223
224The `Wrapper` struct has two new methods that will wrap the input text
225lazily: `Wrapper::wrap_iter` and `Wrapper::into_wrap_iter`. Use those
226if you will be iterating over the wrapped lines one by one.
227
228* Fixed [#59][issue-59]: `wrap` could return an iterator. Thanks
229 @hcpl!
230* Fixed [#81][issue-81]: Set `html_root_url`.
231
232### Version 0.7.0 — July 20th, 2017
233
234Version 0.7.0 changes the return type of `Wrapper::wrap` from
235`Vec<String>` to `Vec<Cow<'a, str>>`. This means that the output lines
236borrow data from the input string. This is a *breaking API change* if
237you relied on the exact return type of `Wrapper::wrap`. Callers of the
238`textwrap::fill` convenience function will see no breakage.
239
240The above change and other optimizations makes version 0.7.0 roughly
24115-30% faster than version 0.6.0.
242
243The `squeeze_whitespace` option has been removed since it was
244complicating the above optimization. Let us know if this option is
245important for you so we can provide a work around.
246
247* Fixed [#58][issue-58]: Add a "fast_wrap" function.
248* Fixed [#61][issue-61]: Documentation errors.
249
250### Version 0.6.0 — May 22nd, 2017
251
252Version 0.6.0 adds builder methods to `Wrapper` for easy one-line
253initialization and configuration:
254
255```rust
256let wrapper = Wrapper::new(60).break_words(false);
257```
258
259It also add a new `NoHyphenation` word splitter that will never split
260words, not even at existing hyphens.
261
262* Fixed [#28][issue-28]: Support not squeezing whitespace.
263
264### Version 0.5.0 — May 15th, 2017
265
266Version 0.5.0 has *breaking API changes*. However, this only affects
267code using the hyphenation feature. The feature is now optional, so
268you will first need to enable the `hyphenation` feature as described
269above. Afterwards, please change your code from
270```rust
271wrapper.corpus = Some(&corpus);
272```
273to
274```rust
275wrapper.splitter = Box::new(corpus);
276```
277
278Other changes include optimizations, so version 0.5.0 is roughly
27910-15% faster than version 0.4.0.
280
281* Fixed [#19][issue-19]: Add support for finding terminal size.
282* Fixed [#25][issue-25]: Handle words longer than `self.width`.
283* Fixed [#26][issue-26]: Support custom indentation.
284* Fixed [#36][issue-36]: Support building without `hyphenation`.
285* Fixed [#39][issue-39]: Respect non-breaking spaces.
286
287### Version 0.4.0 — January 24th, 2017
288
289Documented complexities and tested these via `cargo bench`.
290
291* Fixed [#13][issue-13]: Immediatedly add word if it fits.
292* Fixed [#14][issue-14]: Avoid splitting on initial hyphens.
293
294### Version 0.3.0 — January 7th, 2017
295
296Added support for automatic hyphenation.
297
298### Version 0.2.0 — December 28th, 2016
299
300Introduced `Wrapper` struct. Added support for wrapping on hyphens.
301
302### Version 0.1.0 — December 17th, 2016
303
304First public release with support for wrapping strings on whitespace.
305
306## License
307
308Textwrap can be distributed according to the [MIT license][mit].
309Contributions will be accepted under the same license.
310
311[crates-io]: https://crates.io/crates/textwrap
312[travis-ci]: https://travis-ci.org/mgeisler/textwrap
313[appveyor]: https://ci.appveyor.com/project/mgeisler/textwrap
314[codecov]: https://codecov.io/gh/mgeisler/textwrap
315[py-textwrap]: https://docs.python.org/library/textwrap
316[patterns]: https://github.com/tapeinosyne/hyphenation/tree/master/patterns-tex
317[api-docs]: https://docs.rs/textwrap/
318[issue-13]: https://github.com/mgeisler/textwrap/issues/13
319[issue-14]: https://github.com/mgeisler/textwrap/issues/14
320[issue-19]: https://github.com/mgeisler/textwrap/issues/19
321[issue-25]: https://github.com/mgeisler/textwrap/issues/25
322[issue-26]: https://github.com/mgeisler/textwrap/issues/26
323[issue-28]: https://github.com/mgeisler/textwrap/issues/28
324[issue-36]: https://github.com/mgeisler/textwrap/issues/36
325[issue-39]: https://github.com/mgeisler/textwrap/issues/39
326[issue-58]: https://github.com/mgeisler/textwrap/issues/58
327[issue-59]: https://github.com/mgeisler/textwrap/issues/59
328[issue-61]: https://github.com/mgeisler/textwrap/issues/61
329[issue-81]: https://github.com/mgeisler/textwrap/issues/81
330[issue-99]: https://github.com/mgeisler/textwrap/issues/99
331[issue-101]: https://github.com/mgeisler/textwrap/issues/101
332[issue-107]: https://github.com/mgeisler/textwrap/issues/107
333[issue-122]: https://github.com/mgeisler/textwrap/issues/122
334[issue-129]: https://github.com/mgeisler/textwrap/issues/129
335[issue-141]: https://github.com/mgeisler/textwrap/issues/141
336[issue-151]: https://github.com/mgeisler/textwrap/issues/151
337[mit]: LICENSE
338