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" ;; create a couple shapes and get their area (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() }} {# outputs 'WELCOME' #} </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');