4 CodeMirror.defineMode("smarty", function(config) {
7 // our default settings; check to see if they're overridden
11 smartyVersion: 2 // for backward compatibility
13 if (config.hasOwnProperty("leftDelimiter")) {
14 settings.leftDelimiter = config.leftDelimiter;
16 if (config.hasOwnProperty("rightDelimiter")) {
17 settings.rightDelimiter = config.rightDelimiter;
19 if (config.hasOwnProperty("smartyVersion") && config.smartyVersion === 3) {
20 settings.smartyVersion = 3;
23 var keyFunctions = ["debug", "extends", "function", "include", "literal"];
26 operatorChars: /[+\-*&%=<>!?]/,
27 validIdentifier: /[a-zA-Z0-9_]/,
32 cont: function(style, lastType) {
36 chain: function(stream, state, parser) {
37 state.tokenize = parser;
38 return parser(stream, state);
43 // our various parsers
47 tokenizer: function(stream, state) {
48 if (stream.match(settings.leftDelimiter, true)) {
49 if (stream.eat("*")) {
50 return helpers.chain(stream, state, parsers.inBlock("comment", "*" + settings.rightDelimiter));
52 // Smarty 3 allows { and } surrounded by whitespace to NOT slip into Smarty mode
54 var isEol = stream.eol();
55 var isFollowedByWhitespace = /\s/.test(stream.peek());
56 if (settings.smartyVersion === 3 && settings.leftDelimiter === "{" && (isEol || isFollowedByWhitespace)) {
60 state.tokenize = parsers.smarty;
71 // parsing Smarty content
72 smarty: function(stream, state) {
73 if (stream.match(settings.rightDelimiter, true)) {
74 if (settings.smartyVersion === 3) {
76 if (state.depth <= 0) {
77 state.tokenize = parsers.tokenizer;
80 state.tokenize = parsers.tokenizer;
82 return helpers.cont("tag", null);
85 if (stream.match(settings.leftDelimiter, true)) {
87 return helpers.cont("tag", "startTag");
90 var ch = stream.next();
92 stream.eatWhile(regs.validIdentifier);
93 return helpers.cont("variable-2", "variable");
94 } else if (ch == "|") {
95 return helpers.cont("operator", "pipe");
96 } else if (ch == ".") {
97 return helpers.cont("operator", "property");
98 } else if (regs.stringChar.test(ch)) {
99 state.tokenize = parsers.inAttribute(ch);
100 return helpers.cont("string", "string");
101 } else if (regs.operatorChars.test(ch)) {
102 stream.eatWhile(regs.operatorChars);
103 return helpers.cont("operator", "operator");
104 } else if (ch == "[" || ch == "]") {
105 return helpers.cont("bracket", "bracket");
106 } else if (ch == "(" || ch == ")") {
107 return helpers.cont("bracket", "operator");
108 } else if (/\d/.test(ch)) {
109 stream.eatWhile(/\d/);
110 return helpers.cont("number", "number");
113 if (state.last == "variable") {
115 stream.eatWhile(regs.validIdentifier);
116 return helpers.cont("property", "property");
117 } else if (ch == "|") {
118 stream.eatWhile(regs.validIdentifier);
119 return helpers.cont("qualifier", "modifier");
121 } else if (state.last == "pipe") {
122 stream.eatWhile(regs.validIdentifier);
123 return helpers.cont("qualifier", "modifier");
124 } else if (state.last == "whitespace") {
125 stream.eatWhile(regs.validIdentifier);
126 return helpers.cont("attribute", "modifier");
127 } if (state.last == "property") {
128 stream.eatWhile(regs.validIdentifier);
129 return helpers.cont("property", null);
130 } else if (/\s/.test(ch)) {
140 while (c = stream.eat(regs.validIdentifier)) {
143 for (var i=0, j=keyFunctions.length; i<j; i++) {
144 if (keyFunctions[i] == str) {
145 return helpers.cont("keyword", "keyword");
151 return helpers.cont("tag", "tag");
155 inAttribute: function(quote) {
156 return function(stream, state) {
159 while (!stream.eol()) {
160 currChar = stream.peek();
161 if (stream.next() == quote && prevChar !== '\\') {
162 state.tokenize = parsers.smarty;
171 inBlock: function(style, terminator) {
172 return function(stream, state) {
173 while (!stream.eol()) {
174 if (stream.match(terminator)) {
175 state.tokenize = parsers.tokenizer;
186 // the public API for CodeMirror
188 startState: function() {
190 tokenize: parsers.tokenizer,
196 token: function(stream, state) {
197 var style = state.tokenize(stream, state);
205 CodeMirror.defineMIME("text/x-smarty", "smarty");