comparison .cms/lib/codemirror/mode/velocity/velocity.js @ 0:78edf6b517a0 draft

24.10
author Coffee CMS <info@coffee-cms.ru>
date Fri, 11 Oct 2024 22:40:23 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:78edf6b517a0
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: https://codemirror.net/5/LICENSE
3
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
6 mod(require("../../lib/codemirror"));
7 else if (typeof define == "function" && define.amd) // AMD
8 define(["../../lib/codemirror"], mod);
9 else // Plain browser env
10 mod(CodeMirror);
11 })(function(CodeMirror) {
12 "use strict";
13
14 CodeMirror.defineMode("velocity", function() {
15 function parseWords(str) {
16 var obj = {}, words = str.split(" ");
17 for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
18 return obj;
19 }
20
21 var keywords = parseWords("#end #else #break #stop #[[ #]] " +
22 "#{end} #{else} #{break} #{stop}");
23 var functions = parseWords("#if #elseif #foreach #set #include #parse #macro #define #evaluate " +
24 "#{if} #{elseif} #{foreach} #{set} #{include} #{parse} #{macro} #{define} #{evaluate}");
25 var specials = parseWords("$foreach.count $foreach.hasNext $foreach.first $foreach.last $foreach.topmost $foreach.parent.count $foreach.parent.hasNext $foreach.parent.first $foreach.parent.last $foreach.parent $velocityCount $!bodyContent $bodyContent");
26 var isOperatorChar = /[+\-*&%=<>!?:\/|]/;
27
28 function chain(stream, state, f) {
29 state.tokenize = f;
30 return f(stream, state);
31 }
32 function tokenBase(stream, state) {
33 var beforeParams = state.beforeParams;
34 state.beforeParams = false;
35 var ch = stream.next();
36 // start of unparsed string?
37 if ((ch == "'") && !state.inString && state.inParams) {
38 state.lastTokenWasBuiltin = false;
39 return chain(stream, state, tokenString(ch));
40 }
41 // start of parsed string?
42 else if ((ch == '"')) {
43 state.lastTokenWasBuiltin = false;
44 if (state.inString) {
45 state.inString = false;
46 return "string";
47 }
48 else if (state.inParams)
49 return chain(stream, state, tokenString(ch));
50 }
51 // is it one of the special signs []{}().,;? Separator?
52 else if (/[\[\]{}\(\),;\.]/.test(ch)) {
53 if (ch == "(" && beforeParams)
54 state.inParams = true;
55 else if (ch == ")") {
56 state.inParams = false;
57 state.lastTokenWasBuiltin = true;
58 }
59 return null;
60 }
61 // start of a number value?
62 else if (/\d/.test(ch)) {
63 state.lastTokenWasBuiltin = false;
64 stream.eatWhile(/[\w\.]/);
65 return "number";
66 }
67 // multi line comment?
68 else if (ch == "#" && stream.eat("*")) {
69 state.lastTokenWasBuiltin = false;
70 return chain(stream, state, tokenComment);
71 }
72 // unparsed content?
73 else if (ch == "#" && stream.match(/ *\[ *\[/)) {
74 state.lastTokenWasBuiltin = false;
75 return chain(stream, state, tokenUnparsed);
76 }
77 // single line comment?
78 else if (ch == "#" && stream.eat("#")) {
79 state.lastTokenWasBuiltin = false;
80 stream.skipToEnd();
81 return "comment";
82 }
83 // variable?
84 else if (ch == "$") {
85 stream.eat("!");
86 stream.eatWhile(/[\w\d\$_\.{}-]/);
87 // is it one of the specials?
88 if (specials && specials.propertyIsEnumerable(stream.current())) {
89 return "keyword";
90 }
91 else {
92 state.lastTokenWasBuiltin = true;
93 state.beforeParams = true;
94 return "builtin";
95 }
96 }
97 // is it a operator?
98 else if (isOperatorChar.test(ch)) {
99 state.lastTokenWasBuiltin = false;
100 stream.eatWhile(isOperatorChar);
101 return "operator";
102 }
103 else {
104 // get the whole word
105 stream.eatWhile(/[\w\$_{}@]/);
106 var word = stream.current();
107 // is it one of the listed keywords?
108 if (keywords && keywords.propertyIsEnumerable(word))
109 return "keyword";
110 // is it one of the listed functions?
111 if (functions && functions.propertyIsEnumerable(word) ||
112 (stream.current().match(/^#@?[a-z0-9_]+ *$/i) && stream.peek()=="(") &&
113 !(functions && functions.propertyIsEnumerable(word.toLowerCase()))) {
114 state.beforeParams = true;
115 state.lastTokenWasBuiltin = false;
116 return "keyword";
117 }
118 if (state.inString) {
119 state.lastTokenWasBuiltin = false;
120 return "string";
121 }
122 if (stream.pos > word.length && stream.string.charAt(stream.pos-word.length-1)=="." && state.lastTokenWasBuiltin)
123 return "builtin";
124 // default: just a "word"
125 state.lastTokenWasBuiltin = false;
126 return null;
127 }
128 }
129
130 function tokenString(quote) {
131 return function(stream, state) {
132 var escaped = false, next, end = false;
133 while ((next = stream.next()) != null) {
134 if ((next == quote) && !escaped) {
135 end = true;
136 break;
137 }
138 if (quote=='"' && stream.peek() == '$' && !escaped) {
139 state.inString = true;
140 end = true;
141 break;
142 }
143 escaped = !escaped && next == "\\";
144 }
145 if (end) state.tokenize = tokenBase;
146 return "string";
147 };
148 }
149
150 function tokenComment(stream, state) {
151 var maybeEnd = false, ch;
152 while (ch = stream.next()) {
153 if (ch == "#" && maybeEnd) {
154 state.tokenize = tokenBase;
155 break;
156 }
157 maybeEnd = (ch == "*");
158 }
159 return "comment";
160 }
161
162 function tokenUnparsed(stream, state) {
163 var maybeEnd = 0, ch;
164 while (ch = stream.next()) {
165 if (ch == "#" && maybeEnd == 2) {
166 state.tokenize = tokenBase;
167 break;
168 }
169 if (ch == "]")
170 maybeEnd++;
171 else if (ch != " ")
172 maybeEnd = 0;
173 }
174 return "meta";
175 }
176 // Interface
177
178 return {
179 startState: function() {
180 return {
181 tokenize: tokenBase,
182 beforeParams: false,
183 inParams: false,
184 inString: false,
185 lastTokenWasBuiltin: false
186 };
187 },
188
189 token: function(stream, state) {
190 if (stream.eatSpace()) return null;
191 return state.tokenize(stream, state);
192 },
193 blockCommentStart: "#*",
194 blockCommentEnd: "*#",
195 lineComment: "##",
196 fold: "velocity"
197 };
198 });
199
200 CodeMirror.defineMIME("text/velocity", "velocity");
201
202 });