57852feb0e22e1e26300404ef20c00e747d5c06f
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: https://codemirror.net/LICENSE
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
15 })(function(CodeMirror
) {
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");
24 var keyFunctions
= ["debug", "extends", "function", "include", "literal"];
26 operatorChars
: /[+\-*&%=<>!?]/,
27 validIdentifier
: /[a-zA-Z0-9_]/,
32 function cont(style
, lastType
) {
37 function chain(stream
, state
, parser
) {
38 state
.tokenize
= parser
;
39 return parser(stream
, state
);
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
)));
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;
56 if (nextMatch
== stream
.pos
) {
57 stream
.match(leftDelimiter
);
58 if (stream
.eat("*")) {
59 return chain(stream
, state
, tokenBlock("comment", "*" + rightDelimiter
));
62 state
.tokenize
= tokenSmarty
;
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
;
74 // parsing Smarty content
75 function tokenSmarty(stream
, state
) {
76 if (stream
.match(rightDelimiter
, true)) {
79 if (state
.depth
<= 0) {
80 state
.tokenize
= tokenTop
;
83 state
.tokenize
= tokenTop
;
85 return cont("tag", null);
88 if (stream
.match(leftDelimiter
, true)) {
90 return cont("tag", "startTag");
93 var ch
= stream
.next();
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");
116 if (state
.last
== "variable") {
118 stream
.eatWhile(regs
.validIdentifier
);
119 return cont("property", "property");
120 } else if (ch
== "|") {
121 stream
.eatWhile(regs
.validIdentifier
);
122 return cont("qualifier", "modifier");
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
)) {
143 while (c
= stream
.eat(regs
.validIdentifier
)) {
146 for (var i
=0, j
=keyFunctions
.length
; i
<j
; i
++) {
147 if (keyFunctions
[i
] == str
) {
148 return cont("keyword", "keyword");
154 return cont("tag", "tag");
158 function tokenAttribute(quote
) {
159 return function(stream
, state
) {
162 while (!stream
.eol()) {
163 currChar
= stream
.peek();
164 if (stream
.next() == quote
&& prevChar
!== '\\') {
165 state
.tokenize
= tokenSmarty
;
174 function tokenBlock(style
, terminator
) {
175 return function(stream
, state
) {
176 while (!stream
.eol()) {
177 if (stream
.match(terminator
)) {
178 state
.tokenize
= tokenTop
;
188 startState: function() {
190 base
: CodeMirror
.startState(baseMode
),
196 copyState: function(state
) {
198 base
: CodeMirror
.copyState(baseMode
, state
.base
),
199 tokenize
: state
.tokenize
,
204 innerMode: function(state
) {
205 if (state
.tokenize
== tokenTop
)
206 return {mode
: baseMode
, state
: state
.base
};
208 token: function(stream
, state
) {
209 var style
= state
.tokenize(stream
, state
);
213 indent: function(state
, text
, line
) {
214 if (state
.tokenize
== tokenTop
&& baseMode
.indent
)
215 return baseMode
.indent(state
.base
, text
, line
);
217 return CodeMirror
.Pass
;
219 blockCommentStart
: leftDelimiter
+ "*",
220 blockCommentEnd
: "*" + rightDelimiter
224 CodeMirror
.defineMIME("text/x-smarty", "smarty");