Skip to content

Ignoring code blocks when trimming comments #4770

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

Open
wants to merge 2 commits into
base: rustfmt-2.0.0-rc.2
Choose a base branch
from
Open
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
252 changes: 252 additions & 0 deletions src/formatting/comment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1125,6 +1125,12 @@ enum CharClassesStatus {
/// Character inside a block-commented string, with the integer indicating the nesting deepness
/// of the comment
StringInBlockComment(u32),
CodeBlockPrefix(u32, u32),
CodeBlockSuffix(u32, u32, u32),
/// Character inside a multiline code block, with the first integer indicating the number of
/// backticks used to open the block and the second integer indicating the nesting deepness of
/// the comment
CodeBlock(u32, u32),
/// Status when the '/' has been consumed, but not yet the '*', deepness is
/// the new deepness (after the comment opening).
BlockCommentOpening(u32),
Expand Down Expand Up @@ -1167,6 +1173,12 @@ pub(crate) enum FullCodeCharKind {
EndString,
/// Inside a string.
InString,
/// Start of a multiline doc code block
StartCodeBlock,
/// Inside a multilne doc code block
InCodeBlock,
/// End of mutline doc code block
EndCodeBlock,
}

impl FullCodeCharKind {
Expand All @@ -1179,6 +1191,9 @@ impl FullCodeCharKind {
| FullCodeCharKind::StartStringCommented
| FullCodeCharKind::InStringCommented
| FullCodeCharKind::EndStringCommented
| FullCodeCharKind::StartCodeBlock
| FullCodeCharKind::InCodeBlock
| FullCodeCharKind::EndCodeBlock
)
}

Expand All @@ -1190,6 +1205,9 @@ impl FullCodeCharKind {
| FullCodeCharKind::StartStringCommented
| FullCodeCharKind::InStringCommented
| FullCodeCharKind::EndStringCommented
| FullCodeCharKind::StartCodeBlock
| FullCodeCharKind::InCodeBlock
| FullCodeCharKind::EndCodeBlock
)
}

Expand All @@ -1202,6 +1220,10 @@ impl FullCodeCharKind {
self == FullCodeCharKind::InStringCommented
|| self == FullCodeCharKind::StartStringCommented
}

pub(crate) fn is_code_block(self) -> bool {
self == FullCodeCharKind::InCodeBlock || self == FullCodeCharKind::StartCodeBlock
}
}

impl<T> CharClasses<T>
Expand Down Expand Up @@ -1349,6 +1371,49 @@ where
CharClassesStatus::StringInBlockComment(deepness)
}
}
CharClassesStatus::CodeBlock(backticks, deepness) => {
char_kind = FullCodeCharKind::InCodeBlock;
if chr == '`' && self.base.peek().map(RichChar::get_char) == Some('`') {
CharClassesStatus::CodeBlockSuffix(1, backticks, deepness)
} else if chr == '*' && self.base.peek().map(RichChar::get_char) == Some('/') {
char_kind = FullCodeCharKind::InComment;
CharClassesStatus::BlockCommentClosing(deepness - 1)
} else {
CharClassesStatus::CodeBlock(backticks, deepness)
}
}
CharClassesStatus::CodeBlockPrefix(backticks, deepness) => {
char_kind = FullCodeCharKind::InComment;
match chr {
'`' => CharClassesStatus::CodeBlockPrefix(backticks + 1, deepness),
'\n' if backticks > 2 => CharClassesStatus::CodeBlock(backticks, deepness),
'*' if self.base.peek().map(RichChar::get_char) == Some('/') => {
char_kind = FullCodeCharKind::InComment;
CharClassesStatus::BlockCommentClosing(deepness - 1)
}
_ if backticks < 3 => CharClassesStatus::BlockComment(deepness),
_ => CharClassesStatus::CodeBlockPrefix(backticks, deepness),
}
}
CharClassesStatus::CodeBlockSuffix(backticks, need_backticks, deepness) => {
char_kind = FullCodeCharKind::InCodeBlock;
match chr {
'`' => {
CharClassesStatus::CodeBlockSuffix(backticks + 1, need_backticks, deepness)
}
'\n' if backticks >= need_backticks => {
CharClassesStatus::BlockComment(deepness)
}
'*' if self.base.peek().map(RichChar::get_char) == Some('/') => {
char_kind = FullCodeCharKind::InComment;
CharClassesStatus::BlockCommentClosing(deepness - 1)
}
_ if char::is_whitespace(chr) && backticks >= need_backticks => {
CharClassesStatus::CodeBlockSuffix(backticks, need_backticks, deepness)
}
_ => CharClassesStatus::CodeBlock(need_backticks, deepness),
}
}
CharClassesStatus::BlockComment(deepness) => {
assert_ne!(deepness, 0);
char_kind = FullCodeCharKind::InComment;
Expand All @@ -1359,6 +1424,9 @@ where
Some(next) if next.get_char() == '*' && chr == '/' => {
CharClassesStatus::BlockCommentOpening(deepness + 1)
}
Some(next) if next.get_char() == '`' && chr == '`' => {
CharClassesStatus::CodeBlockPrefix(1, deepness)
}
_ if chr == '"' => CharClassesStatus::StringInBlockComment(deepness),
_ => self.status,
}
Expand Down Expand Up @@ -1435,6 +1503,12 @@ impl<'a> Iterator for LineClasses<'a> {
(FullCodeCharKind::InString, FullCodeCharKind::Normal) => {
FullCodeCharKind::EndString
}
(FullCodeCharKind::InComment, FullCodeCharKind::InCodeBlock) => {
FullCodeCharKind::StartCodeBlock
}
(FullCodeCharKind::InCodeBlock, FullCodeCharKind::InComment) => {
FullCodeCharKind::EndCodeBlock
}
(FullCodeCharKind::InComment, FullCodeCharKind::InStringCommented) => {
FullCodeCharKind::StartStringCommented
}
Expand Down Expand Up @@ -1745,6 +1819,184 @@ mod test {
assert_eq!(None, iter.next());
}

#[test]
fn char_classes_code_block() {
fn check(cmnt: &str, kinds: &[(FullCodeCharKind, char)]) {
let mut iter = CharClasses::new(cmnt.chars());
let mut kind_iter = kinds.iter();
assert_eq!(cmnt.len(), kinds.len());

while let Some(((act_kind, act_char), (expt_kind, expt_char))) =
iter.next().zip(kind_iter.next())
{
assert_eq!((expt_kind, expt_char), (&act_kind, &act_char));
}
}

check(
"/*\n````test\nc\n```\nc\n````\n */",
&[
(FullCodeCharKind::StartComment, '/'),
(FullCodeCharKind::InComment, '*'),
(FullCodeCharKind::InComment, '\n'),
(FullCodeCharKind::InComment, '`'),
(FullCodeCharKind::InComment, '`'),
(FullCodeCharKind::InComment, '`'),
(FullCodeCharKind::InComment, '`'),
(FullCodeCharKind::InComment, 't'),
(FullCodeCharKind::InComment, 'e'),
(FullCodeCharKind::InComment, 's'),
(FullCodeCharKind::InComment, 't'),
(FullCodeCharKind::InComment, '\n'),
(FullCodeCharKind::InCodeBlock, 'c'),
(FullCodeCharKind::InCodeBlock, '\n'),
(FullCodeCharKind::InCodeBlock, '`'),
(FullCodeCharKind::InCodeBlock, '`'),
(FullCodeCharKind::InCodeBlock, '`'),
(FullCodeCharKind::InCodeBlock, '\n'),
(FullCodeCharKind::InCodeBlock, 'c'),
(FullCodeCharKind::InCodeBlock, '\n'),
(FullCodeCharKind::InCodeBlock, '`'),
(FullCodeCharKind::InCodeBlock, '`'),
(FullCodeCharKind::InCodeBlock, '`'),
(FullCodeCharKind::InCodeBlock, '`'),
(FullCodeCharKind::InCodeBlock, '\n'),
(FullCodeCharKind::InComment, ' '),
(FullCodeCharKind::InComment, '*'),
(FullCodeCharKind::EndComment, '/'),
],
);

check(
"/*\n``test\n``abc`\n```test\nc\n``a`\n```\n */",
&[
(FullCodeCharKind::StartComment, '/'),
(FullCodeCharKind::InComment, '*'),
(FullCodeCharKind::InComment, '\n'),
(FullCodeCharKind::InComment, '`'),
(FullCodeCharKind::InComment, '`'),
(FullCodeCharKind::InComment, 't'),
(FullCodeCharKind::InComment, 'e'),
(FullCodeCharKind::InComment, 's'),
(FullCodeCharKind::InComment, 't'),
(FullCodeCharKind::InComment, '\n'),
(FullCodeCharKind::InComment, '`'),
(FullCodeCharKind::InComment, '`'),
(FullCodeCharKind::InComment, 'a'),
(FullCodeCharKind::InComment, 'b'),
(FullCodeCharKind::InComment, 'c'),
(FullCodeCharKind::InComment, '`'),
(FullCodeCharKind::InComment, '\n'),
(FullCodeCharKind::InComment, '`'),
(FullCodeCharKind::InComment, '`'),
(FullCodeCharKind::InComment, '`'),
(FullCodeCharKind::InComment, 't'),
(FullCodeCharKind::InComment, 'e'),
(FullCodeCharKind::InComment, 's'),
(FullCodeCharKind::InComment, 't'),
(FullCodeCharKind::InComment, '\n'),
(FullCodeCharKind::InCodeBlock, 'c'),
(FullCodeCharKind::InCodeBlock, '\n'),
(FullCodeCharKind::InCodeBlock, '`'),
(FullCodeCharKind::InCodeBlock, '`'),
(FullCodeCharKind::InCodeBlock, 'a'),
(FullCodeCharKind::InCodeBlock, '`'),
(FullCodeCharKind::InCodeBlock, '\n'),
(FullCodeCharKind::InCodeBlock, '`'),
(FullCodeCharKind::InCodeBlock, '`'),
(FullCodeCharKind::InCodeBlock, '`'),
(FullCodeCharKind::InCodeBlock, '\n'),
(FullCodeCharKind::InComment, ' '),
(FullCodeCharKind::InComment, '*'),
(FullCodeCharKind::EndComment, '/'),
],
);

check(
"/*\n```*/",
&[
(FullCodeCharKind::StartComment, '/'),
(FullCodeCharKind::InComment, '*'),
(FullCodeCharKind::InComment, '\n'),
(FullCodeCharKind::InComment, '`'),
(FullCodeCharKind::InComment, '`'),
(FullCodeCharKind::InComment, '`'),
(FullCodeCharKind::InComment, '*'),
(FullCodeCharKind::EndComment, '/'),
],
);

check(
"/*\n``*/",
&[
(FullCodeCharKind::StartComment, '/'),
(FullCodeCharKind::InComment, '*'),
(FullCodeCharKind::InComment, '\n'),
(FullCodeCharKind::InComment, '`'),
(FullCodeCharKind::InComment, '`'),
(FullCodeCharKind::InComment, '*'),
(FullCodeCharKind::EndComment, '/'),
],
);

check(
"/*\n```\n */",
&[
(FullCodeCharKind::StartComment, '/'),
(FullCodeCharKind::InComment, '*'),
(FullCodeCharKind::InComment, '\n'),
(FullCodeCharKind::InComment, '`'),
(FullCodeCharKind::InComment, '`'),
(FullCodeCharKind::InComment, '`'),
(FullCodeCharKind::InComment, '\n'),
(FullCodeCharKind::InCodeBlock, ' '),
(FullCodeCharKind::InComment, '*'),
(FullCodeCharKind::EndComment, '/'),
],
);

check(
"/*\n```\nc\n``*/",
&[
(FullCodeCharKind::StartComment, '/'),
(FullCodeCharKind::InComment, '*'),
(FullCodeCharKind::InComment, '\n'),
(FullCodeCharKind::InComment, '`'),
(FullCodeCharKind::InComment, '`'),
(FullCodeCharKind::InComment, '`'),
(FullCodeCharKind::InComment, '\n'),
(FullCodeCharKind::InCodeBlock, 'c'),
(FullCodeCharKind::InCodeBlock, '\n'),
(FullCodeCharKind::InCodeBlock, '`'),
(FullCodeCharKind::InCodeBlock, '`'),
(FullCodeCharKind::InComment, '*'),
(FullCodeCharKind::EndComment, '/'),
],
);

check(
"/*\n`````\nc\n```*/",
&[
(FullCodeCharKind::StartComment, '/'),
(FullCodeCharKind::InComment, '*'),
(FullCodeCharKind::InComment, '\n'),
(FullCodeCharKind::InComment, '`'),
(FullCodeCharKind::InComment, '`'),
(FullCodeCharKind::InComment, '`'),
(FullCodeCharKind::InComment, '`'),
(FullCodeCharKind::InComment, '`'),
(FullCodeCharKind::InComment, '\n'),
(FullCodeCharKind::InCodeBlock, 'c'),
(FullCodeCharKind::InCodeBlock, '\n'),
(FullCodeCharKind::InCodeBlock, '`'),
(FullCodeCharKind::InCodeBlock, '`'),
(FullCodeCharKind::InCodeBlock, '`'),
(FullCodeCharKind::InComment, '*'),
(FullCodeCharKind::EndComment, '/'),
],
);
}

#[test]
fn comment_code_slices() {
let input = "code(); /* test */ 1 + 1";
Expand Down
3 changes: 2 additions & 1 deletion src/formatting/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,8 @@ pub(crate) fn trim_left_preserve_layout(
let new_veto_trim_value = (kind == FullCodeCharKind::InString
|| kind == FullCodeCharKind::InStringCommented)
&& !line.ends_with('\\');
let line = if veto_trim || new_veto_trim_value {
let code_block = kind.is_code_block();
let line = if veto_trim || new_veto_trim_value || code_block {
veto_trim = new_veto_trim_value;
trimmed = false;
line
Expand Down
13 changes: 13 additions & 0 deletions tests/source/issue-4753.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// rustfmt-hard_tabs: true

/*!
```yaml
foo:
bar:
rustfmt: "don't touch this"
```
*/

fn main() {
println!("Hello, world!");
}
13 changes: 13 additions & 0 deletions tests/target/issue-4753.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// rustfmt-hard_tabs: true

/*!
```yaml
foo:
bar:
rustfmt: "don't touch this"
```
*/

fn main() {
println!("Hello, world!");
}