summaryrefslogtreecommitdiffstats
path: root/third_party/rust/textwrap/src/options.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/textwrap/src/options.rs')
-rw-r--r--third_party/rust/textwrap/src/options.rs300
1 files changed, 300 insertions, 0 deletions
diff --git a/third_party/rust/textwrap/src/options.rs b/third_party/rust/textwrap/src/options.rs
new file mode 100644
index 0000000000..80e420d195
--- /dev/null
+++ b/third_party/rust/textwrap/src/options.rs
@@ -0,0 +1,300 @@
+//! Options for wrapping text.
+
+use crate::{LineEnding, WordSeparator, WordSplitter, WrapAlgorithm};
+
+/// Holds configuration options for wrapping and filling text.
+#[non_exhaustive]
+#[derive(Debug, Clone)]
+pub struct Options<'a> {
+ /// The width in columns at which the text will be wrapped.
+ pub width: usize,
+ /// Line ending used for breaking lines.
+ pub line_ending: LineEnding,
+ /// Indentation used for the first line of output. See the
+ /// [`Options::initial_indent`] method.
+ pub initial_indent: &'a str,
+ /// Indentation used for subsequent lines of output. See the
+ /// [`Options::subsequent_indent`] method.
+ pub subsequent_indent: &'a str,
+ /// Allow long words to be broken if they cannot fit on a line.
+ /// When set to `false`, some lines may be longer than
+ /// `self.width`. See the [`Options::break_words`] method.
+ pub break_words: bool,
+ /// Wrapping algorithm to use, see the implementations of the
+ /// [`WrapAlgorithm`] trait for details.
+ pub wrap_algorithm: WrapAlgorithm,
+ /// The line breaking algorithm to use, see the [`WordSeparator`]
+ /// trait for an overview and possible implementations.
+ pub word_separator: WordSeparator,
+ /// The method for splitting words. This can be used to prohibit
+ /// splitting words on hyphens, or it can be used to implement
+ /// language-aware machine hyphenation.
+ pub word_splitter: WordSplitter,
+}
+
+impl<'a> From<&'a Options<'a>> for Options<'a> {
+ fn from(options: &'a Options<'a>) -> Self {
+ Self {
+ width: options.width,
+ line_ending: options.line_ending,
+ initial_indent: options.initial_indent,
+ subsequent_indent: options.subsequent_indent,
+ break_words: options.break_words,
+ word_separator: options.word_separator,
+ wrap_algorithm: options.wrap_algorithm,
+ word_splitter: options.word_splitter.clone(),
+ }
+ }
+}
+
+impl<'a> From<usize> for Options<'a> {
+ fn from(width: usize) -> Self {
+ Options::new(width)
+ }
+}
+
+impl<'a> Options<'a> {
+ /// Creates a new [`Options`] with the specified width.
+ ///
+ /// The other fields are given default values as follows:
+ ///
+ /// ```
+ /// # use textwrap::{LineEnding, Options, WordSplitter, WordSeparator, WrapAlgorithm};
+ /// # let width = 80;
+ /// let options = Options::new(width);
+ /// assert_eq!(options.line_ending, LineEnding::LF);
+ /// assert_eq!(options.initial_indent, "");
+ /// assert_eq!(options.subsequent_indent, "");
+ /// assert_eq!(options.break_words, true);
+ ///
+ /// #[cfg(feature = "unicode-linebreak")]
+ /// assert_eq!(options.word_separator, WordSeparator::UnicodeBreakProperties);
+ /// #[cfg(not(feature = "unicode-linebreak"))]
+ /// assert_eq!(options.word_separator, WordSeparator::AsciiSpace);
+ ///
+ /// #[cfg(feature = "smawk")]
+ /// assert_eq!(options.wrap_algorithm, WrapAlgorithm::new_optimal_fit());
+ /// #[cfg(not(feature = "smawk"))]
+ /// assert_eq!(options.wrap_algorithm, WrapAlgorithm::FirstFit);
+ ///
+ /// assert_eq!(options.word_splitter, WordSplitter::HyphenSplitter);
+ /// ```
+ ///
+ /// Note that the default word separator and wrap algorithms
+ /// changes based on the available Cargo features. The best
+ /// available algorithms are used by default.
+ pub const fn new(width: usize) -> Self {
+ Options {
+ width,
+ line_ending: LineEnding::LF,
+ initial_indent: "",
+ subsequent_indent: "",
+ break_words: true,
+ word_separator: WordSeparator::new(),
+ wrap_algorithm: WrapAlgorithm::new(),
+ word_splitter: WordSplitter::HyphenSplitter,
+ }
+ }
+
+ /// Change [`self.line_ending`]. This specifies which of the
+ /// supported line endings should be used to break the lines of the
+ /// input text.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use textwrap::{refill, LineEnding, Options};
+ ///
+ /// let options = Options::new(15).line_ending(LineEnding::CRLF);
+ /// assert_eq!(refill("This is a little example.", options),
+ /// "This is a\r\nlittle example.");
+ /// ```
+ ///
+ /// [`self.line_ending`]: #structfield.line_ending
+ pub fn line_ending(self, line_ending: LineEnding) -> Self {
+ Options {
+ line_ending,
+ ..self
+ }
+ }
+
+ /// Set [`self.width`] to the given value.
+ ///
+ /// [`self.width`]: #structfield.width
+ pub fn width(self, width: usize) -> Self {
+ Options { width, ..self }
+ }
+
+ /// Change [`self.initial_indent`]. The initial indentation is
+ /// used on the very first line of output.
+ ///
+ /// # Examples
+ ///
+ /// Classic paragraph indentation can be achieved by specifying an
+ /// initial indentation and wrapping each paragraph by itself:
+ ///
+ /// ```
+ /// use textwrap::{wrap, Options};
+ ///
+ /// let options = Options::new(16).initial_indent(" ");
+ /// assert_eq!(wrap("This is a little example.", options),
+ /// vec![" This is a",
+ /// "little example."]);
+ /// ```
+ ///
+ /// [`self.initial_indent`]: #structfield.initial_indent
+ pub fn initial_indent(self, initial_indent: &'a str) -> Self {
+ Options {
+ initial_indent,
+ ..self
+ }
+ }
+
+ /// Change [`self.subsequent_indent`]. The subsequent indentation
+ /// is used on lines following the first line of output.
+ ///
+ /// # Examples
+ ///
+ /// Combining initial and subsequent indentation lets you format a
+ /// single paragraph as a bullet list:
+ ///
+ /// ```
+ /// use textwrap::{wrap, Options};
+ ///
+ /// let options = Options::new(12)
+ /// .initial_indent("* ")
+ /// .subsequent_indent(" ");
+ /// #[cfg(feature = "smawk")]
+ /// assert_eq!(wrap("This is a little example.", options),
+ /// vec!["* This is",
+ /// " a little",
+ /// " example."]);
+ ///
+ /// // Without the `smawk` feature, the wrapping is a little different:
+ /// #[cfg(not(feature = "smawk"))]
+ /// assert_eq!(wrap("This is a little example.", options),
+ /// vec!["* This is a",
+ /// " little",
+ /// " example."]);
+ /// ```
+ ///
+ /// [`self.subsequent_indent`]: #structfield.subsequent_indent
+ pub fn subsequent_indent(self, subsequent_indent: &'a str) -> Self {
+ Options {
+ subsequent_indent,
+ ..self
+ }
+ }
+
+ /// Change [`self.break_words`]. This controls if words longer
+ /// than `self.width` can be broken, or if they will be left
+ /// sticking out into the right margin.
+ ///
+ /// See [`Options::word_splitter`] instead if you want to control
+ /// hyphenation.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use textwrap::{wrap, Options};
+ ///
+ /// let options = Options::new(4).break_words(true);
+ /// assert_eq!(wrap("This is a little example.", options),
+ /// vec!["This",
+ /// "is a",
+ /// "litt",
+ /// "le",
+ /// "exam",
+ /// "ple."]);
+ /// ```
+ ///
+ /// [`self.break_words`]: #structfield.break_words
+ pub fn break_words(self, break_words: bool) -> Self {
+ Options {
+ break_words,
+ ..self
+ }
+ }
+
+ /// Change [`self.word_separator`].
+ ///
+ /// See the [`WordSeparator`] trait for details on the choices.
+ ///
+ /// [`self.word_separator`]: #structfield.word_separator
+ pub fn word_separator(self, word_separator: WordSeparator) -> Options<'a> {
+ Options {
+ word_separator,
+ ..self
+ }
+ }
+
+ /// Change [`self.wrap_algorithm`].
+ ///
+ /// See the [`WrapAlgorithm`] trait for details on the choices.
+ ///
+ /// [`self.wrap_algorithm`]: #structfield.wrap_algorithm
+ pub fn wrap_algorithm(self, wrap_algorithm: WrapAlgorithm) -> Options<'a> {
+ Options {
+ wrap_algorithm,
+ ..self
+ }
+ }
+
+ /// Change [`self.word_splitter`]. The [`WordSplitter`] is used to
+ /// fit part of a word into the current line when wrapping text.
+ ///
+ /// See [`Options::break_words`] instead if you want to control the
+ /// handling of words longer than the line width.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use textwrap::{wrap, Options, WordSplitter};
+ ///
+ /// // The default is WordSplitter::HyphenSplitter.
+ /// let options = Options::new(5);
+ /// assert_eq!(wrap("foo-bar-baz", &options),
+ /// vec!["foo-", "bar-", "baz"]);
+ ///
+ /// // The word is now so long that break_words kick in:
+ /// let options = Options::new(5)
+ /// .word_splitter(WordSplitter::NoHyphenation);
+ /// assert_eq!(wrap("foo-bar-baz", &options),
+ /// vec!["foo-b", "ar-ba", "z"]);
+ ///
+ /// // If you want to breaks at all, disable both:
+ /// let options = Options::new(5)
+ /// .break_words(false)
+ /// .word_splitter(WordSplitter::NoHyphenation);
+ /// assert_eq!(wrap("foo-bar-baz", &options),
+ /// vec!["foo-bar-baz"]);
+ /// ```
+ ///
+ /// [`self.word_splitter`]: #structfield.word_splitter
+ pub fn word_splitter(self, word_splitter: WordSplitter) -> Options<'a> {
+ Options {
+ word_splitter,
+ ..self
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn options_agree_with_usize() {
+ let opt_usize = Options::from(42_usize);
+ let opt_options = Options::new(42);
+
+ assert_eq!(opt_usize.width, opt_options.width);
+ assert_eq!(opt_usize.initial_indent, opt_options.initial_indent);
+ assert_eq!(opt_usize.subsequent_indent, opt_options.subsequent_indent);
+ assert_eq!(opt_usize.break_words, opt_options.break_words);
+ assert_eq!(
+ opt_usize.word_splitter.split_points("hello-world"),
+ opt_options.word_splitter.split_points("hello-world")
+ );
+ }
+}