Mercurial
comparison .cms/lib/codemirror/mode/smarty/smarty.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 /** | |
5 * Smarty 2 and 3 mode. | |
6 */ | |
7 | |
8 (function(mod) { | |
9 if (typeof exports == "object" && typeof module == "object") // CommonJS | |
10 mod(require("../../lib/codemirror")); | |
11 else if (typeof define == "function" && define.amd) // AMD | |
12 define(["../../lib/codemirror"], mod); | |
13 else // Plain browser env | |
14 mod(CodeMirror); | |
15 })(function(CodeMirror) { | |
16 "use strict"; | |
17 | |
18 CodeMirror.defineMode("smarty", function(config, parserConf) { | |
19 var rightDelimiter = parserConf.rightDelimiter || "}"; | |
20 var leftDelimiter = parserConf.leftDelimiter || "{"; | |
21 var version = parserConf.version || 2; | |
22 var baseMode = CodeMirror.getMode(config, parserConf.baseMode || "null"); | |
23 | |
24 var keyFunctions = ["debug", "extends", "function", "include", "literal"]; | |
25 var regs = { | |
26 operatorChars: /[+\-*&%=<>!?]/, | |
27 validIdentifier: /[a-zA-Z0-9_]/, | |
28 stringChar: /['"]/ | |
29 }; | |
30 | |
31 var last; | |
32 function cont(style, lastType) { | |
33 last = lastType; | |
34 return style; | |
35 } | |
36 | |
37 function chain(stream, state, parser) { | |
38 state.tokenize = parser; | |
39 return parser(stream, state); | |
40 } | |
41 | |
42 // Smarty 3 allows { and } surrounded by whitespace to NOT slip into Smarty mode | |
43 function doesNotCount(stream, pos) { | |
44 if (pos == null) pos = stream.pos; | |
45 return version === 3 && leftDelimiter == "{" && | |
46 (pos == stream.string.length || /\s/.test(stream.string.charAt(pos))); | |
47 } | |
48 | |
49 function tokenTop(stream, state) { | |
50 var string = stream.string; | |
51 for (var scan = stream.pos;;) { | |
52 var nextMatch = string.indexOf(leftDelimiter, scan); | |
53 scan = nextMatch + leftDelimiter.length; | |
54 if (nextMatch == -1 || !doesNotCount(stream, nextMatch + leftDelimiter.length)) break; | |
55 } | |
56 if (nextMatch == stream.pos) { | |
57 stream.match(leftDelimiter); | |
58 if (stream.eat("*")) { | |
59 return chain(stream, state, tokenBlock("comment", "*" + rightDelimiter)); | |
60 } else { | |
61 state.depth++; | |
62 state.tokenize = tokenSmarty; | |
63 last = "startTag"; | |
64 return "tag"; | |
65 } | |
66 } | |
67 | |
68 if (nextMatch > -1) stream.string = string.slice(0, nextMatch); | |
69 var token = baseMode.token(stream, state.base); | |
70 if (nextMatch > -1) stream.string = string; | |
71 return token; | |
72 } | |
73 | |
74 // parsing Smarty content | |
75 function tokenSmarty(stream, state) { | |
76 if (stream.match(rightDelimiter, true)) { | |
77 if (version === 3) { | |
78 state.depth--; | |
79 if (state.depth <= 0) { | |
80 state.tokenize = tokenTop; | |
81 } | |
82 } else { | |
83 state.tokenize = tokenTop; | |
84 } | |
85 return cont("tag", null); | |
86 } | |
87 | |
88 if (stream.match(leftDelimiter, true)) { | |
89 state.depth++; | |
90 return cont("tag", "startTag"); | |
91 } | |
92 | |
93 var ch = stream.next(); | |
94 if (ch == "$") { | |
95 stream.eatWhile(regs.validIdentifier); | |
96 return cont("variable-2", "variable"); | |
97 } else if (ch == "|") { | |
98 return cont("operator", "pipe"); | |
99 } else if (ch == ".") { | |
100 return cont("operator", "property"); | |
101 } else if (regs.stringChar.test(ch)) { | |
102 state.tokenize = tokenAttribute(ch); | |
103 return cont("string", "string"); | |
104 } else if (regs.operatorChars.test(ch)) { | |
105 stream.eatWhile(regs.operatorChars); | |
106 return cont("operator", "operator"); | |
107 } else if (ch == "[" || ch == "]") { | |
108 return cont("bracket", "bracket"); | |
109 } else if (ch == "(" || ch == ")") { | |
110 return cont("bracket", "operator"); | |
111 } else if (/\d/.test(ch)) { | |
112 stream.eatWhile(/\d/); | |
113 return cont("number", "number"); | |
114 } else { | |
115 | |
116 if (state.last == "variable") { | |
117 if (ch == "@") { | |
118 stream.eatWhile(regs.validIdentifier); | |
119 return cont("property", "property"); | |
120 } else if (ch == "|") { | |
121 stream.eatWhile(regs.validIdentifier); | |
122 return cont("qualifier", "modifier"); | |
123 } | |
124 } else if (state.last == "pipe") { | |
125 stream.eatWhile(regs.validIdentifier); | |
126 return cont("qualifier", "modifier"); | |
127 } else if (state.last == "whitespace") { | |
128 stream.eatWhile(regs.validIdentifier); | |
129 return cont("attribute", "modifier"); | |
130 } if (state.last == "property") { | |
131 stream.eatWhile(regs.validIdentifier); | |
132 return cont("property", null); | |
133 } else if (/\s/.test(ch)) { | |
134 last = "whitespace"; | |
135 return null; | |
136 } | |
137 | |
138 var str = ""; | |
139 if (ch != "/") { | |
140 str += ch; | |
141 } | |
142 var c = null; | |
143 while (c = stream.eat(regs.validIdentifier)) { | |
144 str += c; | |
145 } | |
146 for (var i=0, j=keyFunctions.length; i<j; i++) { | |
147 if (keyFunctions[i] == str) { | |
148 return cont("keyword", "keyword"); | |
149 } | |
150 } | |
151 if (/\s/.test(ch)) { | |
152 return null; | |
153 } | |
154 return cont("tag", "tag"); | |
155 } | |
156 } | |
157 | |
158 function tokenAttribute(quote) { | |
159 return function(stream, state) { | |
160 var prevChar = null; | |
161 var currChar = null; | |
162 while (!stream.eol()) { | |
163 currChar = stream.peek(); | |
164 if (stream.next() == quote && prevChar !== '\\') { | |
165 state.tokenize = tokenSmarty; | |
166 break; | |
167 } | |
168 prevChar = currChar; | |
169 } | |
170 return "string"; | |
171 }; | |
172 } | |
173 | |
174 function tokenBlock(style, terminator) { | |
175 return function(stream, state) { | |
176 while (!stream.eol()) { | |
177 if (stream.match(terminator)) { | |
178 state.tokenize = tokenTop; | |
179 break; | |
180 } | |
181 stream.next(); | |
182 } | |
183 return style; | |
184 }; | |
185 } | |
186 | |
187 return { | |
188 startState: function() { | |
189 return { | |
190 base: CodeMirror.startState(baseMode), | |
191 tokenize: tokenTop, | |
192 last: null, | |
193 depth: 0 | |
194 }; | |
195 }, | |
196 copyState: function(state) { | |
197 return { | |
198 base: CodeMirror.copyState(baseMode, state.base), | |
199 tokenize: state.tokenize, | |
200 last: state.last, | |
201 depth: state.depth | |
202 }; | |
203 }, | |
204 innerMode: function(state) { | |
205 if (state.tokenize == tokenTop) | |
206 return {mode: baseMode, state: state.base}; | |
207 }, | |
208 token: function(stream, state) { | |
209 var style = state.tokenize(stream, state); | |
210 state.last = last; | |
211 return style; | |
212 }, | |
213 indent: function(state, text, line) { | |
214 if (state.tokenize == tokenTop && baseMode.indent) | |
215 return baseMode.indent(state.base, text, line); | |
216 else | |
217 return CodeMirror.Pass; | |
218 }, | |
219 blockCommentStart: leftDelimiter + "*", | |
220 blockCommentEnd: "*" + rightDelimiter | |
221 }; | |
222 }); | |
223 | |
224 CodeMirror.defineMIME("text/x-smarty", "smarty"); | |
225 }); |