about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNick Cameron <nrc@ncameron.org>2018-09-19 11:31:28 +1200
committerGitHub <noreply@github.com>2018-09-19 11:31:28 +1200
commit829dbfabe94004b6a535c9e1ffdd55eefef7c59f (patch)
treea679bf8bb31baadde9a08c65116d868480b96e68
parent1739041f0372b336ca727585fb7c2ecda07e889c (diff)
parentc3edf6d3a1f72088a4343948f6aafe1fc74a3208 (diff)
Merge pull request #3028 from scampi/issue2973
Fix indent computation of a macro with braces.
-rw-r--r--src/comment.rs43
-rw-r--r--src/macros.rs10
-rw-r--r--tests/source/issue-2973.rs158
-rw-r--r--tests/target/issue-2973.rs158
4 files changed, 354 insertions, 15 deletions
diff --git a/src/comment.rs b/src/comment.rs
index a48012d411e..17ec29c3cbc 100644
--- a/src/comment.rs
+++ b/src/comment.rs
@@ -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
-                }
-                _ => {
-                    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
@@ -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');
         }
diff --git a/src/macros.rs b/src/macros.rs
index 2cc8482a1b0..736333cf44d 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -1126,6 +1126,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;
@@ -1134,7 +1135,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(
@@ -1147,7 +1153,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(),
                 },
diff --git a/tests/source/issue-2973.rs b/tests/source/issue-2973.rs
new file mode 100644
index 00000000000..5256dd7c960
--- /dev/null
+++ b/tests/source/issue-2973.rs
@@ -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",
+    "#$#$.",
+  }
+}
diff --git a/tests/target/issue-2973.rs b/tests/target/issue-2973.rs
new file mode 100644
index 00000000000..86574bd8668
--- /dev/null
+++ b/tests/target/issue-2973.rs
@@ -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",
+      "#$#$.",
+    }
+}