Skip to content

Commit 1c9f6d8

Browse files
authored
Fix introduction of extra newlines at the end of multiline arrays
1 parent 4a1ecf0 commit 1c9f6d8

File tree

2 files changed

+144
-25
lines changed

2 files changed

+144
-25
lines changed

examp/clippy.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,5 +71,5 @@ integration = [
7171

7272
"tempfile", # Here is another comment.
7373

74-
"abc"
74+
"abc",
7575
]

src/fmt.rs

Lines changed: 143 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -184,41 +184,88 @@ fn fmt_value(value: &mut Value, config: &Config) {
184184
match value {
185185
Value::Array(arr) => {
186186
if arr.to_string().len() > config.max_array_line_len {
187+
let old_trailing_comma = arr.trailing_comma();
188+
let new_trailing_comma = config.multiline_trailing_comma;
189+
190+
let trailing = arr.trailing().as_str().unwrap_or_default().to_owned();
191+
187192
let indent = " ".repeat(config.indent_count);
193+
let arr_len = arr.len();
188194

189-
// Move all array elements onto a new line and indent them.
190-
for val in arr.iter_mut() {
191-
// Trim exessive whitespace.
195+
// Process all elements' prefix and suffix.
196+
for (i, val) in arr.iter_mut().enumerate() {
192197
let mut prefix = val.prefix().trim().to_owned();
193-
let suffix = val.suffix().trim().to_owned();
198+
let suffix = val.suffix();
199+
200+
let mut last_suffix = None;
201+
202+
// Handle suffix: Add comma for the last element only.
203+
let new_suffix = if i == arr_len - 1 {
204+
if old_trailing_comma != new_trailing_comma {
205+
// The last line's suffix must be cleared anyway,
206+
// and append it to the prefix.
207+
if !suffix.trim().is_empty() {
208+
last_suffix = Some(suffix.trim());
209+
}
210+
if new_trailing_comma {
211+
"".to_owned()
212+
} else {
213+
"".to_owned() + NEWLINE_PATTERN
214+
}
215+
} else {
216+
suffix.to_owned()
217+
}
218+
} else {
219+
suffix.trim_end().to_owned()
220+
};
221+
222+
if let Some(s) = last_suffix {
223+
prefix.push_str(&format!("{NEWLINE_PATTERN}{s}"));
224+
prefix = prefix.trim().to_owned();
225+
}
194226

195-
// Handle prefix comments. Put them on a dedicated line.
196-
if !prefix.is_empty() {
197-
prefix.push_str(NEWLINE_PATTERN);
198-
prefix.push_str(&indent);
227+
if i == arr_len - 1 && !new_trailing_comma {
228+
prefix.push_str(&format!("{NEWLINE_PATTERN}{}", trailing.trim()));
229+
prefix = prefix.trim().to_owned();
199230
}
200231

201-
val.decor_mut()
202-
.set_prefix(format!("{NEWLINE_PATTERN}{indent}{prefix}"));
203-
val.decor_mut().set_suffix(suffix);
232+
let n_i = format!("{NEWLINE_PATTERN}{indent}");
233+
234+
// Handle prefix: Add newline and indent, preserve comments.
235+
let new_prefix = if !prefix.is_empty() {
236+
prefix
237+
.lines()
238+
.map(|line| format!("{n_i}{}", line.trim()))
239+
.collect::<String>()
240+
+ &n_i
241+
} else {
242+
n_i
243+
};
244+
245+
val.decor_mut().set_prefix(new_prefix);
246+
val.decor_mut().set_suffix(new_suffix);
204247
}
205248

206-
// Fix up the last one.
207-
if let Some(last) = arr.iter_mut().last() {
208-
let suffix = last.suffix().to_owned();
209-
210-
let comma = if config.multiline_trailing_comma { "," } else { "" };
211-
212-
last.decor_mut()
213-
.set_suffix(format!("{comma}{suffix}{NEWLINE_PATTERN}"));
249+
if old_trailing_comma != new_trailing_comma {
250+
if new_trailing_comma {
251+
let trailing = trailing.trim_end().to_owned();
252+
arr.set_trailing(trailing + NEWLINE_PATTERN);
253+
} else {
254+
arr.set_trailing("".to_owned());
255+
}
214256
}
257+
arr.set_trailing_comma(new_trailing_comma);
215258
} else {
259+
// Single-line array: Ensure no extra commas.
260+
// Clear suffixes first to remove input commas.
261+
for val in arr.iter_mut() {
262+
val.decor_mut().set_suffix("");
263+
}
216264
arr.fmt();
265+
arr.decor_mut().set_prefix(" ");
266+
// Apply trailing comma to the last element if configured.
267+
arr.set_trailing_comma(config.always_trailing_comma);
217268
}
218-
// TODO: this is most likely after an equal sign but not always...
219-
arr.decor_mut().set_prefix(" ");
220-
// TODO: can this be moved into the else of the above if/else
221-
arr.set_trailing_comma(config.always_trailing_comma);
222269
}
223270
Value::InlineTable(table) => {
224271
table.decor_mut().set_prefix(" ");
@@ -228,7 +275,11 @@ fn fmt_value(value: &mut Value, config: &Config) {
228275
// get here from a headed table (`[header] key = val`)
229276
val => {
230277
if config.space_around_eq
231-
&& val.decor().prefix().and_then(|r| r.as_str()).is_none_or(str::is_empty)
278+
&& val
279+
.decor()
280+
.prefix()
281+
.and_then(RawString::as_str)
282+
.is_none_or(str::is_empty)
232283
{
233284
val.decor_mut().set_prefix(" ");
234285
}
@@ -414,4 +465,72 @@ mod test {
414465
assert_ne!(input, toml.to_string());
415466
// println!("{}", toml.to_string());
416467
}
468+
469+
#[test]
470+
fn array_integration() {
471+
let input = r#"
472+
[package]
473+
authors = [
474+
"Manish Goregaokar <[email protected]>",
475+
"Andre Bogus <[email protected]>",
476+
"Oliver Schneider <[email protected]>" # Here is a comment
477+
]
478+
xyzabc = [
479+
"foo",
480+
"bar",
481+
"baz",
482+
]
483+
integration = [
484+
485+
# A feature comment that makes this line very long.
486+
"git2",
487+
488+
489+
"tempfile", # Here is another comment.
490+
"abc", # Here is another comment at the end of the array.
491+
]
492+
"#;
493+
let expected = r#"
494+
[package]
495+
authors = [
496+
"Manish Goregaokar <[email protected]>",
497+
"Andre Bogus <[email protected]>",
498+
# Here is a comment
499+
"Oliver Schneider <[email protected]>",
500+
]
501+
xyzabc = ["foo", "bar", "baz"]
502+
integration = [
503+
# A feature comment that makes this line very long.
504+
"git2",
505+
"tempfile",
506+
# Here is another comment.
507+
"abc", # Here is another comment at the end of the array.
508+
]
509+
"#;
510+
let mut toml = input.parse::<DocumentMut>().unwrap();
511+
fmt_toml(&mut toml, &Config::new());
512+
similar_asserts::assert_eq!(expected, toml.to_string());
513+
514+
let expected2 = r#"
515+
[package]
516+
authors = [
517+
"Manish Goregaokar <[email protected]>",
518+
"Andre Bogus <[email protected]>",
519+
"Oliver Schneider <[email protected]>" # Here is a comment
520+
]
521+
xyzabc = ["foo", "bar", "baz"]
522+
integration = [
523+
# A feature comment that makes this line very long.
524+
"git2",
525+
"tempfile",
526+
# Here is another comment.
527+
# Here is another comment at the end of the array.
528+
"abc"
529+
]
530+
"#;
531+
let mut toml = input.parse::<DocumentMut>().unwrap();
532+
let cfg = Config { multiline_trailing_comma: false, ..Config::new() };
533+
fmt_toml(&mut toml, &cfg);
534+
similar_asserts::assert_eq!(expected2, toml.to_string());
535+
}
417536
}

0 commit comments

Comments
 (0)