1use regex::Regex;
17
18#[derive(Debug)]
34pub struct Config<'a> {
35 pub delimiter: &'a str,
37 pub ignore_first_n: usize,
39 pub ignore_last_n: usize,
41 pub ignore_regex: Option<Regex>,
43}
44
45impl<'a> Default for Config<'a> {
46 fn default() -> Self {
47 Config {
48 delimiter: "/",
49 ignore_first_n: 0,
50 ignore_last_n: 1,
51 ignore_regex: None,
52 }
53 }
54}
55
56pub fn shorten_line(cfg: &Config, line: &str) -> Vec<String> {
86 let num_elements = line.matches(cfg.delimiter).count();
87 let line_iter = line.split(cfg.delimiter);
88 let mut shortened_elements: Vec<String> = Vec::new();
89
90 for (i, component) in line_iter.enumerate() {
91 if i < cfg.ignore_first_n
92 || (cfg.ignore_last_n > num_elements || i > num_elements - cfg.ignore_last_n)
93 {
94 shortened_elements.push(component.to_string());
95 continue;
96 }
97
98 let shorten_element = match cfg.ignore_regex {
99 Some(ref r) => match r.is_match(component) {
100 true => false,
101 false => true,
102 },
103 None => true,
104 };
105
106 let shortened_element = match shorten_element {
107 true => match component.chars().next() {
108 Some(c) => c.to_string(),
109 None => String::new(),
110 },
111 false => component.to_string(),
112 };
113
114 shortened_elements.push(shortened_element);
115 }
116 shortened_elements
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122
123 #[test]
124 fn shorten_line_works_with_default_config() {
125 let line = "module/submodule/service/lib.rs";
127
128 let result = shorten_line(&Config::default(), line);
130
131 let expected = vec!["m", "s", "s", "lib.rs"];
133 assert_eq!(result, expected);
134 }
135
136 #[test]
137 fn shorten_line_works_with_a_starting_delimiter() {
138 let line = "/module/submodule/service/lib.rs";
140
141 let result = shorten_line(&Config::default(), line);
143
144 let expected = vec!["", "m", "s", "s", "lib.rs"];
146 assert_eq!(result, expected);
147 }
148
149 #[test]
150 fn shorten_line_respects_delimiter() {
151 let line = "module,submodule,service,lib.rs";
153 let cfg = Config {
154 delimiter: ",",
155 ..Config::default()
156 };
157
158 let result = shorten_line(&cfg, line);
160
161 let expected = vec!["m", "s", "s", "lib.rs"];
163 assert_eq!(result, expected);
164 }
165
166 #[test]
167 fn shorten_line_ignores_components_matching_regex() {
168 let line = "module/submodule/service/lib.rs";
170 let re = Regex::new("module").unwrap();
171 let cfg = Config {
172 ignore_regex: Some(re),
173 ..Config::default()
174 };
175
176 let result = shorten_line(&cfg, line);
178
179 let expected = vec!["module", "submodule", "s", "lib.rs"];
181 assert_eq!(result, expected);
182 }
183
184 #[test]
185 fn shorten_line_ignores_last_n_components() {
186 let line = "module/submodule/service/lib.rs";
188 let cfg = Config {
189 ignore_last_n: 3,
190 ..Config::default()
191 };
192
193 let result = shorten_line(&cfg, line);
195
196 let expected = vec!["m", "submodule", "service", "lib.rs"];
198 assert_eq!(result, expected);
199 }
200
201 #[test]
202 fn shorten_line_works_when_ignore_last_n_is_greater_than_num_components() {
203 let line = "module/submodule/service/lib.rs";
205 let cfg = Config {
206 ignore_last_n: 6,
207 ..Config::default()
208 };
209
210 let result = shorten_line(&cfg, line);
212
213 let expected = vec!["module", "submodule", "service", "lib.rs"];
215 assert_eq!(result, expected);
216 }
217
218 #[test]
219 fn shorten_line_ignores_first_n_components() {
220 let line = "module/submodule/service/lib.rs";
222 let cfg = Config {
223 ignore_first_n: 1,
224 ..Config::default()
225 };
226
227 let result = shorten_line(&cfg, line);
229
230 let expected = vec!["module", "s", "s", "lib.rs"];
232 assert_eq!(result, expected);
233 }
234
235 #[test]
236 fn shorten_line_works_when_ignore_first_n_is_greater_than_num_components() {
237 let line = "module/submodule/service/lib.rs";
239 let cfg = Config {
240 ignore_first_n: 6,
241 ..Config::default()
242 };
243
244 let result = shorten_line(&cfg, line);
246
247 let expected = vec!["module", "submodule", "service", "lib.rs"];
249 assert_eq!(result, expected);
250 }
251
252 #[test]
253 fn shorten_line_ignores_first_n_and_last_m_components() {
254 let line = "module/submodule/service/lib.rs";
256 let cfg = Config {
257 ignore_first_n: 1,
258 ignore_last_n: 2,
259 ..Config::default()
260 };
261
262 let result = shorten_line(&cfg, line);
264
265 let expected = vec!["module", "s", "service", "lib.rs"];
267 assert_eq!(result, expected);
268 }
269
270 #[test]
271 fn shorten_line_works_when_a_component_is_empty() {
272 let line = "module//service/lib.rs";
274 let result = shorten_line(&Config::default(), line);
275
276 let expected = vec!["m", "", "s", "lib.rs"];
278 assert_eq!(result, expected);
279 }
280
281 #[test]
282 fn shorten_line_works_with_non_default_config() {
283 let line = "/path/to/a/module/submodule/service/lib.rs";
285 let re = Regex::new("module").unwrap();
286 let cfg = Config {
287 ignore_first_n: 2,
288 ignore_last_n: 2,
289 ignore_regex: Some(re),
290 ..Config::default()
291 };
292
293 let result = shorten_line(&cfg, line);
295
296 let expected = vec![
298 "",
299 "path",
300 "t",
301 "a",
302 "module",
303 "submodule",
304 "service",
305 "lib.rs",
306 ];
307 assert_eq!(result, expected);
308 }
309
310 #[test]
311 fn shorten_line_works_with_line_that_is_not_delimited() {
312 let line = "/path/to/a/module/submodule/service/lib.rs";
314 let cfg = Config {
315 delimiter: ":",
316 ..Config::default()
317 };
318
319 let result = shorten_line(&cfg, line);
321
322 let expected = vec!["/path/to/a/module/submodule/service/lib.rs"];
324 assert_eq!(result, expected);
325 }
326
327 #[test]
328 fn shorten_line_works_with_empty_delimiter() {
329 let line = "/path/to/lib.rs";
331 let cfg = Config {
332 delimiter: "",
333 ..Config::default()
334 };
335
336 let result = shorten_line(&cfg, line);
338
339 let expected = vec![
341 "", "/", "p", "a", "t", "h", "/", "t", "o", "/", "l", "i", "b", ".", "r", "s", "",
342 ];
343 assert_eq!(result, expected);
344 }
345
346 #[test]
347 fn shorten_line_works_line_with_delimiters_only() {
348 let line = "/////";
350
351 let result = shorten_line(&Config::default(), line);
353
354 let expected = vec!["", "", "", "", "", ""];
356 assert_eq!(result, expected);
357 }
358}