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