textwrap/lib.rs
1//! The textwrap library provides functions for word wrapping and
2//! indenting text.
3//!
4//! # Wrapping Text
5//!
6//! Wrapping text can be very useful in command-line programs where
7//! you want to format dynamic output nicely so it looks good in a
8//! terminal. A quick example:
9//!
10//! ```
11//! # #[cfg(feature = "smawk")] {
12//! let text = "textwrap: a small library for wrapping text.";
13//! assert_eq!(textwrap::wrap(text, 18),
14//! vec!["textwrap: a",
15//! "small library for",
16//! "wrapping text."]);
17//! # }
18//! ```
19//!
20//! The [`wrap()`] function returns the individual lines, use
21//! [`fill()`] is you want the lines joined with `'\n'` to form a
22//! `String`.
23//!
24//! If you enable the `hyphenation` Cargo feature, you can get
25//! automatic hyphenation for a number of languages:
26//!
27//! ```
28//! #[cfg(feature = "hyphenation")] {
29//! use hyphenation::{Language, Load, Standard};
30//! use textwrap::{wrap, Options, WordSplitter};
31//!
32//! let text = "textwrap: a small library for wrapping text.";
33//! let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap();
34//! let options = Options::new(18).word_splitter(WordSplitter::Hyphenation(dictionary));
35//! assert_eq!(wrap(text, &options),
36//! vec!["textwrap: a small",
37//! "library for wrap-",
38//! "ping text."]);
39//! }
40//! ```
41//!
42//! See also the [`unfill()`] and [`refill()`] functions which allow
43//! you to manipulate already wrapped text.
44//!
45//! ## Wrapping Strings at Compile Time
46//!
47//! If your strings are known at compile time, please take a look at
48//! the procedural macros from the [textwrap-macros] crate.
49//!
50//! ## Displayed Width vs Byte Size
51//!
52//! To word wrap text, one must know the width of each word so one can
53//! know when to break lines. This library will by default measure the
54//! width of text using the _displayed width_, not the size in bytes.
55//! The `unicode-width` Cargo feature controls this.
56//!
57//! This is important for non-ASCII text. ASCII characters such as `a`
58//! and `!` are simple and take up one column each. This means that
59//! the displayed width is equal to the string length in bytes.
60//! However, non-ASCII characters and symbols take up more than one
61//! byte when UTF-8 encoded: `é` is `0xc3 0xa9` (two bytes) and `⚙` is
62//! `0xe2 0x9a 0x99` (three bytes) in UTF-8, respectively.
63//!
64//! This is why we take care to use the displayed width instead of the
65//! byte count when computing line lengths. All functions in this
66//! library handle Unicode characters like this when the
67//! `unicode-width` Cargo feature is enabled (it is enabled by
68//! default).
69//!
70//! # Indentation and Dedentation
71//!
72//! The textwrap library also offers functions for adding a prefix to
73//! every line of a string and to remove leading whitespace. As an
74//! example, [`indent()`] allows you to turn lines of text into a
75//! bullet list:
76//!
77//! ```
78//! let before = "\
79//! foo
80//! bar
81//! baz
82//! ";
83//! let after = "\
84//! * foo
85//! * bar
86//! * baz
87//! ";
88//! assert_eq!(textwrap::indent(before, "* "), after);
89//! ```
90//!
91//! Removing leading whitespace is done with [`dedent()`]:
92//!
93//! ```
94//! let before = "
95//! Some
96//! indented
97//! text
98//! ";
99//! let after = "
100//! Some
101//! indented
102//! text
103//! ";
104//! assert_eq!(textwrap::dedent(before), after);
105//! ```
106//!
107//! # Cargo Features
108//!
109//! The textwrap library can be slimmed down as needed via a number of
110//! Cargo features. This means you only pay for the features you
111//! actually use.
112//!
113//! The full dependency graph, where dashed lines indicate optional
114//! dependencies, is shown below:
115//!
116//! <img src="https://raw.githubusercontent.com/mgeisler/textwrap/master/images/textwrap-0.16.2.svg">
117//!
118//! ## Default Features
119//!
120//! These features are enabled by default:
121//!
122//! * `unicode-linebreak`: enables finding words using the
123//! [unicode-linebreak] crate, which implements the line breaking
124//! algorithm described in [Unicode Standard Annex
125//! #14](https://www.unicode.org/reports/tr14/).
126//!
127//! This feature can be disabled if you are happy to find words
128//! separated by ASCII space characters only. People wrapping text
129//! with emojis or East-Asian characters will want most likely want
130//! to enable this feature. See [`WordSeparator`] for details.
131//!
132//! * `unicode-width`: enables correct width computation of non-ASCII
133//! characters via the [unicode-width] crate. Without this feature,
134//! every [`char`] is 1 column wide, except for emojis which are 2
135//! columns wide. See [`core::display_width()`] for details.
136//!
137//! This feature can be disabled if you only need to wrap ASCII
138//! text, or if the functions in [`core`] are used directly with
139//! [`core::Fragment`]s for which the widths have been computed in
140//! other ways.
141//!
142//! * `smawk`: enables linear-time wrapping of the whole paragraph via
143//! the [smawk] crate. See [`wrap_algorithms::wrap_optimal_fit()`]
144//! for details on the optimal-fit algorithm.
145//!
146//! This feature can be disabled if you only ever intend to use
147//! [`wrap_algorithms::wrap_first_fit()`].
148//!
149//! <!-- begin binary-sizes -->
150//!
151//! With Rust 1.64.0, the size impact of the above features on your
152//! binary is as follows:
153//!
154//! | Configuration | Binary Size | Delta |
155//! | :--- | ---: | ---: |
156//! | quick-and-dirty implementation | 289 KB | — KB |
157//! | textwrap without default features | 305 KB | 16 KB |
158//! | textwrap with smawk | 317 KB | 28 KB |
159//! | textwrap with unicode-width | 309 KB | 20 KB |
160//! | textwrap with unicode-linebreak | 342 KB | 53 KB |
161//!
162//! <!-- end binary-sizes -->
163//!
164//! The above sizes are the stripped sizes and the binary is compiled
165//! in release mode with this profile:
166//!
167//! ```toml
168//! [profile.release]
169//! lto = true
170//! codegen-units = 1
171//! ```
172//!
173//! See the [binary-sizes demo] if you want to reproduce these
174//! results.
175//!
176//! ## Optional Features
177//!
178//! These Cargo features enable new functionality:
179//!
180//! * `terminal_size`: enables automatic detection of the terminal
181//! width via the [terminal_size] crate. See
182//! [`Options::with_termwidth()`] for details.
183//!
184//! * `hyphenation`: enables language-sensitive hyphenation via the
185//! [hyphenation] crate. See the [`word_splitters::WordSplitter`]
186//! trait for details.
187//!
188//! [unicode-linebreak]: https://docs.rs/unicode-linebreak/
189//! [unicode-width]: https://docs.rs/unicode-width/
190//! [smawk]: https://docs.rs/smawk/
191//! [binary-sizes demo]: https://github.com/mgeisler/textwrap/tree/master/examples/binary-sizes
192//! [textwrap-macros]: https://docs.rs/textwrap-macros/
193//! [terminal_size]: https://docs.rs/terminal_size/
194//! [hyphenation]: https://docs.rs/hyphenation/
195
196#![doc(html_root_url = "https://docs.rs/textwrap/0.16.2")]
197#![forbid(unsafe_code)] // See https://github.com/mgeisler/textwrap/issues/210
198#![deny(missing_docs)]
199#![deny(missing_debug_implementations)]
200#![allow(clippy::redundant_field_names)]
201
202// Make `cargo test` execute the README doctests.
203#[cfg(doctest)]
204#[doc = include_str!("../README.md")]
205mod readme_doctest {}
206
207pub mod core;
208#[cfg(fuzzing)]
209pub mod fuzzing;
210pub mod word_splitters;
211pub mod wrap_algorithms;
212
213mod columns;
214mod fill;
215mod indentation;
216mod line_ending;
217mod options;
218mod refill;
219#[cfg(feature = "terminal_size")]
220mod termwidth;
221mod word_separators;
222mod wrap;
223
224pub use columns::wrap_columns;
225pub use fill::{fill, fill_inplace};
226pub use indentation::{dedent, indent};
227pub use line_ending::LineEnding;
228pub use options::Options;
229pub use refill::{refill, unfill};
230#[cfg(feature = "terminal_size")]
231pub use termwidth::termwidth;
232pub use word_separators::WordSeparator;
233pub use word_splitters::WordSplitter;
234pub use wrap::wrap;
235pub use wrap_algorithms::WrapAlgorithm;