arc_fmt/
formatter.rs

1use arc_parser::{ArcParser, Rule};
2use pest::iterators::Pair;
3use pest::Parser;
4use std::fs::{read_to_string, File};
5use std::io::Write;
6use textwrap::indent;
7
8macro_rules! debug_cases {
9    ($i:ident) => {{
10        println!("Rule::{:?}=>continue,", $i.as_rule());
11        println!("Span: {:?}", $i.as_span());
12        println!("Text: {}", $i.as_str());
13        unreachable!();
14    }};
15}
16
17#[derive(Debug)]
18pub struct Settings {
19    pub arc_indent: usize,
20    pub arc_symbol_set: String,
21    pub arc_dict_separator: String,
22    pub arc_list_separator: String,
23    pub arc_list_max_length: usize,
24}
25
26impl Settings {
27    pub fn format_file(&self, path_from: &str, path_to: &str) -> Result<(), std::io::Error> {
28        let r = read_to_string(path_from)?;
29        let s = self.format(&r);
30        let mut file = File::create(path_to)?;
31        file.write_all(s.as_bytes())?;
32        return Ok(());
33    }
34    pub fn format(&self, text: &str) -> String {
35        let pairs = ArcParser::parse(Rule::program, text).unwrap_or_else(|e| panic!("{}", e));
36        let mut code = String::new();
37        for pair in pairs {
38            match pair.as_rule() {
39                Rule::EOI => continue,
40                Rule::WHITESPACE => continue,
41                Rule::dict_literal => {
42                    return self.format_json_dict(pair);
43                }
44                _ => debug_cases!(pair),
45            };
46        }
47        //        println!("{:#?}", codes);
48        //        unreachable!();
49        return code;
50    }
51    fn format_json_dict(&self, pairs: Pair<Rule>) -> String {
52        let mut codes = vec![];
53        for pair in pairs.into_inner() {
54            match pair.as_rule() {
55                Rule::WHITESPACE => continue,
56                Rule::SEPARATOR => continue,
57                Rule::dict_pair => codes.push(self.format_dict_pair(pair)),
58                _ => debug_cases!(pair),
59            };
60        }
61        return codes.join("\n");
62    }
63    fn format_dict_literal(&self, pairs: Pair<Rule>) -> String {
64        let mut max = 0;
65        let mut codes = vec![];
66        for pair in pairs.into_inner() {
67            match pair.as_rule() {
68                Rule::WHITESPACE => continue,
69                Rule::SEPARATOR => continue,
70                Rule::dict_empty => return String::from("{}"),
71                Rule::dict_pair => {
72                    let s = self.format_dict_pair(pair);
73                    if s.lines().count() > max {
74                        max = s.lines().count()
75                    }
76                    codes.push(s)
77                }
78                _ => debug_cases!(pair),
79            };
80        }
81        let i = &" ".repeat(self.arc_indent);
82
83        if codes.len() == 1 {
84            if max <= 1 {
85                format!("{{{}}}", codes[0])
86            } else {
87                println!("{:#?}", codes);
88                unreachable!();
89            }
90        } else {
91            let s = match self.arc_dict_separator.as_str() {
92                "," => ",",
93                ";" => ";",
94                _ => "",
95            };
96            let mut code = String::new();
97            for c in &codes {
98                code.push_str(c);
99                code.push_str(s);
100                code.push('\n')
101            }
102            format!("{{\n{}}}", indent(&code, i))
103        }
104    }
105    fn format_list_literal(&self, pairs: Pair<Rule>) -> String {
106        let mut lens = 0;
107        let mut max = 0;
108        let mut codes = vec![];
109        for pair in pairs.into_inner() {
110            match pair.as_rule() {
111                Rule::WHITESPACE => continue,
112                Rule::SEPARATOR => continue,
113                Rule::list_empty => return String::from("[]"),
114                Rule::Value => {
115                    let s = self.format_value(pair);
116                    lens += s.chars().count();
117                    if s.lines().count() > max {
118                        max = s.lines().count()
119                    }
120                    codes.push(s)
121                }
122                _ => debug_cases!(pair),
123            };
124        }
125        let i = &" ".repeat(self.arc_indent);
126        if codes.len() == 1 {
127            if max <= 1 {
128                format!("[{}]", codes[0])
129            } else {
130                format!("[\n{}]", indent(&codes[0], i))
131            }
132        } else if lens <= self.arc_list_max_length {
133            format!("[{}]", codes.join(", "))
134        } else {
135            let s = match self.arc_list_separator.as_str() {
136                "," => ",",
137                ";" => ";",
138                _ => "",
139            };
140            let mut code = String::new();
141            for c in &codes {
142                code.push_str(c);
143                code.push_str(s);
144                code.push('\n')
145            }
146            format!("[\n{}]", indent(&code, i))
147        }
148    }
149    fn format_dict_pair(&self, pairs: Pair<Rule>) -> String {
150        let mut key = String::new();
151        let mut value = String::new();
152        for pair in pairs.into_inner() {
153            match pair.as_rule() {
154                Rule::WHITESPACE => continue,
155                Rule::Set => continue,
156                Rule::NameSpace => {
157                    key = self.format_name_space(pair);
158                }
159                Rule::Value => {
160                    value = self.format_value(pair);
161                }
162                _ => debug_cases!(pair),
163            };
164        }
165        match self.arc_symbol_set.as_str() {
166            "=" => format!("{} = {}", key, value),
167            _ => format!("{}: {}", key, value),
168        }
169    }
170    fn format_name_space(&self, pairs: Pair<Rule>) -> String {
171        let mut codes = vec![];
172        for pair in pairs.into_inner() {
173            match pair.as_rule() {
174                Rule::Key => {
175                    codes.push(self.format_key(pair));
176                }
177                _ => debug_cases!(pair),
178            };
179        }
180        return codes.join(".");
181    }
182    fn format_key(&self, pairs: Pair<Rule>) -> String {
183        for pair in pairs.into_inner() {
184            match pair.as_rule() {
185                Rule::StringNormal => {
186                    let s = pair.as_str();
187                    //FIXME
188                    return if s.contains('.') {
189                        pair.as_str().to_string()
190                    } else {
191                        s.trim_matches('"').to_string()
192                    };
193                }
194                _ => debug_cases!(pair),
195            };
196        }
197        return String::new();
198    }
199    fn format_value(&self, pairs: Pair<Rule>) -> String {
200        let mut code = String::new();
201        for pair in pairs.into_inner() {
202            match pair.as_rule() {
203                Rule::String => {
204                    return self.format_string(pair);
205                }
206                Rule::dict_literal => {
207                    return self.format_dict_literal(pair);
208                }
209                Rule::list_literal => {
210                    return self.format_list_literal(pair);
211                }
212                Rule::Number => {
213                    return self.format_number(pair);
214                }
215                Rule::Boolean => {
216                    return pair.as_str().to_string();
217                }
218                _ => debug_cases!(pair),
219            };
220        }
221        return code;
222    }
223    fn format_string(&self, pairs: Pair<Rule>) -> String {
224        let mut code = String::new();
225        let mut text = String::new();
226        for pair in pairs.into_inner() {
227            match pair.as_rule() {
228                Rule::StringNormal => {
229                    text = pair.as_str().to_string();
230                    return text;
231                }
232                _ => debug_cases!(pair),
233            };
234        }
235        return code;
236    }
237    fn format_number(&self, pairs: Pair<Rule>) -> String {
238        let mut code = String::new();
239        let mut text = String::new();
240        for pair in pairs.into_inner() {
241            match pair.as_rule() {
242                //FIXME
243                Rule::SignedNumber => continue,
244                _ => debug_cases!(pair),
245            };
246        }
247        return code;
248    }
249}