Allow escaping double braces with {{{{
(#765)
This commit is contained in:
parent
7cbce4374f
commit
d3b277c04c
11
README.adoc
11
README.adoc
@ -446,11 +446,11 @@ publish:
|
||||
|
||||
==== Escaping `{{`
|
||||
|
||||
To write a recipe containing `{{`, use `{{ "{{" }}`:
|
||||
To write a recipe containing `{{`, use `{{{{`:
|
||||
|
||||
```make
|
||||
braces:
|
||||
echo 'I {{ "{{" }}LOVE}} curly braces!'
|
||||
echo 'I {{{{LOVE}} curly braces!'
|
||||
```
|
||||
|
||||
(An unmatched `}}` is ignored, so it doesn't need to be escaped.)
|
||||
@ -462,6 +462,13 @@ braces:
|
||||
echo '{{'I {{LOVE}} curly braces!'}}'
|
||||
```
|
||||
|
||||
Yet another option is to use `{{ "{{" }}`:
|
||||
|
||||
```make
|
||||
braces:
|
||||
echo 'I {{ "{{" }}LOVE}} curly braces!'
|
||||
```
|
||||
|
||||
=== Strings
|
||||
|
||||
Double-quoted strings support escape sequences:
|
||||
|
@ -169,11 +169,14 @@ impl<'src, 'run> Evaluator<'src, 'run> {
|
||||
let mut evaluated = String::new();
|
||||
for (i, fragment) in line.fragments.iter().enumerate() {
|
||||
match fragment {
|
||||
Fragment::Text { token } =>
|
||||
Fragment::Text { token } => {
|
||||
let lexeme = token.lexeme().replace("{{{{", "{{");
|
||||
|
||||
if i == 0 && continued {
|
||||
evaluated += token.lexeme().trim_start();
|
||||
evaluated += lexeme.trim_start();
|
||||
} else {
|
||||
evaluated += token.lexeme();
|
||||
evaluated += &lexeme;
|
||||
}
|
||||
},
|
||||
Fragment::Interpolation { expression } => {
|
||||
evaluated += &self.evaluate_expression(expression)?;
|
||||
|
31
src/lexer.rs
31
src/lexer.rs
@ -91,6 +91,15 @@ impl<'src> Lexer<'src> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Advance over N characters.
|
||||
fn skip(&mut self, n: usize) -> CompilationResult<'src, ()> {
|
||||
for _ in 0..n {
|
||||
self.advance()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Lexeme of in-progress token
|
||||
fn lexeme(&self) -> &'src str {
|
||||
&self.src[self.token_start.offset..self.token_end.offset]
|
||||
@ -515,6 +524,11 @@ impl<'src> Lexer<'src> {
|
||||
use Terminator::*;
|
||||
|
||||
let terminator = loop {
|
||||
if self.rest_starts_with("{{{{") {
|
||||
self.skip(4)?;
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some('\n') = self.next {
|
||||
break Newline;
|
||||
}
|
||||
@ -1239,6 +1253,23 @@ mod tests {
|
||||
)
|
||||
}
|
||||
|
||||
test! {
|
||||
name: brace_escape,
|
||||
text: "
|
||||
foo:
|
||||
{{{{
|
||||
",
|
||||
tokens: (
|
||||
Identifier:"foo",
|
||||
Colon,
|
||||
Eol,
|
||||
Indent,
|
||||
Text:"{{{{",
|
||||
Eol,
|
||||
Dedent,
|
||||
)
|
||||
}
|
||||
|
||||
test! {
|
||||
name: indented_block_followed_by_item,
|
||||
text: "
|
||||
|
@ -2600,6 +2600,30 @@ test! {
|
||||
shell: false,
|
||||
}
|
||||
|
||||
test! {
|
||||
name: brace_escape,
|
||||
justfile: "
|
||||
foo:
|
||||
echo '{{{{'
|
||||
",
|
||||
stdout: "{{\n",
|
||||
stderr: "
|
||||
echo '{{'
|
||||
",
|
||||
}
|
||||
|
||||
test! {
|
||||
name: brace_escape_extra,
|
||||
justfile: "
|
||||
foo:
|
||||
echo '{{{{{'
|
||||
",
|
||||
stdout: "{{{\n",
|
||||
stderr: "
|
||||
echo '{{{'
|
||||
",
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
test! {
|
||||
name: windows_interpreter_path_no_base,
|
||||
|
Loading…
Reference in New Issue
Block a user