123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- // CodeMirror, copyright (c) by Marijn Haverbeke and others
- // Distributed under an MIT license: http://codemirror.net/LICENSE
- /**
- * Smarty 2 and 3 mode.
- */
- (function(mod) {
- if (typeof exports == "object" && typeof module == "object") // CommonJS
- mod(require("../../lib/codemirror"));
- else if (typeof define == "function" && define.amd) // AMD
- define(["../../lib/codemirror"], mod);
- else // Plain browser env
- mod(CodeMirror);
- })(function(CodeMirror) {
- "use strict";
- CodeMirror.defineMode("smarty", function(config) {
- "use strict";
- // our default settings; check to see if they're overridden
- var settings = {
- rightDelimiter: '}',
- leftDelimiter: '{',
- smartyVersion: 2 // for backward compatibility
- };
- if (config.hasOwnProperty("leftDelimiter")) {
- settings.leftDelimiter = config.leftDelimiter;
- }
- if (config.hasOwnProperty("rightDelimiter")) {
- settings.rightDelimiter = config.rightDelimiter;
- }
- if (config.hasOwnProperty("smartyVersion") && config.smartyVersion === 3) {
- settings.smartyVersion = 3;
- }
- var keyFunctions = ["debug", "extends", "function", "include", "literal"];
- var last;
- var regs = {
- operatorChars: /[+\-*&%=<>!?]/,
- validIdentifier: /[a-zA-Z0-9_]/,
- stringChar: /['"]/
- };
- var helpers = {
- cont: function(style, lastType) {
- last = lastType;
- return style;
- },
- chain: function(stream, state, parser) {
- state.tokenize = parser;
- return parser(stream, state);
- }
- };
- // our various parsers
- var parsers = {
- // the main tokenizer
- tokenizer: function(stream, state) {
- if (stream.match(settings.leftDelimiter, true)) {
- if (stream.eat("*")) {
- return helpers.chain(stream, state, parsers.inBlock("comment", "*" + settings.rightDelimiter));
- } else {
- // Smarty 3 allows { and } surrounded by whitespace to NOT slip into Smarty mode
- state.depth++;
- var isEol = stream.eol();
- var isFollowedByWhitespace = /\s/.test(stream.peek());
- if (settings.smartyVersion === 3 && settings.leftDelimiter === "{" && (isEol || isFollowedByWhitespace)) {
- state.depth--;
- return null;
- } else {
- state.tokenize = parsers.smarty;
- last = "startTag";
- return "tag";
- }
- }
- } else {
- stream.next();
- return null;
- }
- },
- // parsing Smarty content
- smarty: function(stream, state) {
- if (stream.match(settings.rightDelimiter, true)) {
- if (settings.smartyVersion === 3) {
- state.depth--;
- if (state.depth <= 0) {
- state.tokenize = parsers.tokenizer;
- }
- } else {
- state.tokenize = parsers.tokenizer;
- }
- return helpers.cont("tag", null);
- }
- if (stream.match(settings.leftDelimiter, true)) {
- state.depth++;
- return helpers.cont("tag", "startTag");
- }
- var ch = stream.next();
- if (ch == "$") {
- stream.eatWhile(regs.validIdentifier);
- return helpers.cont("variable-2", "variable");
- } else if (ch == "|") {
- return helpers.cont("operator", "pipe");
- } else if (ch == ".") {
- return helpers.cont("operator", "property");
- } else if (regs.stringChar.test(ch)) {
- state.tokenize = parsers.inAttribute(ch);
- return helpers.cont("string", "string");
- } else if (regs.operatorChars.test(ch)) {
- stream.eatWhile(regs.operatorChars);
- return helpers.cont("operator", "operator");
- } else if (ch == "[" || ch == "]") {
- return helpers.cont("bracket", "bracket");
- } else if (ch == "(" || ch == ")") {
- return helpers.cont("bracket", "operator");
- } else if (/\d/.test(ch)) {
- stream.eatWhile(/\d/);
- return helpers.cont("number", "number");
- } else {
- if (state.last == "variable") {
- if (ch == "@") {
- stream.eatWhile(regs.validIdentifier);
- return helpers.cont("property", "property");
- } else if (ch == "|") {
- stream.eatWhile(regs.validIdentifier);
- return helpers.cont("qualifier", "modifier");
- }
- } else if (state.last == "pipe") {
- stream.eatWhile(regs.validIdentifier);
- return helpers.cont("qualifier", "modifier");
- } else if (state.last == "whitespace") {
- stream.eatWhile(regs.validIdentifier);
- return helpers.cont("attribute", "modifier");
- } if (state.last == "property") {
- stream.eatWhile(regs.validIdentifier);
- return helpers.cont("property", null);
- } else if (/\s/.test(ch)) {
- last = "whitespace";
- return null;
- }
- var str = "";
- if (ch != "/") {
- str += ch;
- }
- var c = null;
- while (c = stream.eat(regs.validIdentifier)) {
- str += c;
- }
- for (var i=0, j=keyFunctions.length; i<j; i++) {
- if (keyFunctions[i] == str) {
- return helpers.cont("keyword", "keyword");
- }
- }
- if (/\s/.test(ch)) {
- return null;
- }
- return helpers.cont("tag", "tag");
- }
- },
- inAttribute: function(quote) {
- return function(stream, state) {
- var prevChar = null;
- var currChar = null;
- while (!stream.eol()) {
- currChar = stream.peek();
- if (stream.next() == quote && prevChar !== '\\') {
- state.tokenize = parsers.smarty;
- break;
- }
- prevChar = currChar;
- }
- return "string";
- };
- },
- inBlock: function(style, terminator) {
- return function(stream, state) {
- while (!stream.eol()) {
- if (stream.match(terminator)) {
- state.tokenize = parsers.tokenizer;
- break;
- }
- stream.next();
- }
- return style;
- };
- }
- };
- // the public API for CodeMirror
- return {
- startState: function() {
- return {
- tokenize: parsers.tokenizer,
- mode: "smarty",
- last: null,
- depth: 0
- };
- },
- token: function(stream, state) {
- var style = state.tokenize(stream, state);
- state.last = last;
- return style;
- },
- electricChars: ""
- };
- });
- CodeMirror.defineMIME("text/x-smarty", "smarty");
- });
|