recognize strings inside comments in order to avoid indenting them

Close #3270
This commit is contained in:
Stéphane Campinas 2019-01-10 14:25:07 +01:00
parent 2c204c11d1
commit baa62c609e
No known key found for this signature in database
GPG key ID: 6D5620D908210133
7 changed files with 114 additions and 38 deletions

View file

@ -1029,21 +1029,28 @@ impl RichChar for (usize, char) {
#[derive(PartialEq, Eq, Debug, Clone, Copy)] #[derive(PartialEq, Eq, Debug, Clone, Copy)]
enum CharClassesStatus { enum CharClassesStatus {
Normal, Normal,
/// Character is within a string
LitString, LitString,
LitStringEscape, LitStringEscape,
/// Character is within a raw string
LitRawString(u32), LitRawString(u32),
RawStringPrefix(u32), RawStringPrefix(u32),
RawStringSuffix(u32), RawStringSuffix(u32),
LitChar, LitChar,
LitCharEscape, LitCharEscape,
// The u32 is the nesting deepness of the comment /// Character inside a block comment, with the integer indicating the nesting deepness of the
/// comment
BlockComment(u32), BlockComment(u32),
// Status when the '/' has been consumed, but not yet the '*', deepness is /// Character inside a block-commented string, with the integer indicating the nesting deepness
// the new deepness (after the comment opening). /// of the comment
StringInBlockComment(u32),
/// Status when the '/' has been consumed, but not yet the '*', deepness is
/// the new deepness (after the comment opening).
BlockCommentOpening(u32), BlockCommentOpening(u32),
// Status when the '*' has been consumed, but not yet the '/', deepness is /// Status when the '*' has been consumed, but not yet the '/', deepness is
// the new deepness (after the comment closing). /// the new deepness (after the comment closing).
BlockCommentClosing(u32), BlockCommentClosing(u32),
/// Character is within a line comment
LineComment, LineComment,
} }
@ -1067,6 +1074,12 @@ pub enum FullCodeCharKind {
InComment, InComment,
/// Last character of a comment, '\n' for a line comment, '/' for a block comment. /// Last character of a comment, '\n' for a line comment, '/' for a block comment.
EndComment, EndComment,
/// Start of a mutlitine string inside a comment
StartStringCommented,
/// End of a mutlitine string inside a comment
EndStringCommented,
/// Inside a commented string
InStringCommented,
/// Start of a mutlitine string /// Start of a mutlitine string
StartString, StartString,
/// End of a mutlitine string /// End of a mutlitine string
@ -1080,7 +1093,21 @@ impl FullCodeCharKind {
match self { match self {
FullCodeCharKind::StartComment FullCodeCharKind::StartComment
| FullCodeCharKind::InComment | FullCodeCharKind::InComment
| FullCodeCharKind::EndComment => true, | FullCodeCharKind::EndComment
| FullCodeCharKind::StartStringCommented
| FullCodeCharKind::InStringCommented
| FullCodeCharKind::EndStringCommented => true,
_ => false,
}
}
/// Returns true if the character is inside a comment
pub fn inside_comment(self) -> bool {
match self {
FullCodeCharKind::InComment
| FullCodeCharKind::StartStringCommented
| FullCodeCharKind::InStringCommented
| FullCodeCharKind::EndStringCommented => true,
_ => false, _ => false,
} }
} }
@ -1089,6 +1116,12 @@ impl FullCodeCharKind {
self == FullCodeCharKind::InString || self == FullCodeCharKind::StartString self == FullCodeCharKind::InString || self == FullCodeCharKind::StartString
} }
/// Returns true if the character is within a commented string
pub fn is_commented_string(self) -> bool {
self == FullCodeCharKind::InStringCommented
|| self == FullCodeCharKind::StartStringCommented
}
fn to_codecharkind(self) -> CodeCharKind { fn to_codecharkind(self) -> CodeCharKind {
if self.is_comment() { if self.is_comment() {
CodeCharKind::Comment CodeCharKind::Comment
@ -1232,18 +1265,27 @@ where
}, },
_ => CharClassesStatus::Normal, _ => CharClassesStatus::Normal,
}, },
CharClassesStatus::StringInBlockComment(deepness) => {
char_kind = FullCodeCharKind::InStringCommented;
if chr == '"' {
CharClassesStatus::BlockComment(deepness)
} else {
CharClassesStatus::StringInBlockComment(deepness)
}
}
CharClassesStatus::BlockComment(deepness) => { CharClassesStatus::BlockComment(deepness) => {
assert_ne!(deepness, 0); assert_ne!(deepness, 0);
self.status = match self.base.peek() { char_kind = FullCodeCharKind::InComment;
match self.base.peek() {
Some(next) if next.get_char() == '/' && chr == '*' => { Some(next) if next.get_char() == '/' && chr == '*' => {
CharClassesStatus::BlockCommentClosing(deepness - 1) CharClassesStatus::BlockCommentClosing(deepness - 1)
} }
Some(next) if next.get_char() == '*' && chr == '/' => { Some(next) if next.get_char() == '*' && chr == '/' => {
CharClassesStatus::BlockCommentOpening(deepness + 1) CharClassesStatus::BlockCommentOpening(deepness + 1)
} }
_ => CharClassesStatus::BlockComment(deepness), _ if chr == '"' => CharClassesStatus::StringInBlockComment(deepness),
}; _ => self.status,
return Some((FullCodeCharKind::InComment, item)); }
} }
CharClassesStatus::BlockCommentOpening(deepness) => { CharClassesStatus::BlockCommentOpening(deepness) => {
assert_eq!(chr, '*'); assert_eq!(chr, '*');
@ -1299,26 +1341,33 @@ impl<'a> Iterator for LineClasses<'a> {
let mut line = String::new(); let mut line = String::new();
let start_class = match self.base.peek() { let start_kind = match self.base.peek() {
Some((kind, _)) => *kind, Some((kind, _)) => *kind,
None => unreachable!(), None => unreachable!(),
}; };
while let Some((kind, c)) = self.base.next() { while let Some((kind, c)) = self.base.next() {
// needed to set the kind of the ending character on the last line
self.kind = kind;
if c == '\n' { if c == '\n' {
self.kind = match (start_class, kind) { self.kind = match (start_kind, kind) {
(FullCodeCharKind::Normal, FullCodeCharKind::InString) => { (FullCodeCharKind::Normal, FullCodeCharKind::InString) => {
FullCodeCharKind::StartString FullCodeCharKind::StartString
} }
(FullCodeCharKind::InString, FullCodeCharKind::Normal) => { (FullCodeCharKind::InString, FullCodeCharKind::Normal) => {
FullCodeCharKind::EndString FullCodeCharKind::EndString
} }
(FullCodeCharKind::InComment, FullCodeCharKind::InStringCommented) => {
FullCodeCharKind::StartStringCommented
}
(FullCodeCharKind::InStringCommented, FullCodeCharKind::InComment) => {
FullCodeCharKind::EndStringCommented
}
_ => kind, _ => kind,
}; };
break; break;
} else {
line.push(c);
} }
line.push(c);
} }
// Workaround for CRLF newline. // Workaround for CRLF newline.
@ -1364,7 +1413,12 @@ impl<'a> Iterator for UngroupedCommentCodeSlices<'a> {
} }
FullCodeCharKind::StartComment => { FullCodeCharKind::StartComment => {
// Consume the whole comment // Consume the whole comment
while let Some((FullCodeCharKind::InComment, (_, _))) = self.iter.next() {} loop {
match self.iter.next() {
Some((kind, ..)) if kind.inside_comment() => continue,
_ => break,
}
}
} }
_ => panic!(), _ => panic!(),
} }

View file

@ -527,8 +527,10 @@ pub fn trim_left_preserve_layout(orig: &str, indent: Indent, config: &Config) ->
Some(get_prefix_space_width(config, &line)) Some(get_prefix_space_width(config, &line))
}; };
let line = if veto_trim || (kind.is_string() && !line.ends_with('\\')) { let new_veto_trim_value =
veto_trim = kind.is_string() && !line.ends_with('\\'); (kind.is_string() || kind.is_commented_string()) && !line.ends_with('\\');
let line = if veto_trim || new_veto_trim_value {
veto_trim = new_veto_trim_value;
trimmed = false; trimmed = false;
line line
} else { } else {
@ -536,10 +538,13 @@ pub fn trim_left_preserve_layout(orig: &str, indent: Indent, config: &Config) ->
}; };
trimmed_lines.push((trimmed, line, prefix_space_width)); trimmed_lines.push((trimmed, line, prefix_space_width));
// When computing the minimum, do not consider lines within a string. // Because there is a veto against trimming and indenting lines within a string,
// The reason is there is a veto against trimming and indenting such lines // such lines should not be taken into account when computing the minimum.
match kind { match kind {
FullCodeCharKind::InString | FullCodeCharKind::EndString => None, FullCodeCharKind::InString
| FullCodeCharKind::EndString
| FullCodeCharKind::InStringCommented
| FullCodeCharKind::EndStringCommented => None,
_ => prefix_space_width, _ => prefix_space_width,
} }
}) })

View file

@ -1,13 +0,0 @@
fn test() {
/*
a
*/
let x = 42;
/*
aaa
"line 1
line 2
line 3"
*/
let x = 42;
}

View file

@ -0,0 +1,10 @@
pub fn main() {
/* let s = String::from(
"
hello
world
",
); */
assert_eq!(s, "\nhello\nworld\n");
}

View file

@ -0,0 +1,10 @@
// rustfmt-wrap_comments: true
fn func() {
let x = 42;
/*
let something = "one line line line line line line line line line line line line
two lines
three lines";
*/
}

View file

@ -0,0 +1,10 @@
pub fn main() {
/* let s = String::from(
"
hello
world
",
); */
assert_eq!(s, "\nhello\nworld\n");
}