#![allow(clippy::comparison_to_empty)]
use crate::ansi::measure_text_width;
pub fn wrap(text: &str, width: usize, indent_with: &str, no_indent: &str, no_wrap: &str) -> String {
let mut result = String::with_capacity(text.len());
let indent_len = measure_text_width(indent_with);
for line in text.lines() {
let line = line.trim_end_matches(' ');
let (line, indent) =
if let (Some(line), true) = (line.strip_prefix(no_indent), no_indent != "") {
(line, "")
} else {
result.push_str(indent_with);
(line, indent_with)
};
if let (Some(line), true) = (line.strip_prefix(no_wrap), no_wrap != "") {
result.push_str(line);
} else {
let mut wordit = line.split_inclusive(' ');
let mut curr_len = indent_len;
if let Some(word) = wordit.next() {
result.push_str(word);
curr_len += measure_text_width(word);
}
while let Some(mut word) = wordit.next() {
let word_len = measure_text_width(word);
if curr_len + word_len == width + 1 && word.ends_with(' ') {
} else if curr_len + word_len > width {
let pos = result.trim_end_matches(' ').len();
result.truncate(pos);
result.push('\n');
if word == " " {
for nextword in wordit.by_ref() {
word = nextword;
if word != " " {
break;
}
}
}
let (indent, space_pos) =
if let Some(space_prefix_len) = line.find(|c: char| c != ' ') {
(
format!("{}{}", indent, " ".repeat(space_prefix_len)),
space_prefix_len,
)
} else {
debug_assert!(false, "line.trim_end_matches() missing?");
(indent.to_string(), 0)
};
let indent = if line[space_pos..].starts_with("- ") {
format!("{}{}", indent, " ")
} else {
indent
};
result.push_str(&indent);
curr_len = measure_text_width(&indent);
}
curr_len += word_len;
result.push_str(word);
}
}
let pos = result.trim_end_matches(' ').len();
result.truncate(pos);
result.push('\n');
}
#[cfg(test)]
if !result.contains("no-sanity") {
let stripped_input = text
.replace(" ", "")
.replace("\n", "")
.replace(no_wrap, "")
.replace(no_indent, "");
let stripped_output = result
.replace(" ", "")
.replace("\n", "")
.replace(indent_with, "");
assert_eq!(stripped_input, stripped_output);
}
result
}
#[cfg(test)]
mod test {
use super::*;
use insta::assert_snapshot;
#[test]
fn simple_ascii_can_not_split() {
let input = "000 123456789 abcdefghijklmnopqrstuvwxyz ok";
let result = wrap(input, 5, "", "", "");
assert_snapshot!(result, @r###"
000
123456789
abcdefghijklmnopqrstuvwxyz
ok
"###);
}
#[test]
fn simple_ascii_just_whitespace() {
let input = " \n \n \n \n \n \n";
let result = wrap(input, 3, "__", "", "");
assert_snapshot!(result, @r###"
__
__
__
__
__
__
"###);
let result = wrap(input, 3, "", "", "");
assert_eq!(result, "\n\n\n\n\n\n");
}
#[test]
fn simple_ascii_can_not_split_plus_whitespace() {
let input = "000 123456789 abcdefghijklmnopqrstuvwxyz ok";
let result = wrap(input, 5, "", "", "");
assert_snapshot!(result, @r###"
000
123456789
abcdefghijklmnopqrstuvwxyz
ok
"###);
}
#[test]
fn simple_ascii_keep_leading_input_indent() {
let input = "abc\n Def ghi jkl mno pqr stuv xyz\n Abc def ghijklm\nok";
let result = wrap(input, 10, "_", "", "");
assert_snapshot!(result, @r###"
_abc
_ Def ghi
_ jkl mno
_ pqr
_ stuv
_ xyz
_ Abc
_ def
_ ghijklm
_ok
"###);
}
#[test]
fn simple_ascii_indent_and_bullet_points() {
let input = "- ABC ABC abc\n def ghi - jkl\n - 1 22 3 4 55 6 7 8 9\n - 1 22 3 4 55 6 7 8 9\n!- 0 0 0 0 0 0 0 \n";
let result = wrap(input, 10, "", "!", "");
assert_snapshot!(result, @r###"
- ABC ABC
abc
def ghi
- jkl
- 1 22 3
4 55 6
7 8 9
- 1 22
3 4
55 6
7 8
9
- 0 0 0 0
0 0 0
"###);
}
#[test]
fn simple_ascii_all_overlong_after_indent() {
let input = "0000 1111 2222";
let result = wrap(input, 5, "__", "", "");
assert_snapshot!(result, @r###"
__0000
__1111
__2222
"###);
}
#[test]
fn simple_ascii_one_line() {
let input = "123 456 789 abc def ghi jkl mno pqr stu vwx yz";
let result = wrap(input, 10, "__", "", "");
assert_snapshot!(result, @r###"
__123 456
__789 abc
__def ghi
__jkl mno
__pqr stu
__vwx yz
"###);
}
#[test]
fn simple_ascii_trailing_space() {
let input = "123 \n\n \n 456 \n a b \n\n";
let result = wrap(input, 10, " ", "", "");
assert_eq!(result, " 123\n\n\n 456\n a\n b\n\n");
}
#[test]
fn simple_ascii_two_lines() {
let input = "123 456 789 abc def\nghi jkl mno pqr stu vwx yz\n1234 567 89 876 54321\n";
let result = wrap(input, 10, "__", "", "");
assert_snapshot!(result, @r###"
__123 456
__789 abc
__def
__ghi jkl
__mno pqr
__stu vwx
__yz
__1234 567
__89 876
__54321
"###);
}
#[test]
fn simple_ascii_no_indent() {
let input = "123 456 789\n!!abc def ghi jkl mno pqr\nstu vwx yz\n\n";
let result = wrap(input, 10, "__", "!!", "");
assert_snapshot!(result, @r###"
__123 456
__789
abc def
ghi jkl
mno pqr
__stu vwx
__yz
__
"###);
}
#[test]
fn simple_ascii_no_wrap() {
let input = "123 456 789\n|abc def ghi jkl mno pqr\nstu vwx yz\n|W\nA B C D E F G H I\n";
let result = wrap(input, 10, "__", "!!", "|");
assert_snapshot!(result, @r###"
__123 456
__789
__abc def ghi jkl mno pqr
__stu vwx
__yz
__W
__A B C D
__E F G H
__I
"###);
}
#[test]
fn simple_ascii_no_both() {
let input = "123 456 789\n!!|abc def ghi jkl mno pqr\nstu vwx yz\n|W\nA B C D E F G H I\n";
let result = wrap(input, 10, "__", "!!", "|");
assert_snapshot!(result, @r###"
__123 456
__789
abc def ghi jkl mno pqr
__stu vwx
__yz
__W
__A B C D
__E F G H
__I
"###);
}
#[test]
fn simple_ascii_no_both_wrong_order() {
let input = "!!|abc def ghi jkl\n|!!ABC DEF GHI JKL + no-sanity\n";
let result = wrap(input, 7, "__", "!!", "|");
assert_snapshot!(result, @r###"
abc def ghi jkl
__!!ABC DEF GHI JKL + no-sanity
"###);
let wrapped = wrap(
"ab cd ef\n!NI!123\n|AB CD EF GH\n!NI!|123 456 789",
6,
"_",
"!NI!",
"|",
);
assert_snapshot!(wrapped, @r###"
_ab cd
_ef
123
_AB CD EF GH
123 456 789
"###);
}
#[test]
fn simple_ascii_much_whitespace() {
let input = "123 456 789\nabc def ghi jkl mno pqr \nstu vwx yz";
let result = wrap(input, 10, "__", "!!", "|");
assert_snapshot!(result, @r###"
__123
__456
__789
__abc
__def ghi
__jkl mno
__pqr
__stu
__vwx yz
"###);
}
}