+27
CHANGELOG.md
+27
CHANGELOG.md
···
77
77
78
78
([Giacomo Cavalieri](https://github.com/giacomocavalieri))
79
79
80
+
- The formatter no longer removes empty lines between list items. In case an
81
+
empty line is added between list items they will all be split on multiple
82
+
lines.
83
+
84
+
```gleam
85
+
pub fn main() {
86
+
[
87
+
"natu", "xatu",
88
+
89
+
"chimeco"
90
+
]
91
+
}
92
+
```
93
+
94
+
Is formatted as:
95
+
96
+
```gleam
97
+
pub fn main() {
98
+
[
99
+
"natu",
100
+
"xatu",
101
+
102
+
"chimeco",
103
+
]
104
+
}
105
+
```
106
+
80
107
### Compiler
81
108
82
109
- Generated JavaScript functions, constants, and custom type constructors now
+61
-14
compiler-core/src/format.rs
+61
-14
compiler-core/src/format.rs
···
587
587
}
588
588
};
589
589
590
-
let elements = join(
591
-
elements.iter().map(|element| self.const_expr(element)),
592
-
comma,
593
-
);
590
+
let mut elements_doc = nil();
591
+
for element in elements.iter() {
592
+
let empty_lines = self.pop_empty_lines(element.location().start);
593
+
let element_doc = self.const_expr(element);
594
+
595
+
elements_doc = if elements_doc.is_empty() {
596
+
element_doc
597
+
} else if empty_lines {
598
+
// If there's empty lines before the list item we want to add an
599
+
// empty line here. Notice how we're making sure no nesting is
600
+
// added after the comma, otherwise we would be adding needless
601
+
// whitespace in the empty line!
602
+
docvec![
603
+
elements_doc,
604
+
comma.clone().set_nesting(0),
605
+
line(),
606
+
element_doc
607
+
]
608
+
} else {
609
+
docvec![elements_doc, comma.clone(), element_doc]
610
+
};
611
+
}
612
+
elements_doc = elements_doc.next_break_fits(NextBreakFitsMode::Disabled);
594
613
595
-
let doc = break_("[", "[").append(elements).nest(INDENT);
614
+
let doc = break_("[", "[").append(elements_doc).nest(INDENT);
596
615
597
616
// We get all remaining comments that come before the list's closing
598
617
// square bracket.
···
1999
2018
None => 0,
2000
2019
};
2001
2020
2002
-
let elements = join(
2003
-
elements
2004
-
.iter()
2005
-
.map(|e| self.comma_separated_item(e, list_size)),
2006
-
comma,
2007
-
)
2008
-
.next_break_fits(NextBreakFitsMode::Disabled);
2021
+
let mut elements_doc = nil();
2022
+
for element in elements.iter() {
2023
+
let empty_lines = self.pop_empty_lines(element.location().start);
2024
+
let element_doc = self.comma_separated_item(element, list_size);
2009
2025
2010
-
let doc = break_("[", "[").append(elements);
2026
+
elements_doc = if elements_doc.is_empty() {
2027
+
element_doc
2028
+
} else if empty_lines {
2029
+
// If there's empty lines before the list item we want to add an
2030
+
// empty line here. Notice how we're making sure no nesting is
2031
+
// added after the comma, otherwise we would be adding needless
2032
+
// whitespace in the empty line!
2033
+
docvec![
2034
+
elements_doc,
2035
+
comma.clone().set_nesting(0),
2036
+
line(),
2037
+
element_doc
2038
+
]
2039
+
} else {
2040
+
docvec![elements_doc, comma.clone(), element_doc]
2041
+
};
2042
+
}
2043
+
elements_doc = elements_doc.next_break_fits(NextBreakFitsMode::Disabled);
2044
+
2045
+
let doc = break_("[", "[").append(elements_doc);
2011
2046
// We need to keep the last break aside and do not add it immediately
2012
2047
// because in case there's a final comment before the closing square
2013
2048
// bracket we want to add indentation (to just that break). Otherwise,
···
2068
2103
let has_multiple_elements_per_line =
2069
2104
self.has_items_on_the_same_line(items.iter().chain(tail));
2070
2105
2071
-
if !ends_with_trailing_comma {
2106
+
let has_empty_lines_between_elements = match (items.first(), items.last().or(tail)) {
2107
+
(Some(first), Some(last)) => self.empty_lines.first().is_some_and(|empty_line| {
2108
+
*empty_line >= first.location().end && *empty_line < last.location().start
2109
+
}),
2110
+
_ => false,
2111
+
};
2112
+
2113
+
if has_empty_lines_between_elements {
2114
+
// If there's any empty line between elements we want to force each
2115
+
// item onto its own line to preserve the empty lines that were
2116
+
// intentionally added.
2117
+
ListItemsPacking::BreakOnePerLine
2118
+
} else if !ends_with_trailing_comma {
2072
2119
// If the list doesn't end with a trailing comma we try and pack it in
2073
2120
// a single line; if we can't we'll put one item per line, no matter
2074
2121
// the content of the list.
+90
compiler-core/src/format/tests/lists.rs
+90
compiler-core/src/format/tests/lists.rs
···
273
273
"#
274
274
);
275
275
}
276
+
277
+
#[test]
278
+
fn empty_lines_in_list_are_not_ignored() {
279
+
assert_format_rewrite!(
280
+
"pub fn main() {
281
+
[1, 2,
282
+
283
+
3
284
+
]
285
+
}
286
+
",
287
+
"pub fn main() {
288
+
[
289
+
1,
290
+
2,
291
+
292
+
3,
293
+
]
294
+
}
295
+
"
296
+
);
297
+
}
298
+
299
+
#[test]
300
+
fn empty_lines_in_const_list_are_not_ignored() {
301
+
assert_format_rewrite!(
302
+
"const list =
303
+
[1, 2,
304
+
305
+
3
306
+
]
307
+
",
308
+
"const list = [
309
+
1,
310
+
2,
311
+
312
+
3,
313
+
]
314
+
"
315
+
);
316
+
}
317
+
318
+
#[test]
319
+
fn lists_with_empty_lines_are_always_broken() {
320
+
assert_format_rewrite!(
321
+
"pub fn main() {
322
+
[
323
+
1,
324
+
2,
325
+
326
+
3, 4, 5
327
+
]
328
+
}
329
+
",
330
+
"pub fn main() {
331
+
[
332
+
1,
333
+
2,
334
+
335
+
3,
336
+
4,
337
+
5,
338
+
]
339
+
}
340
+
"
341
+
);
342
+
}
343
+
344
+
#[test]
345
+
fn const_lists_with_empty_lines_are_always_broken() {
346
+
assert_format_rewrite!(
347
+
"const list =
348
+
[
349
+
1,
350
+
2,
351
+
352
+
3, 4, 5
353
+
]
354
+
",
355
+
"const list = [
356
+
1,
357
+
2,
358
+
359
+
3,
360
+
4,
361
+
5,
362
+
]
363
+
"
364
+
);
365
+
}