textwrap/
lib.rs

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")]
49extern crate hyphenation;
50#[cfg(feature = "term_size")]
51extern crate term_size;
52extern crate unicode_width;
53
54use std::borrow::Cow;
55use std::str::CharIndices;
56
57use unicode_width::UnicodeWidthChar;
58use unicode_width::UnicodeWidthStr;
59
60/// A non-breaking space.
61const NBSP: char = '\u{a0}';
62
63mod indentation;
64pub use indentation::dedent;
65pub use indentation::indent;
66
67mod splitting;
68pub 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)]
84pub 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
101impl<'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
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")]
128    pub fn with_termwidth() -> Wrapper<'a, HyphenSplitter> {
129        Wrapper::new(termwidth())
130    }
131}
132
133impl<'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
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
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
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
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    /// ```
231    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    ///
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
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
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)]
391pub struct IntoWrapIter<'a, S: WordSplitter> {
392    wrapper: Wrapper<'a, S>,
393    inner: WrapIterImpl<'a>,
394}
395
396impl<'a, S: WordSplitter> Iterator for IntoWrapIter<'a, S> {
397    type Item = Cow<'a, str>;
398
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)]
413pub struct WrapIter<'w, 'a: 'w, S: WordSplitter + 'w> {
414    wrapper: &'w Wrapper<'a, S>,
415    inner: WrapIterImpl<'a>,
416}
417
418impl<'w, 'a: 'w, S: WordSplitter> Iterator for WrapIter<'w, 'a, S> {
419    type Item = Cow<'a, str>;
420
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]
428fn is_whitespace(ch: char) -> bool {
429    ch.is_whitespace() && ch != NBSP
430}
431
432/// Common implementation details for `WrapIter` and `IntoWrapIter`.
433#[derive(Debug)]
434struct 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
455impl<'a> 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
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
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")]
604pub 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
630pub 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
662pub 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
698pub fn wrap_iter(s: &str, width: usize) -> IntoWrapIter<HyphenSplitter> {
699    Wrapper::new(width).into_wrap_iter(s)
700}
701
702#[cfg(test)]
703mod 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]
712    fn no_wrap() {
713        assert_eq!(wrap("foo", 10), vec!["foo"]);
714    }
715
716    #[test]
717    fn simple() {
718        assert_eq!(wrap("foo bar baz", 5), vec!["foo", "bar", "baz"]);
719    }
720
721    #[test]
722    fn multi_word_on_line() {
723        assert_eq!(wrap("foo bar baz", 10), vec!["foo bar", "baz"]);
724    }
725
726    #[test]
727    fn long_word() {
728        assert_eq!(wrap("foo", 0), vec!["f", "o", "o"]);
729    }
730
731    #[test]
732    fn long_words() {
733        assert_eq!(wrap("foo bar", 0), vec!["f", "o", "o", "b", "a", "r"]);
734    }
735
736    #[test]
737    fn max_width() {
738        assert_eq!(wrap("foo bar", usize::max_value()), vec!["foo bar"]);
739    }
740
741    #[test]
742    fn leading_whitespace() {
743        assert_eq!(wrap("  foo bar", 6), vec!["  foo", "bar"]);
744    }
745
746    #[test]
747    fn trailing_whitespace() {
748        assert_eq!(wrap("foo bar  ", 6), vec!["foo", "bar  "]);
749    }
750
751    #[test]
752    fn interior_whitespace() {
753        assert_eq!(wrap("foo:   bar baz", 10), vec!["foo:   bar", "baz"]);
754    }
755
756    #[test]
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]
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]
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]
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]
792    fn empty_input_not_indented() {
793        let wrapper = Wrapper::new(10).initial_indent("!!!");
794        assert_eq!(wrapper.fill(""), "");
795    }
796
797    #[test]
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]
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]
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]
816    fn hyphens() {
817        assert_eq!(wrap("foo-bar", 5), vec!["foo-", "bar"]);
818    }
819
820    #[test]
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]
827    fn multiple_hyphens() {
828        assert_eq!(wrap("foo-bar-baz", 5), vec!["foo-", "bar-", "baz"]);
829    }
830
831    #[test]
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]
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]
847    fn hyphens_alphanumeric() {
848        assert_eq!(wrap("Na2-CH4", 5), vec!["Na2-", "CH4"]);
849    }
850
851    #[test]
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]
858    fn multiple_splits() {
859        assert_eq!(wrap("foo-bar-baz", 9), vec!["foo-bar-", "baz"]);
860    }
861
862    #[test]
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]
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")]
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")]
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")]
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")]
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]
939    fn break_words() {
940        assert_eq!(wrap("foobarbaz", 3), vec!["foo", "bar", "baz"]);
941    }
942
943    #[test]
944    fn break_words_wide_characters() {
945        assert_eq!(wrap("Hello", 5), vec!["He", "ll", "o"]);
946    }
947
948    #[test]
949    fn break_words_zero_width() {
950        assert_eq!(wrap("foobar", 0), vec!["f", "o", "o", "b", "a", "r"]);
951    }
952
953    #[test]
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]
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]
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]
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]
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]
984    fn fill_simple() {
985        assert_eq!(fill("foo bar baz", 10), "foo bar\nbaz");
986    }
987}