Skip to content

Indentation of multi post-comments to a list item #4606

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 115 additions & 14 deletions src/formatting/lists.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use unicode_segmentation::UnicodeSegmentation;

use crate::config::{lists::*, Config, IndentStyle};
use crate::formatting::{
comment::{find_comment_end, rewrite_comment, FindUncommented},
comment::{comment_style, find_comment_end, rewrite_comment, FindUncommented},
rewrite::RewriteContext,
shape::{Indent, Shape},
utils::{
Expand Down Expand Up @@ -421,6 +421,33 @@ where
result.push_str(formatting.separator);
}

// Note about post-comments indentation:
// In the original code the the item separator may follow some comments that
// may span over some lines. E.g.:
// item1 /* 1st comment line 1
// * line 2 */
// /* 2nd comment */,
// item2,
//
// In this case, rustfmt moves the separator right after the item:
// item1, /* 1st comment line 1
// * line 2 */
// /* 2nd comment */
// item2,
//
// In this code, only the 1st comment is regarded as post comment of item1.
// 2nd comment is regarded as pre-comment of item2, therefore the output
// of another round of formatting this code is:
// item1, /* 1st comment line 1
// * line 2 */
// /* 2nd comment */
// item2,
//
// i.e. 2nd comment is now indented as pre-comment.
//
// This why in the code below a first multiline post-comment is indented
// differently then the other post-comments.

if tactic != DefinitiveListTactic::Horizontal && item.post_comment.is_some() {
let comment = item.post_comment.as_ref().unwrap();
let overhead = last_line_width(&result) + first_line_width(comment.trim());
Expand All @@ -444,19 +471,88 @@ where
};
let width = formatting.shape.width.checked_sub(overhead).unwrap_or(1);
let offset = formatting.shape.indent + overhead;
let comment_shape = Shape::legacy(width, offset);

// Use block-style only for the last item or multiline comments.
let block_style = !formatting.ends_with_newline && last
|| comment.trim().contains('\n')
|| comment.trim().len() > width;

rewrite_comment(
comment.trim_start(),
block_style,
comment_shape,
formatting.config,
)
let comment_start_trimmed = comment.trim_start();

// Find if first comment is single line and the end of the first comment
// when it is a multi-line block comment (since the first post-comment
// is added to the same line of the list item, its indentation is important
// only when it is a multiline comment).
let style = comment_style(
comment_start_trimmed,
formatting.config.normalize_comments(),
);
let (first_comment_single_line, first_comment_end) =
if !formatting.config.normalize_comments() && style.is_line_comment() {
// Line comment (not normalizaed)
(true, None)
} else if style.is_block_comment() {
match find_comment_end(&comment_start_trimmed) {
Some(i) => {
if comment_start_trimmed[..i].contains('\n') {
// Multiline-comment (may be because of normalization)
(false, Some(i))
} else {
// One line coment (Block or normalizaed Line)
(true, None)
}
}
_ => (false, None), // Unknow comment end
}
} else {
(false, None) // Unexpected case - non-block comment with normalization
};

// Closure for formatting post-comment with specific Shape
let rewrite_post_comment_with_shape = |cmt: &str, shape: Shape| {
// Use block-style only for the last item or multiline comments.
let block_style = !formatting.ends_with_newline && last
|| cmt.trim().contains('\n')
|| cmt.trim().len() > width;
rewrite_comment(&cmt, block_style, shape, formatting.config)
};

// Properly indent first and other comments
match (first_comment_single_line, first_comment_end) {
(_, None) => {
// First comment not multiline - same indentation for all comments
let comment_shape =
if first_comment_single_line && comment_start_trimmed.contains("\n") {
formatting.shape
} else {
Shape::legacy(width, offset)
};
rewrite_post_comment_with_shape(comment_start_trimmed, comment_shape)
}
(false, Some(comment_end)) => {
// Separate indentation for first multi-line block comment
let formatted_first_comment = rewrite_comment(
&comment_start_trimmed[..comment_end],
true,
Shape::legacy(width, offset),
formatting.config,
)?;
let second_comment_start = comment_start_trimmed[comment_end..]
.find(|c: char| !c.is_whitespace())
.map_or(None, |i| Some(i + comment_end));
let formatted_all_comments = match second_comment_start {
Some(i) => {
let second_comment = comment_start_trimmed[i..].to_string();
let formatted = rewrite_post_comment_with_shape(
&second_comment,
formatting.shape,
)?;
let indent = formatting
.shape
.indent
.to_string_with_newline(formatting.config);
format!("{}{}{}", formatted_first_comment, indent, formatted)
}
_ => formatted_first_comment,
};
Some(formatted_all_comments)
}
(_, _) => unreachable!(),
}
};

let mut formatted_comment = rewrite_post_comment(&mut item_max_width)?;
Expand Down Expand Up @@ -699,6 +795,11 @@ pub(crate) fn get_comment_end(
find_comment_end(&post_snippet[i..]).unwrap() + i,
separator_index + 1,
),
// Comment is preceeded by new line and followed by a separator.
(Some(i), Some(_)) if separator_index > i => cmp::max(
find_comment_end(&post_snippet[i..]).unwrap() + i,
separator_index + 1,
),
// Potential *single* line comment.
(_, Some(j)) if j > separator_index => j + 1,
_ => post_snippet.len(),
Expand Down
205 changes: 205 additions & 0 deletions tests/source/issue-3847.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
// Tests for multi one-line post-comments of list item
// (related cases when `normalize_comments` is set are already included in other test files).

// Original cases from issue #3847
type T1 = Result<
u32 // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam
// diam ac cursus. Aliquam condimentum in erat quis pretium.
// accumsan urna. Cras volutpat sit amet quam.
,
bool,
>;
type T2 = Result<
u32, // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam
// diam ac cursus. Aliquam condimentum in erat quis pretium.
// accumsan urna. Cras volutpat sit amet quam.
bool,
>;

// Additional test cases with lists
fn main() {
let a = ["GOOD" // Comment1
// Comment2
,
];
let b = ["WASBAD" // Comment1
// Comment2
,
"CCC",
];
}

// Tests with one multi-line block comment
type T3_good = Result<
u32 /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam
* diam ac cursus. Aliquam condimentum in erat quis pretium.
* accumsan urna. Cras volutpat sit amet quam. */
,
bool,
>;
type T4_good = Result<
u32, /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam
* diam ac cursus. Aliquam condimentum in erat quis pretium.
* accumsan urna. Cras volutpat sit amet quam. */
bool,
>;

fn main() {
let a = ["WASGOOD1" /* Comment1
* Comment2 */
,
"WASGOOD2", /* Comment1
* Comment2 */
"CCC",
];
}

// Tests with one-line block-comments
type T5_good = Result<
u32 /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */
/* diam ac cursus. Aliquam condimentum in erat quis pretium. */
/* accumsan urna. Cras volutpat sit amet quam. */
,
bool,
>;
type T6_good = Result<
u32, /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */
/* diam ac cursus. Aliquam condimentum in erat quis pretium. */
/* accumsan urna. Cras volutpat sit amet quam. */
bool,
>;

// Tests with mix one-line and multi-linecomments - one-line is first
type T8_good = Result<
u32 // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam
/* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam
* diam ac cursus. Aliquam condimentum in erat quis pretium.
* accumsan urna. Cras volutpat sit amet quam. */,
bool,
>;
type T9_good = Result<
u32 /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */
/* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam
* diam ac cursus. Aliquam condimentum in erat quis pretium.
* accumsan urna. Cras volutpat sit amet quam. */
// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam
,
bool,
>;
type T9_good = Result<
u32 /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */
/* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam
* diam ac cursus. Aliquam condimentum in erat quis pretium.
* accumsan urna. Cras volutpat sit amet quam. */,
// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam
bool,
>;

// Tests with mix one-line and multi-linecomments - multi-line is first
type T10_good = Result<
u32 /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam
* diam ac cursus. Aliquam condimentum in erat quis pretium.
* accumsan urna. Cras volutpat sit amet quam. */
// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam
,
bool,
>;
type T11_good = Result<
u32 /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam
* diam ac cursus. Aliquam condimentum in erat quis pretium.
* accumsan urna. Cras volutpat sit amet quam. */
/* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */,
// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam
bool,
>;
type T12_good = Result<
u32 /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam
* diam ac cursus. Aliquam condimentum in erat quis pretium.
* accumsan urna. Cras volutpat sit amet quam. */
/* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */
// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam
,
bool,
>;
type T12_good = Result<
u32 /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam
* diam ac cursus. Aliquam condimentum in erat quis pretium.
* accumsan urna. Cras volutpat sit amet quam. */
/* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */,
// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam
bool,
>;
type T13_good = Result<
u32 /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam
* diam ac cursus. Aliquam condimentum in erat quis pretium.
* accumsan urna. */ /*Cras volutpat sit amet quam. */
/* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */
,
bool,
>;

// Tests with mix one-line and multi-linecomments -
// multi-line is first with newline between comments
type T14_good = Result<
u32 /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam
* diam ac cursus. Aliquam condimentum in erat quis pretium.
* accumsan urna. Cras volutpat sit amet quam. */

/* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */,
// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam
bool,
>;
type T15_good = Result<
u32 /* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam
* diam ac cursus. Aliquam condimentum in erat quis pretium.
* accumsan urna. Cras volutpat sit amet quam. */


/* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */

// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam
,
bool,
>;

// Tests with first comment is not in same line of item
type T16_good = Result<
u32
/* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */
/* diam ac cursus. Aliquam condimentum in erat quis pretium. */
/* accumsan urna. Cras volutpat sit amet quam. */,
bool,
>;
type T17_good = Result<
u32
/* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */
/* diam ac cursus. Aliquam condimentum in erat quis pretium. */
/* accumsan urna. Cras volutpat sit amet quam. */
,
bool,
>;
type T18_good = Result<
u32
/* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */
/* diam ac cursus. Aliquam condimentum in erat quis pretium. */,
/* accumsan urna. Cras volutpat sit amet quam. */
bool,
>;
type T19_good = Result<
u32
/* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam
* diam ac cursus. Aliquam condimentum in erat quis pretium.
* accumsan urna. Cras volutpat sit amet quam. */,
/* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */
// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam
bool,
>;
type T20_good = Result<
u32
/* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam
* diam ac cursus. Aliquam condimentum in erat quis pretium.
* accumsan urna. Cras volutpat sit amet quam. */
/* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam */,
// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam
bool,
>;
Loading