• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Fork of `textwrap` crate
2 //!
3 //! Benefits of forking:
4 //! - Pull in only what we need rather than relying on the compiler to remove what we don't need
5 //! - `LineWrapper` is able to incrementally wrap which will help with `StyledStr
6 
7 pub(crate) mod core;
8 #[cfg(feature = "wrap_help")]
9 pub(crate) mod word_separators;
10 #[cfg(feature = "wrap_help")]
11 pub(crate) mod wrap_algorithms;
12 
13 #[cfg(feature = "wrap_help")]
wrap(content: &str, hard_width: usize) -> String14 pub(crate) fn wrap(content: &str, hard_width: usize) -> String {
15     let mut wrapper = wrap_algorithms::LineWrapper::new(hard_width);
16     let mut total = Vec::new();
17     for line in content.split_inclusive('\n') {
18         wrapper.reset();
19         let line = word_separators::find_words_ascii_space(line).collect::<Vec<_>>();
20         total.extend(wrapper.wrap(line));
21     }
22     total.join("")
23 }
24 
25 #[cfg(not(feature = "wrap_help"))]
wrap(content: &str, _hard_width: usize) -> String26 pub(crate) fn wrap(content: &str, _hard_width: usize) -> String {
27     content.to_owned()
28 }
29 
30 #[cfg(test)]
31 #[cfg(feature = "wrap_help")]
32 mod test {
33     /// Compatibility shim to keep textwrap's tests
wrap(content: &str, hard_width: usize) -> Vec<String>34     fn wrap(content: &str, hard_width: usize) -> Vec<String> {
35         super::wrap(content, hard_width)
36             .trim_end()
37             .split('\n')
38             .map(|s| s.to_owned())
39             .collect::<Vec<_>>()
40     }
41 
42     #[test]
no_wrap()43     fn no_wrap() {
44         assert_eq!(wrap("foo", 10), vec!["foo"]);
45     }
46 
47     #[test]
wrap_simple()48     fn wrap_simple() {
49         assert_eq!(wrap("foo bar baz", 5), vec!["foo", "bar", "baz"]);
50     }
51 
52     #[test]
to_be_or_not()53     fn to_be_or_not() {
54         assert_eq!(
55             wrap("To be, or not to be, that is the question.", 10),
56             vec!["To be, or", "not to be,", "that is", "the", "question."]
57         );
58     }
59 
60     #[test]
multiple_words_on_first_line()61     fn multiple_words_on_first_line() {
62         assert_eq!(wrap("foo bar baz", 10), vec!["foo bar", "baz"]);
63     }
64 
65     #[test]
long_word()66     fn long_word() {
67         assert_eq!(wrap("foo", 0), vec!["foo"]);
68     }
69 
70     #[test]
long_words()71     fn long_words() {
72         assert_eq!(wrap("foo bar", 0), vec!["foo", "bar"]);
73     }
74 
75     #[test]
max_width()76     fn max_width() {
77         assert_eq!(wrap("foo bar", usize::MAX), vec!["foo bar"]);
78 
79         let text = "Hello there! This is some English text. \
80                     It should not be wrapped given the extents below.";
81         assert_eq!(wrap(text, usize::MAX), vec![text]);
82     }
83 
84     #[test]
leading_whitespace()85     fn leading_whitespace() {
86         assert_eq!(wrap("  foo bar", 6), vec!["  foo", "bar"]);
87     }
88 
89     #[test]
leading_whitespace_empty_first_line()90     fn leading_whitespace_empty_first_line() {
91         // If there is no space for the first word, the first line
92         // will be empty. This is because the string is split into
93         // words like [" ", "foobar ", "baz"], which puts "foobar " on
94         // the second line. We never output trailing whitespace
95         assert_eq!(wrap(" foobar baz", 6), vec!["", "foobar", "baz"]);
96     }
97 
98     #[test]
trailing_whitespace()99     fn trailing_whitespace() {
100         // Whitespace is only significant inside a line. After a line
101         // gets too long and is broken, the first word starts in
102         // column zero and is not indented.
103         assert_eq!(wrap("foo     bar     baz  ", 5), vec!["foo", "bar", "baz"]);
104     }
105 
106     #[test]
issue_99()107     fn issue_99() {
108         // We did not reset the in_whitespace flag correctly and did
109         // not handle single-character words after a line break.
110         assert_eq!(
111             wrap("aaabbbccc x yyyzzzwww", 9),
112             vec!["aaabbbccc", "x", "yyyzzzwww"]
113         );
114     }
115 
116     #[test]
issue_129()117     fn issue_129() {
118         // The dash is an em-dash which takes up four bytes. We used
119         // to panic since we tried to index into the character.
120         assert_eq!(wrap("x – x", 1), vec!["x", "–", "x"]);
121     }
122 }
123