Skip to content

Commit feae8cd

Browse files
lu-zeroshssoichiro
authored andcommitted
fix: Keep the previous tokens per-block
1 parent 80255c7 commit feae8cd

File tree

3 files changed

+109
-13
lines changed

3 files changed

+109
-13
lines changed

src/formatter.rs

+7-12
Original file line numberDiff line numberDiff line change
@@ -89,21 +89,19 @@ pub(crate) fn format(
8989
}
9090
TokenKind::ReservedTopLevel => {
9191
formatter.format_top_level_reserved_word(token, &mut formatted_query);
92-
formatter.previous_reserved_word = Some(token);
93-
formatter.previous_top_level_reserved_word = Some(token);
92+
formatter.indentation.set_previous_top_level(token);
9493
}
9594
TokenKind::ReservedTopLevelNoIndent => {
9695
formatter.format_top_level_reserved_word_no_indent(token, &mut formatted_query);
97-
formatter.previous_reserved_word = Some(token);
98-
formatter.previous_top_level_reserved_word = Some(token);
96+
formatter.indentation.set_previous_top_level(token);
9997
}
10098
TokenKind::ReservedNewline => {
10199
formatter.format_newline_reserved_word(token, &mut formatted_query);
102-
formatter.previous_reserved_word = Some(token);
100+
formatter.indentation.set_previous_reserved(token);
103101
}
104102
TokenKind::Reserved => {
105103
formatter.format_with_spaces(token, &mut formatted_query);
106-
formatter.previous_reserved_word = Some(token);
104+
formatter.indentation.set_previous_reserved(token);
107105
}
108106
TokenKind::OpenParen => {
109107
formatter.format_opening_parentheses(token, &mut formatted_query);
@@ -141,8 +139,6 @@ pub(crate) fn format(
141139

142140
struct Formatter<'a> {
143141
index: usize,
144-
previous_reserved_word: Option<&'a Token<'a>>,
145-
previous_top_level_reserved_word: Option<&'a Token<'a>>,
146142
tokens: &'a [Token<'a>],
147143
params: Params<'a>,
148144
options: &'a FormatOptions<'a>,
@@ -155,8 +151,6 @@ impl<'a> Formatter<'a> {
155151
fn new(tokens: &'a [Token<'a>], params: &'a QueryParams, options: &'a FormatOptions) -> Self {
156152
Formatter {
157153
index: 0,
158-
previous_reserved_word: None,
159-
previous_top_level_reserved_word: None,
160154
tokens,
161155
params: Params::new(params),
162156
options,
@@ -389,14 +383,15 @@ impl<'a> Formatter<'a> {
389383
return;
390384
}
391385
if self
392-
.previous_reserved_word
386+
.indentation
387+
.previous_reserved()
393388
.map(|word| word.value.to_lowercase() == "limit")
394389
.unwrap_or(false)
395390
{
396391
return;
397392
}
398393

399-
if matches!((self.previous_top_level_reserved_word, self.options.max_inline_arguments),
394+
if matches!((self.indentation.previous_top_level_reserved(), self.options.max_inline_arguments),
400395
(Some(word), Some(limit)) if ["select", "from"].contains(&word.value.to_lowercase().as_str()) &&
401396
limit > self.indentation.span())
402397
{

src/indentation.rs

+59-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1-
use crate::{FormatOptions, Indent, SpanInfo};
1+
use crate::{tokenizer::Token, FormatOptions, Indent, SpanInfo};
2+
3+
#[derive(Debug, Default)]
4+
struct PreviousTokens<'a> {
5+
top_level_reserved: Option<&'a Token<'a>>,
6+
reserved: Option<&'a Token<'a>>,
7+
}
28

39
pub(crate) struct Indentation<'a> {
410
options: &'a FormatOptions<'a>,
511
indent_types: Vec<IndentType>,
612
top_level_span: Vec<SpanInfo>,
13+
previous: Vec<PreviousTokens<'a>>,
714
}
815

916
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -18,6 +25,7 @@ impl<'a> Indentation<'a> {
1825
options,
1926
indent_types: Vec::new(),
2027
top_level_span: Vec::new(),
28+
previous: Vec::new(),
2129
}
2230
}
2331

@@ -37,18 +45,21 @@ impl<'a> Indentation<'a> {
3745

3846
pub fn increase_block_level(&mut self) {
3947
self.indent_types.push(IndentType::BlockLevel);
48+
self.previous.push(Default::default());
4049
}
4150

4251
pub fn decrease_top_level(&mut self) {
4352
if self.indent_types.last() == Some(&IndentType::TopLevel) {
4453
self.indent_types.pop();
4554
self.top_level_span.pop();
55+
self.previous.pop();
4656
}
4757
}
4858

4959
pub fn decrease_block_level(&mut self) {
5060
while !self.indent_types.is_empty() {
5161
let kind = self.indent_types.pop();
62+
self.previous.pop();
5263
if kind != Some(IndentType::TopLevel) {
5364
break;
5465
}
@@ -58,6 +69,53 @@ impl<'a> Indentation<'a> {
5869
pub fn reset_indentation(&mut self) {
5970
self.indent_types.clear();
6071
self.top_level_span.clear();
72+
self.previous.clear();
73+
}
74+
75+
pub fn set_previous_reserved(&mut self, token: &'a Token<'a>) {
76+
if let Some(previous) = self.previous.last_mut() {
77+
previous.reserved = Some(token);
78+
} else {
79+
self.previous.push(PreviousTokens {
80+
top_level_reserved: None,
81+
reserved: Some(token),
82+
});
83+
}
84+
}
85+
86+
pub fn set_previous_top_level(&mut self, token: &'a Token<'a>) {
87+
if let Some(previous) = self.previous.last_mut() {
88+
previous.top_level_reserved = Some(token);
89+
} else {
90+
self.previous.push(PreviousTokens {
91+
top_level_reserved: Some(token),
92+
reserved: Some(token),
93+
});
94+
}
95+
}
96+
97+
pub fn previous_reserved(&'a self) -> Option<&'a Token<'a>> {
98+
if let Some(PreviousTokens {
99+
reserved,
100+
top_level_reserved: _,
101+
}) = self.previous.last()
102+
{
103+
reserved.as_deref()
104+
} else {
105+
None
106+
}
107+
}
108+
109+
pub fn previous_top_level_reserved(&'a self) -> Option<&'a Token<'a>> {
110+
if let Some(PreviousTokens {
111+
top_level_reserved,
112+
reserved: _,
113+
}) = self.previous.last()
114+
{
115+
top_level_reserved.as_deref()
116+
} else {
117+
None
118+
}
61119
}
62120

63121
/// The full span between two top level tokens

src/lib.rs

+43
Original file line numberDiff line numberDiff line change
@@ -2053,6 +2053,49 @@ mod tests {
20532053
assert_eq!(format(input, &QueryParams::None, &options), expected);
20542054
}
20552055

2056+
#[test]
2057+
fn format_nested_select_nested_blocks() {
2058+
let input =
2059+
"WITH a AS ( SELECT a, b, c FROM t WHERE a > 100 ), aa AS ( SELECT field FROM table ),
2060+
bb AS ( SELECT count(*) as c FROM d ), cc AS ( INSERT INTO C (a, b, c, d) VALUES (1 ,2 ,3 ,4) )
2061+
SELECT b, field FROM a, aa;";
2062+
let max_line = 20;
2063+
let options = FormatOptions {
2064+
max_inline_block: max_line,
2065+
max_inline_arguments: Some(max_line),
2066+
max_inline_top_level: Some(max_line / 2),
2067+
joins_as_top_level: true,
2068+
..Default::default()
2069+
};
2070+
let expected = indoc! {
2071+
"
2072+
WITH
2073+
a AS (
2074+
SELECT a, b, c
2075+
FROM t
2076+
WHERE a > 100
2077+
),
2078+
aa AS (
2079+
SELECT field
2080+
FROM table
2081+
),
2082+
bb AS (
2083+
SELECT
2084+
count(*) as c
2085+
FROM d
2086+
),
2087+
cc AS (
2088+
INSERT INTO
2089+
C (a, b, c, d)
2090+
VALUES
2091+
(1, 2, 3, 4)
2092+
)
2093+
SELECT b, field
2094+
FROM a, aa;"
2095+
};
2096+
assert_eq!(format(input, &QueryParams::None, &options), expected);
2097+
}
2098+
20562099
#[test]
20572100
fn it_converts_keywords_nothing_when_no_option_passed_in() {
20582101
let input = "select distinct * frOM foo left join bar WHERe cola > 1 and colb = 3";

0 commit comments

Comments
 (0)