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 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 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 pub fn span(&self) -> usize {
140 self.top_level_span.last().map_or(0, |span| span.full_span)
141 }
142}