1use std::default::Default;
3
4use crate::common::Directive;
5
6
7#[derive(Debug, PartialEq)]
8pub(crate) struct Formatter<'a> {
9 buf: String,
10 style: &'a Style,
11 indent: u32,
12}
13
14#[derive(Debug, PartialEq, Clone)]
19pub struct Style {
20 indent: u32,
21 multiline_arguments: bool,
22}
23
24impl Default for Style {
25 fn default() -> Style {
26 Style {
27 indent: 2,
28 multiline_arguments: false,
29 }
30 }
31}
32
33impl Style {
34 pub fn indent(&mut self, indent: u32) -> &mut Self {
36 self.indent = indent;
37 self
38 }
39
40 pub fn multiline_arguments(&mut self, multiline_arguments: bool) -> &mut Self {
42 self.multiline_arguments = multiline_arguments;
43 self
44 }
45}
46
47pub(crate) trait Displayable {
48 fn display(&self, f: &mut Formatter);
49}
50
51impl<'a> Formatter<'a> {
52 pub fn new(style: &Style) -> Formatter {
53 Formatter {
54 buf: String::with_capacity(1024),
55 style,
56 indent: 0,
57 }
58 }
59
60 pub fn indent(&mut self) {
61 for _ in 0..self.indent {
62 self.buf.push(' ');
63 }
64 }
65
66 pub fn endline(&mut self) {
67 self.buf.push('\n');
68 }
69
70 pub fn start_argument_block(&mut self, open_char: char) {
71 self.buf.push(open_char);
72 if self.style.multiline_arguments {
73 self.inc_indent();
74 }
75 }
76
77 pub fn end_argument_block(&mut self, close_char: char) {
78 if self.style.multiline_arguments {
79 self.endline();
80 self.dec_indent();
81 self.indent();
82 }
83 self.buf.push(close_char);
84 }
85
86 pub fn start_argument(&mut self) {
87 if self.style.multiline_arguments {
88 self.endline();
89 self.indent();
90 }
91 }
92
93 pub fn deliniate_argument(&mut self) {
94 self.buf.push(',');
95 if !self.style.multiline_arguments {
96 self.buf.push(' ');
97 }
98 }
99
100 pub fn start_block(&mut self) {
101 self.buf.push('{');
102 self.endline();
103 self.inc_indent();
104 }
105
106 pub fn end_block(&mut self) {
107 self.dec_indent();
108 self.indent();
109 self.buf.push('}');
110 self.endline();
111 }
112
113 pub fn margin(&mut self) {
114 if !self.buf.is_empty() {
115 self.buf.push('\n');
116 }
117 }
118
119 pub fn write(&mut self, s: &str) {
120 self.buf.push_str(s);
121 }
122
123 pub fn into_string(self) -> String {
124 self.buf
125 }
126
127 pub fn write_quoted(&mut self, s: &str) {
128 let mut has_newline = false;
129 let mut has_nonprintable = false;
130 for c in s.chars() {
131 match c {
132 '\n' => has_newline = true,
133 '\r' | '\t' | '\u{0020}'..='\u{FFFF}' => {}
134 _ => has_nonprintable = true,
135 }
136 }
137 if !has_newline || has_nonprintable {
138 use std::fmt::Write;
139 self.buf.push('"');
140 for c in s.chars() {
141 match c {
142 '\r' => self.write(r"\r"),
143 '\n' => self.write(r"\n"),
144 '\t' => self.write(r"\t"),
145 '"' => self.write("\\\""),
146 '\\' => self.write(r"\\"),
147 '\u{0020}'..='\u{FFFF}' => self.buf.push(c),
148 _ => write!(&mut self.buf, "\\u{:04}", c as u32).unwrap(),
149 }
150 }
151 self.buf.push('"');
152 } else {
153 self.buf.push_str(r#"""""#);
154 self.endline();
155 self.indent += self.style.indent;
156 for line in s.lines() {
157 if !line.trim().is_empty() {
158 self.indent();
159 self.write(&line.replace(r#"""""#, r#"\""""#));
160 }
161 self.endline();
162 }
163 self.indent -= self.style.indent;
164 self.indent();
165 self.buf.push_str(r#"""""#);
166 }
167 }
168
169 fn inc_indent(&mut self) {
170 self.indent += self.style.indent;
171 }
172
173 fn dec_indent(&mut self) {
174 self.indent = self.indent.checked_sub(self.style.indent)
175 .expect("negative indent");
176 }
177}
178
179pub(crate) fn format_directives<'a, T>(dirs: &[Directive<'a, T>], f: &mut Formatter)
180 where T: crate::common::Text<'a>,
181{
182 for dir in dirs {
183 f.write(" ");
184 dir.display(f);
185 }
186}
187
188macro_rules! impl_display {
189 ($( $typ: ident, )+) => {
190 $(
191 impl fmt::Display for $typ {
192 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
193 f.write_str(&to_string(self))
194 }
195 }
196 )+
197 };
198
199 ('a $($typ: ident, )+) => {
200 $(
201 impl<'a, T> fmt::Display for $typ<'a, T>
202 where T: Text<'a>,
203 {
204 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
205 f.write_str(&to_string(self))
206 }
207 }
208 )+
209 };
210}