libgir/writer/
primitives.rs

1use super::defines::*;
2
3// TODO: convert to macro with usage
4// format!(indent!(5, "format:{}"), 6)
5pub fn tabs(num: usize) -> String {
6    format!("{:1$}", "", TAB_SIZE * num)
7}
8
9pub fn format_block(prefix: &str, suffix: &str, body: &[String]) -> Vec<String> {
10    let mut v = Vec::new();
11    if !prefix.is_empty() {
12        v.push(prefix.into());
13    }
14    for s in body.iter() {
15        let s = format!("{TAB}{s}");
16        v.push(s);
17    }
18    if !suffix.is_empty() {
19        v.push(suffix.into());
20    }
21    v
22}
23
24pub fn format_block_one_line(
25    prefix: &str,
26    suffix: &str,
27    body: &[String],
28    outer_separator: &str,
29    inner_separator: &str,
30) -> String {
31    let mut s = format!("{prefix}{outer_separator}");
32    let mut first = true;
33    for s_ in body {
34        if first {
35            first = false;
36            s = s + s_;
37        } else {
38            s = s + inner_separator + s_;
39        }
40    }
41    s + outer_separator + suffix
42}
43
44pub fn format_block_smart(
45    prefix: &str,
46    suffix: &str,
47    body: &[String],
48    outer_separator: &str,
49    inner_separator: &str,
50) -> Vec<String> {
51    format_block_smart_width(
52        prefix,
53        suffix,
54        body,
55        outer_separator,
56        inner_separator,
57        MAX_TEXT_WIDTH,
58    )
59}
60
61pub fn format_block_smart_width(
62    prefix: &str,
63    suffix: &str,
64    body: &[String],
65    outer_separator: &str,
66    inner_separator: &str,
67    max_width: usize,
68) -> Vec<String> {
69    let outer_len = prefix.len() + suffix.len() + 2 * outer_separator.len();
70    let mut inner_len = inner_separator.len() * (body.len() - 1);
71    // TODO: change to sum()
72    for s in body {
73        inner_len += s.len();
74    }
75    if (outer_len + inner_len) > max_width {
76        format_block(prefix, suffix, body)
77    } else {
78        let s = format_block_one_line(prefix, suffix, body, outer_separator, inner_separator);
79        vec![s]
80    }
81}
82
83pub fn comment_block(body: &[String]) -> Vec<String> {
84    body.iter().map(|s| format!("//{s}")).collect()
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90
91    #[test]
92    fn test_tabs() {
93        assert_eq!(tabs(0), "");
94        assert_eq!(tabs(1), TAB);
95        assert_eq!(tabs(2), format!("{TAB}{TAB}"));
96    }
97
98    #[test]
99    fn test_format_block() {
100        let body = vec!["0 => 1,".into(), "1 => 0,".into()];
101        let actual = format_block("match a {", "}", &body);
102        let expected = ["match a {", "    0 => 1,", "    1 => 0,", "}"];
103        assert_eq!(actual, expected);
104    }
105
106    #[test]
107    fn test_format_block_smart_width_one_line_outer_separator() {
108        let body = vec!["f()".into()];
109        let actual = format_block_smart_width("unsafe {", "}", &body, " ", "", 14);
110        let expected = ["unsafe { f() }"];
111        assert_eq!(actual, expected);
112    }
113
114    #[test]
115    fn test_format_block_smart_width_many_lines_outer_separator() {
116        let body = vec!["f()".into()];
117        let actual = format_block_smart_width("unsafe {", "}", &body, " ", "", 13);
118        let expected = ["unsafe {", "    f()", "}"];
119        assert_eq!(actual, expected);
120    }
121
122    #[test]
123    fn test_format_block_smart_one_line_inner_separator() {
124        let body = vec!["a: &str".into(), "b: &str".into()];
125        let actual = format_block_smart("f(", ")", &body, "", ", ");
126        let expected = ["f(a: &str, b: &str)"];
127        assert_eq!(actual, expected);
128    }
129
130    #[test]
131    fn test_comment_block() {
132        let body = vec!["f(a,".into(), "  b)".into()];
133        let actual = comment_block(&body);
134        let expected = ["//f(a,", "//  b)"];
135        assert_eq!(actual, expected);
136    }
137}