1use std::borrow::Cow;
2use std::fmt::Write;
3
4pub trait StringExt {
5 fn expand_tabs_default(&self) -> Cow<str> {
6 self.expand_tabs(8)
7 }
8
9 fn expand_tabs(&self, tab_size: u16) -> Cow<str>;
10}
11
12impl<T> StringExt for T
13where
14 T: AsRef<str>,
15{
16 fn expand_tabs(&self, tab_size: u16) -> Cow<str> {
17 let s = self.as_ref();
18 let tab = '\t';
19 if s.contains(tab) {
20 let mut res = String::new();
21 let mut last_pos = 0;
22
23 while let Some(pos) = &s[last_pos..].find(tab) {
24 res.push_str(&s[last_pos..*pos + last_pos]);
25
26 let spaces_to_add = if tab_size != 0 {
27 tab_size - (*pos as u16 % tab_size)
28 } else {
29 0
30 };
31
32 if spaces_to_add != 0 {
33 let _ = write!(res, "{:width$}", "", width = spaces_to_add as usize);
34 }
35
36 last_pos += *pos + 1;
37 }
38
39 res.push_str(&s[last_pos..]);
40
41 Cow::from(res)
42 } else {
43 Cow::from(s)
44 }
45 }
46}
47
48#[cfg(test)]
49mod tests {
50 use super::StringExt;
51
52 #[test]
53 fn test_default_tab_size_works() {
54 assert_eq!("H e", "H\te".expand_tabs_default());
55 }
56
57 #[test]
58 fn test_tab_size_of_two_works() {
59 assert_eq!("H e", "H\te".expand_tabs(2));
60 }
61
62 #[test]
63 fn test_tab_size_of_four_works() {
64 assert_eq!("H e", "H\te".expand_tabs(4));
65 }
66
67 #[test]
68 fn test_tab_size_of_one_works() {
69 assert_eq!("H e", "H\te".expand_tabs(1));
70 }
71
72 #[test]
73 fn test_tab_size_of_zero_works() {
74 assert_eq!("He", "H\te".expand_tabs(0));
75 }
76
77 #[test]
78 fn test_tab_size_of_three_works() {
79 assert_eq!("H e", "H\te".expand_tabs(3));
80 }
81
82 #[test]
83 fn test_tab_size_of_nine_works() {
84 assert_eq!("H e", "H\te".expand_tabs(9));
85 }
86
87 #[test]
88 fn test_tab_at_position_larger_than_tab_size_works() {
89 assert_eq!("Hello World", "Hello\tWorld".expand_tabs(1));
90 assert_eq!("HelloWorld", "Hello\tWorld".expand_tabs(0));
91 assert_eq!("Hello World", "Hello\tWorld".expand_tabs(4));
92 }
93
94 #[test]
95 fn test_expand_multiple_tabs_works() {
96 assert_eq!("H ello World", "H\tello\tWorld".expand_tabs(1));
97 }
98}