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