Source code

Revision control

Copy as Markdown

Other Tools

//! 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:
//!
//!
//! ## 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
//!
//! 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/
//! [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;