From 94f81dc4ae2d94181c2ed6957667e82cb2ee8edd Mon Sep 17 00:00:00 2001 From: Andre Wachsmuth Date: Sun, 12 Dec 2021 01:55:01 +0100 Subject: [PATCH] Implements #2383 Add syntax modes for FreeMarker template language --- .../freemarker2-angle-bracket.test.ts | 3099 ++++++++++ .../freemarker2-angle-dollar.test.ts | 3099 ++++++++++ .../freemarker2-auto-bracket.test.ts | 5358 ++++++++++++++++ .../freemarker2-auto-dollar.test.ts | 5361 +++++++++++++++++ .../freemarker2-bracket-bracket.test.ts | 3086 ++++++++++ .../freemarker2-bracket-dollar.test.ts | 3086 ++++++++++ .../freemarker2/freemarker2.contribution.ts | 111 + .../freemarker2/freemarker2.ts | 1230 ++++ src/basic-languages/monaco.contribution.ts | 1 + ...arker2.tag-angle.interpolation-bracket.txt | 61 + ...marker2.tag-angle.interpolation-dollar.txt | 61 + ...marker2.tag-auto.interpolation-bracket.txt | 65 + ...emarker2.tag-auto.interpolation-dollar.txt | 65 + ...ker2.tag-bracket.interpolation-bracket.txt | 61 + ...rker2.tag-bracket.interpolation-dollar.txt | 61 + website/index/samples/sample.freemarker2.txt | 61 + 16 files changed, 24866 insertions(+) create mode 100644 src/basic-languages/freemarker2/freemarker2-angle-bracket.test.ts create mode 100644 src/basic-languages/freemarker2/freemarker2-angle-dollar.test.ts create mode 100644 src/basic-languages/freemarker2/freemarker2-auto-bracket.test.ts create mode 100644 src/basic-languages/freemarker2/freemarker2-auto-dollar.test.ts create mode 100644 src/basic-languages/freemarker2/freemarker2-bracket-bracket.test.ts create mode 100644 src/basic-languages/freemarker2/freemarker2-bracket-dollar.test.ts create mode 100644 src/basic-languages/freemarker2/freemarker2.contribution.ts create mode 100644 src/basic-languages/freemarker2/freemarker2.ts create mode 100644 website/index/samples/sample.freemarker2.tag-angle.interpolation-bracket.txt create mode 100644 website/index/samples/sample.freemarker2.tag-angle.interpolation-dollar.txt create mode 100644 website/index/samples/sample.freemarker2.tag-auto.interpolation-bracket.txt create mode 100644 website/index/samples/sample.freemarker2.tag-auto.interpolation-dollar.txt create mode 100644 website/index/samples/sample.freemarker2.tag-bracket.interpolation-bracket.txt create mode 100644 website/index/samples/sample.freemarker2.tag-bracket.interpolation-dollar.txt create mode 100644 website/index/samples/sample.freemarker2.txt diff --git a/src/basic-languages/freemarker2/freemarker2-angle-bracket.test.ts b/src/basic-languages/freemarker2/freemarker2-angle-bracket.test.ts new file mode 100644 index 00000000..28736a15 --- /dev/null +++ b/src/basic-languages/freemarker2/freemarker2-angle-bracket.test.ts @@ -0,0 +1,3099 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { testTokenization } from '../test/testRunner'; + +testTokenization('freemarker2.tag-angle.interpolation-bracket', [ + // Plain text + [ + { + line: 'abc123./]})>', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + // HTML comment is not FreeMarker comment + { + line: '', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + // Bracket tag syntax is plain text in angle tag syntax mode + { + line: '[#if user == "Big Joe"] Hello user [/#if]', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + // Dollar interpolation syntax is plain text in bracket interpolation syntax mode + { + line: 'Hello, ${user} !', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + } + ], + + // Block comment (terse) + [ + { + line: 'x<#--a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'comment.freemarker2' } + ] + }, + { + line: 'b <#if><#noparse>', + tokens: [{ startIndex: 0, type: 'comment.freemarker2' }] + }, + { + line: 'c-->y', + tokens: [ + { startIndex: 0, type: 'comment.freemarker2' }, + { startIndex: 4, type: 'source.freemarker2' } + ] + } + ], + // Not a block comment (terse) + [ + { + line: 'x[#--a', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'b', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'c--]y', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + } + ], + // Block comment (tag) + [ + { + line: 'x<#comment>a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 11, type: 'comment.freemarker2' } + ] + }, + { + line: 'b <#if> <#noparse> -->', + tokens: [{ startIndex: 0, type: 'comment.freemarker2' }] + }, + { + line: 'cy', + tokens: [ + { startIndex: 0, type: 'comment.freemarker2' }, + { startIndex: 1, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 12, type: 'source.freemarker2' } + ] + } + ], + + // Not a block comment (tag) + [ + { + line: 'x[#comment]a', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'b', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'c[/#comment]y', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + } + ], + + // Expression comments + [ + // Angle syntax (no spaces) + { + line: '[=2+3]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'comment.freemarker2' }, + { startIndex: 20, type: 'number.freemarker2' }, + { startIndex: 21, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Angle syntax (spaces) + { + line: '[=2+ 3]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'comment.freemarker2' }, + { startIndex: 21, type: '' }, + { startIndex: 22, type: 'number.freemarker2' }, + { startIndex: 23, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Bracket syntax (no spaces) + { + line: '[=2+[!-- comment --]3]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'comment.freemarker2' }, + { startIndex: 20, type: 'number.freemarker2' }, + { startIndex: 21, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=[[!-- comment --]3]]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.square.freemarker2' }, + { startIndex: 3, type: 'comment.freemarker2' }, + { startIndex: 19, type: 'number.freemarker2' }, + { startIndex: 20, type: 'delimiter.square.freemarker2' }, + { startIndex: 21, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Bracket syntax (spaces) + { + line: '[=2+ [!-- comment --] 3]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'comment.freemarker2' }, + { startIndex: 21, type: '' }, + { startIndex: 22, type: 'number.freemarker2' }, + { startIndex: 23, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // noparse (ignores everything until the matching closing tag) + [ + { + line: 'x<#noparse>a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 11, type: 'source.freemarker2' } + ] + }, + { + line: 'b <#if> ', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'cy', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 12, type: 'source.freemarker2' } + ] + } + ], + + // noParse (ignores everything until the matching closing tag) + [ + { + line: 'x<#noParse>a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 11, type: 'source.freemarker2' } + ] + }, + { + line: 'b <#if> ', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'cy', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 12, type: 'source.freemarker2' } + ] + } + ], + + // Closing angle bracket treatment + [ + // Comparison operator when inside an interpolation + { + line: '[=1>2]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'number.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=1>=2]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Directive end tag when inside a directive + { + line: '<#if 1>2', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 7, type: 'source.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 9, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'tag.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Normal comparison operator when inside parentheses within a directive + // Only considers parentheses, not other brackets + { + line: '<#if (1>2)>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 14, type: 'tag.freemarker2' }, + { startIndex: 16, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#if (1>=2)>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 13, type: 'delimiter.directive.freemarker2' }, + { startIndex: 15, type: 'tag.freemarker2' }, + { startIndex: 17, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#if [1>2]>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.square.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 8, type: 'source.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 14, type: 'tag.freemarker2' }, + { startIndex: 16, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#if [(1>2)]>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.square.freemarker2' }, + { startIndex: 6, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'operators.freemarker2' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 14, type: 'delimiter.directive.freemarker2' }, + { startIndex: 16, type: 'tag.freemarker2' }, + { startIndex: 18, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + + // Mismatched closing bracket / parenthesis does not end expression mode + [ + // Interpolation + { + line: '[=)1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=}1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.curly.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=>1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'operators.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // // Directive + { + line: '<#if )1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#if ]1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.square.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#if }1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + + // Boolean literals + [ + { + line: '[=false]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=true]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.true.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Number literals + [ + { + line: '[=123]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=123.456]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'number.float.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Interpolated string literals (single quote) + [ + // Empty string + { + line: "[='']", + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Literal content + { + line: "[='abc']", + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Escaped characters (named) + { + line: "[='\\n\\t\\r\\f\\b\\g\\l\\a\\\\\\'\\{\\=']", + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 3, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 28, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Escaped characters (unicode, 1-4 hex digits) + { + line: "[='\\x1\\x11\\x111\\x1111\\x11111']", + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 3, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 29, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // String interpolation (unsupported, not possible with Monarch?) + { + // this evaluates to "ab0cd" and contains three interpolations + line: "[='a[=\\'b[=\\\\\\'[=0]\\\\\\']c\\'}d']", + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 6, type: 'string.escape.freemarker2' }, + { startIndex: 8, type: 'string.freemarker2' }, + { startIndex: 11, type: 'string.escape.freemarker2' }, + { startIndex: 15, type: 'string.freemarker2' }, + { startIndex: 19, type: 'string.escape.freemarker2' }, + { startIndex: 23, type: 'string.freemarker2' }, + { startIndex: 25, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 30, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + // Interpolated string literals (double quote) + [ + // Empty string + { + line: '[=""]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Literal content + { + line: '[="abc"]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Escaped characters (named) + { + line: '[="\\n\\t\\r\\f\\b\\g\\l\\a\\\\\\\'\\{\\="]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 3, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 28, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Escaped characters (unicode, 1-4 hex digits) + { + line: '[="\\x1\\x11\\x111\\x1111\\x11111"]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 3, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 29, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // String interpolation (unsupported, not possible with Monarch?) + { + // this evaluates to "ab0cd" and contains three interpolations + line: '[="a[=\\"b[=\\\\\\"[=0}\\\\\\"]c\\"]d"]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 6, type: 'string.escape.freemarker2' }, + { startIndex: 8, type: 'string.freemarker2' }, + { startIndex: 11, type: 'string.escape.freemarker2' }, + { startIndex: 15, type: 'string.freemarker2' }, + { startIndex: 19, type: 'string.escape.freemarker2' }, + { startIndex: 23, type: 'string.freemarker2' }, + { startIndex: 25, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 30, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Raw string literals (single quote) + [ + // Empty string + { + line: "[=r'']", + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Literal content + { + line: "[=r'abc']", + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Raw string can contain anything other than the opening quote mark + { + line: "[=r'\"\\n\\x1']", + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Raw string literals (double quote) + [ + // Empty string + { + line: '[=r""]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Literal content + { + line: '[=r"abc"]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Raw string can contain anything other than the opening quote mark + { + line: '[=r"\'\\n\\x1"]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Boolean operators + [ + { + line: '[=!false]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'operators.freemarker2' }, + { startIndex: 3, type: 'keyword.false.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=false&true]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 8, type: 'keyword.true.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=false&&true]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 9, type: 'keyword.true.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=false&&true]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 17, type: 'keyword.true.freemarker2' }, + { startIndex: 21, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=false\\andtrue]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'keyword.true.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=false|true]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 8, type: 'keyword.true.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=false||true]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 9, type: 'keyword.true.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Sequence literals + [ + // range (inclusive) + { + line: '[=(1..3)]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // range (exclusive) + { + line: '[=(1..<3)]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // range (exclusive) (alternative form) + { + line: '[=(1..!3)]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // range (length-limited) + { + line: '[=(1..*3)]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // range (right-unbounded) + { + line: '[=(1..)]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 6, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // List literals + [ + // Can be used in directives + { + line: '<#assign s=[1,2]>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.freemarker2' }, + { startIndex: 14, type: 'number.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2' }, + { startIndex: 16, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Can be used in interpolations + { + line: '[=[1,2]]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.square.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.freemarker2' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Hash literals + [ + // Can be used in directives + { + line: '<#assign s={"foo":9}>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.curly.freemarker2' }, + { startIndex: 12, type: 'string.freemarker2' }, + { startIndex: 17, type: 'delimiter.freemarker2' }, + { startIndex: 18, type: 'number.freemarker2' }, + { startIndex: 19, type: 'delimiter.curly.freemarker2' }, + { startIndex: 20, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Can be used in interpolations + { + line: '[={"foo":9}.foo+4]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.curly.freemarker2' }, + { startIndex: 3, type: 'string.freemarker2' }, + { startIndex: 8, type: 'delimiter.freemarker2' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.curly.freemarker2' }, + { startIndex: 11, type: 'delimiter.freemarker2' }, + { startIndex: 12, type: 'identifier.freemarker2' }, + { startIndex: 15, type: 'operators.freemarker2' }, + { startIndex: 16, type: 'number.freemarker2' }, + { startIndex: 17, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Comparison operators + [ + { + line: '[=a=b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a==b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a!=b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=ab]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a gt b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a \\gt b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a > b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a>=b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a \\gte b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a >= b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'identifier.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + // Assignment operators + [ + { + line: '<#assign a+=2>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#assign a-=2>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#assign a*=2>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#assign a/=2>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#assign a%=2>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + + // Increment operators + [ + { + line: '<#assign a++>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#assign a-->', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + + // Numerical operators + [ + { + line: '[=a+b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a-b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a*b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a/b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a%b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Not an operator, only used to index hashes + // But still tokenized as 2 operators + { + line: '[=a**b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Missing value test operator + [ + { + line: '[=a??]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Lambdas + [ + // Single argument without parentheses + { + line: '[=a?map(x->x*2)]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'meta.arrow.freemarker2' }, + { startIndex: 11, type: 'identifier.freemarker2' }, + { startIndex: 12, type: 'operators.freemarker2' }, + { startIndex: 13, type: 'number.freemarker2' }, + { startIndex: 14, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Alternative arrow representation + { + line: '[=a?map(x->x*2)]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'meta.arrow.freemarker2' }, + { startIndex: 14, type: 'identifier.freemarker2' }, + { startIndex: 15, type: 'operators.freemarker2' }, + { startIndex: 16, type: 'number.freemarker2' }, + { startIndex: 17, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 18, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Single argument with parentheses + { + line: '[=a?map((x)->x*2)]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 11, type: 'meta.arrow.freemarker2' }, + { startIndex: 13, type: 'identifier.freemarker2' }, + { startIndex: 14, type: 'operators.freemarker2' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 17, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Multiple arguments with parentheses + { + line: '[=a?map((x,y)->x*2)]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.freemarker2' }, + { startIndex: 11, type: 'identifier.freemarker2' }, + { startIndex: 12, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 13, type: 'meta.arrow.freemarker2' }, + { startIndex: 15, type: 'identifier.freemarker2' }, + { startIndex: 16, type: 'operators.freemarker2' }, + { startIndex: 17, type: 'number.freemarker2' }, + { startIndex: 18, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 19, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Built-ins + [ + { + line: '[=x?length?string]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'identifier.freemarker2' }, + { startIndex: 17, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=x?string.currency]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.freemarker2' }, + { startIndex: 11, type: 'identifier.freemarker2' }, + { startIndex: 19, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Directives + [ + // List + { + line: '<#list users as user>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 12, type: '' }, + { startIndex: 13, type: 'keyword.as.freemarker2' }, + { startIndex: 15, type: '' }, + { startIndex: 16, type: 'identifier.freemarker2' }, + { startIndex: 20, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 22, type: 'delimiter.directive.freemarker2' }, + { startIndex: 24, type: 'tag.freemarker2' }, + { startIndex: 28, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Unknown directive + { + line: '<#foobar>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Directives with no expressions allowed, no closing slash + { + line: '<#attempt>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#attempt 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#attempt />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#recover>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#recover 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#recover />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#sep>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#sep 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#sep />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#autoesc>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#autoesc 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#autoesc />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#autoEsc>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#autoEsc 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#autoEsc />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noautoesc>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noautoesc 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noautoesc />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noAutoEsc>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noAutoEsc 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noAutoEsc />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#compress>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#compress 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#compress />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#default>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#default 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#default />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noescape>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noescape 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noescape />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noEscape>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noEscape 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noEscape />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Directives with no expressions allowed, closing slash allowed + { + line: '<#else>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#else/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#else 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.directive.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#break>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#break/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.directive.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#break 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.directive.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#continue>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#continue/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#continue 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#return>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#return/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.directive.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#stop>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#stop/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#flush>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#flush/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.directive.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#flush 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.directive.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#t>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 3, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#t/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 3, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#t 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'number.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#lt>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#lt/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.directive.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#lt 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#rt>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#rt/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.directive.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#rt 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#lt>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#nt>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#nt/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.directive.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#nt 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#nested>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#nested/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.directive.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#recurse>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#recurse/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.directive.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#fallback>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#fallback/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#fallback 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#ftl>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#ftl/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Directives that allow expressions + { + line: '<#if 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#elseif 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#elseIf 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#list 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#foreach 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#forEach 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#switch 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#case 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#assign 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#global 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#local 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#include 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#import 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#function 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#macro 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#transform 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#visit 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#stop 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#return 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#call 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#setting 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#outputformat 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 14, type: '' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#outputFormat 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 14, type: '' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#nested 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#recurse 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#escape 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#ftl 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#items 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Closable tags + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 15, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 15, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + + // Macro definitions + [ + // No argument + { + line: '<#macro x>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'tag.freemarker2' }, + { startIndex: 18, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + + // With arguments + { + line: '<#macro x a1 a2>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'identifier.freemarker2' }, + { startIndex: 12, type: '' }, + { startIndex: 13, type: 'identifier.freemarker2' }, + { startIndex: 15, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 17, type: 'delimiter.directive.freemarker2' }, + { startIndex: 19, type: 'tag.freemarker2' }, + { startIndex: 24, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + + // Catch all parameter + { + line: '<#macro x foo...>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'identifier.freemarker2' }, + { startIndex: 13, type: 'operators.freemarker2' }, + { startIndex: 16, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 18, type: 'delimiter.directive.freemarker2' }, + { startIndex: 20, type: 'tag.freemarker2' }, + { startIndex: 25, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + + // Macro calls + [ + // Without content + { + line: '<@foo/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // With content and named ending tag + { + line: '<@foo>aaa', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 6, type: 'source.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'tag.freemarker2' }, + { startIndex: 15, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // With content and unnamed ending tag + { + line: '<@foo>aaa', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 6, type: 'source.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Special highlighting when the expression to call consists + // solely of an identifier. + { + line: '<@foo>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<@foo >', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<@foo/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<@foo />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Normal highlighting when the expression to call + // is an expression. + { + line: '<@foo()/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 7, type: 'delimiter.directive.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Positional parameters + { + line: '<@join [1] ":"/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'delimiter.square.freemarker2' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'string.freemarker2' }, + { startIndex: 14, type: 'delimiter.directive.freemarker2' }, + { startIndex: 15, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Named parameters + { + line: '<@join arr=[1] sep=":"/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2' }, + { startIndex: 14, type: '' }, + { startIndex: 15, type: 'identifier.freemarker2' }, + { startIndex: 18, type: 'operators.freemarker2' }, + { startIndex: 19, type: 'string.freemarker2' }, + { startIndex: 22, type: 'delimiter.directive.freemarker2' }, + { startIndex: 23, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // ! should not end macro parameters + { + line: '<@join arr=[1]! sep=":"/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2' }, + { startIndex: 14, type: 'operators.freemarker2' }, + { startIndex: 15, type: '' }, + { startIndex: 16, type: 'identifier.freemarker2' }, + { startIndex: 19, type: 'operators.freemarker2' }, + { startIndex: 20, type: 'string.freemarker2' }, + { startIndex: 23, type: 'delimiter.directive.freemarker2' }, + { startIndex: 24, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // repeat + { + line: '<@repeat count=4 ; c, halfc, last>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 14, type: 'operators.freemarker2' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: '' }, + { startIndex: 17, type: 'delimiter.freemarker2' }, + { startIndex: 18, type: '' }, + { startIndex: 19, type: 'identifier.freemarker2' }, + { startIndex: 20, type: 'delimiter.freemarker2' }, + { startIndex: 21, type: '' }, + { startIndex: 22, type: 'identifier.freemarker2' }, + { startIndex: 27, type: 'delimiter.freemarker2' }, + { startIndex: 28, type: '' }, + { startIndex: 29, type: 'identifier.freemarker2' }, + { startIndex: 33, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 35, type: 'delimiter.directive.freemarker2' }, + { startIndex: 37, type: 'tag.freemarker2' }, + { startIndex: 43, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + + // Hash keys + [ + // Normal hash keys (dot notation) + { + line: '[=a.a]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Normal hash keys (square bracket notation) + { + line: '[=a["a"]]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.square.freemarker2' }, + { startIndex: 4, type: 'string.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Special hash keys (dot notation, these are usually operators / keywords) + { + line: '[=a.*]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a.**]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a.false]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a.true]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a.in]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a.as]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a.using]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Spaces are allowed + { + line: '[=a . **]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 5, type: 'delimiter.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // *** is not a valid key name + { + line: '[=a.***]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'operators.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Special hash keys (square bracket notation) + { + line: '[=a["**"]]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.square.freemarker2' }, + { startIndex: 4, type: 'string.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ] +]); diff --git a/src/basic-languages/freemarker2/freemarker2-angle-dollar.test.ts b/src/basic-languages/freemarker2/freemarker2-angle-dollar.test.ts new file mode 100644 index 00000000..3aece875 --- /dev/null +++ b/src/basic-languages/freemarker2/freemarker2-angle-dollar.test.ts @@ -0,0 +1,3099 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { testTokenization } from '../test/testRunner'; + +testTokenization('freemarker2.tag-angle.interpolation-dollar', [ + // Plain text + [ + { + line: 'abc123./]})>', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + // HTML comment is not FreeMarker comment + { + line: '', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + // Bracket tag syntax is plain text in angle tag syntax mode + { + line: '[#if user == "Big Joe"] Hello user [/#if]', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + // Bracket interpolation syntax is plain text in dollar interpolation syntax mode + { + line: 'Hello, [=user] !', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + } + ], + + // Block comment (terse) + [ + { + line: 'x<#--a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'comment.freemarker2' } + ] + }, + { + line: 'b <#if><#noparse>', + tokens: [{ startIndex: 0, type: 'comment.freemarker2' }] + }, + { + line: 'c-->y', + tokens: [ + { startIndex: 0, type: 'comment.freemarker2' }, + { startIndex: 4, type: 'source.freemarker2' } + ] + } + ], + // Not a block comment (terse) + [ + { + line: 'x[#--a', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'b', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'c--]y', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + } + ], + // Block comment (tag) + [ + { + line: 'x<#comment>a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 11, type: 'comment.freemarker2' } + ] + }, + { + line: 'b <#if> <#noparse> -->', + tokens: [{ startIndex: 0, type: 'comment.freemarker2' }] + }, + { + line: 'cy', + tokens: [ + { startIndex: 0, type: 'comment.freemarker2' }, + { startIndex: 1, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 12, type: 'source.freemarker2' } + ] + } + ], + + // Not a block comment (tag) + [ + { + line: 'x[#comment]a', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'b', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'c[/#comment]y', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + } + ], + + // Expression comments + [ + // Angle syntax (no spaces) + { + line: '${2+3}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'comment.freemarker2' }, + { startIndex: 20, type: 'number.freemarker2' }, + { startIndex: 21, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Angle syntax (spaces) + { + line: '${2+ 3}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'comment.freemarker2' }, + { startIndex: 21, type: '' }, + { startIndex: 22, type: 'number.freemarker2' }, + { startIndex: 23, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Bracket syntax (no spaces) + { + line: '${2+[!-- comment --]3}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'comment.freemarker2' }, + { startIndex: 20, type: 'number.freemarker2' }, + { startIndex: 21, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${[[!-- comment --]3]}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.square.freemarker2' }, + { startIndex: 3, type: 'comment.freemarker2' }, + { startIndex: 19, type: 'number.freemarker2' }, + { startIndex: 20, type: 'delimiter.square.freemarker2' }, + { startIndex: 21, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Bracket syntax (spaces) + { + line: '${2+ [!-- comment --] 3}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'comment.freemarker2' }, + { startIndex: 21, type: '' }, + { startIndex: 22, type: 'number.freemarker2' }, + { startIndex: 23, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // noparse (ignores everything until the matching closing tag) + [ + { + line: 'x<#noparse>a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 11, type: 'source.freemarker2' } + ] + }, + { + line: 'b <#if> ', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'cy', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 12, type: 'source.freemarker2' } + ] + } + ], + + // noParse (ignores everything until the matching closing tag) + [ + { + line: 'x<#noParse>a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 11, type: 'source.freemarker2' } + ] + }, + { + line: 'b <#if> ', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'cy', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 12, type: 'source.freemarker2' } + ] + } + ], + + // Closing angle bracket treatment + [ + // Comparison operator when inside an interpolation + { + line: '${1>2}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'number.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${1>=2}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Directive end tag when inside a directive + { + line: '<#if 1>2', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 7, type: 'source.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 9, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'tag.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Normal comparison operator when inside parentheses within a directive + // Only considers parentheses, not other brackets + { + line: '<#if (1>2)>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 14, type: 'tag.freemarker2' }, + { startIndex: 16, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#if (1>=2)>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 13, type: 'delimiter.directive.freemarker2' }, + { startIndex: 15, type: 'tag.freemarker2' }, + { startIndex: 17, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#if [1>2]>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.square.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 8, type: 'source.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 14, type: 'tag.freemarker2' }, + { startIndex: 16, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#if [(1>2)]>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.square.freemarker2' }, + { startIndex: 6, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'operators.freemarker2' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 14, type: 'delimiter.directive.freemarker2' }, + { startIndex: 16, type: 'tag.freemarker2' }, + { startIndex: 18, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + + // Mismatched closing bracket / parenthesis does not end expression mode + [ + // Interpolation + { + line: '${)1}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${]1}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.square.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${>1}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'operators.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Directive + { + line: '<#if )1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#if ]1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.square.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#if }1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + + // Boolean literals + [ + { + line: '${false}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${true}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.true.freemarker2' }, + { startIndex: 6, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Number literals + [ + { + line: '${123}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${123.456}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'number.float.freemarker2' }, + { startIndex: 9, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Interpolated string literals (single quote) + [ + // Empty string + { + line: "${''}", + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 4, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Literal content + { + line: "${'abc'}", + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 7, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Escaped characters (named) + { + line: "${'\\n\\t\\r\\f\\b\\g\\l\\a\\\\\\'\\{\\='}", + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 3, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 28, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Escaped characters (unicode, 1-4 hex digits) + { + line: "${'\\x1\\x11\\x111\\x1111\\x11111'}", + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 3, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 29, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // String interpolation (unsupported, not possible with Monarch?) + { + // this evaluates to "ab0cd" and contains three interpolations + line: "${'a${\\'b${\\\\\\'${0}\\\\\\'}c\\'}d'}", + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 6, type: 'string.escape.freemarker2' }, + { startIndex: 8, type: 'string.freemarker2' }, + { startIndex: 11, type: 'string.escape.freemarker2' }, + { startIndex: 15, type: 'string.freemarker2' }, + { startIndex: 19, type: 'string.escape.freemarker2' }, + { startIndex: 23, type: 'string.freemarker2' }, + { startIndex: 25, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 30, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + // Interpolated string literals (double quote) + [ + // Empty string + { + line: '${""}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 4, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Literal content + { + line: '${"abc"}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 7, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Escaped characters (named) + { + line: '${"\\n\\t\\r\\f\\b\\g\\l\\a\\\\\\\'\\{\\="}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 3, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 28, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Escaped characters (unicode, 1-4 hex digits) + { + line: '${"\\x1\\x11\\x111\\x1111\\x11111"}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 3, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 29, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // String interpolation (unsupported, not possible with Monarch?) + { + // this evaluates to "ab0cd" and contains three interpolations + line: '${"a${\\"b${\\\\\\"${0}\\\\\\"}c\\"}d"}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 6, type: 'string.escape.freemarker2' }, + { startIndex: 8, type: 'string.freemarker2' }, + { startIndex: 11, type: 'string.escape.freemarker2' }, + { startIndex: 15, type: 'string.freemarker2' }, + { startIndex: 19, type: 'string.escape.freemarker2' }, + { startIndex: 23, type: 'string.freemarker2' }, + { startIndex: 25, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 30, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Raw string literals (single quote) + [ + // Empty string + { + line: "${r''}", + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Literal content + { + line: "${r'abc'}", + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 8, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Raw string can contain anything other than the opening quote mark + { + line: "${r'\"\\n\\x1'}", + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 11, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Raw string literals (double quote) + [ + // Empty string + { + line: '${r""}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Literal content + { + line: '${r"abc"}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 8, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Raw string can contain anything other than the opening quote mark + { + line: '${r"\'\\n\\x1"}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 11, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Boolean operators + [ + { + line: '${!false}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'operators.freemarker2' }, + { startIndex: 3, type: 'keyword.false.freemarker2' }, + { startIndex: 8, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${false&true}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 8, type: 'keyword.true.freemarker2' }, + { startIndex: 12, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${false&&true}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 9, type: 'keyword.true.freemarker2' }, + { startIndex: 13, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${false&&true}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 17, type: 'keyword.true.freemarker2' }, + { startIndex: 21, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${false\\andtrue}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'keyword.true.freemarker2' }, + { startIndex: 15, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${false|true}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 8, type: 'keyword.true.freemarker2' }, + { startIndex: 12, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${false||true}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 9, type: 'keyword.true.freemarker2' }, + { startIndex: 13, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Sequence literals + [ + // range (inclusive) + { + line: '${(1..3)}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 8, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // range (exclusive) + { + line: '${(1..<3)}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // range (exclusive) (alternative form) + { + line: '${(1..!3)}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // range (length-limited) + { + line: '${(1..*3)}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // range (right-unbounded) + { + line: '${(1..)}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 6, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 7, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // List literals + [ + // Can be used in directives + { + line: '<#assign s=[1,2]>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.freemarker2' }, + { startIndex: 14, type: 'number.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2' }, + { startIndex: 16, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Can be used in interpolations + { + line: '${[1,2]}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.square.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.freemarker2' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2' }, + { startIndex: 7, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Hash literals + [ + // Can be used in directives + { + line: '<#assign s={"foo":9}>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.curly.freemarker2' }, + { startIndex: 12, type: 'string.freemarker2' }, + { startIndex: 17, type: 'delimiter.freemarker2' }, + { startIndex: 18, type: 'number.freemarker2' }, + { startIndex: 19, type: 'delimiter.curly.freemarker2' }, + { startIndex: 20, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Can be used in interpolations + { + line: '${{"foo":9}.foo+4}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.curly.freemarker2' }, + { startIndex: 3, type: 'string.freemarker2' }, + { startIndex: 8, type: 'delimiter.freemarker2' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.curly.freemarker2' }, + { startIndex: 11, type: 'delimiter.freemarker2' }, + { startIndex: 12, type: 'identifier.freemarker2' }, + { startIndex: 15, type: 'operators.freemarker2' }, + { startIndex: 16, type: 'number.freemarker2' }, + { startIndex: 17, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Comparison operators + [ + { + line: '${a=b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a==b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a!=b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${ab}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a gt b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 8, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a \\gt b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a > b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a>=b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a \\gte b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a >= b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'identifier.freemarker2' }, + { startIndex: 11, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + // Assignment operators + [ + { + line: '<#assign a+=2>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#assign a-=2>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#assign a*=2>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#assign a/=2>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#assign a%=2>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + + // Increment operators + [ + { + line: '<#assign a++>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#assign a-->', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + + // Numerical operators + [ + { + line: '${a+b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a-b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a*b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a/b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a%b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Not an operator, only used to index hashes + // But still tokenized as 2 operators + { + line: '${a**b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Missing value test operator + [ + { + line: '${a??}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Lambdas + [ + // Single argument without parentheses + { + line: '${a?map(x->x*2)}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'meta.arrow.freemarker2' }, + { startIndex: 11, type: 'identifier.freemarker2' }, + { startIndex: 12, type: 'operators.freemarker2' }, + { startIndex: 13, type: 'number.freemarker2' }, + { startIndex: 14, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 15, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Alternative arrow representation + { + line: '${a?map(x->x*2)}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'meta.arrow.freemarker2' }, + { startIndex: 14, type: 'identifier.freemarker2' }, + { startIndex: 15, type: 'operators.freemarker2' }, + { startIndex: 16, type: 'number.freemarker2' }, + { startIndex: 17, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 18, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Single argument with parentheses + { + line: '${a?map((x)->x*2)}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 11, type: 'meta.arrow.freemarker2' }, + { startIndex: 13, type: 'identifier.freemarker2' }, + { startIndex: 14, type: 'operators.freemarker2' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 17, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Multiple arguments with parentheses + { + line: '${a?map((x,y)->x*2)}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.freemarker2' }, + { startIndex: 11, type: 'identifier.freemarker2' }, + { startIndex: 12, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 13, type: 'meta.arrow.freemarker2' }, + { startIndex: 15, type: 'identifier.freemarker2' }, + { startIndex: 16, type: 'operators.freemarker2' }, + { startIndex: 17, type: 'number.freemarker2' }, + { startIndex: 18, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 19, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Built-ins + [ + { + line: '${x?length?string}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'identifier.freemarker2' }, + { startIndex: 17, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${x?string.currency}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.freemarker2' }, + { startIndex: 11, type: 'identifier.freemarker2' }, + { startIndex: 19, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Directives + [ + // List + { + line: '<#list users as user>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 12, type: '' }, + { startIndex: 13, type: 'keyword.as.freemarker2' }, + { startIndex: 15, type: '' }, + { startIndex: 16, type: 'identifier.freemarker2' }, + { startIndex: 20, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 22, type: 'delimiter.directive.freemarker2' }, + { startIndex: 24, type: 'tag.freemarker2' }, + { startIndex: 28, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Unknown directive + { + line: '<#foobar>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Directives with no expressions allowed, no closing slash + { + line: '<#attempt>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#attempt 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#attempt />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#recover>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#recover 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#recover />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#sep>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#sep 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#sep />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#autoesc>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#autoesc 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#autoesc />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#autoEsc>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#autoEsc 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#autoEsc />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noautoesc>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noautoesc 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noautoesc />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noAutoEsc>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noAutoEsc 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noAutoEsc />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#compress>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#compress 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#compress />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#default>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#default 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#default />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noescape>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noescape 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noescape />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noEscape>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noEscape 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noEscape />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Directives with no expressions allowed, closing slash allowed + { + line: '<#else>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#else/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#else 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.directive.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#break>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#break/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.directive.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#break 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.directive.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#continue>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#continue/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#continue 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#return>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#return/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.directive.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#stop>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#stop/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#flush>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#flush/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.directive.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#flush 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.directive.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#t>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 3, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#t/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 3, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#t 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'number.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#lt>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#lt/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.directive.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#lt 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#rt>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#rt/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.directive.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#rt 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#lt>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#nt>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#nt/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.directive.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#nt 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#nested>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#nested/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.directive.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#recurse>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#recurse/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.directive.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#fallback>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#fallback/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#fallback 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#ftl>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#ftl/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Directives that allow expressions + { + line: '<#if 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#elseif 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#elseIf 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#list 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#foreach 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#forEach 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#switch 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#case 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#assign 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#global 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#local 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#include 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#import 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#function 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#macro 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#transform 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#visit 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#stop 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#return 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#call 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#setting 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#outputformat 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 14, type: '' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#outputFormat 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 14, type: '' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#nested 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#recurse 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#escape 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#ftl 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#items 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Closable tags + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 15, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 15, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + + // Macro definitions + [ + // No argument + { + line: '<#macro x>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'tag.freemarker2' }, + { startIndex: 18, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + + // With arguments + { + line: '<#macro x a1 a2>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'identifier.freemarker2' }, + { startIndex: 12, type: '' }, + { startIndex: 13, type: 'identifier.freemarker2' }, + { startIndex: 15, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 17, type: 'delimiter.directive.freemarker2' }, + { startIndex: 19, type: 'tag.freemarker2' }, + { startIndex: 24, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + + // Catch all parameter + { + line: '<#macro x foo...>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'identifier.freemarker2' }, + { startIndex: 13, type: 'operators.freemarker2' }, + { startIndex: 16, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 18, type: 'delimiter.directive.freemarker2' }, + { startIndex: 20, type: 'tag.freemarker2' }, + { startIndex: 25, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + + // Macro calls + [ + // Without content + { + line: '<@foo/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // With content and named ending tag + { + line: '<@foo>aaa', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 6, type: 'source.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'tag.freemarker2' }, + { startIndex: 15, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // With content and unnamed ending tag + { + line: '<@foo>aaa', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 6, type: 'source.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Special highlighting when the expression to call consists + // solely of an identifier. + { + line: '<@foo>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<@foo >', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<@foo/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<@foo />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Normal highlighting when the expression to call + // is an expression. + { + line: '<@foo()/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 7, type: 'delimiter.directive.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Positional parameters + { + line: '<@join [1] ":"/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'delimiter.square.freemarker2' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'string.freemarker2' }, + { startIndex: 14, type: 'delimiter.directive.freemarker2' }, + { startIndex: 15, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Named parameters + { + line: '<@join arr=[1] sep=":"/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2' }, + { startIndex: 14, type: '' }, + { startIndex: 15, type: 'identifier.freemarker2' }, + { startIndex: 18, type: 'operators.freemarker2' }, + { startIndex: 19, type: 'string.freemarker2' }, + { startIndex: 22, type: 'delimiter.directive.freemarker2' }, + { startIndex: 23, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // ! should not end macro parameters + { + line: '<@join arr=[1]! sep=":"/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2' }, + { startIndex: 14, type: 'operators.freemarker2' }, + { startIndex: 15, type: '' }, + { startIndex: 16, type: 'identifier.freemarker2' }, + { startIndex: 19, type: 'operators.freemarker2' }, + { startIndex: 20, type: 'string.freemarker2' }, + { startIndex: 23, type: 'delimiter.directive.freemarker2' }, + { startIndex: 24, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // repeat + { + line: '<@repeat count=4 ; c, halfc, last>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 14, type: 'operators.freemarker2' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: '' }, + { startIndex: 17, type: 'delimiter.freemarker2' }, + { startIndex: 18, type: '' }, + { startIndex: 19, type: 'identifier.freemarker2' }, + { startIndex: 20, type: 'delimiter.freemarker2' }, + { startIndex: 21, type: '' }, + { startIndex: 22, type: 'identifier.freemarker2' }, + { startIndex: 27, type: 'delimiter.freemarker2' }, + { startIndex: 28, type: '' }, + { startIndex: 29, type: 'identifier.freemarker2' }, + { startIndex: 33, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 35, type: 'delimiter.directive.freemarker2' }, + { startIndex: 37, type: 'tag.freemarker2' }, + { startIndex: 43, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + + // Hash keys + [ + // Normal hash keys (dot notation) + { + line: '${a.a}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Normal hash keys (square bracket notation) + { + line: '${a["a"]}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.square.freemarker2' }, + { startIndex: 4, type: 'string.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2' }, + { startIndex: 8, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Special hash keys (dot notation, these are usually operators / keywords) + { + line: '${a.*}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a.**}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a.false}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a.true}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 8, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a.in}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a.as}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a.using}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Spaces are allowed + { + line: '${a . **}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 5, type: 'delimiter.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // *** is not a valid key name + { + line: '${a.***}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'operators.freemarker2' }, + { startIndex: 7, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Special hash keys (square bracket notation) + { + line: '${a["**"]}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.square.freemarker2' }, + { startIndex: 4, type: 'string.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2' }, + { startIndex: 9, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ] +]); diff --git a/src/basic-languages/freemarker2/freemarker2-auto-bracket.test.ts b/src/basic-languages/freemarker2/freemarker2-auto-bracket.test.ts new file mode 100644 index 00000000..65956edd --- /dev/null +++ b/src/basic-languages/freemarker2/freemarker2-auto-bracket.test.ts @@ -0,0 +1,5358 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { testTokenization } from '../test/testRunner'; + +testTokenization('freemarker2.tag-auto.interpolation-bracket', [ + // Plain text + [ + { + line: 'abc123./]})>', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + // HTML comment is not FreeMarker comment + { + line: '', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + } + ], + + // Auto mode: bracket directive sets bracket mode + [ + { + line: '[#attempt]<#attempt>', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 10, type: 'source.freemarker2' } + ] + } + ], + // Auto mode: angle directive sets angle mode + [ + { + line: '<#attempt>[#attempt]', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 10, type: 'source.freemarker2' } + ] + } + ], + // Auto mode: invalid directive sets mode + [ + { + line: '[#foobar]<#foobar>', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 9, type: 'source.freemarker2' } + ] + } + ], + // Auto mode: angle tag comment sets mode + [ + { + line: '<#-- asd -->', + tokens: [{ startIndex: 0, type: 'comment.freemarker2' }] + }, + { + line: '[#-- asd --]', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: '[#if true]B[/#if]', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: '<#if true>A', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'keyword.true.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 10, type: 'source.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 14, type: 'tag.freemarker2' }, + { startIndex: 16, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + // Auto mode: bracket tag comment sets mode + [ + { + line: '[#-- asd --]', + tokens: [{ startIndex: 0, type: 'comment.freemarker2' }] + }, + { + line: '<#-- asd -->', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: '<#if true>A', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: '[#if true]B[/#if]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'keyword.true.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 10, type: 'source.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 14, type: 'tag.freemarker2' }, + { startIndex: 16, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + // Auto mode: angle unified call sets mode + [ + { + line: '<@join/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '[@join/]', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: '[#if true]B[/#if]', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: '<#if true>A', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'keyword.true.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 10, type: 'source.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 14, type: 'tag.freemarker2' }, + { startIndex: 16, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + // Auto mode: bracket unified call sets mode + [ + { + line: '[@join/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '<@join/>', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: '<#if true>A', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: '[#if true]B[/#if]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'keyword.true.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 10, type: 'source.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 14, type: 'tag.freemarker2' }, + { startIndex: 16, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + // Auto mode: bracket expression comment does not set tag syntax mode + [ + { + line: '[=[!-- asd --]0]<#if true>[#if]', + tokens: [ + { + startIndex: 0, + type: 'delimiter.square.freemarker2.interpolation' + }, + { + startIndex: 1, + type: 'delimiter.interpolation.freemarker2' + }, + { + startIndex: 2, + type: 'comment.freemarker2' + }, + { + startIndex: 14, + type: 'number.freemarker2' + }, + { + startIndex: 15, + type: 'delimiter.square.freemarker2.interpolation' + }, + { + startIndex: 16, + type: 'delimiter.angle.freemarker2.directive' + }, + { + startIndex: 17, + type: 'delimiter.directive.freemarker2' + }, + { + startIndex: 18, + type: 'tag.freemarker2' + }, + { + startIndex: 20, + type: '' + }, + { + startIndex: 21, + type: 'keyword.true.freemarker2' + }, + { + startIndex: 25, + type: 'delimiter.angle.freemarker2.directive' + }, + { + startIndex: 27, + type: 'delimiter.directive.freemarker2' + }, + { + startIndex: 29, + type: 'tag.freemarker2' + }, + { + startIndex: 31, + type: 'delimiter.angle.freemarker2.directive' + }, + { + startIndex: 32, + type: 'source.freemarker2' + } + ] + } + ], + // Auto mode: angle expression comment does not set tag syntax mode + [ + { + line: '[=0][#if true][/#if]<#if>', + tokens: [ + { + startIndex: 0, + type: 'delimiter.square.freemarker2.interpolation' + }, + { + startIndex: 1, + type: 'delimiter.interpolation.freemarker2' + }, + { + startIndex: 2, + type: 'comment.freemarker2' + }, + { + startIndex: 14, + type: 'number.freemarker2' + }, + { + startIndex: 15, + type: 'delimiter.square.freemarker2.interpolation' + }, + { + startIndex: 16, + type: 'delimiter.square.freemarker2.directive' + }, + { + startIndex: 17, + type: 'delimiter.directive.freemarker2' + }, + { + startIndex: 18, + type: 'tag.freemarker2' + }, + { + startIndex: 20, + type: '' + }, + { + startIndex: 21, + type: 'keyword.true.freemarker2' + }, + { + startIndex: 25, + type: 'delimiter.square.freemarker2.directive' + }, + { + startIndex: 27, + type: 'delimiter.directive.freemarker2' + }, + { + startIndex: 29, + type: 'tag.freemarker2' + }, + { + startIndex: 31, + type: 'delimiter.square.freemarker2.directive' + }, + { + startIndex: 32, + type: 'source.freemarker2' + } + ] + } + ], + + // Block comment (terse) (angle) + [ + { + line: 'x<#--a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'comment.freemarker2' } + ] + }, + { + line: 'b <#if><#noparse>', + tokens: [{ startIndex: 0, type: 'comment.freemarker2' }] + }, + { + line: 'c-->y', + tokens: [ + { startIndex: 0, type: 'comment.freemarker2' }, + { startIndex: 4, type: 'source.freemarker2' } + ] + } + ], + // Block comment (terse) (bracket) + [ + { + line: 'x[#--a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'comment.freemarker2' } + ] + }, + { + line: 'b', + tokens: [{ startIndex: 0, type: 'comment.freemarker2' }] + }, + { + line: 'c--]y', + tokens: [ + { startIndex: 0, type: 'comment.freemarker2' }, + { startIndex: 4, type: 'source.freemarker2' } + ] + } + ], + // Block comment (tag) (angle) + [ + { + line: 'x<#comment>a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 11, type: 'comment.freemarker2' } + ] + }, + { + line: 'b', + tokens: [{ startIndex: 0, type: 'comment.freemarker2' }] + }, + { + line: 'cy', + tokens: [ + { startIndex: 0, type: 'comment.freemarker2' }, + { startIndex: 1, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 12, type: 'source.freemarker2' } + ] + } + ], + + // Block comment (tag) (bracket) + [ + { + line: 'x[#comment]a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 11, type: 'comment.freemarker2' } + ] + }, + { + line: 'b', + tokens: [{ startIndex: 0, type: 'comment.freemarker2' }] + }, + { + line: 'c[/#comment]y', + tokens: [ + { startIndex: 0, type: 'comment.freemarker2' }, + { startIndex: 1, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 12, type: 'source.freemarker2' } + ] + } + ], + + // Expression comments + [ + // Angle syntax (no spaces) + { + line: '[=2+3]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'comment.freemarker2' }, + { startIndex: 20, type: 'number.freemarker2' }, + { startIndex: 21, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Angle syntax (spaces) + { + line: '[=2+ 3]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'comment.freemarker2' }, + { startIndex: 21, type: '' }, + { startIndex: 22, type: 'number.freemarker2' }, + { startIndex: 23, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Bracket syntax (no spaces) + { + line: '[=2+[!-- comment --]3]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'comment.freemarker2' }, + { startIndex: 20, type: 'number.freemarker2' }, + { startIndex: 21, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=[[!-- comment --]3]]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.square.freemarker2' }, + { startIndex: 3, type: 'comment.freemarker2' }, + { startIndex: 19, type: 'number.freemarker2' }, + { startIndex: 20, type: 'delimiter.square.freemarker2' }, + { startIndex: 21, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Bracket syntax (spaces) + { + line: '[=2+ [!-- comment --] 3]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'comment.freemarker2' }, + { startIndex: 21, type: '' }, + { startIndex: 22, type: 'number.freemarker2' }, + { startIndex: 23, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // noparse (ignores everything until the matching closing tag) + [ + { + line: 'x<#noparse>a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 11, type: 'source.freemarker2' } + ] + }, + { + line: 'b <#if> ', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'cy', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 12, type: 'source.freemarker2' } + ] + } + ], + + // noParse (ignores everything until the matching closing tag) + [ + { + line: 'x<#noParse>a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 11, type: 'source.freemarker2' } + ] + }, + { + line: 'b <#if> ', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'cy', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 12, type: 'source.freemarker2' } + ] + } + ], + + // Closing angle bracket treatment + [ + // Comparison operator when inside an interpolation + { + line: '[=1>2]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'number.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=1>=2]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Directive end tag when inside a directive + { + line: '<#if 1>2', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 7, type: 'source.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 9, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'tag.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Normal comparison operator when inside parentheses within a directive + // Only considers parentheses, not other brackets + { + line: '<#if (1>2)>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 14, type: 'tag.freemarker2' }, + { startIndex: 16, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#if (1>=2)>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 13, type: 'delimiter.directive.freemarker2' }, + { startIndex: 15, type: 'tag.freemarker2' }, + { startIndex: 17, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#if [1>2]>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.square.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 8, type: 'source.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 14, type: 'tag.freemarker2' }, + { startIndex: 16, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#if [(1>2)]>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.square.freemarker2' }, + { startIndex: 6, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'operators.freemarker2' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 14, type: 'delimiter.directive.freemarker2' }, + { startIndex: 16, type: 'tag.freemarker2' }, + { startIndex: 18, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + + // Mismatched closing bracket / parenthesis does not end expression mode + [ + // Interpolation + { + line: '[=)1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=}1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.curly.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=>1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'operators.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // // Directive + { + line: '<#if )1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#if ]1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.square.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#if }1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + + // Boolean literals + [ + { + line: '[=false]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=true]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.true.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Number literals + [ + { + line: '[=123]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=123.456]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'number.float.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Interpolated string literals (single quote) + [ + // Empty string + { + line: "[='']", + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Literal content + { + line: "[='abc']", + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Escaped characters (named) + { + line: "[='\\n\\t\\r\\f\\b\\g\\l\\a\\\\\\'\\{\\=']", + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 3, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 28, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Escaped characters (unicode, 1-4 hex digits) + { + line: "[='\\x1\\x11\\x111\\x1111\\x11111']", + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 3, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 29, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // String interpolation (unsupported, not possible with Monarch?) + { + // this evaluates to "ab0cd" and contains three interpolations + line: "[='a[=\\'b[=\\\\\\'[=0]\\\\\\']c\\'}d']", + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 6, type: 'string.escape.freemarker2' }, + { startIndex: 8, type: 'string.freemarker2' }, + { startIndex: 11, type: 'string.escape.freemarker2' }, + { startIndex: 15, type: 'string.freemarker2' }, + { startIndex: 19, type: 'string.escape.freemarker2' }, + { startIndex: 23, type: 'string.freemarker2' }, + { startIndex: 25, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 30, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + // Interpolated string literals (double quote) + [ + // Empty string + { + line: '[=""]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Literal content + { + line: '[="abc"]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Escaped characters (named) + { + line: '[="\\n\\t\\r\\f\\b\\g\\l\\a\\\\\\\'\\{\\="]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 3, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 28, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Escaped characters (unicode, 1-4 hex digits) + { + line: '[="\\x1\\x11\\x111\\x1111\\x11111"]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 3, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 29, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // String interpolation (unsupported, not possible with Monarch?) + { + // this evaluates to "ab0cd" and contains three interpolations + line: '[="a[=\\"b[=\\\\\\"[=0}\\\\\\"]c\\"]d"]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 6, type: 'string.escape.freemarker2' }, + { startIndex: 8, type: 'string.freemarker2' }, + { startIndex: 11, type: 'string.escape.freemarker2' }, + { startIndex: 15, type: 'string.freemarker2' }, + { startIndex: 19, type: 'string.escape.freemarker2' }, + { startIndex: 23, type: 'string.freemarker2' }, + { startIndex: 25, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 30, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Raw string literals (single quote) + [ + // Empty string + { + line: "[=r'']", + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Literal content + { + line: "[=r'abc']", + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Raw string can contain anything other than the opening quote mark + { + line: "[=r'\"\\n\\x1']", + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Raw string literals (double quote) + [ + // Empty string + { + line: '[=r""]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Literal content + { + line: '[=r"abc"]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Raw string can contain anything other than the opening quote mark + { + line: '[=r"\'\\n\\x1"]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Boolean operators + [ + { + line: '[=!false]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'operators.freemarker2' }, + { startIndex: 3, type: 'keyword.false.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=false&true]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 8, type: 'keyword.true.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=false&&true]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 9, type: 'keyword.true.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=false&&true]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 17, type: 'keyword.true.freemarker2' }, + { startIndex: 21, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=false\\andtrue]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'keyword.true.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=false|true]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 8, type: 'keyword.true.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=false||true]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 9, type: 'keyword.true.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Sequence literals + [ + // range (inclusive) + { + line: '[=(1..3)]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // range (exclusive) + { + line: '[=(1..<3)]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // range (exclusive) (alternative form) + { + line: '[=(1..!3)]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // range (length-limited) + { + line: '[=(1..*3)]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // range (right-unbounded) + { + line: '[=(1..)]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 6, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // List literals + [ + // Can be used in directives + { + line: '<#assign s=[1,2]>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.freemarker2' }, + { startIndex: 14, type: 'number.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2' }, + { startIndex: 16, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Can be used in interpolations + { + line: '[=[1,2]]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.square.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.freemarker2' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Hash literals + [ + // Can be used in directives + { + line: '<#assign s={"foo":9}>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.curly.freemarker2' }, + { startIndex: 12, type: 'string.freemarker2' }, + { startIndex: 17, type: 'delimiter.freemarker2' }, + { startIndex: 18, type: 'number.freemarker2' }, + { startIndex: 19, type: 'delimiter.curly.freemarker2' }, + { startIndex: 20, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Can be used in interpolations + { + line: '[={"foo":9}.foo+4]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.curly.freemarker2' }, + { startIndex: 3, type: 'string.freemarker2' }, + { startIndex: 8, type: 'delimiter.freemarker2' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.curly.freemarker2' }, + { startIndex: 11, type: 'delimiter.freemarker2' }, + { startIndex: 12, type: 'identifier.freemarker2' }, + { startIndex: 15, type: 'operators.freemarker2' }, + { startIndex: 16, type: 'number.freemarker2' }, + { startIndex: 17, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Comparison operators + [ + { + line: '[=a=b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a==b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a!=b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=ab]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a gt b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a \\gt b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a > b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a>=b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a \\gte b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a >= b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'identifier.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + // Assignment operators + [ + { + line: '<#assign a+=2>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#assign a-=2>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#assign a*=2>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#assign a/=2>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#assign a%=2>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + + // Increment operators + [ + { + line: '<#assign a++>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#assign a-->', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + + // Numerical operators + [ + { + line: '[=a+b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a-b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a*b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a/b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a%b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Not an operator, only used to index hashes + // But still tokenized as 2 operators + { + line: '[=a**b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Missing value test operator + [ + { + line: '[=a??]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Lambdas + [ + // Single argument without parentheses + { + line: '[=a?map(x->x*2)]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'meta.arrow.freemarker2' }, + { startIndex: 11, type: 'identifier.freemarker2' }, + { startIndex: 12, type: 'operators.freemarker2' }, + { startIndex: 13, type: 'number.freemarker2' }, + { startIndex: 14, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Alternative arrow representation + { + line: '[=a?map(x->x*2)]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'meta.arrow.freemarker2' }, + { startIndex: 14, type: 'identifier.freemarker2' }, + { startIndex: 15, type: 'operators.freemarker2' }, + { startIndex: 16, type: 'number.freemarker2' }, + { startIndex: 17, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 18, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Single argument with parentheses + { + line: '[=a?map((x)->x*2)]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 11, type: 'meta.arrow.freemarker2' }, + { startIndex: 13, type: 'identifier.freemarker2' }, + { startIndex: 14, type: 'operators.freemarker2' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 17, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Multiple arguments with parentheses + { + line: '[=a?map((x,y)->x*2)]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.freemarker2' }, + { startIndex: 11, type: 'identifier.freemarker2' }, + { startIndex: 12, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 13, type: 'meta.arrow.freemarker2' }, + { startIndex: 15, type: 'identifier.freemarker2' }, + { startIndex: 16, type: 'operators.freemarker2' }, + { startIndex: 17, type: 'number.freemarker2' }, + { startIndex: 18, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 19, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Built-ins + [ + { + line: '[=x?length?string]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'identifier.freemarker2' }, + { startIndex: 17, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=x?string.currency]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.freemarker2' }, + { startIndex: 11, type: 'identifier.freemarker2' }, + { startIndex: 19, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Directives + [ + // List + { + line: '<#list users as user>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 12, type: '' }, + { startIndex: 13, type: 'keyword.as.freemarker2' }, + { startIndex: 15, type: '' }, + { startIndex: 16, type: 'identifier.freemarker2' }, + { startIndex: 20, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 22, type: 'delimiter.directive.freemarker2' }, + { startIndex: 24, type: 'tag.freemarker2' }, + { startIndex: 28, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Unknown directive + { + line: '<#foobar>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Directives with no expressions allowed, no closing slash + { + line: '<#attempt>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#attempt 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#attempt />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#recover>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#recover 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#recover />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#sep>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#sep 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#sep />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#autoesc>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#autoesc 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#autoesc />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#autoEsc>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#autoEsc 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#autoEsc />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noautoesc>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noautoesc 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noautoesc />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noAutoEsc>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noAutoEsc 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noAutoEsc />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#compress>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#compress 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#compress />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#default>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#default 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#default />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noescape>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noescape 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noescape />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noEscape>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noEscape 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noEscape />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Directives with no expressions allowed, closing slash allowed + { + line: '<#else>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#else/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#else 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.directive.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#break>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#break/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.directive.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#break 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.directive.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#continue>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#continue/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#continue 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#return>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#return/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.directive.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#stop>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#stop/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#flush>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#flush/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.directive.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#flush 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.directive.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#t>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 3, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#t/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 3, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#t 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'number.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#lt>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#lt/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.directive.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#lt 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#rt>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#rt/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.directive.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#rt 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#lt>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#nt>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#nt/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.directive.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#nt 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#nested>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#nested/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.directive.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#recurse>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#recurse/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.directive.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#fallback>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#fallback/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#fallback 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#ftl>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#ftl/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Directives that allow expressions + { + line: '<#if 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#elseif 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#elseIf 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#list 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#foreach 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#forEach 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#switch 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#case 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#assign 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#global 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#local 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#include 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#import 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#function 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#macro 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#transform 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#visit 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#stop 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#return 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#call 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#setting 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#outputformat 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 14, type: '' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#outputFormat 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 14, type: '' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#nested 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#recurse 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#escape 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#ftl 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#items 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Closable tags + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 15, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 15, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + + // Macro definitions + [ + // No argument + { + line: '<#macro x>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'tag.freemarker2' }, + { startIndex: 18, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + + // With arguments + { + line: '<#macro x a1 a2>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'identifier.freemarker2' }, + { startIndex: 12, type: '' }, + { startIndex: 13, type: 'identifier.freemarker2' }, + { startIndex: 15, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 17, type: 'delimiter.directive.freemarker2' }, + { startIndex: 19, type: 'tag.freemarker2' }, + { startIndex: 24, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + + // Catch all parameter + { + line: '<#macro x foo...>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'identifier.freemarker2' }, + { startIndex: 13, type: 'operators.freemarker2' }, + { startIndex: 16, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 18, type: 'delimiter.directive.freemarker2' }, + { startIndex: 20, type: 'tag.freemarker2' }, + { startIndex: 25, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + + // Macro calls + [ + // Without content + { + line: '<@foo/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // With content and named ending tag + { + line: '<@foo>aaa', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 6, type: 'source.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'tag.freemarker2' }, + { startIndex: 15, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // With content and unnamed ending tag + { + line: '<@foo>aaa', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 6, type: 'source.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Special highlighting when the expression to call consists + // solely of an identifier. + { + line: '<@foo>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<@foo >', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<@foo/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<@foo />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Normal highlighting when the expression to call + // is an expression. + { + line: '<@foo()/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 7, type: 'delimiter.directive.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Positional parameters + { + line: '<@join [1] ":"/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'delimiter.square.freemarker2' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'string.freemarker2' }, + { startIndex: 14, type: 'delimiter.directive.freemarker2' }, + { startIndex: 15, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Named parameters + { + line: '<@join arr=[1] sep=":"/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2' }, + { startIndex: 14, type: '' }, + { startIndex: 15, type: 'identifier.freemarker2' }, + { startIndex: 18, type: 'operators.freemarker2' }, + { startIndex: 19, type: 'string.freemarker2' }, + { startIndex: 22, type: 'delimiter.directive.freemarker2' }, + { startIndex: 23, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // ! should not end macro parameters + { + line: '<@join arr=[1]! sep=":"/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2' }, + { startIndex: 14, type: 'operators.freemarker2' }, + { startIndex: 15, type: '' }, + { startIndex: 16, type: 'identifier.freemarker2' }, + { startIndex: 19, type: 'operators.freemarker2' }, + { startIndex: 20, type: 'string.freemarker2' }, + { startIndex: 23, type: 'delimiter.directive.freemarker2' }, + { startIndex: 24, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // repeat + { + line: '<@repeat count=4 ; c, halfc, last>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 14, type: 'operators.freemarker2' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: '' }, + { startIndex: 17, type: 'delimiter.freemarker2' }, + { startIndex: 18, type: '' }, + { startIndex: 19, type: 'identifier.freemarker2' }, + { startIndex: 20, type: 'delimiter.freemarker2' }, + { startIndex: 21, type: '' }, + { startIndex: 22, type: 'identifier.freemarker2' }, + { startIndex: 27, type: 'delimiter.freemarker2' }, + { startIndex: 28, type: '' }, + { startIndex: 29, type: 'identifier.freemarker2' }, + { startIndex: 33, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 35, type: 'delimiter.directive.freemarker2' }, + { startIndex: 37, type: 'tag.freemarker2' }, + { startIndex: 43, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + + // Hash keys + [ + // Normal hash keys (dot notation) + { + line: '[=a.a]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Normal hash keys (square bracket notation) + { + line: '[=a["a"]]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.square.freemarker2' }, + { startIndex: 4, type: 'string.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Special hash keys (dot notation, these are usually operators / keywords) + { + line: '[=a.*]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a.**]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a.false]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a.true]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a.in]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a.as]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a.using]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Spaces are allowed + { + line: '[=a . **]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 5, type: 'delimiter.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // *** is not a valid key name + { + line: '[=a.***]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'operators.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Special hash keys (square bracket notation) + { + line: '[=a["**"]]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.square.freemarker2' }, + { startIndex: 4, type: 'string.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // noparse (ignores everything until the matching closing tag) + [ + { + line: 'x[#noparse]a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 11, type: 'source.freemarker2' } + ] + }, + { + line: 'b [#if][/#if] [/#noParse] [!-- ... --]', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'c[/#noparse]y', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 12, type: 'source.freemarker2' } + ] + } + ], + + // noParse (ignores everything until the matching closing tag) + [ + { + line: 'x[#noParse]a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 11, type: 'source.freemarker2' } + ] + }, + { + line: 'b [#if][/#if] [/#noparse] [!-- ... --]', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'c[/#noParse]y', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 12, type: 'source.freemarker2' } + ] + } + ], + + // Closing angle bracket treatment + [ + // Comparison operator when inside an interpolation + { + line: '[=1>2]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'number.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=1>=2]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Normal comparison operator within a directive + { + line: '[#if 1>2][/#if]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'operators.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'tag.freemarker2' }, + { startIndex: 14, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#if (1>2)][/#if]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 14, type: 'tag.freemarker2' }, + { startIndex: 16, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#if (1>=2)][/#if]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 13, type: 'delimiter.directive.freemarker2' }, + { startIndex: 15, type: 'tag.freemarker2' }, + { startIndex: 17, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#if [1>2]][/#if]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.square.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 14, type: 'tag.freemarker2' }, + { startIndex: 16, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#if [(1>2)]][/#if]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.square.freemarker2' }, + { startIndex: 6, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'operators.freemarker2' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 14, type: 'delimiter.directive.freemarker2' }, + { startIndex: 16, type: 'tag.freemarker2' }, + { startIndex: 18, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + + // Mismatched closing bracket / parenthesis does not end expression mode + [ + // Interpolation + { + line: '[=)1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=}1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.curly.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=>1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'operators.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Directive + { + line: '[#if )1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#if }1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + // List literals + [ + // Can be used in directives + { + line: '[#assign s=[1,2]]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.freemarker2' }, + { startIndex: 14, type: 'number.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2' }, + { startIndex: 16, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Can be used in interpolations + { + line: '[=[1,2]]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.square.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.freemarker2' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Hash literals + [ + // Can be used in directives + { + line: '[#assign s={"foo":9}]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.curly.freemarker2' }, + { startIndex: 12, type: 'string.freemarker2' }, + { startIndex: 17, type: 'delimiter.freemarker2' }, + { startIndex: 18, type: 'number.freemarker2' }, + { startIndex: 19, type: 'delimiter.curly.freemarker2' }, + { startIndex: 20, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Can be used in interpolations + { + line: '[={"foo":9}.foo+4]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.curly.freemarker2' }, + { startIndex: 3, type: 'string.freemarker2' }, + { startIndex: 8, type: 'delimiter.freemarker2' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.curly.freemarker2' }, + { startIndex: 11, type: 'delimiter.freemarker2' }, + { startIndex: 12, type: 'identifier.freemarker2' }, + { startIndex: 15, type: 'operators.freemarker2' }, + { startIndex: 16, type: 'number.freemarker2' }, + { startIndex: 17, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + // Assignment operators + [ + { + line: '[#assign a+=2]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#assign a-=2]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#assign a*=2]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#assign a/=2]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#assign a%=2]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + + // Increment operators + [ + { + line: '[#assign a++]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#assign a--]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + // Directives + [ + // List + { + line: '[#list users as user][/#list]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 12, type: '' }, + { startIndex: 13, type: 'keyword.as.freemarker2' }, + { startIndex: 15, type: '' }, + { startIndex: 16, type: 'identifier.freemarker2' }, + { startIndex: 20, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 22, type: 'delimiter.directive.freemarker2' }, + { startIndex: 24, type: 'tag.freemarker2' }, + { startIndex: 28, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Unknown directive + { + line: '[#foobar]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Directives with no expressions allowed, no closing slash + { + line: '[#attempt]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#attempt 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#attempt /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#recover]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#recover 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#recover /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#sep]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#sep 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#sep /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#autoesc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#autoesc 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#autoesc /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#autoEsc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#autoEsc 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#autoEsc /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noautoesc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noautoesc 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noautoesc /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noAutoEsc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noAutoEsc 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noAutoEsc /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#compress]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#compress 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#compress /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#default]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#default 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#default /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noescape]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noescape 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noescape /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noEscape]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noEscape 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noEscape /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Directives with no expressions allowed, closing slash allowed + { + line: '[#else]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#else/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#else 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.directive.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#break]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#break/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.directive.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#break 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.directive.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#continue]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#continue/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#continue 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#return]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#return/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.directive.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#stop]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#stop/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#flush]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#flush/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.directive.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#flush 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.directive.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#t]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 3, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#t/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 3, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#t 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'number.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#lt]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#lt/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.directive.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#lt 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#rt]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#rt/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.directive.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#rt 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#lt]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#nt]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#nt/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.directive.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#nt 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#nested]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#nested/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.directive.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#recurse]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#recurse/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.directive.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#fallback]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#fallback/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#fallback 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#ftl]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#ftl/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Directives that allow expressions + { + line: '[#if 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#elseif 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#elseIf 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#list 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#foreach 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#forEach 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#switch 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#case 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#assign 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#global 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#local 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#include 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#import 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#function 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#macro 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#transform 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#visit 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#stop 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#return 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#call 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#setting 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#outputformat 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 14, type: '' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#outputFormat 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 14, type: '' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#nested 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#recurse 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#escape 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#ftl 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#items 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Closable tags + { + line: '[/#if]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#list]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#sep]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#recover]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#attempt]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#foreach]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#forEach]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#local]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#global]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#assign]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#function]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#macro]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#outputformat]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#outputFormat]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#autoesc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#autoEsc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#noautoesc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#noAutoEsc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#compress]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#transform]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#switch]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#escape]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#noescape]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#noEscape]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + + // Macro definitions + [ + // No argument + { + line: '[#macro x][/#macro]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'tag.freemarker2' }, + { startIndex: 18, type: 'delimiter.square.freemarker2.directive' } + ] + }, + + // With arguments + { + line: '[#macro x a1 a2][/#macro]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'identifier.freemarker2' }, + { startIndex: 12, type: '' }, + { startIndex: 13, type: 'identifier.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 17, type: 'delimiter.directive.freemarker2' }, + { startIndex: 19, type: 'tag.freemarker2' }, + { startIndex: 24, type: 'delimiter.square.freemarker2.directive' } + ] + }, + + // Catch all parameter + { + line: '[#macro x foo...][/#macro]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'identifier.freemarker2' }, + { startIndex: 13, type: 'operators.freemarker2' }, + { startIndex: 16, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 18, type: 'delimiter.directive.freemarker2' }, + { startIndex: 20, type: 'tag.freemarker2' }, + { startIndex: 25, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + + // Macro calls + [ + // Without content + { + line: '[@foo/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // With content and named ending tag + { + line: '[@foo]aaa[/@foo]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 6, type: 'source.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'tag.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // With content and unnamed ending tag + { + line: '[@foo]aaa[/@]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 6, type: 'source.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Special highlighting when the expression to call consists + // solely of an identifier. + { + line: '[@foo]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[@foo ]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[@foo/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[@foo /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Normal highlighting when the expression to call + // is an expression. + { + line: '[@foo()/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 7, type: 'delimiter.directive.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Positional parameters + { + line: '[@join [1] ":"/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'delimiter.square.freemarker2' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'string.freemarker2' }, + { startIndex: 14, type: 'delimiter.directive.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Named parameters + { + line: '[@join arr=[1] sep=":"/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2' }, + { startIndex: 14, type: '' }, + { startIndex: 15, type: 'identifier.freemarker2' }, + { startIndex: 18, type: 'operators.freemarker2' }, + { startIndex: 19, type: 'string.freemarker2' }, + { startIndex: 22, type: 'delimiter.directive.freemarker2' }, + { startIndex: 23, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // ! should not end macro parameters + { + line: '[@join arr=[1]! sep=":"/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2' }, + { startIndex: 14, type: 'operators.freemarker2' }, + { startIndex: 15, type: '' }, + { startIndex: 16, type: 'identifier.freemarker2' }, + { startIndex: 19, type: 'operators.freemarker2' }, + { startIndex: 20, type: 'string.freemarker2' }, + { startIndex: 23, type: 'delimiter.directive.freemarker2' }, + { startIndex: 24, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // repeat + { + line: '[@repeat count=4 ; c, halfc, last][/@repeat]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 14, type: 'operators.freemarker2' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: '' }, + { startIndex: 17, type: 'delimiter.freemarker2' }, + { startIndex: 18, type: '' }, + { startIndex: 19, type: 'identifier.freemarker2' }, + { startIndex: 20, type: 'delimiter.freemarker2' }, + { startIndex: 21, type: '' }, + { startIndex: 22, type: 'identifier.freemarker2' }, + { startIndex: 27, type: 'delimiter.freemarker2' }, + { startIndex: 28, type: '' }, + { startIndex: 29, type: 'identifier.freemarker2' }, + { startIndex: 33, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 35, type: 'delimiter.directive.freemarker2' }, + { startIndex: 37, type: 'tag.freemarker2' }, + { startIndex: 43, type: 'delimiter.square.freemarker2.directive' } + ] + } + ] +]); diff --git a/src/basic-languages/freemarker2/freemarker2-auto-dollar.test.ts b/src/basic-languages/freemarker2/freemarker2-auto-dollar.test.ts new file mode 100644 index 00000000..e4beed1d --- /dev/null +++ b/src/basic-languages/freemarker2/freemarker2-auto-dollar.test.ts @@ -0,0 +1,5361 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { testTokenization } from '../test/testRunner'; + +testTokenization('freemarker2.tag-auto.interpolation-dollar', [ + // Plain text + [ + { + line: 'abc123./]})>', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + // HTML comment is not FreeMarker comment + { + line: '', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + } + ], + + // Auto mode: bracket directive sets bracket mode + [ + { + line: '[#attempt]<#attempt>', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 10, type: 'source.freemarker2' } + ] + } + ], + // Auto mode: angle directive sets angle mode + [ + { + line: '<#attempt>[#attempt]', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 10, type: 'source.freemarker2' } + ] + } + ], + // Auto mode: invalid directive sets mode + [ + { + line: '[#foobar]<#foobar>', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 9, type: 'source.freemarker2' } + ] + } + ], + // Auto mode: angle tag comment sets mode + [ + { + line: '<#-- asd -->', + tokens: [{ startIndex: 0, type: 'comment.freemarker2' }] + }, + { + line: '[#-- asd --]', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: '[#if true]B[/#if]', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: '<#if true>A', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'keyword.true.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 10, type: 'source.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 14, type: 'tag.freemarker2' }, + { startIndex: 16, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + // Auto mode: bracket tag comment sets mode + [ + { + line: '[#-- asd --]', + tokens: [{ startIndex: 0, type: 'comment.freemarker2' }] + }, + { + line: '<#-- asd -->', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: '<#if true>A', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: '[#if true]B[/#if]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'keyword.true.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 10, type: 'source.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 14, type: 'tag.freemarker2' }, + { startIndex: 16, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + // Auto mode: angle unified call sets mode + [ + { + line: '<@join/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '[@join/]', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: '[#if true]B[/#if]', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: '<#if true>A', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'keyword.true.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 10, type: 'source.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 14, type: 'tag.freemarker2' }, + { startIndex: 16, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + // Auto mode: bracket unified call sets mode + [ + { + line: '[@join/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '<@join/>', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: '<#if true>A', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: '[#if true]B[/#if]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'keyword.true.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 10, type: 'source.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 14, type: 'tag.freemarker2' }, + { startIndex: 16, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + // Auto mode: bracket expression comment does not set tag syntax mode + [ + { + line: '${[!-- asd --]0}<#if true>[#if]', + tokens: [ + { + startIndex: 0, + type: 'delimiter.interpolation.freemarker2' + }, + { + startIndex: 1, + type: 'delimiter.curly.freemarker2.interpolation' + }, + { + startIndex: 2, + type: 'comment.freemarker2' + }, + { + startIndex: 14, + type: 'number.freemarker2' + }, + { + startIndex: 15, + type: 'delimiter.curly.freemarker2.interpolation' + }, + { + startIndex: 16, + type: 'delimiter.angle.freemarker2.directive' + }, + { + startIndex: 17, + type: 'delimiter.directive.freemarker2' + }, + { + startIndex: 18, + type: 'tag.freemarker2' + }, + { + startIndex: 20, + type: '' + }, + { + startIndex: 21, + type: 'keyword.true.freemarker2' + }, + { + startIndex: 25, + type: 'delimiter.angle.freemarker2.directive' + }, + { + startIndex: 27, + type: 'delimiter.directive.freemarker2' + }, + { + startIndex: 29, + type: 'tag.freemarker2' + }, + { + startIndex: 31, + type: 'delimiter.angle.freemarker2.directive' + }, + { + startIndex: 32, + type: 'source.freemarker2' + } + ] + } + ], + // Auto mode: angle expression comment does not set tag syntax mode + [ + { + line: '${0}[#if true][/#if]<#if>', + tokens: [ + { + startIndex: 0, + type: 'delimiter.interpolation.freemarker2' + }, + { + startIndex: 1, + type: 'delimiter.curly.freemarker2.interpolation' + }, + { + startIndex: 2, + type: 'comment.freemarker2' + }, + { + startIndex: 14, + type: 'number.freemarker2' + }, + { + startIndex: 15, + type: 'delimiter.curly.freemarker2.interpolation' + }, + { + startIndex: 16, + type: 'delimiter.square.freemarker2.directive' + }, + { + startIndex: 17, + type: 'delimiter.directive.freemarker2' + }, + { + startIndex: 18, + type: 'tag.freemarker2' + }, + { + startIndex: 20, + type: '' + }, + { + startIndex: 21, + type: 'keyword.true.freemarker2' + }, + { + startIndex: 25, + type: 'delimiter.square.freemarker2.directive' + }, + { + startIndex: 27, + type: 'delimiter.directive.freemarker2' + }, + { + startIndex: 29, + type: 'tag.freemarker2' + }, + { + startIndex: 31, + type: 'delimiter.square.freemarker2.directive' + }, + { + startIndex: 32, + type: 'source.freemarker2' + } + ] + } + ], + + // Block comment (terse) (angle) + [ + { + line: 'x<#--a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'comment.freemarker2' } + ] + }, + { + line: 'b <#if><#noparse>', + tokens: [{ startIndex: 0, type: 'comment.freemarker2' }] + }, + { + line: 'c-->y', + tokens: [ + { startIndex: 0, type: 'comment.freemarker2' }, + { startIndex: 4, type: 'source.freemarker2' } + ] + } + ], + // Block comment (terse) (bracket) + [ + { + line: 'x[#--a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'comment.freemarker2' } + ] + }, + { + line: 'b', + tokens: [{ startIndex: 0, type: 'comment.freemarker2' }] + }, + { + line: 'c--]y', + tokens: [ + { startIndex: 0, type: 'comment.freemarker2' }, + { startIndex: 4, type: 'source.freemarker2' } + ] + } + ], + // Block comment (tag) (angle) + [ + { + line: 'x<#comment>a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 11, type: 'comment.freemarker2' } + ] + }, + { + line: 'b', + tokens: [{ startIndex: 0, type: 'comment.freemarker2' }] + }, + { + line: 'cy', + tokens: [ + { startIndex: 0, type: 'comment.freemarker2' }, + { startIndex: 1, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 12, type: 'source.freemarker2' } + ] + } + ], + + // Block comment (tag) (bracket) + [ + { + line: 'x[#comment]a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 11, type: 'comment.freemarker2' } + ] + }, + { + line: 'b', + tokens: [{ startIndex: 0, type: 'comment.freemarker2' }] + }, + { + line: 'c[/#comment]y', + tokens: [ + { startIndex: 0, type: 'comment.freemarker2' }, + { startIndex: 1, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 12, type: 'source.freemarker2' } + ] + } + ], + + // Expression comments + [ + // Angle syntax (no spaces) + { + line: '${2+3}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'comment.freemarker2' }, + { startIndex: 20, type: 'number.freemarker2' }, + { startIndex: 21, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Angle syntax (spaces) + { + line: '${2+ 3}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'comment.freemarker2' }, + { startIndex: 21, type: '' }, + { startIndex: 22, type: 'number.freemarker2' }, + { startIndex: 23, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Bracket syntax (no spaces) + { + line: '${2+[!-- comment --]3}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'comment.freemarker2' }, + { startIndex: 20, type: 'number.freemarker2' }, + { startIndex: 21, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${[[!-- comment --]3]}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.square.freemarker2' }, + { startIndex: 3, type: 'comment.freemarker2' }, + { startIndex: 19, type: 'number.freemarker2' }, + { startIndex: 20, type: 'delimiter.square.freemarker2' }, + { startIndex: 21, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Bracket syntax (spaces) + { + line: '${2+ [!-- comment --] 3}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'comment.freemarker2' }, + { startIndex: 21, type: '' }, + { startIndex: 22, type: 'number.freemarker2' }, + { startIndex: 23, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // noparse (ignores everything until the matching closing tag) + [ + { + line: 'x<#noparse>a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 11, type: 'source.freemarker2' } + ] + }, + { + line: 'b <#if> ', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'cy', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 12, type: 'source.freemarker2' } + ] + } + ], + + // noParse (ignores everything until the matching closing tag) + [ + { + line: 'x<#noParse>a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 11, type: 'source.freemarker2' } + ] + }, + { + line: 'b <#if> ', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'cy', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 12, type: 'source.freemarker2' } + ] + } + ], + + // Closing angle bracket treatment + [ + // Comparison operator when inside an interpolation + { + line: '${1>2}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'number.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${1>=2}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Directive end tag when inside a directive + { + line: '<#if 1>2', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 7, type: 'source.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 9, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'tag.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Normal comparison operator when inside parentheses within a directive + // Only considers parentheses, not other brackets + { + line: '<#if (1>2)>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 14, type: 'tag.freemarker2' }, + { startIndex: 16, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#if (1>=2)>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 13, type: 'delimiter.directive.freemarker2' }, + { startIndex: 15, type: 'tag.freemarker2' }, + { startIndex: 17, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#if [1>2]>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.square.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 8, type: 'source.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 14, type: 'tag.freemarker2' }, + { startIndex: 16, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#if [(1>2)]>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.square.freemarker2' }, + { startIndex: 6, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'operators.freemarker2' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 14, type: 'delimiter.directive.freemarker2' }, + { startIndex: 16, type: 'tag.freemarker2' }, + { startIndex: 18, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + + // Mismatched closing bracket / parenthesis does not end expression mode + [ + // Interpolation + { + line: '${)1}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${]1}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.square.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${>1}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'operators.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Directive + { + line: '<#if )1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#if ]1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.square.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#if }1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + + // Boolean literals + [ + { + line: '${false}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${true}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.true.freemarker2' }, + { startIndex: 6, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Number literals + [ + { + line: '${123}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${123.456}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'number.float.freemarker2' }, + { startIndex: 9, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Interpolated string literals (single quote) + [ + // Empty string + { + line: "${''}", + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 4, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Literal content + { + line: "${'abc'}", + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 7, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Escaped characters (named) + { + line: "${'\\n\\t\\r\\f\\b\\g\\l\\a\\\\\\'\\{\\='}", + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 3, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 28, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Escaped characters (unicode, 1-4 hex digits) + { + line: "${'\\x1\\x11\\x111\\x1111\\x11111'}", + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 3, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 29, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // String interpolation (unsupported, not possible with Monarch?) + { + // this evaluates to "ab0cd" and contains three interpolations + line: "${'a${\\'b${\\\\\\'${0}\\\\\\'}c\\'}d'}", + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 6, type: 'string.escape.freemarker2' }, + { startIndex: 8, type: 'string.freemarker2' }, + { startIndex: 11, type: 'string.escape.freemarker2' }, + { startIndex: 15, type: 'string.freemarker2' }, + { startIndex: 19, type: 'string.escape.freemarker2' }, + { startIndex: 23, type: 'string.freemarker2' }, + { startIndex: 25, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 30, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + // Interpolated string literals (double quote) + [ + // Empty string + { + line: '${""}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 4, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Literal content + { + line: '${"abc"}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 7, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Escaped characters (named) + { + line: '${"\\n\\t\\r\\f\\b\\g\\l\\a\\\\\\\'\\{\\="}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 3, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 28, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Escaped characters (unicode, 1-4 hex digits) + { + line: '${"\\x1\\x11\\x111\\x1111\\x11111"}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 3, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 29, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // String interpolation (unsupported, not possible with Monarch?) + { + // this evaluates to "ab0cd" and contains three interpolations + line: '${"a${\\"b${\\\\\\"${0}\\\\\\"}c\\"}d"}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 6, type: 'string.escape.freemarker2' }, + { startIndex: 8, type: 'string.freemarker2' }, + { startIndex: 11, type: 'string.escape.freemarker2' }, + { startIndex: 15, type: 'string.freemarker2' }, + { startIndex: 19, type: 'string.escape.freemarker2' }, + { startIndex: 23, type: 'string.freemarker2' }, + { startIndex: 25, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 30, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Raw string literals (single quote) + [ + // Empty string + { + line: "${r''}", + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Literal content + { + line: "${r'abc'}", + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 8, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Raw string can contain anything other than the opening quote mark + { + line: "${r'\"\\n\\x1'}", + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 11, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Raw string literals (double quote) + [ + // Empty string + { + line: '${r""}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Literal content + { + line: '${r"abc"}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 8, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Raw string can contain anything other than the opening quote mark + { + line: '${r"\'\\n\\x1"}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 11, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Boolean operators + [ + { + line: '${!false}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'operators.freemarker2' }, + { startIndex: 3, type: 'keyword.false.freemarker2' }, + { startIndex: 8, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${false&true}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 8, type: 'keyword.true.freemarker2' }, + { startIndex: 12, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${false&&true}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 9, type: 'keyword.true.freemarker2' }, + { startIndex: 13, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${false&&true}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 17, type: 'keyword.true.freemarker2' }, + { startIndex: 21, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${false\\andtrue}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'keyword.true.freemarker2' }, + { startIndex: 15, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${false|true}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 8, type: 'keyword.true.freemarker2' }, + { startIndex: 12, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${false||true}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 9, type: 'keyword.true.freemarker2' }, + { startIndex: 13, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Sequence literals + [ + // range (inclusive) + { + line: '${(1..3)}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 8, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // range (exclusive) + { + line: '${(1..<3)}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // range (exclusive) (alternative form) + { + line: '${(1..!3)}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // range (length-limited) + { + line: '${(1..*3)}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // range (right-unbounded) + { + line: '${(1..)}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 6, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 7, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // List literals + [ + // Can be used in directives + { + line: '<#assign s=[1,2]>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.freemarker2' }, + { startIndex: 14, type: 'number.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2' }, + { startIndex: 16, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Can be used in interpolations + { + line: '${[1,2]}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.square.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.freemarker2' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2' }, + { startIndex: 7, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Hash literals + [ + // Can be used in directives + { + line: '<#assign s={"foo":9}>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.curly.freemarker2' }, + { startIndex: 12, type: 'string.freemarker2' }, + { startIndex: 17, type: 'delimiter.freemarker2' }, + { startIndex: 18, type: 'number.freemarker2' }, + { startIndex: 19, type: 'delimiter.curly.freemarker2' }, + { startIndex: 20, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Can be used in interpolations + { + line: '${{"foo":9}.foo+4}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.curly.freemarker2' }, + { startIndex: 3, type: 'string.freemarker2' }, + { startIndex: 8, type: 'delimiter.freemarker2' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.curly.freemarker2' }, + { startIndex: 11, type: 'delimiter.freemarker2' }, + { startIndex: 12, type: 'identifier.freemarker2' }, + { startIndex: 15, type: 'operators.freemarker2' }, + { startIndex: 16, type: 'number.freemarker2' }, + { startIndex: 17, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Comparison operators + [ + { + line: '${a=b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a==b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a!=b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${ab}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a gt b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 8, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a \\gt b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a > b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a>=b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a \\gte b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a >= b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'identifier.freemarker2' }, + { startIndex: 11, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + // Assignment operators + [ + { + line: '<#assign a+=2>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#assign a-=2>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#assign a*=2>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#assign a/=2>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#assign a%=2>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + + // Increment operators + [ + { + line: '<#assign a++>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#assign a-->', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + + // Numerical operators + [ + { + line: '${a+b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a-b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a*b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a/b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a%b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Not an operator, only used to index hashes + // But still tokenized as 2 operators + { + line: '${a**b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Missing value test operator + [ + { + line: '${a??}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Lambdas + [ + // Single argument without parentheses + { + line: '${a?map(x->x*2)}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'meta.arrow.freemarker2' }, + { startIndex: 11, type: 'identifier.freemarker2' }, + { startIndex: 12, type: 'operators.freemarker2' }, + { startIndex: 13, type: 'number.freemarker2' }, + { startIndex: 14, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 15, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Alternative arrow representation + { + line: '${a?map(x->x*2)}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'meta.arrow.freemarker2' }, + { startIndex: 14, type: 'identifier.freemarker2' }, + { startIndex: 15, type: 'operators.freemarker2' }, + { startIndex: 16, type: 'number.freemarker2' }, + { startIndex: 17, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 18, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Single argument with parentheses + { + line: '${a?map((x)->x*2)}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 11, type: 'meta.arrow.freemarker2' }, + { startIndex: 13, type: 'identifier.freemarker2' }, + { startIndex: 14, type: 'operators.freemarker2' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 17, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Multiple arguments with parentheses + { + line: '${a?map((x,y)->x*2)}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.freemarker2' }, + { startIndex: 11, type: 'identifier.freemarker2' }, + { startIndex: 12, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 13, type: 'meta.arrow.freemarker2' }, + { startIndex: 15, type: 'identifier.freemarker2' }, + { startIndex: 16, type: 'operators.freemarker2' }, + { startIndex: 17, type: 'number.freemarker2' }, + { startIndex: 18, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 19, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Built-ins + [ + { + line: '${x?length?string}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'identifier.freemarker2' }, + { startIndex: 17, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${x?string.currency}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.freemarker2' }, + { startIndex: 11, type: 'identifier.freemarker2' }, + { startIndex: 19, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Directives + [ + // List + { + line: '<#list users as user>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 12, type: '' }, + { startIndex: 13, type: 'keyword.as.freemarker2' }, + { startIndex: 15, type: '' }, + { startIndex: 16, type: 'identifier.freemarker2' }, + { startIndex: 20, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 22, type: 'delimiter.directive.freemarker2' }, + { startIndex: 24, type: 'tag.freemarker2' }, + { startIndex: 28, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Unknown directive + { + line: '<#foobar>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Directives with no expressions allowed, no closing slash + { + line: '<#attempt>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#attempt 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#attempt />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#recover>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#recover 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#recover />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#sep>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#sep 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#sep />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#autoesc>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#autoesc 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#autoesc />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#autoEsc>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#autoEsc 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#autoEsc />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noautoesc>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noautoesc 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noautoesc />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noAutoEsc>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noAutoEsc 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noAutoEsc />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#compress>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#compress 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#compress />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#default>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#default 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#default />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noescape>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noescape 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noescape />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noEscape>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noEscape 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#noEscape />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Directives with no expressions allowed, closing slash allowed + { + line: '<#else>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#else/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#else 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.directive.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#break>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#break/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.directive.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#break 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.directive.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#continue>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#continue/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#continue 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#return>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#return/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.directive.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#stop>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#stop/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#flush>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#flush/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.directive.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#flush 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.directive.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#t>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 3, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#t/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 3, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#t 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'number.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#lt>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#lt/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.directive.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#lt 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#rt>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#rt/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.directive.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#rt 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#lt>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#nt>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#nt/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.directive.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#nt 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#nested>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#nested/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.directive.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#recurse>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#recurse/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.directive.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#fallback>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#fallback/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#fallback 1/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#ftl>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#ftl/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Directives that allow expressions + { + line: '<#if 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#elseif 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#elseIf 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#list 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#foreach 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#forEach 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#switch 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#case 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#assign 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#global 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#local 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#include 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#import 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#function 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#macro 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#transform 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#visit 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#stop 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#return 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#call 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#setting 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#outputformat 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 14, type: '' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#outputFormat 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 14, type: '' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#nested 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#recurse 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#escape 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#ftl 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<#items 1>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Closable tags + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 15, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 15, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + + // Macro definitions + [ + // No argument + { + line: '<#macro x>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'tag.freemarker2' }, + { startIndex: 18, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + + // With arguments + { + line: '<#macro x a1 a2>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'identifier.freemarker2' }, + { startIndex: 12, type: '' }, + { startIndex: 13, type: 'identifier.freemarker2' }, + { startIndex: 15, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 17, type: 'delimiter.directive.freemarker2' }, + { startIndex: 19, type: 'tag.freemarker2' }, + { startIndex: 24, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + + // Catch all parameter + { + line: '<#macro x foo...>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'identifier.freemarker2' }, + { startIndex: 13, type: 'operators.freemarker2' }, + { startIndex: 16, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 18, type: 'delimiter.directive.freemarker2' }, + { startIndex: 20, type: 'tag.freemarker2' }, + { startIndex: 25, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + + // Macro calls + [ + // Without content + { + line: '<@foo/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // With content and named ending tag + { + line: '<@foo>aaa', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 6, type: 'source.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'tag.freemarker2' }, + { startIndex: 15, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // With content and unnamed ending tag + { + line: '<@foo>aaa', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 6, type: 'source.freemarker2' }, + { startIndex: 9, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Special highlighting when the expression to call consists + // solely of an identifier. + { + line: '<@foo>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<@foo >', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<@foo/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + { + line: '<@foo />', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Normal highlighting when the expression to call + // is an expression. + { + line: '<@foo()/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 7, type: 'delimiter.directive.freemarker2' }, + { startIndex: 8, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Positional parameters + { + line: '<@join [1] ":"/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'delimiter.square.freemarker2' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'string.freemarker2' }, + { startIndex: 14, type: 'delimiter.directive.freemarker2' }, + { startIndex: 15, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // Named parameters + { + line: '<@join arr=[1] sep=":"/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2' }, + { startIndex: 14, type: '' }, + { startIndex: 15, type: 'identifier.freemarker2' }, + { startIndex: 18, type: 'operators.freemarker2' }, + { startIndex: 19, type: 'string.freemarker2' }, + { startIndex: 22, type: 'delimiter.directive.freemarker2' }, + { startIndex: 23, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // ! should not end macro parameters + { + line: '<@join arr=[1]! sep=":"/>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2' }, + { startIndex: 14, type: 'operators.freemarker2' }, + { startIndex: 15, type: '' }, + { startIndex: 16, type: 'identifier.freemarker2' }, + { startIndex: 19, type: 'operators.freemarker2' }, + { startIndex: 20, type: 'string.freemarker2' }, + { startIndex: 23, type: 'delimiter.directive.freemarker2' }, + { startIndex: 24, type: 'delimiter.angle.freemarker2.directive' } + ] + }, + // repeat + { + line: '<@repeat count=4 ; c, halfc, last>', + tokens: [ + { startIndex: 0, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 14, type: 'operators.freemarker2' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: '' }, + { startIndex: 17, type: 'delimiter.freemarker2' }, + { startIndex: 18, type: '' }, + { startIndex: 19, type: 'identifier.freemarker2' }, + { startIndex: 20, type: 'delimiter.freemarker2' }, + { startIndex: 21, type: '' }, + { startIndex: 22, type: 'identifier.freemarker2' }, + { startIndex: 27, type: 'delimiter.freemarker2' }, + { startIndex: 28, type: '' }, + { startIndex: 29, type: 'identifier.freemarker2' }, + { startIndex: 33, type: 'delimiter.angle.freemarker2.directive' }, + { startIndex: 35, type: 'delimiter.directive.freemarker2' }, + { startIndex: 37, type: 'tag.freemarker2' }, + { startIndex: 43, type: 'delimiter.angle.freemarker2.directive' } + ] + } + ], + + // Hash keys + [ + // Normal hash keys (dot notation) + { + line: '${a.a}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Normal hash keys (square bracket notation) + { + line: '${a["a"]}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.square.freemarker2' }, + { startIndex: 4, type: 'string.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2' }, + { startIndex: 8, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Special hash keys (dot notation, these are usually operators / keywords) + { + line: '${a.*}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a.**}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a.false}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a.true}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 8, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a.in}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a.as}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a.using}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Spaces are allowed + { + line: '${a . **}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 5, type: 'delimiter.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // *** is not a valid key name + { + line: '${a.***}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'operators.freemarker2' }, + { startIndex: 7, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Special hash keys (square bracket notation) + { + line: '${a["**"]}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.square.freemarker2' }, + { startIndex: 4, type: 'string.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2' }, + { startIndex: 9, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // noparse (ignores everything until the matching closing tag) + [ + { + line: 'x[#noparse]a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 11, type: 'source.freemarker2' } + ] + }, + { + line: 'b [#if][/#if] [/#noParse] [!-- ... --]', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'c[/#noparse]y', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 12, type: 'source.freemarker2' } + ] + } + ], + + // noParse (ignores everything until the matching closing tag) + [ + { + line: 'x[#noParse]a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 11, type: 'source.freemarker2' } + ] + }, + { + line: 'b [#if][/#if] [/#noparse] [!-- ... --]', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'c[/#noParse]y', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 12, type: 'source.freemarker2' } + ] + } + ], + + // Closing angle bracket treatment + [ + // Comparison operator when inside an interpolation + { + line: '${1>2}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'number.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${1>=2}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Normal comparison operator within a directive + { + line: '[#if 1>2][/#if]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'operators.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'tag.freemarker2' }, + { startIndex: 14, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#if (1>2)][/#if]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 14, type: 'tag.freemarker2' }, + { startIndex: 16, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#if (1>=2)][/#if]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 13, type: 'delimiter.directive.freemarker2' }, + { startIndex: 15, type: 'tag.freemarker2' }, + { startIndex: 17, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#if [1>2]][/#if]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.square.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 14, type: 'tag.freemarker2' }, + { startIndex: 16, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#if [(1>2)]][/#if]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.square.freemarker2' }, + { startIndex: 6, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'operators.freemarker2' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 14, type: 'delimiter.directive.freemarker2' }, + { startIndex: 16, type: 'tag.freemarker2' }, + { startIndex: 18, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + + // Mismatched closing bracket / parenthesis does not end expression mode + [ + // Interpolation + { + line: '${)1}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${]1}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.square.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${>1}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'operators.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Directive + { + line: '[#if )1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#if }1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + + // List literals + [ + // Can be used in directives + { + line: '[#assign s=[1,2]]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.freemarker2' }, + { startIndex: 14, type: 'number.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2' }, + { startIndex: 16, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Can be used in interpolations + { + line: '${[1,2]}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.square.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.freemarker2' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2' }, + { startIndex: 7, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Hash literals + [ + // Can be used in directives + { + line: '[#assign s={"foo":9}]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.curly.freemarker2' }, + { startIndex: 12, type: 'string.freemarker2' }, + { startIndex: 17, type: 'delimiter.freemarker2' }, + { startIndex: 18, type: 'number.freemarker2' }, + { startIndex: 19, type: 'delimiter.curly.freemarker2' }, + { startIndex: 20, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Can be used in interpolations + { + line: '${{"foo":9}.foo+4}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.curly.freemarker2' }, + { startIndex: 3, type: 'string.freemarker2' }, + { startIndex: 8, type: 'delimiter.freemarker2' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.curly.freemarker2' }, + { startIndex: 11, type: 'delimiter.freemarker2' }, + { startIndex: 12, type: 'identifier.freemarker2' }, + { startIndex: 15, type: 'operators.freemarker2' }, + { startIndex: 16, type: 'number.freemarker2' }, + { startIndex: 17, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Assignment operators + [ + { + line: '[#assign a+=2]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#assign a-=2]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#assign a*=2]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#assign a/=2]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#assign a%=2]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + + // Increment operators + [ + { + line: '[#assign a++]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#assign a--]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + + // Directives + [ + // List + { + line: '[#list users as user][/#list]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 12, type: '' }, + { startIndex: 13, type: 'keyword.as.freemarker2' }, + { startIndex: 15, type: '' }, + { startIndex: 16, type: 'identifier.freemarker2' }, + { startIndex: 20, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 22, type: 'delimiter.directive.freemarker2' }, + { startIndex: 24, type: 'tag.freemarker2' }, + { startIndex: 28, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Unknown directive + { + line: '[#foobar]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Directives with no expressions allowed, no closing slash + { + line: '[#attempt]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#attempt 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#attempt /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#recover]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#recover 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#recover /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#sep]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#sep 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#sep /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#autoesc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#autoesc 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#autoesc /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#autoEsc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#autoEsc 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#autoEsc /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noautoesc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noautoesc 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noautoesc /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noAutoEsc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noAutoEsc 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noAutoEsc /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#compress]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#compress 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#compress /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#default]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#default 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#default /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noescape]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noescape 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noescape /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noEscape]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noEscape 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noEscape /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Directives with no expressions allowed, closing slash allowed + { + line: '[#else]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#else/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#else 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.directive.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#break]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#break/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.directive.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#break 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.directive.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#continue]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#continue/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#continue 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#return]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#return/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.directive.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#stop]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#stop/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#flush]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#flush/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.directive.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#flush 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.directive.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#t]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 3, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#t/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 3, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#t 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'number.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#lt]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#lt/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.directive.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#lt 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#rt]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#rt/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.directive.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#rt 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#lt]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#nt]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#nt/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.directive.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#nt 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#nested]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#nested/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.directive.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#recurse]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#recurse/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.directive.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#fallback]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#fallback/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#fallback 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#ftl]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#ftl/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Directives that allow expressions + { + line: '[#if 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#elseif 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#elseIf 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#list 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#foreach 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#forEach 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#switch 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#case 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#assign 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#global 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#local 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#include 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#import 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#function 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#macro 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#transform 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#visit 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#stop 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#return 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#call 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#setting 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#outputformat 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 14, type: '' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#outputFormat 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 14, type: '' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#nested 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#recurse 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#escape 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#ftl 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#items 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Closable tags + { + line: '[/#if]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#list]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#sep]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#recover]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#attempt]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#foreach]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#forEach]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#local]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#global]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#assign]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#function]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#macro]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#outputformat]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#outputFormat]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#autoesc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#autoEsc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#noautoesc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#noAutoEsc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#compress]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#transform]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#switch]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#escape]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#noescape]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#noEscape]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + + // Macro definitions + [ + // No argument + { + line: '[#macro x][/#macro]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'tag.freemarker2' }, + { startIndex: 18, type: 'delimiter.square.freemarker2.directive' } + ] + }, + + // With arguments + { + line: '[#macro x a1 a2][/#macro]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'identifier.freemarker2' }, + { startIndex: 12, type: '' }, + { startIndex: 13, type: 'identifier.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 17, type: 'delimiter.directive.freemarker2' }, + { startIndex: 19, type: 'tag.freemarker2' }, + { startIndex: 24, type: 'delimiter.square.freemarker2.directive' } + ] + }, + + // Catch all parameter + { + line: '[#macro x foo...][/#macro]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'identifier.freemarker2' }, + { startIndex: 13, type: 'operators.freemarker2' }, + { startIndex: 16, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 18, type: 'delimiter.directive.freemarker2' }, + { startIndex: 20, type: 'tag.freemarker2' }, + { startIndex: 25, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + + // Macro calls + [ + // Without content + { + line: '[@foo/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // With content and named ending tag + { + line: '[@foo]aaa[/@foo]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 6, type: 'source.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'tag.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // With content and unnamed ending tag + { + line: '[@foo]aaa[/@]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 6, type: 'source.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Special highlighting when the expression to call consists + // solely of an identifier. + { + line: '[@foo]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[@foo ]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[@foo/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[@foo /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Normal highlighting when the expression to call + // is an expression. + { + line: '[@foo()/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 7, type: 'delimiter.directive.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Positional parameters + { + line: '[@join [1] ":"/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'delimiter.square.freemarker2' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'string.freemarker2' }, + { startIndex: 14, type: 'delimiter.directive.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Named parameters + { + line: '[@join arr=[1] sep=":"/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2' }, + { startIndex: 14, type: '' }, + { startIndex: 15, type: 'identifier.freemarker2' }, + { startIndex: 18, type: 'operators.freemarker2' }, + { startIndex: 19, type: 'string.freemarker2' }, + { startIndex: 22, type: 'delimiter.directive.freemarker2' }, + { startIndex: 23, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // ! should not end macro parameters + { + line: '[@join arr=[1]! sep=":"/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2' }, + { startIndex: 14, type: 'operators.freemarker2' }, + { startIndex: 15, type: '' }, + { startIndex: 16, type: 'identifier.freemarker2' }, + { startIndex: 19, type: 'operators.freemarker2' }, + { startIndex: 20, type: 'string.freemarker2' }, + { startIndex: 23, type: 'delimiter.directive.freemarker2' }, + { startIndex: 24, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // repeat + { + line: '[@repeat count=4 ; c, halfc, last][/@repeat]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 14, type: 'operators.freemarker2' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: '' }, + { startIndex: 17, type: 'delimiter.freemarker2' }, + { startIndex: 18, type: '' }, + { startIndex: 19, type: 'identifier.freemarker2' }, + { startIndex: 20, type: 'delimiter.freemarker2' }, + { startIndex: 21, type: '' }, + { startIndex: 22, type: 'identifier.freemarker2' }, + { startIndex: 27, type: 'delimiter.freemarker2' }, + { startIndex: 28, type: '' }, + { startIndex: 29, type: 'identifier.freemarker2' }, + { startIndex: 33, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 35, type: 'delimiter.directive.freemarker2' }, + { startIndex: 37, type: 'tag.freemarker2' }, + { startIndex: 43, type: 'delimiter.square.freemarker2.directive' } + ] + } + ] +]); diff --git a/src/basic-languages/freemarker2/freemarker2-bracket-bracket.test.ts b/src/basic-languages/freemarker2/freemarker2-bracket-bracket.test.ts new file mode 100644 index 00000000..6c0fa79c --- /dev/null +++ b/src/basic-languages/freemarker2/freemarker2-bracket-bracket.test.ts @@ -0,0 +1,3086 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { testTokenization } from '../test/testRunner'; + +testTokenization('freemarker2.tag-bracket.interpolation-bracket', [ + // Plain text + [ + { + line: 'abc123./]})>', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + // HTML comment is not FreeMarker comment + { + line: '', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + // Angle tag syntax is plain text in bracket tag syntax mode + { + line: '<#if user == "Big Joe"> Hello user ', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + // Dollar interpolation syntax is plain text in bracket interpolation syntax mode + { + line: 'Hello, ${user} !', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + } + ], + + // Block comment (terse) + [ + { + line: 'x[#--a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'comment.freemarker2' } + ] + }, + { + line: 'b [#if][/#if][/#comment][#noparse]', + tokens: [{ startIndex: 0, type: 'comment.freemarker2' }] + }, + { + line: 'c--]y', + tokens: [ + { startIndex: 0, type: 'comment.freemarker2' }, + { startIndex: 4, type: 'source.freemarker2' } + ] + } + ], + // Not a block comment (terse) + [ + { + line: 'x<#--a', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'b', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'c-->y', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + } + ], + // Block comment (tag) + [ + { + line: 'x[#comment]a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 11, type: 'comment.freemarker2' } + ] + }, + { + line: 'b [#if][/#if] [#noparse] -->', + tokens: [{ startIndex: 0, type: 'comment.freemarker2' }] + }, + { + line: 'c[/#comment]y', + tokens: [ + { startIndex: 0, type: 'comment.freemarker2' }, + { startIndex: 1, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 12, type: 'source.freemarker2' } + ] + } + ], + + // Not a block comment (tag) + [ + { + line: 'x<#comment>a', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'b', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'cy', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + } + ], + + // Expression comments + [ + // Angle syntax (no spaces) + { + line: '[=2+3]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'comment.freemarker2' }, + { startIndex: 20, type: 'number.freemarker2' }, + { startIndex: 21, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Angle syntax (spaces) + { + line: '[=2+ 3]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'comment.freemarker2' }, + { startIndex: 21, type: '' }, + { startIndex: 22, type: 'number.freemarker2' }, + { startIndex: 23, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Bracket syntax (no spaces) + { + line: '[=2+[!-- comment --]3]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'comment.freemarker2' }, + { startIndex: 20, type: 'number.freemarker2' }, + { startIndex: 21, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=[[!-- comment --]3]]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.square.freemarker2' }, + { startIndex: 3, type: 'comment.freemarker2' }, + { startIndex: 19, type: 'number.freemarker2' }, + { startIndex: 20, type: 'delimiter.square.freemarker2' }, + { startIndex: 21, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Bracket syntax (spaces) + { + line: '[=2+ [!-- comment --] 3]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'comment.freemarker2' }, + { startIndex: 21, type: '' }, + { startIndex: 22, type: 'number.freemarker2' }, + { startIndex: 23, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // noparse (ignores everything until the matching closing tag) + [ + { + line: 'x[#noparse]a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 11, type: 'source.freemarker2' } + ] + }, + { + line: 'b [#if][/#if] [/#noParse] [!-- ... --]', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'c[/#noparse]y', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 12, type: 'source.freemarker2' } + ] + } + ], + + // noParse (ignores everything until the matching closing tag) + [ + { + line: 'x[#noParse]a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 11, type: 'source.freemarker2' } + ] + }, + { + line: 'b [#if][/#if] [/#noparse] [!-- ... --]', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'c[/#noParse]y', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 12, type: 'source.freemarker2' } + ] + } + ], + + // Closing angle bracket treatment + [ + // Comparison operator when inside an interpolation + { + line: '[=1>2]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'number.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=1>=2]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Normal comparison operator within a directive + { + line: '[#if 1>2][/#if]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'operators.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'tag.freemarker2' }, + { startIndex: 14, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#if (1>2)][/#if]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 14, type: 'tag.freemarker2' }, + { startIndex: 16, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#if (1>=2)][/#if]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 13, type: 'delimiter.directive.freemarker2' }, + { startIndex: 15, type: 'tag.freemarker2' }, + { startIndex: 17, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#if [1>2]][/#if]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.square.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 14, type: 'tag.freemarker2' }, + { startIndex: 16, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#if [(1>2)]][/#if]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.square.freemarker2' }, + { startIndex: 6, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'operators.freemarker2' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 14, type: 'delimiter.directive.freemarker2' }, + { startIndex: 16, type: 'tag.freemarker2' }, + { startIndex: 18, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + + // Mismatched closing bracket / parenthesis does not end expression mode + [ + // Interpolation + { + line: '[=)1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=}1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.curly.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=>1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'operators.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Directive + { + line: '[#if )1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#if }1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + + // Boolean literals + [ + { + line: '[=false]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=true]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.true.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Number literals + [ + { + line: '[=123]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=123.456]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'number.float.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Interpolated string literals (single quote) + [ + // Empty string + { + line: "[='']", + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Literal content + { + line: "[='abc']", + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Escaped characters (named) + { + line: "[='\\n\\t\\r\\f\\b\\g\\l\\a\\\\\\'\\{\\=']", + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 3, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 28, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Escaped characters (unicode, 1-4 hex digits) + { + line: "[='\\x1\\x11\\x111\\x1111\\x11111']", + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 3, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 29, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // String interpolation (unsupported, not possible with Monarch?) + { + // this evaluates to "ab0cd" and contains three interpolations + line: "[='a$[\\'b$[\\\\\\'$[0]\\\\\\']c\\']d']", + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 6, type: 'string.escape.freemarker2' }, + { startIndex: 8, type: 'string.freemarker2' }, + { startIndex: 11, type: 'string.escape.freemarker2' }, + { startIndex: 15, type: 'string.freemarker2' }, + { startIndex: 19, type: 'string.escape.freemarker2' }, + { startIndex: 23, type: 'string.freemarker2' }, + { startIndex: 25, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 30, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + // Interpolated string literals (double quote) + [ + // Empty string + { + line: '[=""]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Literal content + { + line: '[="abc"]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Escaped characters (named) + { + line: '[="\\n\\t\\r\\f\\b\\g\\l\\a\\\\\\\'\\{\\="]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 3, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 28, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Escaped characters (unicode, 1-4 hex digits) + { + line: '[="\\x1\\x11\\x111\\x1111\\x11111"]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 3, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 29, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // String interpolation (unsupported, not possible with Monarch?) + { + // this evaluates to "ab0cd" and contains three interpolations + line: '[="a$[\\"b$[\\\\\\"$[0]\\\\\\"]c\\"]d"]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 6, type: 'string.escape.freemarker2' }, + { startIndex: 8, type: 'string.freemarker2' }, + { startIndex: 11, type: 'string.escape.freemarker2' }, + { startIndex: 15, type: 'string.freemarker2' }, + { startIndex: 19, type: 'string.escape.freemarker2' }, + { startIndex: 23, type: 'string.freemarker2' }, + { startIndex: 25, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 30, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Raw string literals (single quote) + [ + // Empty string + { + line: "[=r'']", + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Literal content + { + line: "[=r'abc']", + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Raw string can contain anything other than the opening quote mark + { + line: "[=r'\"\\n\\x1']", + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Raw string literals (double quote) + [ + // Empty string + { + line: '[=r""]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Literal content + { + line: '[=r"abc"]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Raw string can contain anything other than the opening quote mark + { + line: '[=r"\'\\n\\x1"]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Boolean operators + [ + { + line: '[=!false]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'operators.freemarker2' }, + { startIndex: 3, type: 'keyword.false.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=false&true]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 8, type: 'keyword.true.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=false&&true]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 9, type: 'keyword.true.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=false&&true]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 17, type: 'keyword.true.freemarker2' }, + { startIndex: 21, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=false\\andtrue]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'keyword.true.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=false|true]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 8, type: 'keyword.true.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=false||true]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 9, type: 'keyword.true.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Sequence literals + [ + // range (inclusive) + { + line: '[=(1..3)]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // range (exclusive) + { + line: '[=(1..<3)]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // range (exclusive) (alternative form) + { + line: '[=(1..!3)]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // range (length-limited) + { + line: '[=(1..*3)]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // range (right-unbounded) + { + line: '[=(1..)]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 6, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // List literals + [ + // Can be used in directives + { + line: '[#assign s=[1,2]]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.freemarker2' }, + { startIndex: 14, type: 'number.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2' }, + { startIndex: 16, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Can be used in interpolations + { + line: '[=[1,2]]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.square.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.freemarker2' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Hash literals + [ + // Can be used in directives + { + line: '[#assign s={"foo":9}]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.curly.freemarker2' }, + { startIndex: 12, type: 'string.freemarker2' }, + { startIndex: 17, type: 'delimiter.freemarker2' }, + { startIndex: 18, type: 'number.freemarker2' }, + { startIndex: 19, type: 'delimiter.curly.freemarker2' }, + { startIndex: 20, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Can be used in interpolations + { + line: '[={"foo":9}.foo+4]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'delimiter.curly.freemarker2' }, + { startIndex: 3, type: 'string.freemarker2' }, + { startIndex: 8, type: 'delimiter.freemarker2' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.curly.freemarker2' }, + { startIndex: 11, type: 'delimiter.freemarker2' }, + { startIndex: 12, type: 'identifier.freemarker2' }, + { startIndex: 15, type: 'operators.freemarker2' }, + { startIndex: 16, type: 'number.freemarker2' }, + { startIndex: 17, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Comparison operators + [ + { + line: '[=a=b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a==b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a!=b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=ab]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a gt b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a \\gt b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a > b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a>=b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a \\gte b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a >= b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'identifier.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + // Assignment operators + [ + { + line: '[#assign a+=2]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#assign a-=2]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#assign a*=2]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#assign a/=2]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#assign a%=2]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + + // Increment operators + [ + { + line: '[#assign a++]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#assign a--]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + + // Numerical operators + [ + { + line: '[=a+b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a-b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a*b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a/b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a%b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Not an operator, only used to index hashes + // But still tokenized as 2 operators + { + line: '[=a**b]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Missing value test operator + [ + { + line: '[=a??]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Lambdas + [ + // Single argument without parentheses + { + line: '[=a?map(x->x*2)]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'meta.arrow.freemarker2' }, + { startIndex: 11, type: 'identifier.freemarker2' }, + { startIndex: 12, type: 'operators.freemarker2' }, + { startIndex: 13, type: 'number.freemarker2' }, + { startIndex: 14, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Alternative arrow representation + { + line: '[=a?map(x->x*2)]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'meta.arrow.freemarker2' }, + { startIndex: 14, type: 'identifier.freemarker2' }, + { startIndex: 15, type: 'operators.freemarker2' }, + { startIndex: 16, type: 'number.freemarker2' }, + { startIndex: 17, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 18, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Single argument with parentheses + { + line: '[=a?map((x)->x*2)]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 11, type: 'meta.arrow.freemarker2' }, + { startIndex: 13, type: 'identifier.freemarker2' }, + { startIndex: 14, type: 'operators.freemarker2' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 17, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Multiple arguments with parentheses + { + line: '[=a?map((x,y)->x*2)]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.freemarker2' }, + { startIndex: 11, type: 'identifier.freemarker2' }, + { startIndex: 12, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 13, type: 'meta.arrow.freemarker2' }, + { startIndex: 15, type: 'identifier.freemarker2' }, + { startIndex: 16, type: 'operators.freemarker2' }, + { startIndex: 17, type: 'number.freemarker2' }, + { startIndex: 18, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 19, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Built-ins + [ + { + line: '[=x?length?string]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'identifier.freemarker2' }, + { startIndex: 17, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=x?string.currency]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.freemarker2' }, + { startIndex: 11, type: 'identifier.freemarker2' }, + { startIndex: 19, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ], + + // Directives + [ + // List + { + line: '[#list users as user][/#list]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 12, type: '' }, + { startIndex: 13, type: 'keyword.as.freemarker2' }, + { startIndex: 15, type: '' }, + { startIndex: 16, type: 'identifier.freemarker2' }, + { startIndex: 20, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 22, type: 'delimiter.directive.freemarker2' }, + { startIndex: 24, type: 'tag.freemarker2' }, + { startIndex: 28, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Unknown directive + { + line: '[#foobar]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Directives with no expressions allowed, no closing slash + { + line: '[#attempt]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#attempt 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#attempt /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#recover]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#recover 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#recover /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#sep]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#sep 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#sep /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#autoesc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#autoesc 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#autoesc /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#autoEsc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#autoEsc 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#autoEsc /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noautoesc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noautoesc 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noautoesc /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noAutoEsc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noAutoEsc 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noAutoEsc /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#compress]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#compress 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#compress /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#default]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#default 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#default /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noescape]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noescape 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noescape /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noEscape]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noEscape 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noEscape /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Directives with no expressions allowed, closing slash allowed + { + line: '[#else]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#else/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#else 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.directive.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#break]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#break/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.directive.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#break 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.directive.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#continue]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#continue/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#continue 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#return]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#return/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.directive.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#stop]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#stop/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#flush]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#flush/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.directive.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#flush 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.directive.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#t]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 3, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#t/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 3, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#t 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'number.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#lt]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#lt/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.directive.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#lt 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#rt]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#rt/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.directive.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#rt 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#lt]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#nt]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#nt/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.directive.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#nt 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#nested]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#nested/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.directive.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#recurse]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#recurse/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.directive.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#fallback]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#fallback/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#fallback 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#ftl]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#ftl/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Directives that allow expressions + { + line: '[#if 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#elseif 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#elseIf 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#list 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#foreach 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#forEach 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#switch 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#case 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#assign 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#global 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#local 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#include 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#import 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#function 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#macro 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#transform 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#visit 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#stop 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#return 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#call 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#setting 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#outputformat 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 14, type: '' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#outputFormat 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 14, type: '' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#nested 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#recurse 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#escape 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#ftl 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#items 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Closable tags + { + line: '[/#if]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#list]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#sep]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#recover]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#attempt]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#foreach]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#forEach]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#local]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#global]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#assign]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#function]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#macro]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#outputformat]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#outputFormat]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#autoesc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#autoEsc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#noautoesc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#noAutoEsc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#compress]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#transform]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#switch]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#escape]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#noescape]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#noEscape]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + + // Macro definitions + [ + // No argument + { + line: '[#macro x][/#macro]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'tag.freemarker2' }, + { startIndex: 18, type: 'delimiter.square.freemarker2.directive' } + ] + }, + + // With arguments + { + line: '[#macro x a1 a2][/#macro]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'identifier.freemarker2' }, + { startIndex: 12, type: '' }, + { startIndex: 13, type: 'identifier.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 17, type: 'delimiter.directive.freemarker2' }, + { startIndex: 19, type: 'tag.freemarker2' }, + { startIndex: 24, type: 'delimiter.square.freemarker2.directive' } + ] + }, + + // Catch all parameter + { + line: '[#macro x foo...][/#macro]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'identifier.freemarker2' }, + { startIndex: 13, type: 'operators.freemarker2' }, + { startIndex: 16, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 18, type: 'delimiter.directive.freemarker2' }, + { startIndex: 20, type: 'tag.freemarker2' }, + { startIndex: 25, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + + // Macro calls + [ + // Without content + { + line: '[@foo/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // With content and named ending tag + { + line: '[@foo]aaa[/@foo]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 6, type: 'source.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'tag.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // With content and unnamed ending tag + { + line: '[@foo]aaa[/@]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 6, type: 'source.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Special highlighting when the expression to call consists + // solely of an identifier. + { + line: '[@foo]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[@foo ]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[@foo/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[@foo /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Normal highlighting when the expression to call + // is an expression. + { + line: '[@foo()/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 7, type: 'delimiter.directive.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Positional parameters + { + line: '[@join [1] ":"/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'delimiter.square.freemarker2' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'string.freemarker2' }, + { startIndex: 14, type: 'delimiter.directive.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Named parameters + { + line: '[@join arr=[1] sep=":"/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2' }, + { startIndex: 14, type: '' }, + { startIndex: 15, type: 'identifier.freemarker2' }, + { startIndex: 18, type: 'operators.freemarker2' }, + { startIndex: 19, type: 'string.freemarker2' }, + { startIndex: 22, type: 'delimiter.directive.freemarker2' }, + { startIndex: 23, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // ! should not end macro parameters + { + line: '[@join arr=[1]! sep=":"/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2' }, + { startIndex: 14, type: 'operators.freemarker2' }, + { startIndex: 15, type: '' }, + { startIndex: 16, type: 'identifier.freemarker2' }, + { startIndex: 19, type: 'operators.freemarker2' }, + { startIndex: 20, type: 'string.freemarker2' }, + { startIndex: 23, type: 'delimiter.directive.freemarker2' }, + { startIndex: 24, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // repeat + { + line: '[@repeat count=4 ; c, halfc, last][/@repeat]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 14, type: 'operators.freemarker2' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: '' }, + { startIndex: 17, type: 'delimiter.freemarker2' }, + { startIndex: 18, type: '' }, + { startIndex: 19, type: 'identifier.freemarker2' }, + { startIndex: 20, type: 'delimiter.freemarker2' }, + { startIndex: 21, type: '' }, + { startIndex: 22, type: 'identifier.freemarker2' }, + { startIndex: 27, type: 'delimiter.freemarker2' }, + { startIndex: 28, type: '' }, + { startIndex: 29, type: 'identifier.freemarker2' }, + { startIndex: 33, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 35, type: 'delimiter.directive.freemarker2' }, + { startIndex: 37, type: 'tag.freemarker2' }, + { startIndex: 43, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + + // Hash keys + [ + // Normal hash keys (dot notation) + { + line: '[=a.a]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Normal hash keys (square bracket notation) + { + line: '[=a["a"]]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.square.freemarker2' }, + { startIndex: 4, type: 'string.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Special hash keys (dot notation, these are usually operators / keywords) + { + line: '[=a.*]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a.**]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a.false]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a.true]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a.in]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a.as]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + { + line: '[=a.using]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Spaces are allowed + { + line: '[=a . **]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 5, type: 'delimiter.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // *** is not a valid key name + { + line: '[=a.***]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'operators.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.interpolation' } + ] + }, + // Special hash keys (square bracket notation) + { + line: '[=a["**"]]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.interpolation' }, + { startIndex: 1, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.square.freemarker2' }, + { startIndex: 4, type: 'string.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.interpolation' } + ] + } + ] +]); diff --git a/src/basic-languages/freemarker2/freemarker2-bracket-dollar.test.ts b/src/basic-languages/freemarker2/freemarker2-bracket-dollar.test.ts new file mode 100644 index 00000000..a79b8401 --- /dev/null +++ b/src/basic-languages/freemarker2/freemarker2-bracket-dollar.test.ts @@ -0,0 +1,3086 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { testTokenization } from '../test/testRunner'; + +testTokenization('freemarker2.tag-bracket.interpolation-dollar', [ + // Plain text + [ + { + line: 'abc123./]})>', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + // HTML comment is not FreeMarker comment + { + line: '', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + // Angle tag syntax is plain text in bracket tag syntax mode + { + line: '<#if user == "Big Joe"> Hello user ', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + // Bracket interpolation syntax is plain text in dollar interpolation syntax mode + { + line: 'Hello, [=user] !', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + } + ], + + // Block comment (terse) + [ + { + line: 'x[#--a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'comment.freemarker2' } + ] + }, + { + line: 'b [#if][/#if][/#comment][#noparse]', + tokens: [{ startIndex: 0, type: 'comment.freemarker2' }] + }, + { + line: 'c--]y', + tokens: [ + { startIndex: 0, type: 'comment.freemarker2' }, + { startIndex: 4, type: 'source.freemarker2' } + ] + } + ], + // Not a block comment (terse) + [ + { + line: 'x<#--a', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'b', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'c-->y', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + } + ], + // Block comment (tag) + [ + { + line: 'x[#comment]a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 11, type: 'comment.freemarker2' } + ] + }, + { + line: 'b [#if][/#if] [#noparse] -->', + tokens: [{ startIndex: 0, type: 'comment.freemarker2' }] + }, + { + line: 'c[/#comment]y', + tokens: [ + { startIndex: 0, type: 'comment.freemarker2' }, + { startIndex: 1, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 12, type: 'source.freemarker2' } + ] + } + ], + + // Not a block comment (tag) + [ + { + line: 'x<#comment>a', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'b', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'cy', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + } + ], + + // Expression comments + [ + // Angle syntax (no spaces) + { + line: '${2+3}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'comment.freemarker2' }, + { startIndex: 20, type: 'number.freemarker2' }, + { startIndex: 21, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Angle syntax (spaces) + { + line: '${2+ 3}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'comment.freemarker2' }, + { startIndex: 21, type: '' }, + { startIndex: 22, type: 'number.freemarker2' }, + { startIndex: 23, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Bracket syntax (no spaces) + { + line: '${2+[!-- comment --]3}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'comment.freemarker2' }, + { startIndex: 20, type: 'number.freemarker2' }, + { startIndex: 21, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${[[!-- comment --]3]}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.square.freemarker2' }, + { startIndex: 3, type: 'comment.freemarker2' }, + { startIndex: 19, type: 'number.freemarker2' }, + { startIndex: 20, type: 'delimiter.square.freemarker2' }, + { startIndex: 21, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Bracket syntax (spaces) + { + line: '${2+ [!-- comment --] 3}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'comment.freemarker2' }, + { startIndex: 21, type: '' }, + { startIndex: 22, type: 'number.freemarker2' }, + { startIndex: 23, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // noparse (ignores everything until the matching closing tag) + [ + { + line: 'x[#noparse]a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 11, type: 'source.freemarker2' } + ] + }, + { + line: 'b [#if][/#if] [/#noParse] [!-- ... --]', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'c[/#noparse]y', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 12, type: 'source.freemarker2' } + ] + } + ], + + // noParse (ignores everything until the matching closing tag) + [ + { + line: 'x[#noParse]a', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 11, type: 'source.freemarker2' } + ] + }, + { + line: 'b [#if][/#if] [/#noparse] [!-- ... --]', + tokens: [{ startIndex: 0, type: 'source.freemarker2' }] + }, + { + line: 'c[/#noParse]y', + tokens: [ + { startIndex: 0, type: 'source.freemarker2' }, + { startIndex: 1, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 2, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 12, type: 'source.freemarker2' } + ] + } + ], + + // Closing angle bracket treatment + [ + // Comparison operator when inside an interpolation + { + line: '${1>2}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'number.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${1>=2}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Normal comparison operator within a directive + { + line: '[#if 1>2][/#if]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'operators.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'tag.freemarker2' }, + { startIndex: 14, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#if (1>2)][/#if]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 14, type: 'tag.freemarker2' }, + { startIndex: 16, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#if (1>=2)][/#if]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 13, type: 'delimiter.directive.freemarker2' }, + { startIndex: 15, type: 'tag.freemarker2' }, + { startIndex: 17, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#if [1>2]][/#if]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.square.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 14, type: 'tag.freemarker2' }, + { startIndex: 16, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#if [(1>2)]][/#if]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.square.freemarker2' }, + { startIndex: 6, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'operators.freemarker2' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 14, type: 'delimiter.directive.freemarker2' }, + { startIndex: 16, type: 'tag.freemarker2' }, + { startIndex: 18, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + + // Mismatched closing bracket / parenthesis does not end expression mode + [ + // Interpolation + { + line: '${)1}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${]1}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.square.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${>1}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'operators.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Directive + { + line: '[#if )1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#if }1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + + // Boolean literals + [ + { + line: '${false}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${true}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.true.freemarker2' }, + { startIndex: 6, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Number literals + [ + { + line: '${123}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'number.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${123.456}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'number.float.freemarker2' }, + { startIndex: 9, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Interpolated string literals (single quote) + [ + // Empty string + { + line: "${''}", + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 4, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Literal content + { + line: "${'abc'}", + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 7, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Escaped characters (named) + { + line: "${'\\n\\t\\r\\f\\b\\g\\l\\a\\\\\\'\\{\\='}", + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 3, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 28, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Escaped characters (unicode, 1-4 hex digits) + { + line: "${'\\x1\\x11\\x111\\x1111\\x11111'}", + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 3, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 29, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // String interpolation (unsupported, not possible with Monarch?) + { + // this evaluates to "ab0cd" and contains three interpolations + line: "${'a${\\'b${\\\\\\'${0}\\\\\\'}c\\'}d'}", + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 6, type: 'string.escape.freemarker2' }, + { startIndex: 8, type: 'string.freemarker2' }, + { startIndex: 11, type: 'string.escape.freemarker2' }, + { startIndex: 15, type: 'string.freemarker2' }, + { startIndex: 19, type: 'string.escape.freemarker2' }, + { startIndex: 23, type: 'string.freemarker2' }, + { startIndex: 25, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 30, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + // Interpolated string literals (double quote) + [ + // Empty string + { + line: '${""}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 4, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Literal content + { + line: '${"abc"}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 7, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Escaped characters (named) + { + line: '${"\\n\\t\\r\\f\\b\\g\\l\\a\\\\\\\'\\{\\="}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 3, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 28, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Escaped characters (unicode, 1-4 hex digits) + { + line: '${"\\x1\\x11\\x111\\x1111\\x11111"}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 3, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 29, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // String interpolation (unsupported, not possible with Monarch?) + { + // this evaluates to "ab0cd" and contains three interpolations + line: '${"a${\\"b${\\\\\\"${0}\\\\\\"}c\\"}d"}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'string.freemarker2' }, + { startIndex: 6, type: 'string.escape.freemarker2' }, + { startIndex: 8, type: 'string.freemarker2' }, + { startIndex: 11, type: 'string.escape.freemarker2' }, + { startIndex: 15, type: 'string.freemarker2' }, + { startIndex: 19, type: 'string.escape.freemarker2' }, + { startIndex: 23, type: 'string.freemarker2' }, + { startIndex: 25, type: 'string.escape.freemarker2' }, + { startIndex: 27, type: 'string.freemarker2' }, + { startIndex: 30, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Raw string literals (single quote) + [ + // Empty string + { + line: "${r''}", + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Literal content + { + line: "${r'abc'}", + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 8, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Raw string can contain anything other than the opening quote mark + { + line: "${r'\"\\n\\x1'}", + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 11, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Raw string literals (double quote) + [ + // Empty string + { + line: '${r""}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Literal content + { + line: '${r"abc"}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 8, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Raw string can contain anything other than the opening quote mark + { + line: '${r"\'\\n\\x1"}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.freemarker2' }, + { startIndex: 3, type: 'string.raw.freemarker2' }, + { startIndex: 11, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Boolean operators + [ + { + line: '${!false}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'operators.freemarker2' }, + { startIndex: 3, type: 'keyword.false.freemarker2' }, + { startIndex: 8, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${false&true}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 8, type: 'keyword.true.freemarker2' }, + { startIndex: 12, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${false&&true}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 9, type: 'keyword.true.freemarker2' }, + { startIndex: 13, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${false&&true}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 17, type: 'keyword.true.freemarker2' }, + { startIndex: 21, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${false\\andtrue}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'keyword.true.freemarker2' }, + { startIndex: 15, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${false|true}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 8, type: 'keyword.true.freemarker2' }, + { startIndex: 12, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${false||true}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'keyword.false.freemarker2' }, + { startIndex: 7, type: 'operators.freemarker2' }, + { startIndex: 9, type: 'keyword.true.freemarker2' }, + { startIndex: 13, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Sequence literals + [ + // range (inclusive) + { + line: '${(1..3)}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 8, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // range (exclusive) + { + line: '${(1..<3)}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // range (exclusive) (alternative form) + { + line: '${(1..!3)}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // range (length-limited) + { + line: '${(1..*3)}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // range (right-unbounded) + { + line: '${(1..)}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 6, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 7, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // List literals + [ + // Can be used in directives + { + line: '[#assign s=[1,2]]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.freemarker2' }, + { startIndex: 14, type: 'number.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2' }, + { startIndex: 16, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Can be used in interpolations + { + line: '${[1,2]}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.square.freemarker2' }, + { startIndex: 3, type: 'number.freemarker2' }, + { startIndex: 4, type: 'delimiter.freemarker2' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2' }, + { startIndex: 7, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Hash literals + [ + // Can be used in directives + { + line: '[#assign s={"foo":9}]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.curly.freemarker2' }, + { startIndex: 12, type: 'string.freemarker2' }, + { startIndex: 17, type: 'delimiter.freemarker2' }, + { startIndex: 18, type: 'number.freemarker2' }, + { startIndex: 19, type: 'delimiter.curly.freemarker2' }, + { startIndex: 20, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Can be used in interpolations + { + line: '${{"foo":9}.foo+4}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'delimiter.curly.freemarker2' }, + { startIndex: 3, type: 'string.freemarker2' }, + { startIndex: 8, type: 'delimiter.freemarker2' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.curly.freemarker2' }, + { startIndex: 11, type: 'delimiter.freemarker2' }, + { startIndex: 12, type: 'identifier.freemarker2' }, + { startIndex: 15, type: 'operators.freemarker2' }, + { startIndex: 16, type: 'number.freemarker2' }, + { startIndex: 17, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Comparison operators + [ + { + line: '${a=b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a==b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a!=b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${ab}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a gt b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 8, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a \\gt b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a > b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a>=b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a \\gte b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a >= b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'operators.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'identifier.freemarker2' }, + { startIndex: 11, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + // Assignment operators + [ + { + line: '[#assign a+=2]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#assign a-=2]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#assign a*=2]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#assign a/=2]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#assign a%=2]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + + // Increment operators + [ + { + line: '[#assign a++]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#assign a--]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + + // Numerical operators + [ + { + line: '${a+b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a-b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a*b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a/b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a%b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Not an operator, only used to index hashes + // But still tokenized as 2 operators + { + line: '${a**b}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Missing value test operator + [ + { + line: '${a??}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Lambdas + [ + // Single argument without parentheses + { + line: '${a?map(x->x*2)}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'meta.arrow.freemarker2' }, + { startIndex: 11, type: 'identifier.freemarker2' }, + { startIndex: 12, type: 'operators.freemarker2' }, + { startIndex: 13, type: 'number.freemarker2' }, + { startIndex: 14, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 15, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Alternative arrow representation + { + line: '${a?map(x->x*2)}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'meta.arrow.freemarker2' }, + { startIndex: 14, type: 'identifier.freemarker2' }, + { startIndex: 15, type: 'operators.freemarker2' }, + { startIndex: 16, type: 'number.freemarker2' }, + { startIndex: 17, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 18, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Single argument with parentheses + { + line: '${a?map((x)->x*2)}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 11, type: 'meta.arrow.freemarker2' }, + { startIndex: 13, type: 'identifier.freemarker2' }, + { startIndex: 14, type: 'operators.freemarker2' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 17, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Multiple arguments with parentheses + { + line: '${a?map((x,y)->x*2)}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 7, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.freemarker2' }, + { startIndex: 11, type: 'identifier.freemarker2' }, + { startIndex: 12, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 13, type: 'meta.arrow.freemarker2' }, + { startIndex: 15, type: 'identifier.freemarker2' }, + { startIndex: 16, type: 'operators.freemarker2' }, + { startIndex: 17, type: 'number.freemarker2' }, + { startIndex: 18, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 19, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Built-ins + [ + { + line: '${x?length?string}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'identifier.freemarker2' }, + { startIndex: 17, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${x?string.currency}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'operators.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.freemarker2' }, + { startIndex: 11, type: 'identifier.freemarker2' }, + { startIndex: 19, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ], + + // Directives + [ + // List + { + line: '[#list users as user][/#list]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 12, type: '' }, + { startIndex: 13, type: 'keyword.as.freemarker2' }, + { startIndex: 15, type: '' }, + { startIndex: 16, type: 'identifier.freemarker2' }, + { startIndex: 20, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 22, type: 'delimiter.directive.freemarker2' }, + { startIndex: 24, type: 'tag.freemarker2' }, + { startIndex: 28, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Unknown directive + { + line: '[#foobar]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Directives with no expressions allowed, no closing slash + { + line: '[#attempt]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#attempt 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#attempt /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#recover]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#recover 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#recover /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#sep]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#sep 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#sep /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#autoesc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#autoesc 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#autoesc /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#autoEsc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#autoEsc 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#autoEsc /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noautoesc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noautoesc 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noautoesc /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noAutoEsc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noAutoEsc 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noAutoEsc /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#compress]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#compress 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#compress /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#default]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#default 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#default /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noescape]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noescape 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noescape /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noEscape]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noEscape 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#noEscape /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Directives with no expressions allowed, closing slash allowed + { + line: '[#else]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#else/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#else 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.directive.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#break]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#break/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.directive.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#break 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.directive.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#continue]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#continue/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#continue 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#return]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#return/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.directive.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#stop]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#stop/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#flush]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#flush/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.directive.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#flush 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.directive.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#t]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 3, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#t/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 3, type: 'delimiter.directive.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#t 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 4, type: 'number.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#lt]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#lt/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.directive.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#lt 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#rt]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#rt/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.directive.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#rt 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#lt]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#nt]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#nt/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: 'delimiter.directive.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#nt 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#nested]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#nested/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.directive.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#recurse]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#recurse/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.directive.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#fallback]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#fallback/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#fallback 1/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.invalid.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#ftl]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#ftl/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Directives that allow expressions + { + line: '[#if 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 4, type: '' }, + { startIndex: 5, type: 'number.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#elseif 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#elseIf 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#list 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#foreach 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#forEach 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#switch 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#case 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#assign 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#global 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#local 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#include 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#import 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#function 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'number.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#macro 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#transform 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 11, type: '' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#visit 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#stop 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#return 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#call 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'number.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#setting 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#outputformat 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 14, type: '' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#outputFormat 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 14, type: '' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#nested 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#recurse 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'number.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#escape 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'number.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#ftl 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'number.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[#items 1]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Closable tags + { + line: '[/#if]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#list]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#sep]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#recover]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#attempt]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#foreach]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#forEach]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#local]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#global]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#assign]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#function]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#macro]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#outputformat]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#outputFormat]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#autoesc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#autoEsc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 10, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#noautoesc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#noAutoEsc]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#compress]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#transform]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#switch]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#escape]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#noescape]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[/#noEscape]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 3, type: 'tag.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + + // Macro definitions + [ + // No argument + { + line: '[#macro x][/#macro]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 11, type: 'delimiter.directive.freemarker2' }, + { startIndex: 13, type: 'tag.freemarker2' }, + { startIndex: 18, type: 'delimiter.square.freemarker2.directive' } + ] + }, + + // With arguments + { + line: '[#macro x a1 a2][/#macro]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'identifier.freemarker2' }, + { startIndex: 12, type: '' }, + { startIndex: 13, type: 'identifier.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 17, type: 'delimiter.directive.freemarker2' }, + { startIndex: 19, type: 'tag.freemarker2' }, + { startIndex: 24, type: 'delimiter.square.freemarker2.directive' } + ] + }, + + // Catch all parameter + { + line: '[#macro x foo...][/#macro]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 7, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 9, type: '' }, + { startIndex: 10, type: 'identifier.freemarker2' }, + { startIndex: 13, type: 'operators.freemarker2' }, + { startIndex: 16, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 18, type: 'delimiter.directive.freemarker2' }, + { startIndex: 20, type: 'tag.freemarker2' }, + { startIndex: 25, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + + // Macro calls + [ + // Without content + { + line: '[@foo/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // With content and named ending tag + { + line: '[@foo]aaa[/@foo]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 6, type: 'source.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'tag.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // With content and unnamed ending tag + { + line: '[@foo]aaa[/@]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 6, type: 'source.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 10, type: 'delimiter.directive.freemarker2' }, + { startIndex: 12, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Special highlighting when the expression to call consists + // solely of an identifier. + { + line: '[@foo]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[@foo ]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[@foo/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: 'delimiter.directive.freemarker2' }, + { startIndex: 6, type: 'delimiter.square.freemarker2.directive' } + ] + }, + { + line: '[@foo /]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 5, type: '' }, + { startIndex: 6, type: 'delimiter.directive.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Normal highlighting when the expression to call + // is an expression. + { + line: '[@foo()/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.parenthesis.freemarker2' }, + { startIndex: 7, type: 'delimiter.directive.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Positional parameters + { + line: '[@join [1] ":"/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'delimiter.square.freemarker2' }, + { startIndex: 8, type: 'number.freemarker2' }, + { startIndex: 9, type: 'delimiter.square.freemarker2' }, + { startIndex: 10, type: '' }, + { startIndex: 11, type: 'string.freemarker2' }, + { startIndex: 14, type: 'delimiter.directive.freemarker2' }, + { startIndex: 15, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // Named parameters + { + line: '[@join arr=[1] sep=":"/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2' }, + { startIndex: 14, type: '' }, + { startIndex: 15, type: 'identifier.freemarker2' }, + { startIndex: 18, type: 'operators.freemarker2' }, + { startIndex: 19, type: 'string.freemarker2' }, + { startIndex: 22, type: 'delimiter.directive.freemarker2' }, + { startIndex: 23, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // ! should not end macro parameters + { + line: '[@join arr=[1]! sep=":"/]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 7, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'operators.freemarker2' }, + { startIndex: 11, type: 'delimiter.square.freemarker2' }, + { startIndex: 12, type: 'number.freemarker2' }, + { startIndex: 13, type: 'delimiter.square.freemarker2' }, + { startIndex: 14, type: 'operators.freemarker2' }, + { startIndex: 15, type: '' }, + { startIndex: 16, type: 'identifier.freemarker2' }, + { startIndex: 19, type: 'operators.freemarker2' }, + { startIndex: 20, type: 'string.freemarker2' }, + { startIndex: 23, type: 'delimiter.directive.freemarker2' }, + { startIndex: 24, type: 'delimiter.square.freemarker2.directive' } + ] + }, + // repeat + { + line: '[@repeat count=4 ; c, halfc, last][/@repeat]', + tokens: [ + { startIndex: 0, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 1, type: 'delimiter.directive.freemarker2' }, + { startIndex: 2, type: 'tag.freemarker2' }, + { startIndex: 8, type: '' }, + { startIndex: 9, type: 'identifier.freemarker2' }, + { startIndex: 14, type: 'operators.freemarker2' }, + { startIndex: 15, type: 'number.freemarker2' }, + { startIndex: 16, type: '' }, + { startIndex: 17, type: 'delimiter.freemarker2' }, + { startIndex: 18, type: '' }, + { startIndex: 19, type: 'identifier.freemarker2' }, + { startIndex: 20, type: 'delimiter.freemarker2' }, + { startIndex: 21, type: '' }, + { startIndex: 22, type: 'identifier.freemarker2' }, + { startIndex: 27, type: 'delimiter.freemarker2' }, + { startIndex: 28, type: '' }, + { startIndex: 29, type: 'identifier.freemarker2' }, + { startIndex: 33, type: 'delimiter.square.freemarker2.directive' }, + { startIndex: 35, type: 'delimiter.directive.freemarker2' }, + { startIndex: 37, type: 'tag.freemarker2' }, + { startIndex: 43, type: 'delimiter.square.freemarker2.directive' } + ] + } + ], + + // Hash keys + [ + // Normal hash keys (dot notation) + { + line: '${a.a}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Normal hash keys (square bracket notation) + { + line: '${a["a"]}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.square.freemarker2' }, + { startIndex: 4, type: 'string.freemarker2' }, + { startIndex: 7, type: 'delimiter.square.freemarker2' }, + { startIndex: 8, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Special hash keys (dot notation, these are usually operators / keywords) + { + line: '${a.*}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 5, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a.**}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a.false}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a.true}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 8, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a.in}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a.as}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + { + line: '${a.using}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 9, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Spaces are allowed + { + line: '${a . **}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: '' }, + { startIndex: 5, type: 'delimiter.freemarker2' }, + { startIndex: 6, type: '' }, + { startIndex: 8, type: 'identifier.freemarker2' }, + { startIndex: 10, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // *** is not a valid key name + { + line: '${a.***}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.freemarker2' }, + { startIndex: 4, type: 'identifier.freemarker2' }, + { startIndex: 6, type: 'operators.freemarker2' }, + { startIndex: 7, type: 'delimiter.curly.freemarker2.interpolation' } + ] + }, + // Special hash keys (square bracket notation) + { + line: '${a["**"]}', + tokens: [ + { startIndex: 0, type: 'delimiter.interpolation.freemarker2' }, + { startIndex: 1, type: 'delimiter.curly.freemarker2.interpolation' }, + { startIndex: 2, type: 'identifier.freemarker2' }, + { startIndex: 3, type: 'delimiter.square.freemarker2' }, + { startIndex: 4, type: 'string.freemarker2' }, + { startIndex: 8, type: 'delimiter.square.freemarker2' }, + { startIndex: 9, type: 'delimiter.curly.freemarker2.interpolation' } + ] + } + ] +]); diff --git a/src/basic-languages/freemarker2/freemarker2.contribution.ts b/src/basic-languages/freemarker2/freemarker2.contribution.ts new file mode 100644 index 00000000..ce4e157f --- /dev/null +++ b/src/basic-languages/freemarker2/freemarker2.contribution.ts @@ -0,0 +1,111 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { registerLanguage } from '../_.contribution'; + +declare var AMD: any; +declare var require: any; + +// freemarker.tag-square.interpolation-dollar is the default +// According the docs tag-auto will be the default for version 2.4+, but that +// hasn't event been released yet. +registerLanguage({ + id: 'freemarker2', + extensions: ['.ftl', '.ftlh', '.ftlx'], + aliases: ['FreeMarker2', 'Apache FreeMarker2'], + loader: () => { + if (AMD) { + return new Promise((resolve, reject) => { + require(['vs/basic-languages/freemarker2/freemarker2'], resolve, reject); + }).then((m) => m.TagAngleInterpolationDollar); + } else { + return import('./freemarker2').then((m) => m.TagAutoInterpolationDollar); + } + } +}); + +registerLanguage({ + id: 'freemarker2.tag-angle.interpolation-dollar', + aliases: ['FreeMarker2 (Angle/Dollar)', 'Apache FreeMarker2 (Angle/Dollar)'], + loader: () => { + if (AMD) { + return new Promise((resolve, reject) => { + require(['vs/basic-languages/freemarker2/freemarker2'], resolve, reject); + }).then((m) => m.TagAngleInterpolationDollar); + } else { + return import('./freemarker2').then((m) => m.TagAngleInterpolationDollar); + } + } +}); + +registerLanguage({ + id: 'freemarker2.tag-bracket.interpolation-dollar', + aliases: ['FreeMarker2 (Bracket/Dollar)', 'Apache FreeMarker2 (Bracket/Dollar)'], + loader: () => { + if (AMD) { + return new Promise((resolve, reject) => { + require(['vs/basic-languages/freemarker2/freemarker2'], resolve, reject); + }).then((m) => m.TagBracketInterpolationDollar); + } else { + return import('./freemarker2').then((m) => m.TagBracketInterpolationDollar); + } + } +}); + +registerLanguage({ + id: 'freemarker2.tag-angle.interpolation-bracket', + aliases: ['FreeMarker2 (Angle/Bracket)', 'Apache FreeMarker2 (Angle/Bracket)'], + loader: () => { + if (AMD) { + return new Promise((resolve, reject) => { + require(['vs/basic-languages/freemarker2/freemarker2'], resolve, reject); + }).then((m) => m.TagAngleInterpolationBracket); + } else { + return import('./freemarker2').then((m) => m.TagAngleInterpolationBracket); + } + } +}); + +registerLanguage({ + id: 'freemarker2.tag-bracket.interpolation-bracket', + aliases: ['FreeMarker2 (Bracket/Bracket)', 'Apache FreeMarker2 (Bracket/Bracket)'], + loader: () => { + if (AMD) { + return new Promise((resolve, reject) => { + require(['vs/basic-languages/freemarker2/freemarker2'], resolve, reject); + }).then((m) => m.TagBracketInterpolationBracket); + } else { + return import('./freemarker2').then((m) => m.TagBracketInterpolationBracket); + } + } +}); + +registerLanguage({ + id: 'freemarker2.tag-auto.interpolation-dollar', + aliases: ['FreeMarker2 (Auto/Dollar)', 'Apache FreeMarker2 (Auto/Dollar)'], + loader: () => { + if (AMD) { + return new Promise((resolve, reject) => { + require(['vs/basic-languages/freemarker2/freemarker2'], resolve, reject); + }).then((m) => m.TagAutoInterpolationDollar); + } else { + return import('./freemarker2').then((m) => m.TagAutoInterpolationDollar); + } + } +}); + +registerLanguage({ + id: 'freemarker2.tag-auto.interpolation-bracket', + aliases: ['FreeMarker2 (Auto/Bracket)', 'Apache FreeMarker2 (Auto/Bracket)'], + loader: () => { + if (AMD) { + return new Promise((resolve, reject) => { + require(['vs/basic-languages/freemarker2/freemarker2'], resolve, reject); + }).then((m) => m.TagAutoInterpolationBracket); + } else { + return import('./freemarker2').then((m) => m.TagAutoInterpolationBracket); + } + } +}); diff --git a/src/basic-languages/freemarker2/freemarker2.ts b/src/basic-languages/freemarker2/freemarker2.ts new file mode 100644 index 00000000..abcfe4f9 --- /dev/null +++ b/src/basic-languages/freemarker2/freemarker2.ts @@ -0,0 +1,1230 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { languages } from '../../fillers/monaco-editor-core'; + +// Difficulty: "Black hole!" +/* + * The grammar for FreeMarker 2.x. We intentionally limit to FreeMarker 2 as the + * next release FreeMarker 3 is a breaking change that will change the syntax, + * see: + * + * https://cwiki.apache.org/confluence/display/FREEMARKER/FreeMarker+3 + * + * FreeMarker does not just have one grammar, it has 6 (!) different syntaxes. + * + * - 3 possibilities for the tag syntax: angle, bracket, auto + * - 2 possibilities for the interpolation syntax: dollar, bracket + * + * These can be combined, resulting in 3*2=6 syntaxes. There's another tag + * syntax, but that one is legacy and therefore ignored by this tokenizer. + * + * - Angle tag syntax is like `<#if true>...` + * - Bracket tag syntax is like `[#if true]...[/#if]` + * - Auto tag syntax inspects the first directive and uses that. + * + * Dollar interpolation syntax is like `${1+2}`, bracket syntax like `[=1+2]`. + * + * To prevent duplicate code, there are factory functions that take a syntax + * mode and dynamically create the tokenizer for that mode. This does not affect + * performance since the tokenizer is created only once. + * + * Auto mode is implemented via parser states. Each parser state exists three + * times, one for each tag syntax mode (e.g. `default.auto`, `default.angle`, + * `default.bracket`). Auto mode starts in `default.auto` and switches to + * `default.angle` or `default.bracket` when it encounters the first directive. + * + * FreeMarker allows expressions within strings ("a${1+2}b"), but these are + * impossible to tokenize. String interpolation is not implemented via a mode + * change when encountering `${`. Rather, FreeMarker tokenizes the string as a + * literal string first. Then, during the AST build phase, it creates a new + * parses and parses the unescaped string content. + * + * This is adapted from the official JavaCC grammar for FreeMarker: + * https://github.com/apache/freemarker/blob/2.3-gae/src/main/javacc/FTL.jj + * + * Taken from the above file, a short rundown of the basic parser states: + * + * > The lexer portion defines 5 lexical states: + * > DEFAULT, FM_EXPRESSION, IN_PAREN, NO_PARSE, and EXPRESSION_COMMENT. + * > The DEFAULT state is when you are parsing + * > text but are not inside a FreeMarker expression. + * > FM_EXPRESSION is the state you are in + * > when the parser wants a FreeMarker expression. + * > IN_PAREN is almost identical really. The difference + * > is that you are in this state when you are within + * > FreeMarker expression and also within (...). + * > This is a necessary subtlety because the + * > ">" and ">=" symbols can only be used + * > within parentheses because otherwise, it would + * > be ambiguous with the end of a directive. + * > So, for example, you enter the FM_EXPRESSION state + * > right after a ${ and leave it after the matching }. + * > Or, you enter the FM_EXPRESSION state right after + * > an "" + * > that ends the if directive, + * > you go back to DEFAULT lexical state. + * > If, within the FM_EXPRESSION state, you enter a + * > parenthetical expression, you enter the IN_PAREN + * > state. + * > Note that whitespace is ignored in the + * > FM_EXPRESSION and IN_PAREN states + * > but is passed through to the parser as PCDATA in the DEFAULT state. + * > NO_PARSE and EXPRESSION_COMMENT are extremely simple + * > lexical states. NO_PARSE is when you are in a comment + * > block and EXPRESSION_COMMENT is when you are in a comment + * > that is within an FTL expression. + * + * It should be noted that there are another parser state not mentioned in the + * above excerpt: NO_DIRECTIVE is used as the initial starting state when + * parsing the contents of a string literal, which is allowed to contain + * interpolations, but no directives. However, note that FreeMarker first + * tokenizes a string literal as-is, then during the parsing stage, it takes the + * (unescaped) content of the string literal, and tokenizes + parses that + * content with a new child parser. + */ + +const EMPTY_ELEMENTS = [ + 'assign', + 'flush', + 'ftl', + 'return', + 'global', + 'import', + 'include', + 'break', + 'continue', + 'local', + 'nested', + 'nt', + 'setting', + 'stop', + 't', + 'lt', + 'rt', + 'fallback' +]; + +const BLOCK_ELEMENTS = [ + 'attempt', + 'autoesc', + 'autoEsc', + 'compress', + 'comment', + 'escape', + 'noescape', + 'function', + 'if', + 'list', + 'items', + 'sep', + 'macro', + 'noparse', + 'noParse', + 'noautoesc', + 'noAutoEsc', + 'outputformat', + 'switch', + 'visit', + 'recurse' +]; + +interface TagSyntax { + close: string; // must be escaped for RegExp! + id: 'angle' | 'bracket' | 'auto'; + open: string; //must be escaped for RegExp! +} + +interface InterpolationSyntax { + close: string; // must be escaped for RegExp! + id: 'dollar' | 'bracket'; + open1: string; //must be escaped for RegExp! + open2: string; // must be escaped for RegExp! +} + +const TagSyntaxAngle: TagSyntax = { + close: '>', + id: 'angle', + open: '<' +}; + +const TagSyntaxBracket: TagSyntax = { + close: '\\]', + id: 'bracket', + open: '\\[' +}; + +const TagSyntaxAuto: TagSyntax = { + close: '[>\\]]', + id: 'auto', + open: '[<\\[]' +}; + +const InterpolationSyntaxDollar: InterpolationSyntax = { + close: '\\}', + id: 'dollar', + open1: '\\$', + open2: '\\{' +}; + +const InterpolationSyntaxBracket: InterpolationSyntax = { + close: '\\]', + id: 'bracket', + open1: '\\[', + open2: '=' +}; + +function createLangConfiguration(ts: TagSyntax): languages.LanguageConfiguration { + return { + brackets: [ + ['<', '>'], + ['[', ']'], + ['(', ')'], + ['{', '}'] + ], + comments: { + blockComment: [`${ts.open}--`, `--${ts.close}`] + }, + autoCloseBefore: '\n\r\t }]),.:;=', + autoClosingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '"', close: '"', notIn: ['string'] }, + { open: "'", close: "'", notIn: ['string'] } + ], + surroundingPairs: [ + { open: '"', close: '"' }, + { open: "'", close: "'" }, + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '<', close: '>' } + ], + folding: { + markers: { + start: new RegExp( + `${ts.open}#(?:${BLOCK_ELEMENTS.join('|')})([^/${ts.close}]*(?!/)${ts.close})[^${ + ts.open + }]*$` + ), + end: new RegExp(`${ts.open}/#(?:${BLOCK_ELEMENTS.join('|')})[\\r\\n\\t ]*>`) + } + }, + onEnterRules: [ + { + beforeText: new RegExp( + `${ts.open}#(?!(?:${EMPTY_ELEMENTS.join('|')}))([a-zA-Z_]+)([^/${ts.close}]*(?!/)${ + ts.close + })[^${ts.open}]*$` + ), + afterText: new RegExp(`^${ts.open}/#([a-zA-Z_]+)[\\r\\n\\t ]*${ts.close}$`), + action: { + indentAction: languages.IndentAction.IndentOutdent + } + }, + { + beforeText: new RegExp( + `${ts.open}#(?!(?:${EMPTY_ELEMENTS.join('|')}))([a-zA-Z_]+)([^/${ts.close}]*(?!/)${ + ts.close + })[^${ts.open}]*$` + ), + action: { indentAction: languages.IndentAction.Indent } + } + ] + }; +} + +function createLangConfigurationAuto(): languages.LanguageConfiguration { + return { + // Cannot set block comment delimiter in auto mode... + // It depends on the content and the cursor position of the file... + + brackets: [ + ['<', '>'], + ['[', ']'], + ['(', ')'], + ['{', '}'] + ], + + autoCloseBefore: '\n\r\t }]),.:;=', + + autoClosingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '"', close: '"', notIn: ['string'] }, + { open: "'", close: "'", notIn: ['string'] } + ], + + surroundingPairs: [ + { open: '"', close: '"' }, + { open: "'", close: "'" }, + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '<', close: '>' } + ], + + folding: { + markers: { + start: new RegExp(`[<\\[]#(?:${BLOCK_ELEMENTS.join('|')})([^/>\\]]*(?!/)[>\\]])[^<\\[]*$`), + end: new RegExp(`[<\\[]/#(?:${BLOCK_ELEMENTS.join('|')})[\\r\\n\\t ]*>`) + } + }, + onEnterRules: [ + { + beforeText: new RegExp( + `[<\\[]#(?!(?:${EMPTY_ELEMENTS.join('|')}))([a-zA-Z_]+)([^/>\\]]*(?!/)[>\\]])[^[<\\[]]*$` + ), + afterText: new RegExp(`^[<\\[]/#([a-zA-Z_]+)[\\r\\n\\t ]*[>\\]]$`), + action: { + indentAction: languages.IndentAction.IndentOutdent + } + }, + { + beforeText: new RegExp( + `[<\\[]#(?!(?:${EMPTY_ELEMENTS.join('|')}))([a-zA-Z_]+)([^/>\\]]*(?!/)[>\\]])[^[<\\[]]*$` + ), + action: { indentAction: languages.IndentAction.Indent } + } + ] + }; +} + +function createMonarchLanguage(ts: TagSyntax, is: InterpolationSyntax): languages.IMonarchLanguage { + // For generating dynamic states with the ID, used for auto mode + // where we switch once we have detected the mode. + const id = `_${ts.id}_${is.id}`; + const s = (name: string): string => name.replace(/__id__/g, id); + const r = (regexp: RegExp): RegExp => { + const source = regexp.source.replace(/__id__/g, id); + return new RegExp(source, regexp.flags); + }; + + return { + // Settings + + unicode: true, + + includeLF: false, + + start: s('default__id__'), + + ignoreCase: false, + + defaultToken: 'invalid', + + tokenPostfix: `.freemarker2`, + + brackets: [ + { open: '{', close: '}', token: 'delimiter.curly' }, + { open: '[', close: ']', token: 'delimiter.square' }, + { open: '(', close: ')', token: 'delimiter.parenthesis' }, + { open: '<', close: '>', token: 'delimiter.angle' } + ], + + // Dynamic RegExp + + [s('open__id__')]: new RegExp(ts.open), + [s('close__id__')]: new RegExp(ts.close), + [s('iOpen1__id__')]: new RegExp(is.open1), + [s('iOpen2__id__')]: new RegExp(is.open2), + [s('iClose__id__')]: new RegExp(is.close), + + // <#START_TAG : "<" | "<#" | "[#"> + // <#END_TAG : " + [s('startTag__id__')]: r(/(@open__id__)(#)/), + [s('endTag__id__')]: r(/(@open__id__)(\/#)/), + [s('startOrEndTag__id__')]: r(/(@open__id__)(\/?#)/), + + // <#CLOSE_TAG1 : ()* (">" | "]")> + [s('closeTag1__id__')]: r(/((?:@blank)*)(@close__id__)/), + + // <#CLOSE_TAG2 : ()* ("/")? (">" | "]")> + [s('closeTag2__id__')]: r(/((?:@blank)*\/?)(@close__id__)/), + + // Static RegExp + + // <#BLANK : " " | "\t" | "\n" | "\r"> + blank: /[ \t\n\r]/, + + // + // + // + // + // + keywords: ['false', 'true', 'in', 'as', 'using'], + + // Directive names that cannot have an expression parameters and cannot be self-closing + // E.g. <#if id==2> ... + directiveStartCloseTag1: + /attempt|recover|sep|auto[eE]sc|no(?:autoe|AutoE)sc|compress|default|no[eE]scape|comment|no[pP]arse/, + + // Directive names that cannot have an expression parameter and can be self-closing + // E.g. <#if> ... <#else> ... + // E.g. <#if> ... <#else /> + directiveStartCloseTag2: + /else|break|continue|return|stop|flush|t|lt|rt|nt|nested|recurse|fallback|ftl/, + + // Directive names that can have an expression parameter and cannot be self-closing + // E.g. <#if id==2> ... + directiveStartBlank: + /if|else[iI]f|list|for[eE]ach|switch|case|assign|global|local|include|import|function|macro|transform|visit|stop|return|call|setting|output[fF]ormat|nested|recurse|escape|ftl|items/, + + // Directive names that can have an end tag + // E.g. + directiveEndCloseTag1: + /if|list|items|sep|recover|attempt|for[eE]ach|local|global|assign|function|macro|output[fF]ormat|auto[eE]sc|no(?:autoe|AutoE)sc|compress|transform|switch|escape|no[eE]scape/, + + // <#ESCAPED_CHAR : + // "\\" + // ( + // ("n" | "t" | "r" | "f" | "b" | "g" | "l" | "a" | "\\" | "'" | "\"" | "{" | "=") + // | + // ("x" ["0"-"9", "A"-"F", "a"-"f"]) + // ) + // > + // Note: While the JavaCC tokenizer rule only specifies one hex digit, + // FreeMarker actually interprets up to 4 hex digits. + escapedChar: /\\(?:[ntrfbgla\\'"\{=]|(?:x[0-9A-Fa-f]{1,4}))/, + + // <#ASCII_DIGIT: ["0" - "9"]> + asciiDigit: /[0-9]/, + + // + integer: /[0-9]+/, + + // <#NON_ESCAPED_ID_START_CHAR: + // [ + // // This was generated on JDK 1.8.0_20 Win64 with src/main/misc/identifierChars/IdentifierCharGenerator.java + // ... + // ] + nonEscapedIdStartChar: + /[\$@-Z_a-z\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u1FFF\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183-\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3006\u3031-\u3035\u303B-\u303C\u3040-\u318F\u31A0-\u31BA\u31F0-\u31FF\u3300-\u337F\u3400-\u4DB5\u4E00-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8D0-\uA8D9\uA8F2-\uA8F7\uA8FB\uA900-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF-\uA9D9\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA50-\uAA59\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5-\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40-\uFB41\uFB43-\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]/, + + // <#ESCAPED_ID_CHAR: "\\" ("-" | "." | ":" | "#")> + escapedIdChar: /\\[\-\.:#]/, + + // <#ID_START_CHAR: |> + idStartChar: /(?:@nonEscapedIdStartChar)|(?:@escapedIdChar)/, + + // (|)*> + id: /(?:@idStartChar)(?:(?:@idStartChar)|(?:@asciiDigit))*/, + + // Certain keywords / operators are allowed to index hashes + // + // Expression DotVariable(Expression exp) : + // { + // Token t; + // } + // { + // + // ( + // t = | t = | t = + // | + // ( + // t = + // | + // t = + // | + // t = + // | + // t = + // | + // t = + // | + // t = + // | + // t = + // | + // t = + // | + // t = + // ) + // { + // if (!Character.isLetter(t.image.charAt(0))) { + // throw new ParseException(t.image + " is not a valid identifier.", template, t); + // } + // } + // ) + // { + // notListLiteral(exp, "hash"); + // notStringLiteral(exp, "hash"); + // notBooleanLiteral(exp, "hash"); + // Dot dot = new Dot(exp, t.image); + // dot.setLocation(template, exp, t); + // return dot; + // } + // } + specialHashKeys: /\*\*|\*|false|true|in|as|using/, + + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // " | "->"> + namedSymbols: + /<=|>=|\\lte|\\lt|<|\\gte|\\gt|>|&&|\\and|->|->|==|!=|\+=|-=|\*=|\/=|%=|\+\+|--|<=|&&|\|\||:|\.\.\.|\.\.\*|\.\.<|\.\.!|\?\?|=|<|\+|-|\*|\/|%|\||\.\.|\?|!|&|\.|,|;/, + arrows: ['->', '->'], + delimiters: [';', ':', ',', '.'], + stringOperators: ['lte', 'lt', 'gte', 'gt'], + + noParseTags: ['noparse', 'noParse', 'comment'], + + tokenizer: { + // Parser states + + // Plain text + [s('default__id__')]: [ + { include: s('@directive_token__id__') }, + { include: s('@interpolation_and_text_token__id__') } + ], + + // A FreeMarker expression inside a directive, e.g. <#if 2<3> + [s('fmExpression__id__.directive')]: [ + { include: s('@blank_and_expression_comment_token__id__') }, + { include: s('@directive_end_token__id__') }, + { include: s('@expression_token__id__') } + ], + + // A FreeMarker expression inside an interpolation, e.g. ${2+3} + [s('fmExpression__id__.interpolation')]: [ + { include: s('@blank_and_expression_comment_token__id__') }, + { include: s('@expression_token__id__') }, + { include: s('@greater_operators_token__id__') } + ], + + // In an expression and inside a not-yet closed parenthesis / bracket + [s('inParen__id__.plain')]: [ + { include: s('@blank_and_expression_comment_token__id__') }, + { include: s('@directive_end_token__id__') }, + { include: s('@expression_token__id__') } + ], + [s('inParen__id__.gt')]: [ + { include: s('@blank_and_expression_comment_token__id__') }, + { include: s('@expression_token__id__') }, + { include: s('@greater_operators_token__id__') } + ], + + // Expression for the unified call, e.g. <@createMacro() ... > + [s('noSpaceExpression__id__')]: [ + { include: s('@no_space_expression_end_token__id__') }, + { include: s('@directive_end_token__id__') }, + { include: s('@expression_token__id__') } + ], + + // For the function of a unified call. Special case for when the + // expression is a simple identifier. + // <@join [1,2] ","> + // <@null!join [1,2] ","> + [s('unifiedCall__id__')]: [{ include: s('@unified_call_token__id__') }], + + // For singly and doubly quoted string (that may contain interpolations) + [s('singleString__id__')]: [{ include: s('@string_single_token__id__') }], + [s('doubleString__id__')]: [{ include: s('@string_double_token__id__') }], + + // For singly and doubly quoted string (that may not contain interpolations) + [s('rawSingleString__id__')]: [{ include: s('@string_single_raw_token__id__') }], + [s('rawDoubleString__id__')]: [{ include: s('@string_double_raw_token__id__') }], + + // For a comment in an expression + // ${ 1 + <#-- comment --> 2} + [s('expressionComment__id__')]: [{ include: s('@expression_comment_token__id__') }], + + // For <#noparse> ... + // For <#noParse> ... + // For <#comment> ... + [s('noParse__id__')]: [{ include: s('@no_parse_token__id__') }], + + // For <#-- ... --> + [s('terseComment__id__')]: [{ include: s('@terse_comment_token__id__') }], + + // Common rules + + [s('directive_token__id__')]: [ + // "attempt" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "recover" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "sep" > + // "auto" ("e"|"E") "sc" > { + // handleTagSyntaxAndSwitch(matchedToken, getTagNamingConvention(matchedToken, 4), DEFAULT); + // } + // "no" ("autoe"|"AutoE") "sc" > { + // handleTagSyntaxAndSwitch(matchedToken, getTagNamingConvention(matchedToken, 2), DEFAULT); + // } + // "compress" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "default" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "no" ("e" | "E") "scape" > { + // handleTagSyntaxAndSwitch(matchedToken, getTagNamingConvention(matchedToken, 2), DEFAULT); + // } + // + // "comment" > { + // handleTagSyntaxAndSwitch(matchedToken, NO_PARSE); noparseTag = "comment"; + // } + // "no" ("p" | "P") "arse" > { + // int tagNamingConvention = getTagNamingConvention(matchedToken, 2); + // handleTagSyntaxAndSwitch(matchedToken, tagNamingConvention, NO_PARSE); + // noparseTag = tagNamingConvention == Configuration.CAMEL_CASE_NAMING_CONVENTION ? "noParse" : "noparse"; + // } + [ + r(/(?:@startTag__id__)(@directiveStartCloseTag1)(?:@closeTag1__id__)/), + ts.id === 'auto' + ? { + cases: { + '$1==<': { token: '@rematch', switchTo: `@default_angle_${is.id}` }, + '$1==[': { token: '@rematch', switchTo: `@default_bracket_${is.id}` } + } + } + : [ + { token: '@brackets.directive' }, + { token: 'delimiter.directive' }, + { + cases: { + '@noParseTags': { token: 'tag', next: s('@noParse__id__.$3') }, + '@default': { token: 'tag' } + } + }, + { token: 'delimiter.directive' }, + { token: '@brackets.directive' } + ] + ], + + // "else" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "break" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "continue" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "return" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "stop" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "flush" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "t" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "lt" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "rt" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "nt" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "nested" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "recurse" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "fallback" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // " | "]")> { ftlHeader(matchedToken); } + [ + r(/(?:@startTag__id__)(@directiveStartCloseTag2)(?:@closeTag2__id__)/), + ts.id === 'auto' + ? { + cases: { + '$1==<': { token: '@rematch', switchTo: `@default_angle_${is.id}` }, + '$1==[': { token: '@rematch', switchTo: `@default_bracket_${is.id}` } + } + } + : [ + { token: '@brackets.directive' }, + { token: 'delimiter.directive' }, + { token: 'tag' }, + { token: 'delimiter.directive' }, + { token: '@brackets.directive' } + ] + ], + + // "if" > { handleTagSyntaxAndSwitch(matchedToken, FM_EXPRESSION); } + // "else" ("i" | "I") "f" > { + // handleTagSyntaxAndSwitch(matchedToken, getTagNamingConvention(matchedToken, 4), FM_EXPRESSION); + // } + // "list" > { handleTagSyntaxAndSwitch(matchedToken, FM_EXPRESSION); } + // "for" ("e" | "E") "ach" > { + // handleTagSyntaxAndSwitch(matchedToken, getTagNamingConvention(matchedToken, 3), FM_EXPRESSION); + // } + // "switch" > { handleTagSyntaxAndSwitch(matchedToken, FM_EXPRESSION); } + // "case" > { handleTagSyntaxAndSwitch(matchedToken, FM_EXPRESSION); } + // "assign" > { handleTagSyntaxAndSwitch(matchedToken, FM_EXPRESSION); } + // "global" > { handleTagSyntaxAndSwitch(matchedToken, FM_EXPRESSION); } + // "local" > { handleTagSyntaxAndSwitch(matchedToken, FM_EXPRESSION); } + // <_INCLUDE : "include" > { handleTagSyntaxAndSwitch(matchedToken, FM_EXPRESSION); } + // "import" > { handleTagSyntaxAndSwitch(matchedToken, FM_EXPRESSION); } + // "function" > { handleTagSyntaxAndSwitch(matchedToken, FM_EXPRESSION); } + // "macro" > { handleTagSyntaxAndSwitch(matchedToken, FM_EXPRESSION); } + // "transform" > { handleTagSyntaxAndSwitch(matchedToken, FM_EXPRESSION); } + // "visit" > { handleTagSyntaxAndSwitch(matchedToken, FM_EXPRESSION); } + // "stop" > { handleTagSyntaxAndSwitch(matchedToken, FM_EXPRESSION); } + // "return" > { handleTagSyntaxAndSwitch(matchedToken, FM_EXPRESSION); } + // "call" > { handleTagSyntaxAndSwitch(matchedToken, FM_EXPRESSION); } + // "setting" > { handleTagSyntaxAndSwitch(matchedToken, FM_EXPRESSION); } + // "output" ("f"|"F") "ormat" > { + // handleTagSyntaxAndSwitch(matchedToken, getTagNamingConvention(matchedToken, 6), FM_EXPRESSION); + // } + // "nested" > { handleTagSyntaxAndSwitch(matchedToken, FM_EXPRESSION); } + // "recurse" > { handleTagSyntaxAndSwitch(matchedToken, FM_EXPRESSION); } + // "escape" > { handleTagSyntaxAndSwitch(matchedToken, FM_EXPRESSION); } + // + // Note: FreeMarker grammar appears to treat the FTL header as a special case, + // in order to remove new lines after the header (?), but since we only need + // to tokenize for highlighting, we can include this directive here. + // > { ftlHeader(matchedToken); } + // + // Note: FreeMarker grammar appears to treat the items directive as a special case for + // the AST parsing process, but since we only need to tokenize, we can include this + // directive here. + // "items" ()+ > { handleTagSyntaxAndSwitch(matchedToken, FM_EXPRESSION); } + [ + r(/(?:@startTag__id__)(@directiveStartBlank)(@blank)/), + ts.id === 'auto' + ? { + cases: { + '$1==<': { token: '@rematch', switchTo: `@default_angle_${is.id}` }, + '$1==[': { token: '@rematch', switchTo: `@default_bracket_${is.id}` } + } + } + : [ + { token: '@brackets.directive' }, + { token: 'delimiter.directive' }, + { token: 'tag' }, + { token: '', next: s('@fmExpression__id__.directive') } + ] + ], + + // "if" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "list" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "sep" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "recover" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "attempt" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "for" ("e" | "E") "ach" > { + // handleTagSyntaxAndSwitch(matchedToken, getTagNamingConvention(matchedToken, 3), DEFAULT); + // } + // "local" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "global" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "assign" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "function" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "macro" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "output" ("f" | "F") "ormat" > { + // handleTagSyntaxAndSwitch(matchedToken, getTagNamingConvention(matchedToken, 6), DEFAULT); + // } + // "auto" ("e" | "E") "sc" > { + // handleTagSyntaxAndSwitch(matchedToken, getTagNamingConvention(matchedToken, 4), DEFAULT); + // } + // "no" ("autoe"|"AutoE") "sc" > { + // handleTagSyntaxAndSwitch(matchedToken, getTagNamingConvention(matchedToken, 2), DEFAULT); + // } + // "compress" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "transform" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "switch" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "escape" > { handleTagSyntaxAndSwitch(matchedToken, DEFAULT); } + // "no" ("e" | "E") "scape" > { + // handleTagSyntaxAndSwitch(matchedToken, getTagNamingConvention(matchedToken, 2), DEFAULT); + // } + [ + r(/(?:@endTag__id__)(@directiveEndCloseTag1)(?:@closeTag1__id__)/), + ts.id === 'auto' + ? { + cases: { + '$1==<': { token: '@rematch', switchTo: `@default_angle_${is.id}` }, + '$1==[': { token: '@rematch', switchTo: `@default_bracket_${is.id}` } + } + } + : [ + { token: '@brackets.directive' }, + { token: 'delimiter.directive' }, + { token: 'tag' }, + { token: 'delimiter.directive' }, + { token: '@brackets.directive' } + ] + ], + + // { unifiedCall(matchedToken); } + [ + r(/(@open__id__)(@)/), + ts.id === 'auto' + ? { + cases: { + '$1==<': { token: '@rematch', switchTo: `@default_angle_${is.id}` }, + '$1==[': { token: '@rematch', switchTo: `@default_bracket_${is.id}` } + } + } + : [ + { token: '@brackets.directive' }, + { token: 'delimiter.directive', next: s('@unifiedCall__id__') } + ] + ], + + // ) (".")*)? > { unifiedCallEnd(matchedToken); } + [ + r(/(@open__id__)(\/@)((?:(?:@id)(?:\.(?:@id))*)?)(?:@closeTag1__id__)/), + [ + { token: '@brackets.directive' }, + { token: 'delimiter.directive' }, + { token: 'tag' }, + { token: 'delimiter.directive' }, + { token: '@brackets.directive' } + ] + ], + + // { noparseTag = "-->"; handleTagSyntaxAndSwitch(matchedToken, NO_PARSE); } + [ + r(/(@open__id__)#--/), + ts.id === 'auto' + ? { + cases: { + '$1==<': { token: '@rematch', switchTo: `@default_angle_${is.id}` }, + '$1==[': { token: '@rematch', switchTo: `@default_bracket_${is.id}` } + } + } + : { token: 'comment', next: s('@terseComment__id__') } + ], + + // + [ + r(/(?:@startOrEndTag__id__)([a-zA-Z_]+)/), + ts.id === 'auto' + ? { + cases: { + '$1==<': { token: '@rematch', switchTo: `@default_angle_${is.id}` }, + '$1==[': { token: '@rematch', switchTo: `@default_bracket_${is.id}` } + } + } + : [ + { token: '@brackets.directive' }, + { token: 'delimiter.directive' }, + { token: 'tag.invalid', next: s('@fmExpression__id__.directive') } + ] + ] + ], + + // TOKEN : + [s('interpolation_and_text_token__id__')]: [ + // { startInterpolation(matchedToken); } + // // to handle a lone dollar sign or "<" or "# or <@ with whitespace after" + // + // + [/[\$#<\[\{]|(?:@blank)+|[^\$<#\[\{\n\r\t ]+/, { token: 'source' }] + ], + + // )* + // "\"" + // ) + // | + // ( + // "'" + // ((~["'", "\\"]) | )* + // "'" + // ) + // > + [s('string_single_token__id__')]: [ + [/[^'\\]/, { token: 'string' }], + [/@escapedChar/, { token: 'string.escape' }], + [/'/, { token: 'string', next: '@pop' }] + ], + [s('string_double_token__id__')]: [ + [/[^"\\]/, { token: 'string' }], + [/@escapedChar/, { token: 'string.escape' }], + [/"/, { token: 'string', next: '@pop' }] + ], + + // + [s('string_single_raw_token__id__')]: [ + [/[^']+/, { token: 'string.raw' }], + [/'/, { token: 'string.raw', next: '@pop' }] + ], + [s('string_double_raw_token__id__')]: [ + [/[^"]+/, { token: 'string.raw' }], + [/"/, { token: 'string.raw', next: '@pop' }] + ], + + // TOKEN : + [s('expression_token__id__')]: [ + // Strings + [ + /(r?)(['"])/, + { + cases: { + "r'": [ + { token: 'keyword' }, + { token: 'string.raw', next: s('@rawSingleString__id__') } + ], + 'r"': [ + { token: 'keyword' }, + { token: 'string.raw', next: s('@rawDoubleString__id__') } + ], + "'": [{ token: 'source' }, { token: 'string', next: s('@singleString__id__') }], + '"': [{ token: 'source' }, { token: 'string', next: s('@doubleString__id__') }] + } + } + ], + + // Numbers + // + // "." > + [ + /(?:@integer)(?:\.(?:@integer))?/, + { + cases: { + '(?:@integer)': { token: 'number' }, + '@default': { token: 'number.float' } + } + } + ], + + // Special hash keys that must not be treated as identifiers + // after a period, e.g. a.** is accessing the key "**" of a + [ + /(\.)(@blank*)(@specialHashKeys)/, + [{ token: 'delimiter' }, { token: '' }, { token: 'identifier' }] + ], + + // Symbols / operators + [ + /(?:@namedSymbols)/, + { + cases: { + '@arrows': { token: 'meta.arrow' }, + '@delimiters': { token: 'delimiter' }, + '@default': { token: 'operators' } + } + } + ], + + // Identifiers + [ + /@id/, + { + cases: { + '@keywords': { token: 'keyword.$0' }, + '@stringOperators': { token: 'operators' }, + '@default': { token: 'identifier' } + } + } + ], + + // + // + // + // + // + // + [ + /[\[\]\(\)\{\}]/, + { + cases: { + '\\[': { + cases: { + '$S2==gt': { token: '@brackets', next: s('@inParen__id__.gt') }, + '@default': { token: '@brackets', next: s('@inParen__id__.plain') } + } + }, + '\\]': { + cases: { + ...(is.id === 'bracket' + ? { + '$S2==interpolation': { token: '@brackets.interpolation', next: '@popall' } + } + : {}), + // This cannot happen while in auto mode, since this applies only to an + // fmExpression inside a directive. But once we encounter the start of a + // directive, we can establish the tag syntax mode. + ...(ts.id === 'bracket' + ? { + '$S2==directive': { token: '@brackets.directive', next: '@popall' } + } + : {}), + // Ignore mismatched paren + [s('$S1==inParen__id__')]: { token: '@brackets', next: '@pop' }, + '@default': { token: '@brackets' } + } + }, + '\\(': { token: '@brackets', next: s('@inParen__id__.gt') }, + '\\)': { + cases: { + [s('$S1==inParen__id__')]: { token: '@brackets', next: '@pop' }, + '@default': { token: '@brackets' } + } + }, + '\\{': { + cases: { + '$S2==gt': { token: '@brackets', next: s('@inParen__id__.gt') }, + '@default': { token: '@brackets', next: s('@inParen__id__.plain') } + } + }, + '\\}': { + cases: { + ...(is.id === 'bracket' + ? {} + : { + '$S2==interpolation': { token: '@brackets.interpolation', next: '@popall' } + }), + // Ignore mismatched paren + [s('$S1==inParen__id__')]: { token: '@brackets', next: '@pop' }, + '@default': { token: '@brackets' } + } + } + } + } + ], + + // + [/(?:@blank)+/, { token: '' }], + + // < ("<" | "[") ("#" | "!") "--"> : EXPRESSION_COMMENT + [/[<\[][#!]--/, { token: 'comment', next: s('@expressionComment__id__') }] + ], + + // TOKEN : + [s('directive_end_token__id__')]: [ + // "> + // { + // if (inFTLHeader) { + // eatNewline(); + // inFTLHeader = false; + // } + // if (squBracTagSyntax || postInterpolationLexState != -1 /* We are in an interpolation */) { + // matchedToken.kind = NATURAL_GT; + // } else { + // SwitchTo(DEFAULT); + // } + // } + // This cannot happen while in auto mode, since this applies only to an + // fmExpression inside a directive. But once we encounter the start of a + // directive, we can establish the tag syntax mode. + [ + />/, + ts.id === 'bracket' + ? { token: 'operators' } + : { token: '@brackets.directive', next: '@popall' } + ], + + // " | "/]"> + // It is a syntax error to end a tag with the wrong close token + // Let's indicate that to the user by not closing the tag + [ + r(/(\/)(@close__id__)/), + [{ token: 'delimiter.directive' }, { token: '@brackets.directive', next: '@popall' }] + ] + ], + + // TOKEN : + [s('greater_operators_token__id__')]: [ + // "> + [/>/, { token: 'operators' }], + + // ="> + [/>=/, { token: 'operators' }] + ], + + // TOKEN : + [s('no_space_expression_end_token__id__')]: [ + // : FM_EXPRESSION + [/(?:@blank)+/, { token: '', switchTo: s('@fmExpression__id__.directive') }] + ], + + [s('unified_call_token__id__')]: [ + // Special case for a call where the expression is just an ID + // + + [ + /(@id)((?:@blank)+)/, + [{ token: 'tag' }, { token: '', next: s('@fmExpression__id__.directive') }] + ], + [ + r(/(@id)(\/?)(@close__id__)/), + [ + { token: 'tag' }, + { token: 'delimiter.directive' }, + { token: '@brackets.directive', next: '@popall' } + ] + ], + [/./, { token: '@rematch', next: s('@noSpaceExpression__id__') }] + ], + + // TOKEN : + [s('no_parse_token__id__')]: [ + // " | "]") + // > + [ + r(/(@open__id__)(\/#?)([a-zA-Z]+)((?:@blank)*)(@close__id__)/), + { + cases: { + '$S2==$3': [ + { token: '@brackets.directive' }, + { token: 'delimiter.directive' }, + { token: 'tag' }, + { token: '' }, + { token: '@brackets.directive', next: '@popall' } + ], + '$S2==comment': [ + { token: 'comment' }, + { token: 'comment' }, + { token: 'comment' }, + { token: 'comment' }, + { token: 'comment' } + ], + '@default': [ + { token: 'source' }, + { token: 'source' }, + { token: 'source' }, + { token: 'source' }, + { token: 'source' } + ] + } + } + ], + + // + // + [ + /[^<\[\-]+|[<\[\-]/, + { + cases: { + '$S2==comment': { token: 'comment' }, + '@default': { token: 'source' } + } + } + ] + ], + + // SKIP: + [s('expression_comment_token__id__')]: [ + // < "-->" | "--]"> + [ + /--[>\]]/, + { + token: 'comment', + next: '@pop' + } + ], + + // < (~["-", ">", "]"])+ > + // < ">"> + // < "]"> + // < "-"> + [/[^\->\]]+|[>\]\-]/, { token: 'comment' }] + ], + + [s('terse_comment_token__id__')]: [ + // " | "--]"> + [r(/--(?:@close__id__)/), { token: 'comment', next: '@popall' }], + + // + // + [/[^<\[\-]+|[<\[\-]/, { token: 'comment' }] + ] + } + }; +} + +function createMonarchLanguageAuto(is: InterpolationSyntax): languages.IMonarchLanguage { + const angle = createMonarchLanguage(TagSyntaxAngle, is); + const bracket = createMonarchLanguage(TagSyntaxBracket, is); + const auto = createMonarchLanguage(TagSyntaxAuto, is); + + return { + // Angle and bracket syntax mode + // We switch to one of these once we have determined the mode + ...angle, + ...bracket, + ...auto, + + // Settings + + unicode: true, + + includeLF: false, + + start: `default_auto_${is.id}`, + + ignoreCase: false, + + defaultToken: 'invalid', + + tokenPostfix: `.freemarker2`, + + brackets: [ + { open: '{', close: '}', token: 'delimiter.curly' }, + { open: '[', close: ']', token: 'delimiter.square' }, + { open: '(', close: ')', token: 'delimiter.parenthesis' }, + { open: '<', close: '>', token: 'delimiter.angle' } + ], + + tokenizer: { + ...angle.tokenizer, + ...bracket.tokenizer, + ...auto.tokenizer + } + }; +} + +export const TagAngleInterpolationDollar = { + conf: createLangConfiguration(TagSyntaxAngle), + language: createMonarchLanguage(TagSyntaxAngle, InterpolationSyntaxDollar) +}; + +export const TagBracketInterpolationDollar = { + conf: createLangConfiguration(TagSyntaxBracket), + language: createMonarchLanguage(TagSyntaxBracket, InterpolationSyntaxDollar) +}; + +export const TagAngleInterpolationBracket = { + conf: createLangConfiguration(TagSyntaxAngle), + language: createMonarchLanguage(TagSyntaxAngle, InterpolationSyntaxBracket) +}; + +export const TagBracketInterpolationBracket = { + conf: createLangConfiguration(TagSyntaxBracket), + language: createMonarchLanguage(TagSyntaxBracket, InterpolationSyntaxBracket) +}; + +export const TagAutoInterpolationDollar = { + conf: createLangConfigurationAuto(), + language: createMonarchLanguageAuto(InterpolationSyntaxDollar) +}; + +export const TagAutoInterpolationBracket = { + conf: createLangConfigurationAuto(), + language: createMonarchLanguageAuto(InterpolationSyntaxBracket) +}; diff --git a/src/basic-languages/monaco.contribution.ts b/src/basic-languages/monaco.contribution.ts index f059eec5..56b078c1 100644 --- a/src/basic-languages/monaco.contribution.ts +++ b/src/basic-languages/monaco.contribution.ts @@ -21,6 +21,7 @@ import './ecl/ecl.contribution'; import './elixir/elixir.contribution'; import './flow9/flow9.contribution'; import './fsharp/fsharp.contribution'; +import './freemarker2/freemarker2.contribution'; import './go/go.contribution'; import './graphql/graphql.contribution'; import './handlebars/handlebars.contribution'; diff --git a/website/index/samples/sample.freemarker2.tag-angle.interpolation-bracket.txt b/website/index/samples/sample.freemarker2.tag-angle.interpolation-bracket.txt new file mode 100644 index 00000000..190a25f8 --- /dev/null +++ b/website/index/samples/sample.freemarker2.tag-angle.interpolation-bracket.txt @@ -0,0 +1,61 @@ +<#ftl stripText=false> + +<#-- Free marker demo --> + +<#comment> +This demonstrates the FreeMarker language. The default theme is not very +colorful and displays many different token types in the same color, but keep in +mind that you can define your own theme (or extend an existing one). + +Note that free marker actually defines 6 similar but different syntax modes: + +- 3 tag syntax modes: Angle (<#if>), Bracket ([#if]), and Auto. +- 2 interpolation modes: Dollar (${...}) and Bracket ([=...]) + +In auto mode, the first tag determines the tag syntax. You can use the language +IDs "freemarker.tag-bracket.interpolation-dollar" etc. to force a specific mode. + +The default FreeMarker mode is Angle/Dollar. + + +<#macro greet name> + Hello [=name]! + + +<#macro border> +
+ <#nested> +
+ + +<#function avg x y> + <#return (x + y) / 2> + + +<#assign user = "Juila Smith"> +<#assign animals = [{"name": "Tanuki", "price": 200}, {"name": "Phoenix", "price": 1111}]> + + + + Welcome! + + + <#-- Greet the user with his/her name --> +

+ <@greet user /> +

+ +

We have these animals: + +

    + <#list animals as animal> +
  • [=animal.name] for [=animal.price] Euros + +
+ + <@border>The bordered text + + The average of 35 and 49 is [=avg(35, 49)]. + + + diff --git a/website/index/samples/sample.freemarker2.tag-angle.interpolation-dollar.txt b/website/index/samples/sample.freemarker2.tag-angle.interpolation-dollar.txt new file mode 100644 index 00000000..c70f1074 --- /dev/null +++ b/website/index/samples/sample.freemarker2.tag-angle.interpolation-dollar.txt @@ -0,0 +1,61 @@ +<#ftl stripText=false> + +<#-- Free marker demo --> + +<#comment> +This demonstrates the FreeMarker language. The default theme is not very +colorful and displays many different token types in the same color, but keep in +mind that you can define your own theme (or extend an existing one). + +Note that free marker actually defines 6 similar but different syntax modes: + +- 3 tag syntax modes: Angle (<#if>), Bracket ([#if]), and Auto. +- 2 interpolation modes: Dollar (${...}) and Bracket ([=...]) + +In auto mode, the first tag determines the tag syntax. You can use the language +IDs "freemarker.tag-bracket.interpolation-dollar" etc. to force a specific mode. + +The default FreeMarker mode is Angle/Dollar. + + +<#macro greet name> + Hello ${name}! + + +<#macro border> +
+ <#nested> +
+ + +<#function avg x y> + <#return (x + y) / 2> + + +<#assign user = "Juila Smith"> +<#assign animals = [{"name": "Tanuki", "price": 200}, {"name": "Phoenix", "price": 1111}]> + + + + Welcome! + + + <#-- Greet the user with his/her name --> +

+ <@greet user /> +

+ +

We have these animals: + +

    + <#list animals as animal> +
  • ${animal.name} for ${animal.price} Euros + +
+ + <@border>The bordered text + + The average of 35 and 49 is ${avg(35, 49)}. + + + diff --git a/website/index/samples/sample.freemarker2.tag-auto.interpolation-bracket.txt b/website/index/samples/sample.freemarker2.tag-auto.interpolation-bracket.txt new file mode 100644 index 00000000..833bb857 --- /dev/null +++ b/website/index/samples/sample.freemarker2.tag-auto.interpolation-bracket.txt @@ -0,0 +1,65 @@ +Auto mode detect the tag syntax mode automatically. +Try exchanging the order of the next two lines and see what happens! + +[#ftl stripText=false] +<#ftl stripText=false> + +<#-- Free marker demo --> + +<#comment> +This demonstrates the FreeMarker language. The default theme is not very +colorful and displays many different token types in the same color, but keep in +mind that you can define your own theme (or extend an existing one). + +Note that free marker actually defines 6 similar but different syntax modes: + +- 3 tag syntax modes: Angle (<#if>), Bracket ([#if]), and Auto. +- 2 interpolation modes: Dollar (${...}) and Bracket ([=...]) + +In auto mode, the first tag determines the tag syntax. You can use the language +IDs "freemarker.tag-bracket.interpolation-dollar" etc. to force a specific mode. + +The default FreeMarker mode is Angle/Dollar. + + +<#macro greet name> + Hello [=name]! + + +<#macro border> +
+ <#nested> +
+ + +<#function avg x y> + <#return (x + y) / 2> + + +<#assign user = "Juila Smith"> +<#assign animals = [{"name": "Tanuki", "price": 200}, {"name": "Phoenix", "price": 1111}]> + + + + Welcome! + + + <#-- Greet the user with his/her name --> +

+ <@greet user /> +

+ +

We have these animals: + +

    + <#list animals as animal> +
  • [=animal.name] for [=animal.price] Euros + +
+ + <@border>The bordered text + + The average of 35 and 49 is [=avg(35, 49)]. + + + diff --git a/website/index/samples/sample.freemarker2.tag-auto.interpolation-dollar.txt b/website/index/samples/sample.freemarker2.tag-auto.interpolation-dollar.txt new file mode 100644 index 00000000..78e66813 --- /dev/null +++ b/website/index/samples/sample.freemarker2.tag-auto.interpolation-dollar.txt @@ -0,0 +1,65 @@ +Auto mode detect the tag syntax mode automatically. +Try exchanging the order of the next two lines and see what happens! + +<#ftl stripText=false> +[#ftl stripText=false] + +<#-- Free marker demo --> + +<#comment> +This demonstrates the FreeMarker language. The default theme is not very +colorful and displays many different token types in the same color, but keep in +mind that you can define your own theme (or extend an existing one). + +Note that free marker actually defines 6 similar but different syntax modes: + +- 3 tag syntax modes: Angle (<#if>), Bracket ([#if]), and Auto. +- 2 interpolation modes: Dollar (${...}) and Bracket ([=...]) + +In auto mode, the first tag determines the tag syntax. You can use the language +IDs "freemarker.tag-bracket.interpolation-dollar" etc. to force a specific mode. + +The default FreeMarker mode is Angle/Dollar. + + +<#macro greet name> + Hello ${name}! + + +<#macro border> +
+ <#nested> +
+ + +<#function avg x y> + <#return (x + y) / 2> + + +<#assign user = "Juila Smith"> +<#assign animals = [{"name": "Tanuki", "price": 200}, {"name": "Phoenix", "price": 1111}]> + + + + Welcome! + + + <#-- Greet the user with his/her name --> +

+ <@greet user /> +

+ +

We have these animals: + +

    + <#list animals as animal> +
  • ${animal.name} for ${animal.price} Euros + +
+ + <@border>The bordered text + + The average of 35 and 49 is ${avg(35, 49)}. + + + diff --git a/website/index/samples/sample.freemarker2.tag-bracket.interpolation-bracket.txt b/website/index/samples/sample.freemarker2.tag-bracket.interpolation-bracket.txt new file mode 100644 index 00000000..c518fd9e --- /dev/null +++ b/website/index/samples/sample.freemarker2.tag-bracket.interpolation-bracket.txt @@ -0,0 +1,61 @@ +[#ftl stripText=false] + +[#-- Free marker demo --] + +[#comment] +This demonstrates the FreeMarker language. The default theme is not very +colorful and displays many different token types in the same color, but keep in +mind that you can define your own theme (or extend an existing one). + +Note that free marker actually defines 6 similar but different syntax modes: + +- 3 tag syntax modes: Angle (<#if>), Bracket ([#if]), and Auto. +- 2 interpolation modes: Dollar (${...}) and Bracket ([=...]) + +In auto mode, the first tag determines the tag syntax. You can use the language +IDs "freemarker.tag-bracket.interpolation-dollar" etc. to force a specific mode. + +The default FreeMarker mode is Angle/Dollar. +[/#comment] + +[#macro greet name] + Hello [=name]! +[/#macro[ + +[#macro border] +
+ [#nested] +
+[/#macro] + +[#function avg x y] + [#return (x + y) / 2] +[/#function] + +[#assign user = "Juila Smith"] +[#assign animals = [{"name": "Tanuki", "price": 200}, {"name": "Phoenix", "price": 1111}]] + + + + Welcome! + + + [#-- Greet the user with his/her name --] +

+ <@greet user /> +

+ +

We have these animals: + +

    + [#list animals as animal] +
  • [=animal.name] for [=animal.price] Euros + [/#list][ +
+ + <@border>The bordered text + + The average of 35 and 49 is [=avg(35, 49]}. + + + diff --git a/website/index/samples/sample.freemarker2.tag-bracket.interpolation-dollar.txt b/website/index/samples/sample.freemarker2.tag-bracket.interpolation-dollar.txt new file mode 100644 index 00000000..2df2a92e --- /dev/null +++ b/website/index/samples/sample.freemarker2.tag-bracket.interpolation-dollar.txt @@ -0,0 +1,61 @@ +[#ftl stripText=false] + +[#-- Free marker demo --] + +[#comment] +This demonstrates the FreeMarker language. The default theme is not very +colorful and displays many different token types in the same color, but keep in +mind that you can define your own theme (or extend an existing one). + +Note that free marker actually defines 6 similar but different syntax modes: + +- 3 tag syntax modes: Angle (<#if>), Bracket ([#if]), and Auto. +- 2 interpolation modes: Dollar (${...}) and Bracket ([=...]) + +In auto mode, the first tag determines the tag syntax. You can use the language +IDs "freemarker.tag-bracket.interpolation-dollar" etc. to force a specific mode. + +The default FreeMarker mode is Angle/Dollar. +[/#comment] + +[#macro greet name] + Hello ${name}! +[/#macro[ + +[#macro border] +
+ [#nested] +
+[/#macro] + +[#function avg x y] + [#return (x + y) / 2] +[/#function] + +[#assign user = "Juila Smith"] +[#assign animals = [{"name": "Tanuki", "price": 200}, {"name": "Phoenix", "price": 1111}]] + + + + Welcome! + + + [#-- Greet the user with his/her name --] +

+ <@greet user /> +

+ +

We have these animals: + +

    + [#list animals as animal] +
  • ${animal.name} for ${animal.price} Euros + [/#list][ +
+ + <@border>The bordered text + + The average of 35 and 49 is ${avg(35, 49)}. + + + diff --git a/website/index/samples/sample.freemarker2.txt b/website/index/samples/sample.freemarker2.txt new file mode 100644 index 00000000..c70f1074 --- /dev/null +++ b/website/index/samples/sample.freemarker2.txt @@ -0,0 +1,61 @@ +<#ftl stripText=false> + +<#-- Free marker demo --> + +<#comment> +This demonstrates the FreeMarker language. The default theme is not very +colorful and displays many different token types in the same color, but keep in +mind that you can define your own theme (or extend an existing one). + +Note that free marker actually defines 6 similar but different syntax modes: + +- 3 tag syntax modes: Angle (<#if>), Bracket ([#if]), and Auto. +- 2 interpolation modes: Dollar (${...}) and Bracket ([=...]) + +In auto mode, the first tag determines the tag syntax. You can use the language +IDs "freemarker.tag-bracket.interpolation-dollar" etc. to force a specific mode. + +The default FreeMarker mode is Angle/Dollar. + + +<#macro greet name> + Hello ${name}! + + +<#macro border> +
+ <#nested> +
+ + +<#function avg x y> + <#return (x + y) / 2> + + +<#assign user = "Juila Smith"> +<#assign animals = [{"name": "Tanuki", "price": 200}, {"name": "Phoenix", "price": 1111}]> + + + + Welcome! + + + <#-- Greet the user with his/her name --> +

+ <@greet user /> +

+ +

We have these animals: + +

    + <#list animals as animal> +
  • ${animal.name} for ${animal.price} Euros + +
+ + <@border>The bordered text + + The average of 35 and 49 is ${avg(35, 49)}. + + +