smarty.js
147 lines
| 3.8 KiB
| application/javascript
|
JavascriptLexer
Matthias BUSSONNIER
|
r8053 | CodeMirror.defineMode("smarty", function(config, parserConfig) { | |
var keyFuncs = ["debug", "extends", "function", "include", "literal"]; | |||
var last; | |||
var regs = { | |||
operatorChars: /[+\-*&%=<>!?]/, | |||
validIdentifier: /[a-zA-Z0-9\_]/, | |||
stringChar: /[\'\"]/ | |||
} | |||
var leftDelim = (typeof config.mode.leftDelimiter != 'undefined') ? config.mode.leftDelimiter : "{"; | |||
var rightDelim = (typeof config.mode.rightDelimiter != 'undefined') ? config.mode.rightDelimiter : "}"; | |||
function ret(style, lst) { last = lst; return style; } | |||
function tokenizer(stream, state) { | |||
function chain(parser) { | |||
state.tokenize = parser; | |||
return parser(stream, state); | |||
} | |||
if (stream.match(leftDelim, true)) { | |||
if (stream.eat("*")) { | |||
return chain(inBlock("comment", "*" + rightDelim)); | |||
} | |||
else { | |||
state.tokenize = inSmarty; | |||
return "tag"; | |||
} | |||
} | |||
else { | |||
// I'd like to do an eatWhile() here, but I can't get it to eat only up to the rightDelim string/char | |||
stream.next(); | |||
return null; | |||
} | |||
} | |||
function inSmarty(stream, state) { | |||
if (stream.match(rightDelim, true)) { | |||
state.tokenize = tokenizer; | |||
return ret("tag", null); | |||
} | |||
var ch = stream.next(); | |||
if (ch == "$") { | |||
stream.eatWhile(regs.validIdentifier); | |||
return ret("variable-2", "variable"); | |||
} | |||
else if (ch == ".") { | |||
return ret("operator", "property"); | |||
} | |||
else if (regs.stringChar.test(ch)) { | |||
state.tokenize = inAttribute(ch); | |||
return ret("string", "string"); | |||
} | |||
else if (regs.operatorChars.test(ch)) { | |||
stream.eatWhile(regs.operatorChars); | |||
return ret("operator", "operator"); | |||
} | |||
else if (ch == "[" || ch == "]") { | |||
return ret("bracket", "bracket"); | |||
} | |||
else if (/\d/.test(ch)) { | |||
stream.eatWhile(/\d/); | |||
return ret("number", "number"); | |||
} | |||
else { | |||
if (state.last == "variable") { | |||
if (ch == "@") { | |||
stream.eatWhile(regs.validIdentifier); | |||
return ret("property", "property"); | |||
} | |||
else if (ch == "|") { | |||
stream.eatWhile(regs.validIdentifier); | |||
return ret("qualifier", "modifier"); | |||
} | |||
} | |||
else if (state.last == "whitespace") { | |||
stream.eatWhile(regs.validIdentifier); | |||
return ret("attribute", "modifier"); | |||
} | |||
else if (state.last == "property") { | |||
stream.eatWhile(regs.validIdentifier); | |||
return ret("property", null); | |||
} | |||
else if (/\s/.test(ch)) { | |||
last = "whitespace"; | |||
return null; | |||
} | |||
var str = ""; | |||
if (ch != "/") { | |||
str += ch; | |||
} | |||
var c = ""; | |||
while ((c = stream.eat(regs.validIdentifier))) { | |||
str += c; | |||
} | |||
var i, j; | |||
for (i=0, j=keyFuncs.length; i<j; i++) { | |||
if (keyFuncs[i] == str) { | |||
return ret("keyword", "keyword"); | |||
} | |||
} | |||
if (/\s/.test(ch)) { | |||
return null; | |||
} | |||
return ret("tag", "tag"); | |||
} | |||
} | |||
function inAttribute(quote) { | |||
return function(stream, state) { | |||
while (!stream.eol()) { | |||
if (stream.next() == quote) { | |||
state.tokenize = inSmarty; | |||
break; | |||
} | |||
} | |||
return "string"; | |||
}; | |||
} | |||
function inBlock(style, terminator) { | |||
return function(stream, state) { | |||
while (!stream.eol()) { | |||
if (stream.match(terminator)) { | |||
state.tokenize = tokenizer; | |||
break; | |||
} | |||
stream.next(); | |||
} | |||
return style; | |||
}; | |||
} | |||
return { | |||
startState: function() { | |||
return { tokenize: tokenizer, mode: "smarty", last: null }; | |||
}, | |||
token: function(stream, state) { | |||
var style = state.tokenize(stream, state); | |||
state.last = last; | |||
return style; | |||
}, | |||
electricChars: "" | |||
} | |||
}); | |||
CodeMirror.defineMIME("text/x-smarty", "smarty"); |