Skip to content

Commit 5f8ffd3

Browse files
committed
templater: relax whitespace requirement by leveraging implicit whitespace rule
This means `f ()`, `x . f()`, etc. are now allowed. Before, `x\n.f()` was syntax error, which seemed unintuitive in multi-line expression. This also means that whitespace around alias declaration is ignored. tempalte-aliases.' foo ' is identical to tempalte-aliases.foo. https://pest.rs/book/grammars/syntax.html#implicit-whitespace Closes #7378
1 parent ba2d3b7 commit 5f8ffd3

File tree

5 files changed

+31
-31
lines changed

5 files changed

+31
-31
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7373

7474
* `jj file show` now accepts `-T`/`--template` option to insert file metadata.
7575

76+
* The template language now allows arbitrary whitespace between any operators.
77+
7678
* The new configuration option `git.colocate=boolean` controls whether or not
7779
Git repositories are colocated by default.
7880

cli/src/template.pest

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
// If making significant changes to this grammar, consider also updating the
2121
// tree-sitter grammar: https://github.com/bryceberger/tree-sitter-jjtemplate
2222

23-
whitespace = _{ " " | "\t" | "\r" | "\n" | "\x0c" }
23+
WHITESPACE = _{ " " | "\t" | "\r" | "\n" | "\x0c" }
2424

2525
string_escape = @{
2626
"\\"
@@ -73,24 +73,23 @@ infix_ops = _{
7373
| rem_op
7474
}
7575

76-
function = { identifier ~ "(" ~ whitespace* ~ function_arguments ~ whitespace* ~ ")" }
77-
keyword_argument = { identifier ~ whitespace* ~ "=" ~ whitespace* ~ template }
76+
function = { identifier ~ "(" ~ function_arguments ~ ")" }
77+
keyword_argument = { identifier ~ "=" ~ template }
7878
argument = _{ keyword_argument | template }
7979
function_arguments = {
80-
argument ~ (whitespace* ~ "," ~ whitespace* ~ argument)* ~ (whitespace* ~ ",")?
80+
argument ~ ("," ~ argument)* ~ ","?
8181
| ""
8282
}
8383
lambda = {
84-
"|" ~ whitespace* ~ formal_parameters ~ whitespace* ~ "|"
85-
~ whitespace* ~ template
84+
"|" ~ formal_parameters ~ "|" ~ template
8685
}
8786
formal_parameters = {
88-
identifier ~ (whitespace* ~ "," ~ whitespace* ~ identifier)* ~ (whitespace* ~ ",")?
87+
identifier ~ ("," ~ identifier)* ~ ","?
8988
| ""
9089
}
9190

9291
primary = _{
93-
("(" ~ whitespace* ~ template ~ whitespace* ~ ")")
92+
("(" ~ template ~ ")")
9493
| function
9594
| lambda
9695
| identifier
@@ -104,18 +103,17 @@ term = {
104103
}
105104

106105
expression = {
107-
(prefix_ops ~ whitespace*)* ~ term
108-
~ (whitespace* ~ infix_ops ~ whitespace* ~ (prefix_ops ~ whitespace*)* ~ term)*
106+
prefix_ops* ~ term ~ (infix_ops ~ prefix_ops* ~ term)*
109107
}
110108

111109
template = {
112-
expression ~ (whitespace* ~ concat_op ~ whitespace* ~ expression)*
110+
expression ~ (concat_op ~ expression)*
113111
}
114112

115-
program = _{ SOI ~ whitespace* ~ template? ~ whitespace* ~ EOI }
113+
program = _{ SOI ~ template? ~ EOI }
116114

117115
function_alias_declaration = {
118-
identifier ~ "(" ~ whitespace* ~ formal_parameters ~ whitespace* ~ ")"
116+
identifier ~ "(" ~ formal_parameters ~ ")"
119117
}
120118
alias_declaration = _{
121119
SOI ~ (function_alias_declaration | identifier) ~ EOI

cli/src/template_builder.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2295,6 +2295,9 @@ mod tests {
22952295

22962296
// Parenthesized method chaining
22972297
insta::assert_snapshot!(env.render_ok(r#"(hello).upper()"#), @"HELLO");
2298+
2299+
// Multi-line method chaining
2300+
insta::assert_snapshot!(env.render_ok("hello\n .upper()"), @"HELLO");
22982301
}
22992302

23002303
#[test]
@@ -2303,11 +2306,11 @@ mod tests {
23032306
env.add_keyword("description", || literal("".to_owned()));
23042307
env.add_keyword("empty", || literal(true));
23052308

2306-
insta::assert_snapshot!(env.parse_err(r#"description ()"#), @r"
2307-
--> 1:13
2309+
insta::assert_snapshot!(env.parse_err(r#"foo bar"#), @r"
2310+
--> 1:5
23082311
|
2309-
1 | description ()
2310-
| ^---
2312+
1 | foo bar
2313+
| ^---
23112314
|
23122315
= expected <EOI>, `++`, `||`, `&&`, `==`, `!=`, `>=`, `>`, `<=`, `<`, `+`, `-`, `*`, `/`, or `%`
23132316
");

cli/src/template_parser.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ impl Rule {
6262
fn to_symbol(self) -> Option<&'static str> {
6363
match self {
6464
Self::EOI => None,
65-
Self::whitespace => None,
65+
Self::WHITESPACE => None,
6666
Self::string_escape => None,
6767
Self::string_content_char => None,
6868
Self::string_content => None,
@@ -1076,6 +1076,16 @@ mod tests {
10761076

10771077
#[test]
10781078
fn test_string_literal() {
1079+
// Whitespace in string literal should be preserved
1080+
assert_eq!(
1081+
parse_into_kind(r#" " " "#),
1082+
Ok(ExpressionKind::String(" ".to_owned())),
1083+
);
1084+
assert_eq!(
1085+
parse_into_kind(r#" ' ' "#),
1086+
Ok(ExpressionKind::String(" ".to_owned())),
1087+
);
1088+
10791089
// "\<char>" escapes
10801090
assert_eq!(
10811091
parse_into_kind(r#" "\t\r\n\"\\\0\e" "#),

cli/tests/test_templater.rs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,6 @@ fn test_templater_parse_error() {
2323
let work_dir = test_env.work_dir("repo");
2424
let render = |template| get_template_output(&work_dir, "@-", template);
2525

26-
insta::assert_snapshot!(render(r#"description ()"#), @r"
27-
------- stderr -------
28-
Error: Failed to parse template: Syntax error
29-
Caused by: --> 1:13
30-
|
31-
1 | description ()
32-
| ^---
33-
|
34-
= expected <EOI>, `++`, `||`, `&&`, `==`, `!=`, `>=`, `>`, `<=`, `<`, `+`, `-`, `*`, `/`, or `%`
35-
[EOF]
36-
[exit status: 1]
37-
");
38-
3926
// Typo
4027
test_env.add_config(
4128
r###"

0 commit comments

Comments
 (0)