diff --git a/CHANGES.md b/CHANGES.md
index 78c9fbe6c7..de2488e9ea 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -2,6 +2,7 @@
Grammars:
+- enh(twig) update keywords list (#3415) [Matthieu Lempereur][]
- fix(python) def, class keywords detected mid-identifier (#3381) [Josh Goebel][]
- fix(python) Fix recognition of numeric literals followed by keywords without whitespace (#2985) [Richard Gibson][]
- enh(swift) add SE-0290 unavailability condition (#3382) [Bradley Mackey][]
@@ -34,6 +35,7 @@ Themes:
[Björn Ebbinghaus]: https://github.com/MrEbbinghaus
[Josh Goebel]: https://github.com/joshgoebel
[Samia Ali]: https://github.com/samiaab1990
+[Matthieu Lempereur]: https://github.com/MrYamous
[idleberg]: https://github.com/idleberg
## Version 11.3.1
diff --git a/src/languages/twig.js b/src/languages/twig.js
index 4ea7bd041a..3e4a26257d 100644
--- a/src/languages/twig.js
+++ b/src/languages/twig.js
@@ -8,67 +8,208 @@ Category: template
*/
export default function(hljs) {
- var PARAMS = {
- className: 'params',
- begin: '\\(', end: '\\)'
+ const regex = hljs.regex;
+ const FUNCTION_NAMES = [
+ "attribute",
+ "block",
+ "constant",
+ "country_timezones",
+ "cycle",
+ "date",
+ "dump",
+ "html_classes",
+ "include",
+ "max",
+ "min",
+ "parent",
+ "random",
+ "range",
+ "source",
+ "template_from_string"
+ ];
+
+ const FILTERS = [
+ "abs",
+ "batch",
+ "capitalize",
+ "column",
+ "convert_encoding",
+ "country_name",
+ "currency_name",
+ "currency_symbol",
+ "data_uri",
+ "date",
+ "date_modify",
+ "default",
+ "escape",
+ "filter",
+ "first",
+ "format",
+ "format_currency",
+ "format_date",
+ "format_datetime",
+ "format_number",
+ "format_time",
+ "html_to_markdown",
+ "inky_to_html",
+ "inline_css",
+ "join",
+ "json_encode",
+ "keys",
+ "language_name",
+ "last",
+ "length",
+ "locale_name",
+ "lower",
+ "map",
+ "markdown",
+ "markdown_to_html",
+ "merge",
+ "nl2br",
+ "number_format",
+ "raw",
+ "reduce",
+ "replace",
+ "reverse",
+ "round",
+ "slice",
+ "slug",
+ "sort",
+ "spaceless",
+ "split",
+ "striptags",
+ "timezone_name",
+ "title",
+ "trim",
+ "u|0",
+ "upper",
+ "url_encode"
+ ];
+
+ let TAG_NAMES = [
+ "apply",
+ "autoescape",
+ "block",
+ "cache",
+ "deprecated",
+ "do",
+ "embed",
+ "extends",
+ "filter",
+ "flush",
+ "for",
+ "from",
+ "if",
+ "import",
+ "include",
+ "macro",
+ "sandbox",
+ "set",
+ "use",
+ "verbatim",
+ "with"
+ ];
+
+ TAG_NAMES = TAG_NAMES.concat(TAG_NAMES.map(t => `end${t}`));
+
+ const STRING = {
+ scope: 'string',
+ variants: [
+ {
+ begin: /'/,
+ end: /'/
+ },
+ {
+ begin: /"/,
+ end: /"/
+ },
+ ]
};
- var FUNCTION_NAMES = 'attribute block constant cycle date dump include ' +
- 'max min parent random range source template_from_string';
+ const NUMBER = {
+ scope: "number",
+ match: /\d+/
+ };
- var FUNCTIONS = {
- beginKeywords: FUNCTION_NAMES,
- keywords: {name: FUNCTION_NAMES},
- relevance: 0,
+ const PARAMS = {
+ begin: /\(/,
+ end: /\)/,
+ excludeBegin: true,
+ excludeEnd: true,
contains: [
- PARAMS
+ STRING,
+ NUMBER
]
};
- var FILTER = {
- begin: /\|[A-Za-z_]+:?/,
- keywords:
- 'abs batch capitalize column convert_encoding date date_modify default ' +
- 'escape filter first format inky_to_html inline_css join json_encode keys last ' +
- 'length lower map markdown merge nl2br number_format raw reduce replace ' +
- 'reverse round slice sort spaceless split striptags title trim upper url_encode',
+
+ const FUNCTIONS = {
+ beginKeywords: FUNCTION_NAMES.join(" "),
+ keywords: { name: FUNCTION_NAMES },
+ relevance: 0,
+ contains: [ PARAMS ]
+ };
+
+ const FILTER = {
+ match: /\|(?=[A-Za-z_]+:?)/,
+ beginScope: "punctuation",
+ relevance: 0,
contains: [
- FUNCTIONS
+ {
+ match: /[A-Za-z_]+:?/,
+ keywords: FILTERS
+ },
]
};
- var TAGS = 'apply autoescape block deprecated do embed extends filter flush for from ' +
- 'if import include macro sandbox set use verbatim with';
+ const tagNamed = (tagnames, {relevance}) => {
+ return {
+ beginScope: {
+ 1: 'template-tag',
+ 3: 'name'
+ },
+ relevance: relevance || 2,
+ endScope: 'template-tag',
+ begin: [
+ /\{%/,
+ /\s*/,
+ regex.either(...tagnames)
+ ],
+ end: /%\}/,
+ keywords: "in",
+ contains: [
+ FILTER,
+ FUNCTIONS,
+ STRING,
+ NUMBER
+ ]
+ };
+ };
- TAGS = TAGS + ' ' + TAGS.split(' ').map(function(t){return 'end' + t}).join(' ');
+ const CUSTOM_TAG_RE = /[a-z_]+/;
+ const TAG = tagNamed(TAG_NAMES, { relevance: 2 });
+ const CUSTOM_TAG = tagNamed([ CUSTOM_TAG_RE ], { relevance: 1 });
return {
name: 'Twig',
- aliases: ['craftcms'],
+ aliases: [ 'craftcms' ],
case_insensitive: true,
subLanguage: 'xml',
contains: [
hljs.COMMENT(/\{#/, /#\}/),
+ TAG,
+ CUSTOM_TAG,
{
- className: 'template-tag',
- begin: /\{%/, end: /%\}/,
+ className: 'template-variable',
+ begin: /\{\{/,
+ end: /\}\}/,
contains: [
- {
- className: 'name',
- begin: /\w+/,
- keywords: TAGS,
- starts: {
- endsWithParent: true,
- contains: [FILTER, FUNCTIONS],
- relevance: 0
- }
- }
+ 'self',
+ FILTER,
+ FUNCTIONS,
+ STRING,
+ NUMBER
]
- },
- {
- className: 'template-variable',
- begin: /\{\{/, end: /\}\}/,
- contains: ['self', FILTER, FUNCTIONS]
}
]
};
diff --git a/test/markup/clojure/globals_definition.expect.txt b/test/markup/clojure/globals_definition.expect.txt
index 832e283cd4..efc8a15c9a 100644
--- a/test/markup/clojure/globals_definition.expect.txt
+++ b/test/markup/clojure/globals_definition.expect.txt
@@ -69,4 +69,4 @@ string"
(def myCircle (Circle. 10))
-(def mySquare (Square. 5 11))
\ No newline at end of file
+(def mySquare (Square. 5 11))
diff --git a/test/markup/clojure/symbols-numbers.expect.txt b/test/markup/clojure/symbols-numbers.expect.txt
index 7813d22876..2808223dcc 100644
--- a/test/markup/clojure/symbols-numbers.expect.txt
+++ b/test/markup/clojure/symbols-numbers.expect.txt
@@ -1,4 +1,4 @@
(def +x [(a 1) +2 -3.0 y-5])
(System/getProperty "java.vm.version")
(.getEnclosingClass java.util.Map$Entry)
-(java.util.Map$Entry. .getEnclosingClass)
+(java.util.Map$Entry. .getEnclosingClass)
\ No newline at end of file
diff --git a/test/markup/fsharp/bang-keywords.expect.txt b/test/markup/fsharp/bang-keywords.expect.txt
index c47d939e94..f681697fdf 100644
--- a/test/markup/fsharp/bang-keywords.expect.txt
+++ b/test/markup/fsharp/bang-keywords.expect.txt
@@ -1 +1 @@
-let! (result2 : byte[]) = stream.AsyncRead(bufferSize)
\ No newline at end of file
+let! (result2 : byte[]) = stream.AsyncRead(bufferSize)
diff --git a/test/markup/fsharp/computation-expressions.expect.txt b/test/markup/fsharp/computation-expressions.expect.txt
index 76cb4486bd..af296f3f2c 100644
--- a/test/markup/fsharp/computation-expressions.expect.txt
+++ b/test/markup/fsharp/computation-expressions.expect.txt
@@ -20,4 +20,4 @@
return result
}
-let result = work |> Async.RunSynchronously
\ No newline at end of file
+let result = work |> Async.RunSynchronously
diff --git a/test/markup/fsharp/types.expect.txt b/test/markup/fsharp/types.expect.txt
index 0ad8b0c6a7..e48881af06 100644
--- a/test/markup/fsharp/types.expect.txt
+++ b/test/markup/fsharp/types.expect.txt
@@ -140,4 +140,4 @@
| CaseK of ``var with spaces``: string
| CaseL of ``var with spaces``: ``type with spaces``
| CaseM of v1 : ``type with spaces``
- | CaseN of ``type with spaces``
\ No newline at end of file
+ | CaseN of ``type with spaces``
diff --git a/test/markup/twig/filter_with_underscore.expect.txt b/test/markup/twig/filter_with_underscore.expect.txt
index 72c93fd877..9d2928531a 100644
--- a/test/markup/twig/filter_with_underscore.expect.txt
+++ b/test/markup/twig/filter_with_underscore.expect.txt
@@ -1 +1 @@
-{{ "string with spaces"|url_encode }}
\ No newline at end of file
+{{ "string with spaces"|url_encode }}
\ No newline at end of file
diff --git a/test/markup/twig/template_tags.expect.txt b/test/markup/twig/template_tags.expect.txt
index 410fb24347..0127a33510 100644
--- a/test/markup/twig/template_tags.expect.txt
+++ b/test/markup/twig/template_tags.expect.txt
@@ -1,12 +1,12 @@
-{% if posts|length %}
- {% for article in articles %}
+{% if posts|length %}
+ {% for article in articles %}
<div>
- {{ article.title|upper() }}
+ {{ article.title|upper() }}
</div>
- {% endfor %}
-{% endif %}
+ {% endfor %}
+{% endif %}
-{% set user = json_encode(user) %}
+{% set user = json_encode(user) %}
\ No newline at end of file
diff --git a/tools/checkAutoDetect.js b/tools/checkAutoDetect.js
index 0a725985a8..0da66c8dfd 100755
--- a/tools/checkAutoDetect.js
+++ b/tools/checkAutoDetect.js
@@ -2,7 +2,7 @@
'use strict';
const fs = require('fs');
-const hljs = require('../build.js');
+const hljs = require('../build/lib/index.js');
const path = require('path');
const utility = require('../test/utility.js');
const Table = require('cli-table');