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