sqlformat/
indentation.rs

1use crate::{tokenizer::Token, FormatOptions, Indent, SpanInfo};
2
3#[derive(Debug, Default)]
4struct PreviousTokens<'a> {
5    top_level_reserved: Option<(&'a Token<'a>, SpanInfo)>,
6    reserved: Option<&'a Token<'a>>,
7}
8
9pub(crate) struct Indentation<'a> {
10    options: &'a FormatOptions<'a>,
11    indent_types: Vec<IndentType>,
12    top_level_span: Vec<SpanInfo>,
13    previous: Vec<PreviousTokens<'a>>,
14}
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17enum IndentType {
18    Top,
19    Block,
20    FoldedBlock,
21}
22
23impl<'a> Indentation<'a> {
24    pub fn new(options: &'a FormatOptions) -> Self {
25        Indentation {
26            options,
27            indent_types: Vec::new(),
28            top_level_span: Vec::new(),
29            previous: Vec::new(),
30        }
31    }
32
33    pub fn get_indent(&self, folded: bool) -> String {
34        // TODO compute in place?
35        let level = self
36            .indent_types
37            .iter()
38            .copied()
39            .filter(|t| *t != IndentType::FoldedBlock)
40            .count()
41            - if folded { 1 } else { 0 };
42        match self.options.indent {
43            Indent::Spaces(num_spaces) => " ".repeat(num_spaces as usize).repeat(level),
44            Indent::Tabs => "\t".repeat(level),
45        }
46    }
47
48    pub fn increase_top_level(&mut self, span: SpanInfo) {
49        self.indent_types.push(IndentType::Top);
50        self.top_level_span.push(span);
51    }
52
53    pub fn increase_block_level(&mut self, folded: bool) {
54        self.indent_types.push(if folded {
55            IndentType::FoldedBlock
56        } else {
57            IndentType::Block
58        });
59        self.previous.push(Default::default());
60    }
61
62    pub fn decrease_top_level(&mut self) {
63        if self.indent_types.last() == Some(&IndentType::Top) {
64            self.indent_types.pop();
65            self.top_level_span.pop();
66            self.previous.pop();
67        }
68    }
69
70    /// Return true if the block was folded
71    pub fn decrease_block_level(&mut self) -> bool {
72        let mut folded = false;
73        while !self.indent_types.is_empty() {
74            let kind = self.indent_types.pop();
75            self.previous.pop();
76            folded = kind == Some(IndentType::FoldedBlock);
77            if kind != Some(IndentType::Top) {
78                break;
79            } else {
80                self.top_level_span.pop();
81            }
82        }
83        folded
84    }
85
86    pub fn reset_indentation(&mut self) {
87        self.indent_types.clear();
88        self.top_level_span.clear();
89        self.previous.clear();
90    }
91
92    pub fn set_previous_reserved(&mut self, token: &'a Token<'a>) {
93        if let Some(previous) = self.previous.last_mut() {
94            previous.reserved = Some(token);
95        } else {
96            self.previous.push(PreviousTokens {
97                top_level_reserved: None,
98                reserved: Some(token),
99            });
100        }
101    }
102
103    pub fn set_previous_top_level(&mut self, token: &'a Token<'a>, span_info: SpanInfo) {
104        if let Some(previous) = self.previous.last_mut() {
105            previous.top_level_reserved = Some((token, span_info));
106        } else {
107            self.previous.push(PreviousTokens {
108                top_level_reserved: Some((token, span_info)),
109                reserved: Some(token),
110            });
111        }
112    }
113
114    pub fn previous_reserved(&'a self) -> Option<&'a Token<'a>> {
115        if let Some(PreviousTokens {
116            reserved,
117            top_level_reserved: _,
118        }) = self.previous.last()
119        {
120            reserved.as_deref()
121        } else {
122            None
123        }
124    }
125
126    pub fn previous_top_level_reserved(&'a self) -> Option<(&'a Token<'a>, &'a SpanInfo)> {
127        if let Some(PreviousTokens {
128            top_level_reserved,
129            reserved: _,
130        }) = self.previous.last()
131        {
132            top_level_reserved.as_ref().map(|&(t, ref s)| (t, s))
133        } else {
134            None
135        }
136    }
137
138    /// The full span between two top level tokens
139    pub fn span(&self) -> usize {
140        self.top_level_span.last().map_or(0, |span| span.full_span)
141    }
142}