1use std::cmp::max;
7
8#[derive(Debug)]
9pub struct CodeBuilder {
10 code: String,
11 indent_level: i32,
12 indent_size: i32,
13}
14
15impl CodeBuilder {
16 pub fn add_line<S>(&mut self, line: S)
18 where S: AsRef<str>
19 {
20 let line = line.as_ref().trim();
21 let indent_change = (line.matches("{").count() as i32) - (line.matches("}").count() as i32);
22 let new_indent_level = max(0, self.indent_level + indent_change);
23
24 let this_line_indent = if line.starts_with("}") || line.ends_with(":") {
27 self.indent_level - 1
28 } else {
29 self.indent_level
30 };
31
32 for _ in 0..this_line_indent * self.indent_size {
34 self.code.push(' ');
35 }
36 self.code.push_str(line);
37 self.code.push_str("\n");
38
39 self.indent_level = new_indent_level;
40 }
41
42 pub fn add<S>(&mut self, code: S)
44 where S: AsRef<str>
45 {
46 for l in code.as_ref().lines() {
47 self.add_line(l);
48 }
49 }
50
51 pub fn add_code(&mut self, builder: &CodeBuilder) {
53 self.code.push_str(builder.code.as_ref());
54 }
55
56 pub fn result(&self) -> &str {
58 self.code.as_str()
59 }
60
61 pub fn new() -> CodeBuilder {
63 CodeBuilder::with_indent_size(2)
64 }
65
66 pub fn with_indent_size(indent_size: i32) -> CodeBuilder {
68 CodeBuilder {
69 code: String::new(),
70 indent_level: 0,
71 indent_size: indent_size,
72 }
73 }
74
75 pub fn format<S>(indent_size: i32, code: S) -> String
77 where S: AsRef<str>
78 {
79 let mut c = CodeBuilder::with_indent_size(indent_size);
80 c.add(code);
81 c.code
82 }
83}
84
85#[test]
86fn code_builder_basic() {
87 let input = "
88class A {
89blahblah;
90}";
91 let expected = "
92class A {
93 blahblah;
94}
95";
96 assert_eq!(CodeBuilder::format(2, input), expected);
97
98 let input = "
99class A {
100if (c) {
101duh
102 }
103}";
104 let expected = "
105class A {
106 if (c) {
107 duh
108 }
109}
110";
111 assert_eq!(CodeBuilder::format(2, input), expected);
112
113 let input = "
114class A {
115if (c) { duh }
116}";
117 let expected = "
118class A {
119 if (c) { duh }
120}
121";
122 assert_eq!(CodeBuilder::format(2, input), expected);
123
124 let input = "
125class A {
126if (c) { duh }
127myLabel:
128blah
129}";
130 let expected = "
131class A {
132 if (c) { duh }
133myLabel:
134 blah
135}
136";
137 assert_eq!(CodeBuilder::format(2, input), expected);
138}