Skip to content

Commit

Permalink
Fix indent computation of a macro with braces.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
scampi committed Sep 17, 2018
1 parent 81a4235 commit c3edf6d
Show file tree
Hide file tree
Showing 4 changed files with 354 additions and 15 deletions.
43 changes: 30 additions & 13 deletions src/comment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand All @@ -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 {
Expand Down Expand Up @@ -924,17 +928,14 @@ where
_ => CharClassesStatus::Normal, // Unreachable
}
}
CharClassesStatus::LitString => match chr {
'"' => CharClassesStatus::Normal,
'\\' => {
char_kind = FullCodeCharKind::InString;
CharClassesStatus::LitStringEscape
}
_ => {
char_kind = FullCodeCharKind::InString;
CharClassesStatus::LitString
CharClassesStatus::LitString => {
char_kind = FullCodeCharKind::InString;
match chr {
'"' => CharClassesStatus::Normal,
'\\' => CharClassesStatus::LitStringEscape,
_ => CharClassesStatus::LitString,
}
},
}
CharClassesStatus::LitStringEscape => {
char_kind = FullCodeCharKind::InString;
CharClassesStatus::LitString
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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');
}
Expand Down
10 changes: 8 additions & 2 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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(
Expand All @@ -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(),
},
Expand Down
158 changes: 158 additions & 0 deletions tests/source/issue-2973.rs
Original file line number Diff line number Diff line change
@@ -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",
"#$#$.",
}
}
Loading

0 comments on commit c3edf6d

Please sign in to comment.