Bug 1870642 - Fix Collection deleted snackbar that overlaps the toolbar r=android...
[gecko.git] / third_party / rust / textwrap / src / options.rs
blob80e420d195c1f84e64b622f7d7bff0613b69d077
1 //! Options for wrapping text.
3 use crate::{LineEnding, WordSeparator, WordSplitter, WrapAlgorithm};
5 /// Holds configuration options for wrapping and filling text.
6 #[non_exhaustive]
7 #[derive(Debug, Clone)]
8 pub struct Options<'a> {
9     /// The width in columns at which the text will be wrapped.
10     pub width: usize,
11     /// Line ending used for breaking lines.
12     pub line_ending: LineEnding,
13     /// Indentation used for the first line of output. See the
14     /// [`Options::initial_indent`] method.
15     pub initial_indent: &'a str,
16     /// Indentation used for subsequent lines of output. See the
17     /// [`Options::subsequent_indent`] method.
18     pub subsequent_indent: &'a str,
19     /// Allow long words to be broken if they cannot fit on a line.
20     /// When set to `false`, some lines may be longer than
21     /// `self.width`. See the [`Options::break_words`] method.
22     pub break_words: bool,
23     /// Wrapping algorithm to use, see the implementations of the
24     /// [`WrapAlgorithm`] trait for details.
25     pub wrap_algorithm: WrapAlgorithm,
26     /// The line breaking algorithm to use, see the [`WordSeparator`]
27     /// trait for an overview and possible implementations.
28     pub word_separator: WordSeparator,
29     /// The method for splitting words. This can be used to prohibit
30     /// splitting words on hyphens, or it can be used to implement
31     /// language-aware machine hyphenation.
32     pub word_splitter: WordSplitter,
35 impl<'a> From<&'a Options<'a>> for Options<'a> {
36     fn from(options: &'a Options<'a>) -> Self {
37         Self {
38             width: options.width,
39             line_ending: options.line_ending,
40             initial_indent: options.initial_indent,
41             subsequent_indent: options.subsequent_indent,
42             break_words: options.break_words,
43             word_separator: options.word_separator,
44             wrap_algorithm: options.wrap_algorithm,
45             word_splitter: options.word_splitter.clone(),
46         }
47     }
50 impl<'a> From<usize> for Options<'a> {
51     fn from(width: usize) -> Self {
52         Options::new(width)
53     }
56 impl<'a> Options<'a> {
57     /// Creates a new [`Options`] with the specified width.
58     ///
59     /// The other fields are given default values as follows:
60     ///
61     /// ```
62     /// # use textwrap::{LineEnding, Options, WordSplitter, WordSeparator, WrapAlgorithm};
63     /// # let width = 80;
64     /// let options = Options::new(width);
65     /// assert_eq!(options.line_ending, LineEnding::LF);
66     /// assert_eq!(options.initial_indent, "");
67     /// assert_eq!(options.subsequent_indent, "");
68     /// assert_eq!(options.break_words, true);
69     ///
70     /// #[cfg(feature = "unicode-linebreak")]
71     /// assert_eq!(options.word_separator, WordSeparator::UnicodeBreakProperties);
72     /// #[cfg(not(feature = "unicode-linebreak"))]
73     /// assert_eq!(options.word_separator, WordSeparator::AsciiSpace);
74     ///
75     /// #[cfg(feature = "smawk")]
76     /// assert_eq!(options.wrap_algorithm, WrapAlgorithm::new_optimal_fit());
77     /// #[cfg(not(feature = "smawk"))]
78     /// assert_eq!(options.wrap_algorithm, WrapAlgorithm::FirstFit);
79     ///
80     /// assert_eq!(options.word_splitter, WordSplitter::HyphenSplitter);
81     /// ```
82     ///
83     /// Note that the default word separator and wrap algorithms
84     /// changes based on the available Cargo features. The best
85     /// available algorithms are used by default.
86     pub const fn new(width: usize) -> Self {
87         Options {
88             width,
89             line_ending: LineEnding::LF,
90             initial_indent: "",
91             subsequent_indent: "",
92             break_words: true,
93             word_separator: WordSeparator::new(),
94             wrap_algorithm: WrapAlgorithm::new(),
95             word_splitter: WordSplitter::HyphenSplitter,
96         }
97     }
99     /// Change [`self.line_ending`]. This specifies which of the
100     /// supported line endings should be used to break the lines of the
101     /// input text.
102     ///
103     /// # Examples
104     ///
105     /// ```
106     /// use textwrap::{refill, LineEnding, Options};
107     ///
108     /// let options = Options::new(15).line_ending(LineEnding::CRLF);
109     /// assert_eq!(refill("This is a little example.", options),
110     ///            "This is a\r\nlittle example.");
111     /// ```
112     ///
113     /// [`self.line_ending`]: #structfield.line_ending
114     pub fn line_ending(self, line_ending: LineEnding) -> Self {
115         Options {
116             line_ending,
117             ..self
118         }
119     }
121     /// Set [`self.width`] to the given value.
122     ///
123     /// [`self.width`]: #structfield.width
124     pub fn width(self, width: usize) -> Self {
125         Options { width, ..self }
126     }
128     /// Change [`self.initial_indent`]. The initial indentation is
129     /// used on the very first line of output.
130     ///
131     /// # Examples
132     ///
133     /// Classic paragraph indentation can be achieved by specifying an
134     /// initial indentation and wrapping each paragraph by itself:
135     ///
136     /// ```
137     /// use textwrap::{wrap, Options};
138     ///
139     /// let options = Options::new(16).initial_indent("    ");
140     /// assert_eq!(wrap("This is a little example.", options),
141     ///            vec!["    This is a",
142     ///                 "little example."]);
143     /// ```
144     ///
145     /// [`self.initial_indent`]: #structfield.initial_indent
146     pub fn initial_indent(self, initial_indent: &'a str) -> Self {
147         Options {
148             initial_indent,
149             ..self
150         }
151     }
153     /// Change [`self.subsequent_indent`]. The subsequent indentation
154     /// is used on lines following the first line of output.
155     ///
156     /// # Examples
157     ///
158     /// Combining initial and subsequent indentation lets you format a
159     /// single paragraph as a bullet list:
160     ///
161     /// ```
162     /// use textwrap::{wrap, Options};
163     ///
164     /// let options = Options::new(12)
165     ///     .initial_indent("* ")
166     ///     .subsequent_indent("  ");
167     /// #[cfg(feature = "smawk")]
168     /// assert_eq!(wrap("This is a little example.", options),
169     ///            vec!["* This is",
170     ///                 "  a little",
171     ///                 "  example."]);
172     ///
173     /// // Without the `smawk` feature, the wrapping is a little different:
174     /// #[cfg(not(feature = "smawk"))]
175     /// assert_eq!(wrap("This is a little example.", options),
176     ///            vec!["* This is a",
177     ///                 "  little",
178     ///                 "  example."]);
179     /// ```
180     ///
181     /// [`self.subsequent_indent`]: #structfield.subsequent_indent
182     pub fn subsequent_indent(self, subsequent_indent: &'a str) -> Self {
183         Options {
184             subsequent_indent,
185             ..self
186         }
187     }
189     /// Change [`self.break_words`]. This controls if words longer
190     /// than `self.width` can be broken, or if they will be left
191     /// sticking out into the right margin.
192     ///
193     /// See [`Options::word_splitter`] instead if you want to control
194     /// hyphenation.
195     ///
196     /// # Examples
197     ///
198     /// ```
199     /// use textwrap::{wrap, Options};
200     ///
201     /// let options = Options::new(4).break_words(true);
202     /// assert_eq!(wrap("This is a little example.", options),
203     ///            vec!["This",
204     ///                 "is a",
205     ///                 "litt",
206     ///                 "le",
207     ///                 "exam",
208     ///                 "ple."]);
209     /// ```
210     ///
211     /// [`self.break_words`]: #structfield.break_words
212     pub fn break_words(self, break_words: bool) -> Self {
213         Options {
214             break_words,
215             ..self
216         }
217     }
219     /// Change [`self.word_separator`].
220     ///
221     /// See the [`WordSeparator`] trait for details on the choices.
222     ///
223     /// [`self.word_separator`]: #structfield.word_separator
224     pub fn word_separator(self, word_separator: WordSeparator) -> Options<'a> {
225         Options {
226             word_separator,
227             ..self
228         }
229     }
231     /// Change [`self.wrap_algorithm`].
232     ///
233     /// See the [`WrapAlgorithm`] trait for details on the choices.
234     ///
235     /// [`self.wrap_algorithm`]: #structfield.wrap_algorithm
236     pub fn wrap_algorithm(self, wrap_algorithm: WrapAlgorithm) -> Options<'a> {
237         Options {
238             wrap_algorithm,
239             ..self
240         }
241     }
243     /// Change [`self.word_splitter`]. The [`WordSplitter`] is used to
244     /// fit part of a word into the current line when wrapping text.
245     ///
246     /// See [`Options::break_words`] instead if you want to control the
247     /// handling of words longer than the line width.
248     ///
249     /// # Examples
250     ///
251     /// ```
252     /// use textwrap::{wrap, Options, WordSplitter};
253     ///
254     /// // The default is WordSplitter::HyphenSplitter.
255     /// let options = Options::new(5);
256     /// assert_eq!(wrap("foo-bar-baz", &options),
257     ///            vec!["foo-", "bar-", "baz"]);
258     ///
259     /// // The word is now so long that break_words kick in:
260     /// let options = Options::new(5)
261     ///     .word_splitter(WordSplitter::NoHyphenation);
262     /// assert_eq!(wrap("foo-bar-baz", &options),
263     ///            vec!["foo-b", "ar-ba", "z"]);
264     ///
265     /// // If you want to breaks at all, disable both:
266     /// let options = Options::new(5)
267     ///     .break_words(false)
268     ///     .word_splitter(WordSplitter::NoHyphenation);
269     /// assert_eq!(wrap("foo-bar-baz", &options),
270     ///            vec!["foo-bar-baz"]);
271     /// ```
272     ///
273     /// [`self.word_splitter`]: #structfield.word_splitter
274     pub fn word_splitter(self, word_splitter: WordSplitter) -> Options<'a> {
275         Options {
276             word_splitter,
277             ..self
278         }
279     }
282 #[cfg(test)]
283 mod tests {
284     use super::*;
286     #[test]
287     fn options_agree_with_usize() {
288         let opt_usize = Options::from(42_usize);
289         let opt_options = Options::new(42);
291         assert_eq!(opt_usize.width, opt_options.width);
292         assert_eq!(opt_usize.initial_indent, opt_options.initial_indent);
293         assert_eq!(opt_usize.subsequent_indent, opt_options.subsequent_indent);
294         assert_eq!(opt_usize.break_words, opt_options.break_words);
295         assert_eq!(
296             opt_usize.word_splitter.split_points("hello-world"),
297             opt_options.word_splitter.split_points("hello-world")
298         );
299     }