diff --git a/README.md b/README.md index f3000902..c6032708 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ Colorization and configuration supports for multiple languages for the Monaco Ed * sql * st * swift +* twig * typescript * vb * xml diff --git a/scripts/bundle.js b/scripts/bundle.js index 251a2439..bf06da5b 100644 --- a/scripts/bundle.js +++ b/scripts/bundle.js @@ -75,6 +75,7 @@ bundleOne('azcli/azcli'); bundleOne('apex/apex'); bundleOne('tcl/tcl'); bundleOne('graphql/graphql'); +bundleOne('twig/twig'); function bundleOne(moduleId, exclude) { requirejs.optimize({ diff --git a/src/monaco.contribution.ts b/src/monaco.contribution.ts index bd1b5303..544ecf2e 100644 --- a/src/monaco.contribution.ts +++ b/src/monaco.contribution.ts @@ -48,6 +48,7 @@ import './sql/sql.contribution'; import './st/st.contribution'; import './swift/swift.contribution'; import './tcl/tcl.contribution'; +import './twig/twig.contribution'; import './typescript/typescript.contribution'; import './vb/vb.contribution'; import './xml/xml.contribution'; diff --git a/src/twig/twig.contribution.ts b/src/twig/twig.contribution.ts new file mode 100644 index 00000000..d5a02590 --- /dev/null +++ b/src/twig/twig.contribution.ts @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { registerLanguage } from '../_.contribution'; + +registerLanguage({ + id: 'twig', + extensions: ['.twig'], + aliases: ['Twig', 'twig'], + mimetypes: ['text/x-twig'], + loader: () => import('./twig') +}); diff --git a/src/twig/twig.test.ts b/src/twig/twig.test.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/twig/twig.ts b/src/twig/twig.ts new file mode 100644 index 00000000..d64787f8 --- /dev/null +++ b/src/twig/twig.ts @@ -0,0 +1,140 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import IRichLanguageConfiguration = monaco.languages.LanguageConfiguration; +import ILanguage = monaco.languages.IMonarchLanguage; + +export const conf: IRichLanguageConfiguration = { +}; + +export const language = { + defaultToken: 'invalid', + + keywords: [ + // (opening) tags + 'apply', 'autoescape', 'block', 'deprecated', 'do', 'embed', 'extends', + 'flush', 'for', 'from', 'if', 'import', 'include', 'macro', 'sandbox', + 'set', 'use', 'verbatim', 'with', + // closing tags + 'endapply', 'endautoescape', 'endblock', 'endembed', 'endfor', 'endif', + 'endmacro', 'endsandbox', 'endset', 'endwith', + ], + + tokenizer: { + root: [ + [/{#/, 'comment.twig', '@commentState'], + [/{%[-~]?/, 'delimiter.twig', '@blockState'], + [/{{[-~]?/, 'delimiter.twig', '@variableState'], + ], + + /** + * Comment Tag Handling + */ + commentState: [ + [/#}/, 'comment.twig', '@pop'], + [/./, 'comment.twig'], + ], + + /** + * Block Tag Handling + */ + blockState: [ + [/[-~]?%}/, 'delimiter.twig', '@pop'], + // whitespace + [/\s+/], + // verbatim + // Unlike other blocks, verbatim ehas its own state + // transition to ensure we mark its contents as strings. + [/(verbatim)(\s*)([-~]?%})/, [ + 'keyword', + '', + { token: 'delimiter.twig', next: '@rawDataState' }, + ]], + { include: 'expression' } + ], + + rawDataState: [ + // endverbatim + [/({%[-~]?)(\s*)(endverbatim)(\s*)([-~]?%})/, [ + 'delimiter.twig', + '', + 'keyword', + '', + { token: 'delimiter.twig', next: '@popall' }, + ]], + [/./, 'string'], + ], + + /** + * Variable Tag Handling + */ + variableState: [ + [/[-~]?}}/, 'delimiter.twig', '@pop'], + { include: 'expression' }, + ], + + stringState: [ + // closing double quoted string + [/"/, 'string.twig', '@pop'], + // interpolation start + [/#{\s*/, 'string.twig', '@interpolationState'], + // string part + [/[^#"\\]*(?:(?:\\.|#(?!\{))[^#"\\]*)*/, 'string.twig'], + ], + + interpolationState: [ + // interpolation end + [/}/, 'string.twig', '@pop'], + { include: 'expression' }, + ], + + /** + * Expression Handling + */ + expression: [ + // whitespace + [/\s+/], + // operators - math + [/\+|-|\/{1,2}|%|\*{1,2}/, 'operators.twig'], + // operators - logic + [/(and|or|not|b-and|b-xor|b-or)(\s+)/, ['operators.twig', '']], + // operators - comparison (symbols) + [/==|!=|<|>|>=|<=/, 'operators.twig'], + // operators - comparison (words) + [/(starts with|ends with|matches)(\s+)/, ['operators.twig', '']], + // operators - containment + [/(in)(\s+)/, ['operators.twig', '']], + // operators - test + [/(is)(\s+)/, ['operators.twig', '']], + // operators - misc + [/\||~|:|\.{1,2}|\?{1,2}/, 'operators.twig'], + // names + [/[^\W\d][\w]*/, { + cases: { + '@keywords': 'keyword.twig', + '@default': 'variable.twig' + } + }], + // numbers + [/\d+(\.\d+)?/, 'number.twig'], + // punctuation + [/\(|\)|\[|\]|{|}|,/, 'delimiter.twig'], + // strings + [/"([^#"\\]*(?:\\.[^#"\\]*)*)"|\'([^\'\\]*(?:\\.[^\'\\]*)*)\'/, 'string.twig'], + // opening double quoted string + [/"/, 'string.twig', '@stringState'], + + // misc syntactic constructs + // These are not operators per se, but for the purposes of lexical analysis we + // can treat them as such. + // arrow functions + [/=>/, 'operators.twig'], + // assignment + [/=/, 'operators.twig'], + ], + } +}; diff --git a/test/setup.js b/test/setup.js index e72fb2c1..cb76ebbc 100644 --- a/test/setup.js +++ b/test/setup.js @@ -75,6 +75,7 @@ define(['require'], function () { 'release/dev/st/st.test', 'release/dev/swift/swift.test', 'release/dev/tcl/tcl.test', + 'release/dev/twig/twig.test', 'release/dev/typescript/typescript.test', 'release/dev/vb/vb.test', 'release/dev/xml/xml.test',