Repository: casey/just
Pull request #635 (2020-06-09 04:12:01)

Strip leading spaces after line continuation
Make line continuations strip leading spaces on the next line.

This changes what is passed to the shell, so this is a breaking change.
However, I don't think that this will break any recipes.

casey:  I am doing a Janus run to try to figure out if there are recipes that are likely to be broken. What I'll be looking for are line continuations without a space before the slash, and with leading whitespace on the next line. Like this:

```
foo:
  echo bar\
    baz
```

This currently runs `echo bar  baz`, but after the change would run `echo barbaz`.
casey: I could only find one justfile on github that seems to be affected, and [opened a PR](https://github.com/jsim2010/paper/pull/166) with a fix.

Patch:
diff --git a/src/evaluator.rs b/src/evaluator.rs
index 603aec58..dddbeee5 100644
--- a/src/evaluator.rs
+++ b/src/evaluator.rs
@@ -145,11 +145,20 @@ impl<'src, 'run> Evaluator<'src, 'run> {
     })
   }
 
-  pub(crate) fn evaluate_line(&mut self, line: &Line<'src>) -> RunResult<'src, String> {
+  pub(crate) fn evaluate_line(
+    &mut self,
+    line: &Line<'src>,
+    continued: bool,
+  ) -> RunResult<'src, String> {
     let mut evaluated = String::new();
-    for fragment in &line.fragments {
+    for (i, fragment) in line.fragments.iter().enumerate() {
       match fragment {
-        Fragment::Text { token } => evaluated += token.lexeme(),
+        Fragment::Text { token } =>
+          if i == 0 && continued {
+            evaluated += token.lexeme().trim_start();
+          } else {
+            evaluated += token.lexeme();
+          },
         Fragment::Interpolation { expression } => {
           evaluated += &self.evaluate_expression(expression)?;
         },
diff --git a/src/recipe.rs b/src/recipe.rs
index fb266a50..43aece3a 100644
--- a/src/recipe.rs
+++ b/src/recipe.rs
@@ -89,7 +89,7 @@ impl<'src, D> Recipe<'src, D> {
     if self.shebang {
       let mut evaluated_lines = vec![];
       for line in &self.body {
-        evaluated_lines.push(evaluator.evaluate_line(line)?);
+        evaluated_lines.push(evaluator.evaluate_line(line, false)?);
       }
 
       if config.dry_run || self.quiet {
@@ -205,14 +205,16 @@ impl<'src, D> Recipe<'src, D> {
           break;
         }
         let mut evaluated = String::new();
+        let mut continued = false;
         loop {
           if lines.peek().is_none() {
             break;
           }
           let line = lines.next().unwrap();
           line_number += 1;
-          evaluated += &evaluator.evaluate_line(line)?;
+          evaluated += &evaluator.evaluate_line(line, continued)?;
           if line.is_continuation() {
+            continued = true;
             evaluated.pop();
           } else {
             break;


Test patch:
diff --git a/tests/integration.rs b/tests/integration.rs
index bc329673..c73b354c 100644
--- a/tests/integration.rs
+++ b/tests/integration.rs
@@ -1292,8 +1292,8 @@ foo:
          b  \
              c
 "#,
-  stdout:   "a b c\n",
-  stderr:   "echo a       b             c\n",
+  stdout:   "ab c\n",
+  stderr:   "echo ab  c\n",
 }
 
 test! {
@@ -1304,8 +1304,8 @@ foo:
          b  \
              c'
 "#,
-  stdout:   "a       b             c\n",
-  stderr:   "echo 'a       b             c'\n",
+  stdout:   "ab  c\n",
+  stderr:   "echo 'ab  c'\n",
 }
 
 test! {