Fix indent computation of a macro with braces.

The leading whitespace of a multine string was taken into account when
computing the `min_prefix_space_width`, even if that line couldn't be
trimmed. The consequence is it was always shifting the macro's content
to the right.
This commit is contained in:
Stéphane Campinas 2018-09-17 23:17:36 +02:00
parent 81a4235c7f
commit c3edf6d3a1
No known key found for this signature in database
GPG key ID: 6D5620D908210133
4 changed files with 354 additions and 15 deletions

View file

@ -821,6 +821,10 @@ pub enum FullCodeCharKind {
InComment,
/// Last character of a comment, '\n' for a line comment, '/' for a block comment.
EndComment,
/// Start of a mutlitine string
StartString,
/// End of a mutlitine string
EndString,
/// Inside a string.
InString,
}
@ -836,7 +840,7 @@ impl FullCodeCharKind {
}
pub fn is_string(self) -> bool {
self == FullCodeCharKind::InString
self == FullCodeCharKind::InString || self == FullCodeCharKind::StartString
}
fn to_codecharkind(self) -> CodeCharKind {
@ -924,17 +928,14 @@ where
_ => CharClassesStatus::Normal, // Unreachable
}
}
CharClassesStatus::LitString => match chr {
'"' => CharClassesStatus::Normal,
'\\' => {
char_kind = FullCodeCharKind::InString;
CharClassesStatus::LitStringEscape
CharClassesStatus::LitString => {
char_kind = FullCodeCharKind::InString;
match chr {
'"' => CharClassesStatus::Normal,
'\\' => CharClassesStatus::LitStringEscape,
_ => CharClassesStatus::LitString,
}
_ => {
char_kind = FullCodeCharKind::InString;
CharClassesStatus::LitString
}
},
}
CharClassesStatus::LitStringEscape => {
char_kind = FullCodeCharKind::InString;
CharClassesStatus::LitString
@ -1052,9 +1053,22 @@ impl<'a> Iterator for LineClasses<'a> {
let mut line = String::new();
let start_class = match self.base.peek() {
Some((kind, _)) => *kind,
None => FullCodeCharKind::Normal,
};
while let Some((kind, c)) = self.base.next() {
self.kind = kind;
if c == '\n' {
self.kind = match (start_class, kind) {
(FullCodeCharKind::Normal, FullCodeCharKind::InString) => {
FullCodeCharKind::StartString
}
(FullCodeCharKind::InString, FullCodeCharKind::Normal) => {
FullCodeCharKind::EndString
}
_ => kind,
};
break;
} else {
line.push(c);
@ -1227,7 +1241,10 @@ pub fn recover_comment_removed(
pub fn filter_normal_code(code: &str) -> String {
let mut buffer = String::with_capacity(code.len());
LineClasses::new(code).for_each(|(kind, line)| match kind {
FullCodeCharKind::Normal | FullCodeCharKind::InString => {
FullCodeCharKind::Normal
| FullCodeCharKind::StartString
| FullCodeCharKind::InString
| FullCodeCharKind::EndString => {
buffer.push_str(&line);
buffer.push('\n');
}

View file

@ -1118,6 +1118,7 @@ fn indent_macro_snippet(
} else {
Some(get_prefix_space_width(context, &line))
};
let line = if veto_trim || (kind.is_string() && !line.ends_with('\\')) {
veto_trim = kind.is_string() && !line.ends_with('\\');
trimmed = false;
@ -1126,7 +1127,12 @@ fn indent_macro_snippet(
line.trim().to_owned()
};
trimmed_lines.push((trimmed, line, prefix_space_width));
prefix_space_width
// when computing the minimum, do not consider lines within a string
match kind {
FullCodeCharKind::InString | FullCodeCharKind::EndString => None,
_ => prefix_space_width,
}
}).min()?;
Some(
@ -1139,7 +1145,7 @@ fn indent_macro_snippet(
let new_indent_width = indent.width() + original_indent_width
.saturating_sub(min_prefix_space_width);
let new_indent = Indent::from_width(context.config, new_indent_width);
format!("{}{}", new_indent.to_string(context.config), line.trim())
format!("{}{}", new_indent.to_string(context.config), line)
}
None => String::new(),
},

158
tests/source/issue-2973.rs Normal file
View file

@ -0,0 +1,158 @@
#[cfg(test)]
mod test {
summary_test! {
tokenize_recipe_interpolation_eol,
"foo: # some comment
{{hello}}
",
"foo: \
{{hello}} \
{{ahah}}",
"N:#$>^{N}$<.",
}
summary_test! {
tokenize_strings,
r#"a = "'a'" + '"b"' + "'c'" + '"d"'#echo hello"#,
r#"N="+'+"+'#."#,
}
summary_test! {
tokenize_recipe_interpolation_eol,
"foo: # some comment
{{hello}}
",
"N:#$>^{N}$<.",
}
summary_test! {
tokenize_recipe_interpolation_eof,
"foo: # more comments
{{hello}}
# another comment
",
"N:#$>^{N}$<#$.",
}
summary_test! {
tokenize_recipe_complex_interpolation_expression,
"foo: #lol\n {{a + b + \"z\" + blarg}}",
"N:#$>^{N+N+\"+N}<.",
}
summary_test! {
tokenize_recipe_multiple_interpolations,
"foo:,#ok\n {{a}}0{{b}}1{{c}}",
"N:,#$>^{N}_{N}_{N}<.",
}
summary_test! {
tokenize_junk,
"bob
hello blah blah blah : a b c #whatever
",
"N$$NNNN:NNN#$.",
}
summary_test! {
tokenize_empty_lines,
"
# this does something
hello:
asdf
bsdf
csdf
dsdf # whatever
# yolo
",
"$#$N:$>^_$^_$$^_$$^_$$<#$.",
}
summary_test! {
tokenize_comment_before_variable,
"
#
A='1'
echo:
echo {{A}}
",
"$#$N='$N:$>^_{N}$<.",
}
summary_test! {
tokenize_interpolation_backticks,
"hello:\n echo {{`echo hello` + `echo goodbye`}}",
"N:$>^_{`+`}<.",
}
summary_test! {
tokenize_assignment_backticks,
"a = `echo hello` + `echo goodbye`",
"N=`+`.",
}
summary_test! {
tokenize_multiple,
"
hello:
a
b
c
d
# hello
bob:
frank
",
"$N:$>^_$^_$$^_$$^_$$<#$N:$>^_$<.",
}
summary_test! {
tokenize_comment,
"a:=#",
"N:=#."
}
summary_test! {
tokenize_comment_with_bang,
"a:=#foo!",
"N:=#."
}
summary_test! {
tokenize_order,
r"
b: a
@mv a b
a:
@touch F
@touch a
d: c
@rm c
c: b
@mv b c",
"$N:N$>^_$$<N:$>^_$^_$$<N:N$>^_$$<N:N$>^_<.",
}
summary_test! {
tokenize_parens,
r"((())) )abc(+",
"((())))N(+.",
}
summary_test! {
crlf_newline,
"#\r\n#asdf\r\n",
"#$#$.",
}
}

158
tests/target/issue-2973.rs Normal file
View file

@ -0,0 +1,158 @@
#[cfg(test)]
mod test {
summary_test! {
tokenize_recipe_interpolation_eol,
"foo: # some comment
{{hello}}
",
"foo: \
{{hello}} \
{{ahah}}",
"N:#$>^{N}$<.",
}
summary_test! {
tokenize_strings,
r#"a = "'a'" + '"b"' + "'c'" + '"d"'#echo hello"#,
r#"N="+'+"+'#."#,
}
summary_test! {
tokenize_recipe_interpolation_eol,
"foo: # some comment
{{hello}}
",
"N:#$>^{N}$<.",
}
summary_test! {
tokenize_recipe_interpolation_eof,
"foo: # more comments
{{hello}}
# another comment
",
"N:#$>^{N}$<#$.",
}
summary_test! {
tokenize_recipe_complex_interpolation_expression,
"foo: #lol\n {{a + b + \"z\" + blarg}}",
"N:#$>^{N+N+\"+N}<.",
}
summary_test! {
tokenize_recipe_multiple_interpolations,
"foo:,#ok\n {{a}}0{{b}}1{{c}}",
"N:,#$>^{N}_{N}_{N}<.",
}
summary_test! {
tokenize_junk,
"bob
hello blah blah blah : a b c #whatever
",
"N$$NNNN:NNN#$.",
}
summary_test! {
tokenize_empty_lines,
"
# this does something
hello:
asdf
bsdf
csdf
dsdf # whatever
# yolo
",
"$#$N:$>^_$^_$$^_$$^_$$<#$.",
}
summary_test! {
tokenize_comment_before_variable,
"
#
A='1'
echo:
echo {{A}}
",
"$#$N='$N:$>^_{N}$<.",
}
summary_test! {
tokenize_interpolation_backticks,
"hello:\n echo {{`echo hello` + `echo goodbye`}}",
"N:$>^_{`+`}<.",
}
summary_test! {
tokenize_assignment_backticks,
"a = `echo hello` + `echo goodbye`",
"N=`+`.",
}
summary_test! {
tokenize_multiple,
"
hello:
a
b
c
d
# hello
bob:
frank
",
"$N:$>^_$^_$$^_$$^_$$<#$N:$>^_$<.",
}
summary_test! {
tokenize_comment,
"a:=#",
"N:=#."
}
summary_test! {
tokenize_comment_with_bang,
"a:=#foo!",
"N:=#."
}
summary_test! {
tokenize_order,
r"
b: a
@mv a b
a:
@touch F
@touch a
d: c
@rm c
c: b
@mv b c",
"$N:N$>^_$$<N:$>^_$^_$$<N:N$>^_$$<N:N$>^_<.",
}
summary_test! {
tokenize_parens,
r"((())) )abc(+",
"((())))N(+.",
}
summary_test! {
crlf_newline,
"#\r\n#asdf\r\n",
"#$#$.",
}
}