Skip to content

Commit 3299c25

Browse files
authored
fix: better formatting of leading/trailing line/block comments in expression lists (#6338)
# Description ## Problem While fixing the bug [this PR](#6337) was fixing I noticed that the formatter destroyed some array formatting, like this one: https://github.com/noir-lang/noir_json_parser/blob/bc7094394baeaa185c5bf56ae806e302c786bdd3/src/_string_tools/slice_packed_field.nr#L13-L19 ## Summary I decided to try to fix this because it's bad if the formatter doesn't respect this initial formatting. And this change if for any expression list, so it applies to arrays, tuples, call arguments, etc, so we only need to fix this once. ## Additional Context With this some leading spaces surrounding block comments are gone, but I think it's better because for example array literals don't have spaces after `[` and before `]`, and before this PR the formatter would generate `[ /* comment */ 1]` while now it generates `[/* comment */ 1]` which I think looks better (and is what rustfmt does too). I think I didn't want to spend too much time on these details on the initial formatter pass to avoid getting into an infinite improvement loop. ## Documentation Check one: - [x] No documentation needed. - [ ] Documentation included in this PR. - [ ] **[For Experimental Features]** Documentation to be submitted in a separate PR. # PR Checklist - [x] I have tested the changes locally. - [x] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings.
1 parent 52f7c0b commit 3299c25

File tree

6 files changed

+102
-35
lines changed

6 files changed

+102
-35
lines changed

tooling/nargo_fmt/src/chunks.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -849,10 +849,10 @@ impl<'a> Formatter<'a> {
849849
}
850850
Chunk::TrailingComment(text_chunk) | Chunk::LeadingComment(text_chunk) => {
851851
self.write(&text_chunk.string);
852-
self.write(" ");
852+
self.write_space_without_skipping_whitespace_and_comments();
853853
}
854854
Chunk::Group(chunks) => self.format_chunk_group_impl(chunks),
855-
Chunk::SpaceOrLine => self.write(" "),
855+
Chunk::SpaceOrLine => self.write_space_without_skipping_whitespace_and_comments(),
856856
Chunk::IncreaseIndentation => self.increase_indentation(),
857857
Chunk::DecreaseIndentation => self.decrease_indentation(),
858858
Chunk::PushIndentation => self.push_indentation(),
@@ -915,9 +915,16 @@ impl<'a> Formatter<'a> {
915915
self.write_indentation();
916916
}
917917
Chunk::LeadingComment(text_chunk) => {
918+
let ends_with_newline = text_chunk.string.ends_with('\n');
918919
self.write_chunk_lines(text_chunk.string.trim());
919-
self.write_line_without_skipping_whitespace_and_comments();
920-
self.write_indentation();
920+
921+
// Respect whether the leading comment had a newline before what comes next or not
922+
if ends_with_newline {
923+
self.write_line_without_skipping_whitespace_and_comments();
924+
self.write_indentation();
925+
} else {
926+
self.write_space_without_skipping_whitespace_and_comments();
927+
}
921928
}
922929
Chunk::Group(mut group) => {
923930
if chunks.force_multiline_on_children_with_same_tag_if_multiline

tooling/nargo_fmt/src/formatter/comments_and_whitespace.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -301,8 +301,8 @@ mod tests {
301301
let src = "global x = [ /* hello */
302302
1 , 2 ] ;";
303303
let expected = "global x = [
304-
/* hello */
305-
1, 2,
304+
/* hello */ 1,
305+
2,
306306
];
307307
";
308308
assert_format_with_max_width(src, expected, 20);

tooling/nargo_fmt/src/formatter/expression.rs

+78-12
Original file line numberDiff line numberDiff line change
@@ -446,23 +446,22 @@ impl<'a, 'b> ChunkFormatter<'a, 'b> {
446446
{
447447
let mut comments_chunk = self.skip_comments_and_whitespace_chunk();
448448

449-
// If the comment is not empty but doesn't have newlines, it's surely `/* comment */`.
450-
// We format that with spaces surrounding it so it looks, for example, like `Foo { /* comment */ field ..`.
451-
if !comments_chunk.string.trim().is_empty() && !comments_chunk.has_newlines {
452-
// Note: there's no space after `{}` because space will be produced by format_items_separated_by_comma
453-
comments_chunk.string = if surround_with_spaces {
454-
format!(" {}", comments_chunk.string.trim())
455-
} else {
456-
format!(" {} ", comments_chunk.string.trim())
457-
};
458-
group.text(comments_chunk);
459-
449+
// Handle leading block vs. line comments a bit differently.
450+
if comments_chunk.string.trim().starts_with("/*") {
460451
group.increase_indentation();
461452
if surround_with_spaces {
462453
group.space_or_line();
463454
} else {
464455
group.line();
465456
}
457+
458+
// Note: there's no space before `{}` because it was just produced
459+
comments_chunk.string = if surround_with_spaces {
460+
comments_chunk.string.trim().to_string()
461+
} else {
462+
format!("{} ", comments_chunk.string.trim())
463+
};
464+
group.leading_comment(comments_chunk);
466465
} else {
467466
group.increase_indentation();
468467
if surround_with_spaces {
@@ -479,7 +478,24 @@ impl<'a, 'b> ChunkFormatter<'a, 'b> {
479478
group.text_attached_to_last_group(self.chunk(|formatter| {
480479
formatter.write_comma();
481480
}));
482-
group.trailing_comment(self.skip_comments_and_whitespace_chunk());
481+
let newlines_count_before_comment = self.following_newlines_count();
482+
group.text(self.chunk(|formatter| {
483+
formatter.skip_whitespace();
484+
}));
485+
if let Token::BlockComment(..) = &self.token {
486+
// We let block comments be part of the item that's going to be formatted
487+
} else {
488+
// Line comments can be trailing or leading, depending on whether there are newlines before them
489+
let comments_and_whitespace_chunk = self.skip_comments_and_whitespace_chunk();
490+
if !comments_and_whitespace_chunk.string.trim().is_empty() {
491+
if newlines_count_before_comment > 0 {
492+
group.line();
493+
group.leading_comment(comments_and_whitespace_chunk);
494+
} else {
495+
group.trailing_comment(comments_and_whitespace_chunk);
496+
}
497+
}
498+
}
483499
group.space_or_line();
484500
}
485501
format_item(self, expr, group);
@@ -1326,6 +1342,56 @@ global y = 1;
13261342
assert_format_with_config(src, expected, config);
13271343
}
13281344

1345+
#[test]
1346+
fn format_short_array_with_block_comment_before_elements() {
1347+
let src = "global x = [ /* one */ 1, /* two */ 2 ] ;";
1348+
let expected = "global x = [/* one */ 1, /* two */ 2];\n";
1349+
1350+
assert_format(src, expected);
1351+
}
1352+
1353+
#[test]
1354+
fn format_long_array_with_block_comment_before_elements() {
1355+
let src = "global x = [ /* one */ 1, /* two */ 123456789012345, 3, 4 ] ;";
1356+
let expected = "global x = [
1357+
/* one */ 1,
1358+
/* two */ 123456789012345,
1359+
3,
1360+
4,
1361+
];
1362+
";
1363+
1364+
let config =
1365+
Config { short_array_element_width_threshold: 5, max_width: 30, ..Config::default() };
1366+
assert_format_with_config(src, expected, config);
1367+
}
1368+
1369+
#[test]
1370+
fn format_long_array_with_line_comment_before_elements() {
1371+
let src = "global x = [
1372+
// one
1373+
1,
1374+
// two
1375+
123456789012345,
1376+
3,
1377+
4,
1378+
];
1379+
";
1380+
let expected = "global x = [
1381+
// one
1382+
1,
1383+
// two
1384+
123456789012345,
1385+
3,
1386+
4,
1387+
];
1388+
";
1389+
1390+
let config =
1391+
Config { short_array_element_width_threshold: 5, max_width: 30, ..Config::default() };
1392+
assert_format_with_config(src, expected, config);
1393+
}
1394+
13291395
#[test]
13301396
fn format_cast() {
13311397
let src = "global x = 1 as u8 ;";

tooling/nargo_fmt/src/formatter/use_tree.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ mod tests {
211211
#[test]
212212
fn format_use_list_one_item_with_comments() {
213213
let src = " use foo::{ /* do not remove me */ bar, };";
214-
let expected = "use foo::{ /* do not remove me */ bar};\n";
214+
let expected = "use foo::{/* do not remove me */ bar};\n";
215215
assert_format(src, expected);
216216
}
217217

tooling/nargo_fmt/src/formatter/use_tree_merge.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ mod tests {
397397
#[test]
398398
fn format_use_list_one_item_with_comments() {
399399
let src = " use foo::{ /* do not remove me */ bar, };";
400-
let expected = "use foo::{ /* do not remove me */ bar};\n";
400+
let expected = "use foo::{/* do not remove me */ bar};\n";
401401
assert_format(src, expected);
402402
}
403403

tooling/nargo_fmt/tests/expected/tuple.nr

+9-15
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ fn main() {
44
// hello
55
1,
66
);
7-
( /*hello*/ 1,);
7+
(/*hello*/ 1,);
88
(1/*hello*/,);
99
(1,);
10-
( /*test*/ 1,);
11-
( /*a*/ 1/*b*/,);
12-
( /*a*/ 1/*b*/, /*c*/ 2/*d*/, /*c*/ 2/*d*/);
13-
( /*a*/ 1/*b*/, /*c*/ 2/*d*/, /*c*/ 2/*d*/, /*e*/ 3/*f*/);
10+
(/*test*/ 1,);
11+
(/*a*/ 1/*b*/,);
12+
(/*a*/ 1/*b*/, /*c*/ 2/*d*/, /*c*/ 2/*d*/);
13+
(/*a*/ 1/*b*/, /*c*/ 2/*d*/, /*c*/ 2/*d*/, /*e*/ 3/*f*/);
1414

1515
(1 /*1*/, 2 /* 2*/);
1616

@@ -28,7 +28,7 @@ fn main() {
2828
2,
2929
);
3030

31-
( /*1*/ 1, /*2*/ 2);
31+
(/*1*/ 1, /*2*/ 2);
3232

3333
(
3434
(
@@ -39,14 +39,8 @@ fn main() {
3939
),
4040
);
4141
(
42-
/*a*/
43-
1
44-
/*b*/,
45-
/*c*/
46-
2/*d*/,
47-
/*c*/
48-
2/*d*/,
49-
/*e*/
50-
3,/*f*/
42+
/*a*/ 1
43+
/*b*/, /*c*/
44+
2/*d*/, /*c*/ 2/*d*/, /*e*/ 3,/*f*/
5145
);
5246
}

0 commit comments

Comments
 (0)