git_prole/
format_bulleted_list.rs1use std::fmt::Display;
2
3use itertools::Itertools;
4
5pub fn format_bulleted_list(items: impl IntoIterator<Item = impl Display>) -> String {
7 let mut items = items.into_iter().peekable();
8 if items.peek().is_none() {
9 String::new()
10 } else {
11 format!("• {}", items.join("\n• "))
13 }
14}
15
16pub fn format_bulleted_list_multiline(items: impl IntoIterator<Item = impl Display>) -> String {
19 format_bulleted_list(items.into_iter().map(|item| {
20 let item = item.to_string();
21 let mut lines = item.lines().peekable();
22 match lines.next() {
23 None => {
24 String::new()
26 }
27 Some(first) => {
28 if lines.peek().is_none() {
29 item
31 } else {
32 format!("{first}\n {}", lines.join("\n "))
34 }
35 }
36 }
37 }))
38}
39
40#[cfg(test)]
41mod tests {
42 use super::*;
43 use indoc::indoc;
44 use pretty_assertions::assert_eq;
45
46 #[test]
47 fn test_format_bulleted_list() {
48 assert_eq!(format_bulleted_list(Vec::<String>::new()), "");
49
50 assert_eq!(format_bulleted_list(["puppy"]), "• puppy");
51 assert_eq!(
52 format_bulleted_list(["puppy", "doggy"]),
53 indoc!(
54 "
55 • puppy
56 • doggy"
57 )
58 );
59 }
60
61 #[test]
62 fn test_format_bulleted_list_multiline() {
63 assert_eq!(format_bulleted_list_multiline(Vec::<String>::new()), "");
64
65 assert_eq!(format_bulleted_list_multiline(["puppy"]), "• puppy");
66 assert_eq!(
67 format_bulleted_list_multiline(["puppy", "doggy"]),
68 indoc!(
69 "
70 • puppy
71 • doggy"
72 )
73 );
74
75 assert_eq!(
76 format_bulleted_list_multiline([
77 "puppy\ndoggy",
78 "sammy\ngoldie",
79 &format_bulleted_list_multiline(["ears", "tail", "fetch!"])
80 ]),
81 indoc!(
82 "
83 • puppy
84 doggy
85 • sammy
86 goldie
87 • • ears
88 • tail
89 • fetch!"
90 )
91 );
92 }
93}