1 //! `textwrap` provides functions for word wrapping and filling text.
2 //!
3 //! Wrapping text can be very useful in commandline programs where you
4 //! want to format dynamic output nicely so it looks good in a
5 //! terminal. A quick example:
6 //!
7 //! ```no_run
8 //! extern crate textwrap;
9 //! use textwrap::fill;
10 //!
11 //! fn main() {
12 //!     let text = "textwrap: a small library for wrapping text.";
13 //!     println!("{}", fill(text, 18));
14 //! }
15 //! ```
16 //!
17 //! This will display the following output:
18 //!
19 //! ```text
20 //! textwrap: a small
21 //! library for
22 //! wrapping text.
23 //! ```
24 //!
25 //! # Displayed Width vs Byte Size
26 //!
27 //! To word wrap text, one must know the width of each word so one can
28 //! know when to break lines. This library measures the width of text
29 //! using the [displayed width][unicode-width], not the size in bytes.
30 //!
31 //! This is important for non-ASCII text. ASCII characters such as `a`
32 //! and `!` are simple and take up one column each. This means that
33 //! the displayed width is equal to the string length in bytes.
34 //! However, non-ASCII characters and symbols take up more than one
35 //! byte when UTF-8 encoded: `é` is `0xc3 0xa9` (two bytes) and `⚙` is
36 //! `0xe2 0x9a 0x99` (three bytes) in UTF-8, respectively.
37 //!
38 //! This is why we take care to use the displayed width instead of the
39 //! byte count when computing line lengths. All functions in this
40 //! library handle Unicode characters like this.
41 //!
42 //! [unicode-width]: https://docs.rs/unicode-width/
43 
44 #![doc(html_root_url = "https://docs.rs/textwrap/0.11.0")]
45 #![deny(missing_docs)]
46 #![deny(missing_debug_implementations)]
47 
48 #[cfg(feature = "hyphenation")]
49 extern crate hyphenation;
50 #[cfg(feature = "term_size")]
51 extern crate term_size;
52 extern crate unicode_width;
53 
54 use std::borrow::Cow;
55 use std::str::CharIndices;
56 
57 use unicode_width::UnicodeWidthChar;
58 use unicode_width::UnicodeWidthStr;
59 
60 /// A non-breaking space.
61 const NBSP: char = '\u{a0}';
62 
63 mod indentation;
64 pub use indentation::dedent;
65 pub use indentation::indent;
66 
67 mod splitting;
68 pub use splitting::{HyphenSplitter, NoHyphenation, WordSplitter};
69 
70 /// A Wrapper holds settings for wrapping and filling text. Use it
71 /// when the convenience [`wrap_iter`], [`wrap`] and [`fill`] functions
72 /// are not flexible enough.
73 ///
74 /// [`wrap_iter`]: fn.wrap_iter.html
75 /// [`wrap`]: fn.wrap.html
76 /// [`fill`]: fn.fill.html
77 ///
78 /// The algorithm used by the `WrapIter` iterator (returned from the
79 /// `wrap_iter` method)  works by doing successive partial scans over
80 /// words in the input string (where each single scan yields a single
81 /// line) so that the overall time and memory complexity is O(*n*) where
82 /// *n* is the length of the input string.
83 #[derive(Clone, Debug)]
84 pub struct Wrapper<'a, S: WordSplitter> {
85     /// The width in columns at which the text will be wrapped.
86     pub width: usize,
87     /// Indentation used for the first line of output.
88     pub initial_indent: &'a str,
89     /// Indentation used for subsequent lines of output.
90     pub subsequent_indent: &'a str,
91     /// Allow long words to be broken if they cannot fit on a line.
92     /// When set to `false`, some lines may be longer than
93     /// `self.width`.
94     pub break_words: bool,
95     /// The method for splitting words. If the `hyphenation` feature
96     /// is enabled, you can use a `hyphenation::Standard` dictionary
97     /// here to get language-aware hyphenation.
98     pub splitter: S,
99 }
100 
101 impl<'a> Wrapper<'a, HyphenSplitter> {
102     /// Create a new Wrapper for wrapping at the specified width. By
103     /// default, we allow words longer than `width` to be broken. A
104     /// [`HyphenSplitter`] will be used by default for splitting
105     /// words. See the [`WordSplitter`] trait for other options.
106     ///
107     /// [`HyphenSplitter`]: struct.HyphenSplitter.html
108     /// [`WordSplitter`]: trait.WordSplitter.html
new(width: usize) -> Wrapper<'a, HyphenSplitter>109     pub fn new(width: usize) -> Wrapper<'a, HyphenSplitter> {
110         Wrapper::with_splitter(width, HyphenSplitter)
111     }
112 
113     /// Create a new Wrapper for wrapping text at the current terminal
114     /// width. If the terminal width cannot be determined (typically
115     /// because the standard input and output is not connected to a
116     /// terminal), a width of 80 characters will be used. Other
117     /// settings use the same defaults as `Wrapper::new`.
118     ///
119     /// Equivalent to:
120     ///
121     /// ```no_run
122     /// # #![allow(unused_variables)]
123     /// use textwrap::{Wrapper, termwidth};
124     ///
125     /// let wrapper = Wrapper::new(termwidth());
126     /// ```
127     #[cfg(feature = "term_size")]
with_termwidth() -> Wrapper<'a, HyphenSplitter>128     pub fn with_termwidth() -> Wrapper<'a, HyphenSplitter> {
129         Wrapper::new(termwidth())
130     }
131 }
132 
133 impl<'a, S: WordSplitter> Wrapper<'a, S> {
134     /// Use the given [`WordSplitter`] to create a new Wrapper for
135     /// wrapping at the specified width. By default, we allow words
136     /// longer than `width` to be broken.
137     ///
138     /// [`WordSplitter`]: trait.WordSplitter.html
with_splitter(width: usize, splitter: S) -> Wrapper<'a, S>139     pub fn with_splitter(width: usize, splitter: S) -> Wrapper<'a, S> {
140         Wrapper {
141             width: width,
142             initial_indent: "",
143             subsequent_indent: "",
144             break_words: true,
145             splitter: splitter,
146         }
147     }
148 
149     /// Change [`self.initial_indent`]. The initial indentation is
150     /// used on the very first line of output.
151     ///
152     /// # Examples
153     ///
154     /// Classic paragraph indentation can be achieved by specifying an
155     /// initial indentation and wrapping each paragraph by itself:
156     ///
157     /// ```no_run
158     /// # #![allow(unused_variables)]
159     /// use textwrap::Wrapper;
160     ///
161     /// let wrapper = Wrapper::new(15).initial_indent("    ");
162     /// ```
163     ///
164     /// [`self.initial_indent`]: #structfield.initial_indent
initial_indent(self, indent: &'a str) -> Wrapper<'a, S>165     pub fn initial_indent(self, indent: &'a str) -> Wrapper<'a, S> {
166         Wrapper {
167             initial_indent: indent,
168             ..self
169         }
170     }
171 
172     /// Change [`self.subsequent_indent`]. The subsequent indentation
173     /// is used on lines following the first line of output.
174     ///
175     /// # Examples
176     ///
177     /// Combining initial and subsequent indentation lets you format a
178     /// single paragraph as a bullet list:
179     ///
180     /// ```no_run
181     /// # #![allow(unused_variables)]
182     /// use textwrap::Wrapper;
183     ///
184     /// let wrapper = Wrapper::new(15)
185     ///     .initial_indent("* ")
186     ///     .subsequent_indent("  ");
187     /// ```
188     ///
189     /// [`self.subsequent_indent`]: #structfield.subsequent_indent
subsequent_indent(self, indent: &'a str) -> Wrapper<'a, S>190     pub fn subsequent_indent(self, indent: &'a str) -> Wrapper<'a, S> {
191         Wrapper {
192             subsequent_indent: indent,
193             ..self
194         }
195     }
196 
197     /// Change [`self.break_words`]. This controls if words longer
198     /// than `self.width` can be broken, or if they will be left
199     /// sticking out into the right margin.
200     ///
201     /// [`self.break_words`]: #structfield.break_words
break_words(self, setting: bool) -> Wrapper<'a, S>202     pub fn break_words(self, setting: bool) -> Wrapper<'a, S> {
203         Wrapper {
204             break_words: setting,
205             ..self
206         }
207     }
208 
209     /// Fill a line of text at `self.width` characters. Strings are
210     /// wrapped based on their displayed width, not their size in
211     /// bytes.
212     ///
213     /// The result is a string with newlines between each line. Use
214     /// the `wrap` method if you need access to the individual lines.
215     ///
216     /// # Complexities
217     ///
218     /// This method simply joins the lines produced by `wrap_iter`. As
219     /// such, it inherits the O(*n*) time and memory complexity where
220     /// *n* is the input string length.
221     ///
222     /// # Examples
223     ///
224     /// ```
225     /// use textwrap::Wrapper;
226     ///
227     /// let wrapper = Wrapper::new(15);
228     /// assert_eq!(wrapper.fill("Memory safety without garbage collection."),
229     ///            "Memory safety\nwithout garbage\ncollection.");
230     /// ```
fill(&self, s: &str) -> String231     pub fn fill(&self, s: &str) -> String {
232         // This will avoid reallocation in simple cases (no
233         // indentation, no hyphenation).
234         let mut result = String::with_capacity(s.len());
235 
236         for (i, line) in self.wrap_iter(s).enumerate() {
237             if i > 0 {
238                 result.push('\n');
239             }
240             result.push_str(&line);
241         }
242 
243         result
244     }
245 
246     /// Wrap a line of text at `self.width` characters. Strings are
247     /// wrapped based on their displayed width, not their size in
248     /// bytes.
249     ///
250     /// # Complexities
251     ///
252     /// This method simply collects the lines produced by `wrap_iter`.
253     /// As such, it inherits the O(*n*) overall time and memory
254     /// complexity where *n* is the input string length.
255     ///
256     /// # Examples
257     ///
258     /// ```
259     /// use textwrap::Wrapper;
260     ///
261     /// let wrap15 = Wrapper::new(15);
262     /// assert_eq!(wrap15.wrap("Concurrency without data races."),
263     ///            vec!["Concurrency",
264     ///                 "without data",
265     ///                 "races."]);
266     ///
267     /// let wrap20 = Wrapper::new(20);
268     /// assert_eq!(wrap20.wrap("Concurrency without data races."),
269     ///            vec!["Concurrency without",
270     ///                 "data races."]);
271     /// ```
272     ///
273     /// Notice that newlines in the input are preserved. This means
274     /// that they force a line break, regardless of how long the
275     /// current line is:
276     ///
277     /// ```
278     /// use textwrap::Wrapper;
279     ///
280     /// let wrapper = Wrapper::new(40);
281     /// assert_eq!(wrapper.wrap("First line.\nSecond line."),
282     ///            vec!["First line.", "Second line."]);
283     /// ```
284     ///
wrap(&self, s: &'a str) -> Vec<Cow<'a, str>>285     pub fn wrap(&self, s: &'a str) -> Vec<Cow<'a, str>> {
286         self.wrap_iter(s).collect::<Vec<_>>()
287     }
288 
289     /// Lazily wrap a line of text at `self.width` characters. Strings
290     /// are wrapped based on their displayed width, not their size in
291     /// bytes.
292     ///
293     /// The [`WordSplitter`] stored in [`self.splitter`] is used
294     /// whenever when a word is too large to fit on the current line.
295     /// By changing the field, different hyphenation strategies can be
296     /// implemented.
297     ///
298     /// # Complexities
299     ///
300     /// This method returns a [`WrapIter`] iterator which borrows this
301     /// `Wrapper`. The algorithm used has a linear complexity, so
302     /// getting the next line from the iterator will take O(*w*) time,
303     /// where *w* is the wrapping width. Fully processing the iterator
304     /// will take O(*n*) time for an input string of length *n*.
305     ///
306     /// When no indentation is used, each line returned is a slice of
307     /// the input string and the memory overhead is thus constant.
308     /// Otherwise new memory is allocated for each line returned.
309     ///
310     /// # Examples
311     ///
312     /// ```
313     /// use std::borrow::Cow;
314     /// use textwrap::Wrapper;
315     ///
316     /// let wrap20 = Wrapper::new(20);
317     /// let mut wrap20_iter = wrap20.wrap_iter("Zero-cost abstractions.");
318     /// assert_eq!(wrap20_iter.next(), Some(Cow::from("Zero-cost")));
319     /// assert_eq!(wrap20_iter.next(), Some(Cow::from("abstractions.")));
320     /// assert_eq!(wrap20_iter.next(), None);
321     ///
322     /// let wrap25 = Wrapper::new(25);
323     /// let mut wrap25_iter = wrap25.wrap_iter("Zero-cost abstractions.");
324     /// assert_eq!(wrap25_iter.next(), Some(Cow::from("Zero-cost abstractions.")));
325     /// assert_eq!(wrap25_iter.next(), None);
326     /// ```
327     ///
328     /// [`self.splitter`]: #structfield.splitter
329     /// [`WordSplitter`]: trait.WordSplitter.html
330     /// [`WrapIter`]: struct.WrapIter.html
wrap_iter<'w>(&'w self, s: &'a str) -> WrapIter<'w, 'a, S>331     pub fn wrap_iter<'w>(&'w self, s: &'a str) -> WrapIter<'w, 'a, S> {
332         WrapIter {
333             wrapper: self,
334             inner: WrapIterImpl::new(self, s),
335         }
336     }
337 
338     /// Lazily wrap a line of text at `self.width` characters. Strings
339     /// are wrapped based on their displayed width, not their size in
340     /// bytes.
341     ///
342     /// The [`WordSplitter`] stored in [`self.splitter`] is used
343     /// whenever when a word is too large to fit on the current line.
344     /// By changing the field, different hyphenation strategies can be
345     /// implemented.
346     ///
347     /// # Complexities
348     ///
349     /// This method consumes the `Wrapper` and returns a
350     /// [`IntoWrapIter`] iterator. Fully processing the iterator has
351     /// the same O(*n*) time complexity as [`wrap_iter`], where *n* is
352     /// the length of the input string.
353     ///
354     /// # Examples
355     ///
356     /// ```
357     /// use std::borrow::Cow;
358     /// use textwrap::Wrapper;
359     ///
360     /// let wrap20 = Wrapper::new(20);
361     /// let mut wrap20_iter = wrap20.into_wrap_iter("Zero-cost abstractions.");
362     /// assert_eq!(wrap20_iter.next(), Some(Cow::from("Zero-cost")));
363     /// assert_eq!(wrap20_iter.next(), Some(Cow::from("abstractions.")));
364     /// assert_eq!(wrap20_iter.next(), None);
365     /// ```
366     ///
367     /// [`self.splitter`]: #structfield.splitter
368     /// [`WordSplitter`]: trait.WordSplitter.html
369     /// [`IntoWrapIter`]: struct.IntoWrapIter.html
370     /// [`wrap_iter`]: #method.wrap_iter
into_wrap_iter(self, s: &'a str) -> IntoWrapIter<'a, S>371     pub fn into_wrap_iter(self, s: &'a str) -> IntoWrapIter<'a, S> {
372         let inner = WrapIterImpl::new(&self, s);
373 
374         IntoWrapIter {
375             wrapper: self,
376             inner: inner,
377         }
378     }
379 }
380 
381 /// An iterator over the lines of the input string which owns a
382 /// `Wrapper`. An instance of `IntoWrapIter` is typically obtained
383 /// through either [`wrap_iter`] or [`Wrapper::into_wrap_iter`].
384 ///
385 /// Each call of `.next()` method yields a line wrapped in `Some` if the
386 /// input hasn't been fully processed yet. Otherwise it returns `None`.
387 ///
388 /// [`wrap_iter`]: fn.wrap_iter.html
389 /// [`Wrapper::into_wrap_iter`]: struct.Wrapper.html#method.into_wrap_iter
390 #[derive(Debug)]
391 pub struct IntoWrapIter<'a, S: WordSplitter> {
392     wrapper: Wrapper<'a, S>,
393     inner: WrapIterImpl<'a>,
394 }
395 
396 impl<'a, S: WordSplitter> Iterator for IntoWrapIter<'a, S> {
397     type Item = Cow<'a, str>;
398 
next(&mut self) -> Option<Cow<'a, str>>399     fn next(&mut self) -> Option<Cow<'a, str>> {
400         self.inner.next(&self.wrapper)
401     }
402 }
403 
404 /// An iterator over the lines of the input string which borrows a
405 /// `Wrapper`. An instance of `WrapIter` is typically obtained
406 /// through the [`Wrapper::wrap_iter`] method.
407 ///
408 /// Each call of `.next()` method yields a line wrapped in `Some` if the
409 /// input hasn't been fully processed yet. Otherwise it returns `None`.
410 ///
411 /// [`Wrapper::wrap_iter`]: struct.Wrapper.html#method.wrap_iter
412 #[derive(Debug)]
413 pub struct WrapIter<'w, 'a: 'w, S: WordSplitter + 'w> {
414     wrapper: &'w Wrapper<'a, S>,
415     inner: WrapIterImpl<'a>,
416 }
417 
418 impl<'w, 'a: 'w, S: WordSplitter> Iterator for WrapIter<'w, 'a, S> {
419     type Item = Cow<'a, str>;
420 
next(&mut self) -> Option<Cow<'a, str>>421     fn next(&mut self) -> Option<Cow<'a, str>> {
422         self.inner.next(self.wrapper)
423     }
424 }
425 
426 /// Like `char::is_whitespace`, but non-breaking spaces don't count.
427 #[inline]
is_whitespace(ch: char) -> bool428 fn is_whitespace(ch: char) -> bool {
429     ch.is_whitespace() && ch != NBSP
430 }
431 
432 /// Common implementation details for `WrapIter` and `IntoWrapIter`.
433 #[derive(Debug)]
434 struct WrapIterImpl<'a> {
435     // String to wrap.
436     source: &'a str,
437     // CharIndices iterator over self.source.
438     char_indices: CharIndices<'a>,
439     // Byte index where the current line starts.
440     start: usize,
441     // Byte index of the last place where the string can be split.
442     split: usize,
443     // Size in bytes of the character at self.source[self.split].
444     split_len: usize,
445     // Width of self.source[self.start..idx].
446     line_width: usize,
447     // Width of self.source[self.start..self.split].
448     line_width_at_split: usize,
449     // Tracking runs of whitespace characters.
450     in_whitespace: bool,
451     // Has iterator finished producing elements?
452     finished: bool,
453 }
454 
455 impl<'a> WrapIterImpl<'a> {
new<S: WordSplitter>(wrapper: &Wrapper<'a, S>, s: &'a str) -> WrapIterImpl<'a>456     fn new<S: WordSplitter>(wrapper: &Wrapper<'a, S>, s: &'a str) -> WrapIterImpl<'a> {
457         WrapIterImpl {
458             source: s,
459             char_indices: s.char_indices(),
460             start: 0,
461             split: 0,
462             split_len: 0,
463             line_width: wrapper.initial_indent.width(),
464             line_width_at_split: wrapper.initial_indent.width(),
465             in_whitespace: false,
466             finished: false,
467         }
468     }
469 
create_result_line<S: WordSplitter>(&self, wrapper: &Wrapper<'a, S>) -> Cow<'a, str>470     fn create_result_line<S: WordSplitter>(&self, wrapper: &Wrapper<'a, S>) -> Cow<'a, str> {
471         if self.start == 0 {
472             Cow::from(wrapper.initial_indent)
473         } else {
474             Cow::from(wrapper.subsequent_indent)
475         }
476     }
477 
next<S: WordSplitter>(&mut self, wrapper: &Wrapper<'a, S>) -> Option<Cow<'a, str>>478     fn next<S: WordSplitter>(&mut self, wrapper: &Wrapper<'a, S>) -> Option<Cow<'a, str>> {
479         if self.finished {
480             return None;
481         }
482 
483         while let Some((idx, ch)) = self.char_indices.next() {
484             let char_width = ch.width().unwrap_or(0);
485             let char_len = ch.len_utf8();
486 
487             if ch == '\n' {
488                 self.split = idx;
489                 self.split_len = char_len;
490                 self.line_width_at_split = self.line_width;
491                 self.in_whitespace = false;
492 
493                 // If this is not the final line, return the current line. Otherwise,
494                 // we will return the line with its line break after exiting the loop
495                 if self.split + self.split_len < self.source.len() {
496                     let mut line = self.create_result_line(wrapper);
497                     line += &self.source[self.start..self.split];
498 
499                     self.start = self.split + self.split_len;
500                     self.line_width = wrapper.subsequent_indent.width();
501 
502                     return Some(line);
503                 }
504             } else if is_whitespace(ch) {
505                 // Extend the previous split or create a new one.
506                 if self.in_whitespace {
507                     self.split_len += char_len;
508                 } else {
509                     self.split = idx;
510                     self.split_len = char_len;
511                 }
512                 self.line_width_at_split = self.line_width + char_width;
513                 self.in_whitespace = true;
514             } else if self.line_width + char_width > wrapper.width {
515                 // There is no room for this character on the current
516                 // line. Try to split the final word.
517                 self.in_whitespace = false;
518                 let remaining_text = &self.source[self.split + self.split_len..];
519                 let final_word = match remaining_text.find(is_whitespace) {
520                     Some(i) => &remaining_text[..i],
521                     None => remaining_text,
522                 };
523 
524                 let mut hyphen = "";
525                 let splits = wrapper.splitter.split(final_word);
526                 for &(head, hyp, _) in splits.iter().rev() {
527                     if self.line_width_at_split + head.width() + hyp.width() <= wrapper.width {
528                         // We can fit head into the current line.
529                         // Advance the split point by the width of the
530                         // whitespace and the head length.
531                         self.split += self.split_len + head.len();
532                         self.split_len = 0;
533                         hyphen = hyp;
534                         break;
535                     }
536                 }
537 
538                 if self.start >= self.split {
539                     // The word is too big to fit on a single line, so we
540                     // need to split it at the current index.
541                     if wrapper.break_words {
542                         // Break work at current index.
543                         self.split = idx;
544                         self.split_len = 0;
545                         self.line_width_at_split = self.line_width;
546                     } else {
547                         // Add smallest split.
548                         self.split = self.start + splits[0].0.len();
549                         self.split_len = 0;
550                         self.line_width_at_split = self.line_width;
551                     }
552                 }
553 
554                 if self.start < self.split {
555                     let mut line = self.create_result_line(wrapper);
556                     line += &self.source[self.start..self.split];
557                     line += hyphen;
558 
559                     self.start = self.split + self.split_len;
560                     self.line_width += wrapper.subsequent_indent.width();
561                     self.line_width -= self.line_width_at_split;
562                     self.line_width += char_width;
563 
564                     return Some(line);
565                 }
566             } else {
567                 self.in_whitespace = false;
568             }
569             self.line_width += char_width;
570         }
571 
572         self.finished = true;
573 
574         // Add final line.
575         if self.start < self.source.len() {
576             let mut line = self.create_result_line(wrapper);
577             line += &self.source[self.start..];
578             return Some(line);
579         }
580 
581         None
582     }
583 }
584 
585 /// Return the current terminal width. If the terminal width cannot be
586 /// determined (typically because the standard output is not connected
587 /// to a terminal), a default width of 80 characters will be used.
588 ///
589 /// # Examples
590 ///
591 /// Create a `Wrapper` for the current terminal with a two column
592 /// margin:
593 ///
594 /// ```no_run
595 /// # #![allow(unused_variables)]
596 /// use textwrap::{Wrapper, NoHyphenation, termwidth};
597 ///
598 /// let width = termwidth() - 4; // Two columns on each side.
599 /// let wrapper = Wrapper::with_splitter(width, NoHyphenation)
600 ///     .initial_indent("  ")
601 ///     .subsequent_indent("  ");
602 /// ```
603 #[cfg(feature = "term_size")]
termwidth() -> usize604 pub fn termwidth() -> usize {
605     term_size::dimensions_stdout().map_or(80, |(w, _)| w)
606 }
607 
608 /// Fill a line of text at `width` characters. Strings are wrapped
609 /// based on their displayed width, not their size in bytes.
610 ///
611 /// The result is a string with newlines between each line. Use
612 /// [`wrap`] if you need access to the individual lines or
613 /// [`wrap_iter`] for its iterator counterpart.
614 ///
615 /// ```
616 /// use textwrap::fill;
617 ///
618 /// assert_eq!(fill("Memory safety without garbage collection.", 15),
619 ///            "Memory safety\nwithout garbage\ncollection.");
620 /// ```
621 ///
622 /// This function creates a Wrapper on the fly with default settings.
623 /// If you need to set a language corpus for automatic hyphenation, or
624 /// need to fill many strings, then it is suggested to create a Wrapper
625 /// and call its [`fill` method].
626 ///
627 /// [`wrap`]: fn.wrap.html
628 /// [`wrap_iter`]: fn.wrap_iter.html
629 /// [`fill` method]: struct.Wrapper.html#method.fill
fill(s: &str, width: usize) -> String630 pub fn fill(s: &str, width: usize) -> String {
631     Wrapper::new(width).fill(s)
632 }
633 
634 /// Wrap a line of text at `width` characters. Strings are wrapped
635 /// based on their displayed width, not their size in bytes.
636 ///
637 /// This function creates a Wrapper on the fly with default settings.
638 /// If you need to set a language corpus for automatic hyphenation, or
639 /// need to wrap many strings, then it is suggested to create a Wrapper
640 /// and call its [`wrap` method].
641 ///
642 /// The result is a vector of strings. Use [`wrap_iter`] if you need an
643 /// iterator version.
644 ///
645 /// # Examples
646 ///
647 /// ```
648 /// use textwrap::wrap;
649 ///
650 /// assert_eq!(wrap("Concurrency without data races.", 15),
651 ///            vec!["Concurrency",
652 ///                 "without data",
653 ///                 "races."]);
654 ///
655 /// assert_eq!(wrap("Concurrency without data races.", 20),
656 ///            vec!["Concurrency without",
657 ///                 "data races."]);
658 /// ```
659 ///
660 /// [`wrap_iter`]: fn.wrap_iter.html
661 /// [`wrap` method]: struct.Wrapper.html#method.wrap
wrap(s: &str, width: usize) -> Vec<Cow<str>>662 pub fn wrap(s: &str, width: usize) -> Vec<Cow<str>> {
663     Wrapper::new(width).wrap(s)
664 }
665 
666 /// Lazily wrap a line of text at `width` characters. Strings are
667 /// wrapped based on their displayed width, not their size in bytes.
668 ///
669 /// This function creates a Wrapper on the fly with default settings.
670 /// It then calls the [`into_wrap_iter`] method. Hence, the return
671 /// value is an [`IntoWrapIter`], not a [`WrapIter`] as the function
672 /// name would otherwise suggest.
673 ///
674 /// If you need to set a language corpus for automatic hyphenation, or
675 /// need to wrap many strings, then it is suggested to create a Wrapper
676 /// and call its [`wrap_iter`] or [`into_wrap_iter`] methods.
677 ///
678 /// # Examples
679 ///
680 /// ```
681 /// use std::borrow::Cow;
682 /// use textwrap::wrap_iter;
683 ///
684 /// let mut wrap20_iter = wrap_iter("Zero-cost abstractions.", 20);
685 /// assert_eq!(wrap20_iter.next(), Some(Cow::from("Zero-cost")));
686 /// assert_eq!(wrap20_iter.next(), Some(Cow::from("abstractions.")));
687 /// assert_eq!(wrap20_iter.next(), None);
688 ///
689 /// let mut wrap25_iter = wrap_iter("Zero-cost abstractions.", 25);
690 /// assert_eq!(wrap25_iter.next(), Some(Cow::from("Zero-cost abstractions.")));
691 /// assert_eq!(wrap25_iter.next(), None);
692 /// ```
693 ///
694 /// [`wrap_iter`]: struct.Wrapper.html#method.wrap_iter
695 /// [`into_wrap_iter`]: struct.Wrapper.html#method.into_wrap_iter
696 /// [`IntoWrapIter`]: struct.IntoWrapIter.html
697 /// [`WrapIter`]: struct.WrapIter.html
wrap_iter(s: &str, width: usize) -> IntoWrapIter<HyphenSplitter>698 pub fn wrap_iter(s: &str, width: usize) -> IntoWrapIter<HyphenSplitter> {
699     Wrapper::new(width).into_wrap_iter(s)
700 }
701 
702 #[cfg(test)]
703 mod tests {
704     #[cfg(feature = "hyphenation")]
705     extern crate hyphenation;
706 
707     use super::*;
708     #[cfg(feature = "hyphenation")]
709     use hyphenation::{Language, Load, Standard};
710 
711     #[test]
no_wrap()712     fn no_wrap() {
713         assert_eq!(wrap("foo", 10), vec!["foo"]);
714     }
715 
716     #[test]
simple()717     fn simple() {
718         assert_eq!(wrap("foo bar baz", 5), vec!["foo", "bar", "baz"]);
719     }
720 
721     #[test]
multi_word_on_line()722     fn multi_word_on_line() {
723         assert_eq!(wrap("foo bar baz", 10), vec!["foo bar", "baz"]);
724     }
725 
726     #[test]
long_word()727     fn long_word() {
728         assert_eq!(wrap("foo", 0), vec!["f", "o", "o"]);
729     }
730 
731     #[test]
long_words()732     fn long_words() {
733         assert_eq!(wrap("foo bar", 0), vec!["f", "o", "o", "b", "a", "r"]);
734     }
735 
736     #[test]
max_width()737     fn max_width() {
738         assert_eq!(wrap("foo bar", usize::max_value()), vec!["foo bar"]);
739     }
740 
741     #[test]
leading_whitespace()742     fn leading_whitespace() {
743         assert_eq!(wrap("  foo bar", 6), vec!["  foo", "bar"]);
744     }
745 
746     #[test]
trailing_whitespace()747     fn trailing_whitespace() {
748         assert_eq!(wrap("foo bar  ", 6), vec!["foo", "bar  "]);
749     }
750 
751     #[test]
interior_whitespace()752     fn interior_whitespace() {
753         assert_eq!(wrap("foo:   bar baz", 10), vec!["foo:   bar", "baz"]);
754     }
755 
756     #[test]
extra_whitespace_start_of_line()757     fn extra_whitespace_start_of_line() {
758         // Whitespace is only significant inside a line. After a line
759         // gets too long and is broken, the first word starts in
760         // column zero and is not indented. The line before might end
761         // up with trailing whitespace.
762         assert_eq!(wrap("foo               bar", 5), vec!["foo", "bar"]);
763     }
764 
765     #[test]
issue_99()766     fn issue_99() {
767         // We did not reset the in_whitespace flag correctly and did
768         // not handle single-character words after a line break.
769         assert_eq!(
770             wrap("aaabbbccc x yyyzzzwww", 9),
771             vec!["aaabbbccc", "x", "yyyzzzwww"]
772         );
773     }
774 
775     #[test]
issue_129()776     fn issue_129() {
777         // The dash is an em-dash which takes up four bytes. We used
778         // to panic since we tried to index into the character.
779         assert_eq!(wrap("x – x", 1), vec!["x", "–", "x"]);
780     }
781 
782     #[test]
wide_character_handling()783     fn wide_character_handling() {
784         assert_eq!(wrap("Hello, World!", 15), vec!["Hello, World!"]);
785         assert_eq!(
786             wrap("Hello, World!", 15),
787             vec!["Hello,", "World!"]
788         );
789     }
790 
791     #[test]
empty_input_not_indented()792     fn empty_input_not_indented() {
793         let wrapper = Wrapper::new(10).initial_indent("!!!");
794         assert_eq!(wrapper.fill(""), "");
795     }
796 
797     #[test]
indent_single_line()798     fn indent_single_line() {
799         let wrapper = Wrapper::new(10).initial_indent(">>>"); // No trailing space
800         assert_eq!(wrapper.fill("foo"), ">>>foo");
801     }
802 
803     #[test]
indent_multiple_lines()804     fn indent_multiple_lines() {
805         let wrapper = Wrapper::new(6).initial_indent("* ").subsequent_indent("  ");
806         assert_eq!(wrapper.wrap("foo bar baz"), vec!["* foo", "  bar", "  baz"]);
807     }
808 
809     #[test]
indent_break_words()810     fn indent_break_words() {
811         let wrapper = Wrapper::new(5).initial_indent("* ").subsequent_indent("  ");
812         assert_eq!(wrapper.wrap("foobarbaz"), vec!["* foo", "  bar", "  baz"]);
813     }
814 
815     #[test]
hyphens()816     fn hyphens() {
817         assert_eq!(wrap("foo-bar", 5), vec!["foo-", "bar"]);
818     }
819 
820     #[test]
trailing_hyphen()821     fn trailing_hyphen() {
822         let wrapper = Wrapper::new(5).break_words(false);
823         assert_eq!(wrapper.wrap("foobar-"), vec!["foobar-"]);
824     }
825 
826     #[test]
multiple_hyphens()827     fn multiple_hyphens() {
828         assert_eq!(wrap("foo-bar-baz", 5), vec!["foo-", "bar-", "baz"]);
829     }
830 
831     #[test]
hyphens_flag()832     fn hyphens_flag() {
833         let wrapper = Wrapper::new(5).break_words(false);
834         assert_eq!(
835             wrapper.wrap("The --foo-bar flag."),
836             vec!["The", "--foo-", "bar", "flag."]
837         );
838     }
839 
840     #[test]
repeated_hyphens()841     fn repeated_hyphens() {
842         let wrapper = Wrapper::new(4).break_words(false);
843         assert_eq!(wrapper.wrap("foo--bar"), vec!["foo--bar"]);
844     }
845 
846     #[test]
hyphens_alphanumeric()847     fn hyphens_alphanumeric() {
848         assert_eq!(wrap("Na2-CH4", 5), vec!["Na2-", "CH4"]);
849     }
850 
851     #[test]
hyphens_non_alphanumeric()852     fn hyphens_non_alphanumeric() {
853         let wrapper = Wrapper::new(5).break_words(false);
854         assert_eq!(wrapper.wrap("foo(-)bar"), vec!["foo(-)bar"]);
855     }
856 
857     #[test]
multiple_splits()858     fn multiple_splits() {
859         assert_eq!(wrap("foo-bar-baz", 9), vec!["foo-bar-", "baz"]);
860     }
861 
862     #[test]
forced_split()863     fn forced_split() {
864         let wrapper = Wrapper::new(5).break_words(false);
865         assert_eq!(wrapper.wrap("foobar-baz"), vec!["foobar-", "baz"]);
866     }
867 
868     #[test]
no_hyphenation()869     fn no_hyphenation() {
870         let wrapper = Wrapper::with_splitter(8, NoHyphenation);
871         assert_eq!(wrapper.wrap("foo bar-baz"), vec!["foo", "bar-baz"]);
872     }
873 
874     #[test]
875     #[cfg(feature = "hyphenation")]
auto_hyphenation()876     fn auto_hyphenation() {
877         let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap();
878         let wrapper = Wrapper::new(10);
879         assert_eq!(
880             wrapper.wrap("Internationalization"),
881             vec!["Internatio", "nalization"]
882         );
883 
884         let wrapper = Wrapper::with_splitter(10, dictionary);
885         assert_eq!(
886             wrapper.wrap("Internationalization"),
887             vec!["Interna-", "tionaliza-", "tion"]
888         );
889     }
890 
891     #[test]
892     #[cfg(feature = "hyphenation")]
split_len_hyphenation()893     fn split_len_hyphenation() {
894         // Test that hyphenation takes the width of the wihtespace
895         // into account.
896         let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap();
897         let wrapper = Wrapper::with_splitter(15, dictionary);
898         assert_eq!(
899             wrapper.wrap("garbage   collection"),
900             vec!["garbage   col-", "lection"]
901         );
902     }
903 
904     #[test]
905     #[cfg(feature = "hyphenation")]
borrowed_lines()906     fn borrowed_lines() {
907         // Lines that end with an extra hyphen are owned, the final
908         // line is borrowed.
909         use std::borrow::Cow::{Borrowed, Owned};
910         let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap();
911         let wrapper = Wrapper::with_splitter(10, dictionary);
912         let lines = wrapper.wrap("Internationalization");
913         if let Borrowed(s) = lines[0] {
914             assert!(false, "should not have been borrowed: {:?}", s);
915         }
916         if let Borrowed(s) = lines[1] {
917             assert!(false, "should not have been borrowed: {:?}", s);
918         }
919         if let Owned(ref s) = lines[2] {
920             assert!(false, "should not have been owned: {:?}", s);
921         }
922     }
923 
924     #[test]
925     #[cfg(feature = "hyphenation")]
auto_hyphenation_with_hyphen()926     fn auto_hyphenation_with_hyphen() {
927         let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap();
928         let wrapper = Wrapper::new(8).break_words(false);
929         assert_eq!(wrapper.wrap("over-caffinated"), vec!["over-", "caffinated"]);
930 
931         let wrapper = Wrapper::with_splitter(8, dictionary).break_words(false);
932         assert_eq!(
933             wrapper.wrap("over-caffinated"),
934             vec!["over-", "caffi-", "nated"]
935         );
936     }
937 
938     #[test]
break_words()939     fn break_words() {
940         assert_eq!(wrap("foobarbaz", 3), vec!["foo", "bar", "baz"]);
941     }
942 
943     #[test]
break_words_wide_characters()944     fn break_words_wide_characters() {
945         assert_eq!(wrap("Hello", 5), vec!["He", "ll", "o"]);
946     }
947 
948     #[test]
break_words_zero_width()949     fn break_words_zero_width() {
950         assert_eq!(wrap("foobar", 0), vec!["f", "o", "o", "b", "a", "r"]);
951     }
952 
953     #[test]
break_words_line_breaks()954     fn break_words_line_breaks() {
955         assert_eq!(fill("ab\ncdefghijkl", 5), "ab\ncdefg\nhijkl");
956         assert_eq!(fill("abcdefgh\nijkl", 5), "abcde\nfgh\nijkl");
957     }
958 
959     #[test]
preserve_line_breaks()960     fn preserve_line_breaks() {
961         assert_eq!(fill("test\n", 11), "test\n");
962         assert_eq!(fill("test\n\na\n\n", 11), "test\n\na\n\n");
963         assert_eq!(fill("1 3 5 7\n1 3 5 7", 7), "1 3 5 7\n1 3 5 7");
964     }
965 
966     #[test]
wrap_preserve_line_breaks()967     fn wrap_preserve_line_breaks() {
968         assert_eq!(fill("1 3 5 7\n1 3 5 7", 5), "1 3 5\n7\n1 3 5\n7");
969     }
970 
971     #[test]
non_breaking_space()972     fn non_breaking_space() {
973         let wrapper = Wrapper::new(5).break_words(false);
974         assert_eq!(wrapper.fill("foo bar baz"), "foo bar baz");
975     }
976 
977     #[test]
non_breaking_hyphen()978     fn non_breaking_hyphen() {
979         let wrapper = Wrapper::new(5).break_words(false);
980         assert_eq!(wrapper.fill("foo‑bar‑baz"), "foo‑bar‑baz");
981     }
982 
983     #[test]
fill_simple()984     fn fill_simple() {
985         assert_eq!(fill("foo bar baz", 10), "foo bar\nbaz");
986     }
987 }
988