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

#![doc(html_root_url = "https://docs.rs/textwrap/0.16.1")]
#![forbid(unsafe_code)] // See https://github.com/mgeisler/textwrap/issues/210
#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
#![allow(clippy::redundant_field_names)]

// Make `cargo test` execute the README doctests.
#[cfg(doctest)]
#[doc = include_str!("../README.md")]
mod readme_doctest {}

pub mod core;
#[cfg(fuzzing)]
pub mod fuzzing;
pub mod word_splitters;
pub mod wrap_algorithms;

mod columns;
mod fill;
mod indentation;
mod line_ending;
mod options;
mod refill;
#[cfg(feature = "terminal_size")]
mod termwidth;
mod word_separators;
mod wrap;

pub use columns::wrap_columns;
pub use fill::{fill, fill_inplace};
pub use indentation::{dedent, indent};
pub use line_ending::LineEnding;
pub use options::Options;
pub use refill::{refill, unfill};
#[cfg(feature = "terminal_size")]
pub use termwidth::termwidth;
pub use word_separators::WordSeparator;
pub use word_splitters::WordSplitter;
pub use wrap::wrap;
pub use wrap_algorithms::WrapAlgorithm;