reedline/painting/
utils.rs1use std::borrow::Cow;
2use unicode_width::UnicodeWidthStr;
3
4pub(crate) fn coerce_crlf(input: &str) -> Cow<str> {
9 let mut result = Cow::Borrowed(input);
10 let mut cursor: usize = 0;
11 for (idx, _) in input.match_indices('\n') {
12 if !(idx > 0 && input.as_bytes()[idx - 1] == b'\r') {
13 if let Cow::Borrowed(_) = result {
14 let mut owned = String::with_capacity(input.len() + 1);
16 owned.push_str(&input[cursor..idx]);
20 result = Cow::Owned(owned);
21 } else {
22 result += &input[cursor..idx];
23 }
24 result += "\r\n";
25 cursor = idx + 1;
27 }
28 }
29 if let Cow::Owned(_) = result {
30 result += &input[cursor..input.len()];
31 }
32 result
33}
34
35pub(crate) fn strip_ansi(string: &str) -> String {
39 String::from_utf8(strip_ansi_escapes::strip(string))
40 .map_err(|_| ())
41 .unwrap_or_else(|_| string.to_owned())
42}
43
44pub(crate) fn estimate_required_lines(input: &str, screen_width: u16) -> usize {
45 input.lines().fold(0, |acc, line| {
46 let wrap = estimate_single_line_wraps(line, screen_width);
47
48 acc + 1 + wrap
49 })
50}
51
52pub(crate) fn estimate_single_line_wraps(line: &str, terminal_columns: u16) -> usize {
58 let estimated_width = line_width(line);
59 let terminal_columns: usize = terminal_columns.into();
60
61 let estimated_line_count = (estimated_width + terminal_columns - 1) / terminal_columns;
63
64 estimated_line_count.saturating_sub(1)
66}
67
68pub(crate) fn line_width(line: &str) -> usize {
70 strip_ansi(line).width()
71}
72
73#[cfg(test)]
74mod test {
75 use super::*;
76 use pretty_assertions::assert_eq;
77 use rstest::rstest;
78
79 #[rstest]
80 #[case("sentence\nsentence", "sentence\r\nsentence")]
81 #[case("sentence\r\nsentence", "sentence\r\nsentence")]
82 #[case("sentence\nsentence\n", "sentence\r\nsentence\r\n")]
83 #[case("š\nsentence", "š\r\nsentence")]
84 #[case("sentence\nš", "sentence\r\nš")]
85 #[case("\n", "\r\n")]
86 #[case("", "")]
87 fn test_coerce_crlf(#[case] input: &str, #[case] expected: &str) {
88 let result = coerce_crlf(input);
89
90 assert_eq!(result, expected);
91
92 assert!(
93 input != expected || matches!(result, Cow::Borrowed(_)),
94 "Unnecessary allocation"
95 )
96 }
97}