Skip to content

Commit dfa1454

Browse files
committed
feat: Correctly inline opening parentheses
1 parent d20763c commit dfa1454

File tree

4 files changed

+177
-63
lines changed

4 files changed

+177
-63
lines changed

src/formatter.rs

Lines changed: 113 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -87,16 +87,19 @@ pub(crate) fn format(
8787
formatter.format_block_comment(token, &mut formatted_query);
8888
}
8989
TokenKind::ReservedTopLevel => {
90-
formatter.format_top_level_reserved_word(token, &mut formatted_query);
91-
formatter.set_top_level_span(token);
90+
let span_info =
91+
formatter.format_top_level_reserved_word(token, &mut formatted_query);
92+
formatter.set_top_level_span(token, span_info);
9293
}
9394
TokenKind::ReservedTopLevelNoIndent => {
94-
formatter.format_top_level_reserved_word_no_indent(token, &mut formatted_query);
95-
formatter.set_top_level_span(token);
95+
let span_info =
96+
formatter.format_top_level_reserved_word_no_indent(token, &mut formatted_query);
97+
formatter.set_top_level_span(token, span_info);
9698
}
9799
TokenKind::ReservedNewlineAfter => {
98-
formatter.format_newline_after_reserved_word(token, &mut formatted_query);
99-
formatter.set_top_level_span(token);
100+
let span_info =
101+
formatter.format_newline_after_reserved_word(token, &mut formatted_query);
102+
formatter.set_top_level_span(token, span_info);
100103
}
101104
TokenKind::ReservedNewline => {
102105
formatter.format_newline_reserved_word(token, &mut formatted_query);
@@ -167,8 +170,7 @@ impl<'a> Formatter<'a> {
167170
}
168171
}
169172

170-
fn set_top_level_span(&mut self, token: &'a Token<'a>) {
171-
let span_info = self.top_level_tokens_info();
173+
fn set_top_level_span(&mut self, token: &'a Token<'a>, span_info: SpanInfo) {
172174
self.indentation.set_previous_top_level(token, span_info);
173175
}
174176

@@ -207,57 +209,54 @@ impl<'a> Formatter<'a> {
207209
self.add_new_line(query);
208210
}
209211

210-
// if we are inside an inline block we decide our behaviour as if were inline
211-
fn top_level_behavior(&self, span_info: &SpanInfo) -> (bool, bool) {
212-
let span_len = span_info.full_span;
213-
let block_len = self.inline_block.cur_len();
214-
if block_len > 0 {
215-
let limit = self.options.max_inline_top_level.unwrap_or(0);
216-
(limit < block_len, limit < span_len)
217-
} else {
218-
(
219-
true,
220-
self.options
221-
.max_inline_top_level
222-
.is_none_or(|limit| limit < span_len),
223-
)
224-
}
225-
}
226-
227-
fn format_top_level_reserved_word(&mut self, token: &Token<'_>, query: &mut String) {
212+
fn format_top_level_reserved_word(
213+
&mut self,
214+
token: &Token<'_>,
215+
query: &mut String,
216+
) -> SpanInfo {
228217
let span_info = self.top_level_tokens_info();
229-
let (newline_before, newline_after) = self.top_level_behavior(&span_info);
230218

231-
if newline_before {
219+
if span_info.newline_before {
232220
self.indentation.decrease_top_level();
233221
self.add_new_line(query);
234222
}
235223
query.push_str(&self.equalize_whitespace(&self.format_reserved_word(token.value)));
236-
if newline_after && token.alias != "CREATE" {
237-
self.indentation.increase_top_level(span_info);
224+
if span_info.newline_after && token.alias != "CREATE" {
225+
self.indentation.increase_top_level(span_info.clone());
238226
self.add_new_line(query);
239227
} else {
240228
query.push(' ');
241229
}
230+
231+
span_info
242232
}
243233

244-
fn format_top_level_reserved_word_no_indent(&mut self, token: &Token<'_>, query: &mut String) {
234+
fn format_top_level_reserved_word_no_indent(
235+
&mut self,
236+
token: &Token<'_>,
237+
query: &mut String,
238+
) -> SpanInfo {
245239
let span_info = self.top_level_tokens_info();
246-
let (newline_before, newline_after) = self.top_level_behavior(&span_info);
247240

248-
if newline_before {
241+
if span_info.newline_before {
249242
self.indentation.decrease_top_level();
250243
self.add_new_line(query);
251244
}
252245
query.push_str(&self.equalize_whitespace(&self.format_reserved_word(token.value)));
253-
if newline_after {
246+
if span_info.newline_after {
254247
self.add_new_line(query);
255248
} else {
256249
query.push(' ');
257250
}
251+
252+
span_info
258253
}
259254

260-
fn format_newline_after_reserved_word(&mut self, token: &Token<'_>, query: &mut String) {
255+
fn format_newline_after_reserved_word(
256+
&mut self,
257+
token: &Token<'_>,
258+
query: &mut String,
259+
) -> SpanInfo {
261260
let span_info = self.top_level_tokens_info();
262261

263262
let newline_before = match (
@@ -278,8 +277,10 @@ impl<'a> Formatter<'a> {
278277

279278
query.push_str(&self.equalize_whitespace(&self.format_reserved_word(token.value)));
280279

281-
self.indentation.increase_top_level(span_info);
280+
self.indentation.increase_top_level(span_info.clone());
282281
self.add_new_line(query);
282+
283+
span_info
283284
}
284285

285286
fn format_newline_reserved_word(&mut self, token: &Token<'_>, query: &mut String) {
@@ -318,6 +319,19 @@ impl<'a> Formatter<'a> {
318319
TokenKind::LineComment,
319320
];
320321

322+
let inlined = self.inline_block.begin_if_possible(self.tokens, self.index);
323+
let fold_in_top_level = !inlined
324+
&& self.options.max_inline_top_level.is_some()
325+
&& self
326+
.previous_non_whitespace_token(1)
327+
.is_some_and(|t| t.kind == TokenKind::ReservedTopLevel)
328+
&& self
329+
.indentation
330+
.previous_top_level_reserved()
331+
.is_some_and(|(_, span)| {
332+
span.blocks == 1 && span.newline_after && span.arguments == 1
333+
});
334+
321335
// Take out the preceding space unless there was whitespace there in the original query
322336
// or another opening parens or line comment
323337
let previous_token = self.previous_token(1);
@@ -348,11 +362,14 @@ impl<'a> Formatter<'a> {
348362
_ => Cow::Borrowed(token.value),
349363
};
350364

351-
query.push_str(&value);
365+
if fold_in_top_level {
366+
self.trim_all_spaces_end(query);
367+
query.push(' ');
368+
}
352369

353-
self.inline_block.begin_if_possible(self.tokens, self.index);
370+
self.indentation.increase_block_level(fold_in_top_level);
354371

355-
self.indentation.increase_block_level();
372+
query.push_str(&value);
356373

357374
if !self.inline_block.is_active() {
358375
self.add_new_line(query);
@@ -388,7 +405,7 @@ impl<'a> Formatter<'a> {
388405

389406
token.value = &value;
390407

391-
self.indentation.decrease_block_level();
408+
let folded = self.indentation.decrease_block_level();
392409

393410
if self.inline_block.is_active() {
394411
self.inline_block.end();
@@ -400,7 +417,7 @@ impl<'a> Formatter<'a> {
400417
self.format_with_space_after(&token, query);
401418
}
402419
} else {
403-
self.add_new_line(query);
420+
self.add_new_line_inner(query, folded);
404421
self.format_with_spaces(&token, query);
405422
}
406423
}
@@ -458,7 +475,7 @@ impl<'a> Formatter<'a> {
458475
}
459476
}
460477

461-
fn add_new_line(&self, query: &mut String) {
478+
fn add_new_line_inner(&self, query: &mut String, folded: bool) {
462479
self.trim_spaces_end(query);
463480
if self.options.inline {
464481
query.push(' ');
@@ -467,7 +484,11 @@ impl<'a> Formatter<'a> {
467484
if !query.ends_with('\n') {
468485
query.push('\n');
469486
}
470-
query.push_str(&self.indentation.get_indent());
487+
query.push_str(&self.indentation.get_indent(folded));
488+
}
489+
490+
fn add_new_line(&self, query: &mut String) {
491+
self.add_new_line_inner(query, false);
471492
}
472493

473494
fn trim_spaces_end(&self, query: &mut String) {
@@ -484,7 +505,7 @@ impl<'a> Formatter<'a> {
484505
if i == 0 {
485506
combined.push_str(line)
486507
} else if line.starts_with([' ', '\t']) {
487-
let indent = self.indentation.get_indent();
508+
let indent = self.indentation.get_indent(false);
488509
let start_trimmed = line.trim_start_matches([' ', '\t']);
489510
combined.reserve(indent.len() + start_trimmed.len() + 2);
490511
combined.push('\n');
@@ -553,13 +574,30 @@ impl<'a> Formatter<'a> {
553574
}
554575
}
555576

577+
fn previous_non_whitespace_token(&self, idx: usize) -> Option<&Token<'_>> {
578+
let index = self.index.checked_sub(idx);
579+
if let Some(index) = index {
580+
self.tokens[..=index]
581+
.iter()
582+
.rev()
583+
.find(|t| t.kind != TokenKind::Whitespace)
584+
} else {
585+
None
586+
}
587+
}
588+
556589
fn top_level_tokens_info(&self) -> SpanInfo {
557590
let mut block_level = self.block_level;
558591
let mut full_span = 0;
592+
let mut blocks = 0;
593+
let mut arguments = 0;
559594

560595
for token in self.tokens[self.index..].iter().skip(1) {
561596
match token.kind {
562597
TokenKind::OpenParen => {
598+
if block_level == self.block_level {
599+
blocks += 1;
600+
}
563601
block_level += 1;
564602
}
565603
TokenKind::CloseParen => {
@@ -579,14 +617,43 @@ impl<'a> Formatter<'a> {
579617
full_span += 1;
580618
continue;
581619
}
620+
TokenKind::Operator if token.value == "," => {
621+
if block_level == self.block_level {
622+
arguments += 1;
623+
}
624+
}
582625

583-
_ => {}
626+
_ => {
627+
if arguments == 0 {
628+
arguments += 1
629+
}
630+
}
584631
}
585632

586633
full_span += token.value.len();
587634
}
588635

589-
SpanInfo { full_span }
636+
// if we are inside an inline block we decide our behaviour as if were inline
637+
let block_len = self.inline_block.cur_len();
638+
let (newline_before, newline_after) = if block_len > 0 {
639+
let limit = self.options.max_inline_top_level.unwrap_or(0);
640+
(limit < block_len, limit < full_span)
641+
} else {
642+
(
643+
true,
644+
self.options
645+
.max_inline_top_level
646+
.is_none_or(|limit| limit < full_span),
647+
)
648+
};
649+
650+
SpanInfo {
651+
full_span,
652+
blocks,
653+
newline_before,
654+
newline_after,
655+
arguments,
656+
}
590657
}
591658

592659
fn format_no_change(&self, token: &Token<'_>, query: &mut String) {

src/indentation.rs

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub(crate) struct Indentation<'a> {
1717
enum IndentType {
1818
TopLevel,
1919
BlockLevel,
20+
FoldedBlockLevel,
2021
}
2122

2223
impl<'a> Indentation<'a> {
@@ -29,12 +30,18 @@ impl<'a> Indentation<'a> {
2930
}
3031
}
3132

32-
pub fn get_indent(&self) -> String {
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::FoldedBlockLevel)
40+
.count()
41+
- if folded { 1 } else { 0 };
3342
match self.options.indent {
34-
Indent::Spaces(num_spaces) => " "
35-
.repeat(num_spaces as usize)
36-
.repeat(self.indent_types.len()),
37-
Indent::Tabs => "\t".repeat(self.indent_types.len()),
43+
Indent::Spaces(num_spaces) => " ".repeat(num_spaces as usize).repeat(level),
44+
Indent::Tabs => "\t".repeat(level),
3845
}
3946
}
4047

@@ -43,8 +50,12 @@ impl<'a> Indentation<'a> {
4350
self.top_level_span.push(span);
4451
}
4552

46-
pub fn increase_block_level(&mut self) {
47-
self.indent_types.push(IndentType::BlockLevel);
53+
pub fn increase_block_level(&mut self, folded: bool) {
54+
self.indent_types.push(if folded {
55+
IndentType::FoldedBlockLevel
56+
} else {
57+
IndentType::BlockLevel
58+
});
4859
self.previous.push(Default::default());
4960
}
5061

@@ -56,14 +67,18 @@ impl<'a> Indentation<'a> {
5667
}
5768
}
5869

59-
pub fn decrease_block_level(&mut self) {
70+
/// Return true if the block was folded
71+
pub fn decrease_block_level(&mut self) -> bool {
72+
let mut folded = false;
6073
while !self.indent_types.is_empty() {
6174
let kind = self.indent_types.pop();
6275
self.previous.pop();
76+
folded = kind == Some(IndentType::FoldedBlockLevel);
6377
if kind != Some(IndentType::TopLevel) {
6478
break;
6579
}
6680
}
81+
folded
6782
}
6883

6984
pub fn reset_indentation(&mut self) {

src/inline_block.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ impl InlineBlock {
4444
&& (!info.has_reseved_tokens || info.length <= self.reserved_limit)
4545
}
4646

47-
pub fn begin_if_possible(&mut self, tokens: &[Token<'_>], index: usize) {
47+
pub fn begin_if_possible(&mut self, tokens: &[Token<'_>], index: usize) -> bool {
4848
let info = self.build_info(tokens, index);
4949
if self.level == 0 && self.is_inline_block(&info) {
5050
self.level = 1;
@@ -55,6 +55,9 @@ impl InlineBlock {
5555
}
5656
if self.level > 0 {
5757
self.info.push(info);
58+
true
59+
} else {
60+
false
5861
}
5962
}
6063

0 commit comments

Comments
 (0)