toml_parse/toml_fmt/
mod.rs1use std::fmt;
2
3pub(self) use super::tkn_tree::{self, walk::walk_tokens_non_ws, SyntaxNode, TomlKind};
4
5mod block;
6mod rules;
7mod ws;
8
9use block::Block;
10use rules::{
11 indent_after_comma, indent_after_open_brace, lf_after_heading, lf_after_table, none_around_dot,
12 space_around_eq, space_lf_after_array_open, space_lf_after_comma,
13 space_lf_after_inline_table_open, space_lf_before_array_close,
14 space_lf_before_inline_table_close,
15};
16use ws::WhiteSpace;
17
18type RuleFn = Box<dyn for<'a> Fn(&'a Block, &'a Block) -> Option<WhiteSpace>>;
19
20pub struct Formatter {
23 blocks: Vec<Block>,
24 rules: Vec<(TomlKind, RuleFn)>,
25 formatted: String,
26}
27
28impl Formatter {
29 pub fn new(root: &SyntaxNode) -> Formatter {
31 Self {
32 blocks: walk_tokens_non_ws(root).map(Block::new).collect(),
33 rules: formatter(),
34 formatted: String::default(),
35 }
36 }
37 pub fn format(mut self) -> Self {
39 let zipped = self.blocks.iter().zip(self.blocks.iter().skip(1));
40
41 for (l_blk, r_blk) in zipped {
42 let rules = self
43 .rules
44 .iter()
45 .filter(|(kind, _)| *kind == l_blk.kind())
46 .chain(self.rules.iter().filter(|(kind, _)| *kind == r_blk.kind()))
47 .map(|(_, func)| func);
48
49 for rule in rules {
50 if let Some(fixed) = rule(l_blk, r_blk) {
51 r_blk.whitespace.set(fixed);
52 }
53 }
54 }
55 self.formatted = self
56 .blocks
57 .clone()
58 .into_iter()
59 .map(|b| b.to_string())
60 .collect();
61
62 if !self.formatted.ends_with('\n') {
63 self.formatted.push('\n')
64 }
65 self
66 }
67}
68impl fmt::Debug for Formatter {
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 f.debug_struct("Formatter")
71 .field("blocks", &self.blocks)
72 .field(
73 "rules",
74 &self.rules.iter().map(|(k, _fn)| k).collect::<Vec<_>>(),
75 )
76 .field("formatted", &self.formatted)
77 .finish()
78 }
79}
80
81impl fmt::Display for Formatter {
82 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83 write!(f, "{}", self.formatted)
84 }
85}
86
87pub fn formatter() -> Vec<(TomlKind, RuleFn)> {
88 vec![
89 (TomlKind::OpenBrace, Box::new(lf_after_table) as RuleFn),
92 (TomlKind::CloseBrace, Box::new(lf_after_heading) as RuleFn),
94 (TomlKind::Dot, Box::new(none_around_dot) as RuleFn),
96 (TomlKind::Equal, Box::new(space_around_eq) as RuleFn),
98 (TomlKind::Comma, Box::new(space_lf_after_comma) as RuleFn),
100 (
102 TomlKind::OpenCurly,
103 Box::new(space_lf_after_inline_table_open) as RuleFn,
104 ),
105 (
107 TomlKind::CloseCurly,
108 Box::new(space_lf_before_inline_table_close) as RuleFn,
109 ),
110 (
112 TomlKind::OpenBrace,
113 Box::new(space_lf_after_array_open) as RuleFn,
114 ),
115 (
117 TomlKind::CloseBrace,
118 Box::new(space_lf_before_array_close) as RuleFn,
119 ),
120 (
123 TomlKind::OpenBrace,
124 Box::new(indent_after_open_brace) as RuleFn,
125 ),
126 (TomlKind::Comma, Box::new(indent_after_comma) as RuleFn),
128 ]
129}