Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Template Toolkit 2 #1418

Merged
merged 17 commits into from
May 10, 2018
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions components.json
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,11 @@
"require": "markup",
"owner": "Golmote"
},
"tt2": {
"title": "Template Toolkit 2",
"require": ["clike", "markup-templating"],
"owner": "gflohr"
},
"twig": {
"title": "Twig",
"require": "markup",
Expand Down
67 changes: 67 additions & 0 deletions components/prism-tt2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
(function(Prism) {

Prism.languages.tt2 = Prism.languages.extend('clike', {
comment: {
pattern: /#.*|\[%#[^]*?%\]/,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've decided to use [\s\S] instead of [^] in #1107. Could you change this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I didn't know that.

lookbehind: true
},
keyword: /\b(?:GET|CALL|SET|DEFAULT|INSERT|INCLUDE|PROCESS|WRAPPER|BLOCK|IF|UNLESS|ELSIF|ELSE|SWITCH|CASE|FOREACH|IN|WHILE|FILTER|USE|MACRO|RAWPERL|PERL|TRY|THROW|CATCH|FINAL|NEXT|LAST|RETURN|STOP|CLEAR|META|TAGS|DEBUG|END)\b/,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considering the large number of keywords here, you might want to consider ordering them alphabetically, for easier addition/removal in the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are in the order of the directives documentation. Switch to alphabetical or go with the docs?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, could you then add a link to this doc page, in a comment above the regexp?

punctuation: /[[\]{},()]/
});

var operatorRE = /(?:=>|==|!=|<=|<|>=|>|=|&&|\|\||\||!|and|or|not)/;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could probably combine some patterns here to avoid backtracking.
Also, the parentheses around the whole regexp are not needed.
Finally, wouldn't it be safer to add \b assertions around the keyword operators?

Something like /=[>=]?|!=?|<=?|>=?|&&|\|\|?|\b(?:and|or|not)\b/?


Prism.languages.insertBefore('tt2', 'number', {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should add a line like delete Prism.languages.tt2['operator']; before you call insertBefore, so that the operator property can effectively be inserted. If it already exists, it will have unexpected behaviour.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I didn't know that and see whether that also fixes the FIXME below.

operator: operatorRE,
// A colon is not allowed inside variables but we want to catch things
// like [% USE Project::Specials %]
variable: {
pattern: /[a-z][:_a-z0-9]*(?:[\011-\015\040]*\.[\011-\015\040]*(?:\d+|\$?[a-z][:_a-z0-9]*))*/i,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't [\011-\015\040] be replaced with \s? Both don't have exactly the same meaning but it would make the regexp more clear I think.
Also, you can replace _a-z0-9 with \w.
Do you need the colon : inside the second part too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, with syntactically correct code \s is equivalent. Same for\w. I will change it to your preferences.

The colon was for fully qualified plug-in names (Foo::Bar). I thought they are supported but it looks like they actually don't work. So I will remove the colons. Even if they did work, the colons will then be highlighted as punctuation which is also okay.

greedy: true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do variables really need to be greedy? The greedy behaviour has a bit of a performance hit, so you should make sure you actually require it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do variables really need to be greedy? The greedy behaviour has a bit of a performance hit, so you should make sure you actually require it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the \b around the keyword-like operators and|or|not it is no longer needed. Thanks for the hint.

}
});

// FIXME! Is this repetition really necessary?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my previous comment regarding the deletion of the operator property. It should allow you to remove those lines.

Prism.languages.insertBefore('tt2', 'variable', {
operator: operatorRE
});

Prism.languages.insertBefore('tt2', 'keyword', {
'delimiter': {
pattern: /^(?:\[%|%%)-?|-?%]$/,
alias: 'punctuation'
}
});

Prism.languages.insertBefore('tt2', 'string', {
'single-quoted-string': {
pattern: /'[^\\']*(?:\\.[^\\']*)*'/,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This regexp is super smart! Love it!

It looks like TT2 allows multiline strings. Souldn't the regexp allow to escape line feeds? That is using \\[\s\S] instead of \\.?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the regexp is very smart. It's from Jeffrey Friedl, see http://regex.info/book.html

And, yes, you're right, in the absence of /s the newline must be matched as well. I'll fix it.

greedy: true,
alias: 'string'
},
'double-quoted-string': {
pattern: /"[^\\"]*(?:\\.[^\\"]*)*"/,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment regarding escaped line feeds.

greedy: true,
alias: 'string',
inside: {
variable: {
pattern: /\$(?:[a-z][_a-z0-9]*(?:\.(?:\d+|\$?[a-z][_a-z0-9]*))*)/i,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can replace [_a-z0-9] with \w.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can replace [_a-z0-9] with \w.

greedy: true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment here about the greedy feature.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment here about the greedy feature.

}
}
}
});

// The different types of TT2 strings "replace" the C-like standard string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please indent this comment with a tab.

delete Prism.languages.tt2.string;

Prism.hooks.add('before-tokenize', function(env) {
var tt2Pattern = /\[%[^]+?%\]/g;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment here about [^]. Please use [\s\S] instead.

Prism.languages['markup-templating'].buildPlaceholders(env, 'tt2', tt2Pattern);
});

Prism.hooks.add('after-tokenize', function(env) {
Prism.languages['markup-templating'].tokenizePlaceholders(env, 'tt2');
});

}(Prism));
61 changes: 61 additions & 0 deletions examples/prism-tt2.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<h2>Comments</h2>
<pre><code class="language-tt2">[%# this entire directive is ignored no
matter how many lines it wraps onto
%]
[% # this is a comment
theta = 20 # so is this
rho = 30 # <aol>me too!</aol>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll probably need to escape the < characters using &lt; in <aol> and </aol>.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll probably need to escape the < characters using &lt; in <aol> and </aol>.

%]
</code></pre>

<h2>Variables</h2>
<pre><code class="language-tt2">[% text %]
[% article.title %]
[%= eat.whitespace.left %]
[% eat.whitespace.right =%]
[%= eat.whitespace.both =%]
[% object.method() %]</code></pre>


<h2>Conditionals and Loops</h2>
<pre><code class="language-tt2">[% IF foo = bar %]
this
[% ELSE %]
that
[% END %]
[% FOREACH post IN q.listPosts(lingua = "de") %]
&lt;a href="[% post.permalink %]"&gt;[% post.title | html %]&lt;/a&gt;
[% END %]</code></pre>

<h2>Multiple Directives</h2>
<pre><code class="language-tt2">[% IF title;
INCLUDE header;
ELSE;
INCLUDE other/header title="Some Other Title";
END
%]</code></pre>

<h2>Operators</h2>
<pre><code class="language-tt2">[% FOREACH post IN q.listPosts(lingua => 'de') %]
[% post.title | myfilter(foo = "bar") %]
[% END %]</code></pre>

<h2>Known Limitations</h2>
<ul>
<li><a href="http://template-toolkit.org/docs/manual/Syntax.html#section_Outline_Tags">
Outline tags</a> are not supported.</li>
<li>The arguments to
<a href="http://template-toolkit.org/docs/manual/Directives.html#section_TAGS">TAGS</a>
are usually misinterpreted</li>
<li>In TT2, you can use keywords as identifiers where this is
unambiguous. But these keywords will be highlighted as keywords, not
as variables here.</li>
<li>The
<a href="http://template-toolkit.org/docs/manual/Config.html#section_ANYCASE">ANYCASE</a>
option is not supprted.</li>
Copy link
Contributor

@Golmote Golmote May 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"supported"

EDIT: Considering the title of the PR, I guess you really don't like the "o" in "support". 😄

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a typo here: "supported".

<li>
Any number of backslashes in front of dollar signs inside of double quoted
strings are ignored since the behavior of Template Toolkit 2.26 seems to be
inconsistent.
</li>
</ul>
89 changes: 89 additions & 0 deletions tests/languages/markup+tt2/tt2_in_markup_feature.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<div>[% foo.bar.baz %]</div>
<div>[%- foo.bar.baz %]</div>
<div>[% foo.bar.baz -%]</div>
<div>[%- foo.bar.baz -%]</div>

----------------------------------------------------

[
["tag", [
["tag", [
["punctuation", "<"],
"div"
]],
["punctuation", ">"]
]],
["tt2", [
["delimiter", "[%"],
["variable", "foo.bar.baz"],
["delimiter", "%]"]
]],
["tag", [
["tag", [
["punctuation", "</"],
"div"
]],
["punctuation", ">"]
]],
["tag", [
["tag", [
["punctuation", "<"],
"div"
]],
["punctuation", ">"]
]],
["tt2", [
["delimiter", "[%-"],
["variable", "foo.bar.baz"],
["delimiter", "%]"]
]],
["tag", [
["tag", [
["punctuation", "</"],
"div"
]],
["punctuation", ">"]
]],
["tag", [
["tag", [
["punctuation", "<"],
"div"
]],
["punctuation", ">"]
]],
["tt2", [
["delimiter", "[%"],
["variable", "foo.bar.baz"],
["delimiter", "-%]"]
]],
["tag", [
["tag", [
["punctuation", "</"],
"div"
]],
["punctuation", ">"]
]],
["tag", [
["tag", [
["punctuation", "<"],
"div"
]],
["punctuation", ">"]
]],
["tt2", [
["delimiter", "[%-"],
["variable", "foo.bar.baz"],
["delimiter", "-%]"]
]],
["tag", [
["tag", [
["punctuation", "</"],
"div"
]],
["punctuation", ">"]
]]
]

----------------------------------------------------

Checks for Template Toolkit 2 inside Markup.
36 changes: 36 additions & 0 deletions tests/languages/tt2/comment_feature.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[%# this entire directive is ignored no
matter how many lines it wraps onto
%]
[% # this is a comment
theta = 20 # so is this
rho = 30 # <aol>me too!</aol>
%]

----------------------------------------------------

[
["tt2",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please indent this line with a tab.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please indent this line with a tab.

[
["comment", "[%# this entire directive is ignored no\r\n matter how many lines it wraps onto\r\n%]" ]
]
],
["tt2",
[
["delimiter", "[%"],
["comment", "# this is a comment" ],
["variable", "theta"],
["operator", "="],
["number", "20"],
["comment", "# so is this" ],
["variable", "rho"],
["operator", "="],
["number", "30"],
["comment", "# <aol>me too!</aol>"],
["delimiter", "%]"]
]
]
]

----------------------------------------------------

Checks for single-line and multi-line comments.
18 changes: 18 additions & 0 deletions tests/languages/tt2/delimiter_feature.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[%- %]
[% -%]
[%- -%]
[%
%]

----------------------------------------------------

[
["tt2", [["delimiter", "[%-"], ["delimiter", "%]"]]],
["tt2", [["delimiter", "[%"], ["delimiter", "-%]"]]],
["tt2", [["delimiter", "[%-"], ["delimiter", "-%]"]]],
["tt2", [["delimiter", "[%"], ["delimiter", "%]"]]]
]

----------------------------------------------------

Checks for delimiters.
Loading