| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 | // 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, parserConf) {    var rightDelimiter = parserConf.rightDelimiter || "}";    var leftDelimiter = parserConf.leftDelimiter || "{";    var version = parserConf.version || 2;    var baseMode = CodeMirror.getMode(config, parserConf.baseMode || "null");    var keyFunctions = ["debug", "extends", "function", "include", "literal"];    var regs = {      operatorChars: /[+\-*&%=<>!?]/,      validIdentifier: /[a-zA-Z0-9_]/,      stringChar: /['"]/    };    var last;    function cont(style, lastType) {      last = lastType;      return style;    }    function chain(stream, state, parser) {      state.tokenize = parser;      return parser(stream, state);    }    // Smarty 3 allows { and } surrounded by whitespace to NOT slip into Smarty mode    function doesNotCount(stream, pos) {      if (pos == null) pos = stream.pos;      return version === 3 && leftDelimiter == "{" &&        (pos == stream.string.length || /\s/.test(stream.string.charAt(pos)));    }    function tokenTop(stream, state) {      var string = stream.string;      for (var scan = stream.pos;;) {        var nextMatch = string.indexOf(leftDelimiter, scan);        scan = nextMatch + leftDelimiter.length;        if (nextMatch == -1 || !doesNotCount(stream, nextMatch + leftDelimiter.length)) break;      }      if (nextMatch == stream.pos) {        stream.match(leftDelimiter);        if (stream.eat("*")) {          return chain(stream, state, tokenBlock("comment", "*" + rightDelimiter));        } else {          state.depth++;          state.tokenize = tokenSmarty;          last = "startTag";          return "tag";        }      }      if (nextMatch > -1) stream.string = string.slice(0, nextMatch);      var token = baseMode.token(stream, state.base);      if (nextMatch > -1) stream.string = string;      return token;    }    // parsing Smarty content    function tokenSmarty(stream, state) {      if (stream.match(rightDelimiter, true)) {        if (version === 3) {          state.depth--;          if (state.depth <= 0) {            state.tokenize = tokenTop;          }        } else {          state.tokenize = tokenTop;        }        return cont("tag", null);      }      if (stream.match(leftDelimiter, true)) {        state.depth++;        return cont("tag", "startTag");      }      var ch = stream.next();      if (ch == "$") {        stream.eatWhile(regs.validIdentifier);        return cont("variable-2", "variable");      } else if (ch == "|") {        return cont("operator", "pipe");      } else if (ch == ".") {        return cont("operator", "property");      } else if (regs.stringChar.test(ch)) {        state.tokenize = tokenAttribute(ch);        return cont("string", "string");      } else if (regs.operatorChars.test(ch)) {        stream.eatWhile(regs.operatorChars);        return cont("operator", "operator");      } else if (ch == "[" || ch == "]") {        return cont("bracket", "bracket");      } else if (ch == "(" || ch == ")") {        return cont("bracket", "operator");      } else if (/\d/.test(ch)) {        stream.eatWhile(/\d/);        return cont("number", "number");      } else {        if (state.last == "variable") {          if (ch == "@") {            stream.eatWhile(regs.validIdentifier);            return cont("property", "property");          } else if (ch == "|") {            stream.eatWhile(regs.validIdentifier);            return cont("qualifier", "modifier");          }        } else if (state.last == "pipe") {          stream.eatWhile(regs.validIdentifier);          return cont("qualifier", "modifier");        } else if (state.last == "whitespace") {          stream.eatWhile(regs.validIdentifier);          return cont("attribute", "modifier");        } if (state.last == "property") {          stream.eatWhile(regs.validIdentifier);          return 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 cont("keyword", "keyword");          }        }        if (/\s/.test(ch)) {          return null;        }        return cont("tag", "tag");      }    }    function tokenAttribute(quote) {      return function(stream, state) {        var prevChar = null;        var currChar = null;        while (!stream.eol()) {          currChar = stream.peek();          if (stream.next() == quote && prevChar !== '\\') {            state.tokenize = tokenSmarty;            break;          }          prevChar = currChar;        }        return "string";      };    }    function tokenBlock(style, terminator) {      return function(stream, state) {        while (!stream.eol()) {          if (stream.match(terminator)) {            state.tokenize = tokenTop;            break;          }          stream.next();        }        return style;      };    }    return {      startState: function() {        return {          base: CodeMirror.startState(baseMode),          tokenize: tokenTop,          last: null,          depth: 0        };      },      copyState: function(state) {        return {          base: CodeMirror.copyState(baseMode, state.base),          tokenize: state.tokenize,          last: state.last,          depth: state.depth        };      },      innerMode: function(state) {        if (state.tokenize == tokenTop)          return {mode: baseMode, state: state.base};      },      token: function(stream, state) {        var style = state.tokenize(stream, state);        state.last = last;        return style;      },      indent: function(state, text) {        if (state.tokenize == tokenTop && baseMode.indent)          return baseMode.indent(state.base, text);        else          return CodeMirror.Pass;      },      blockCommentStart: leftDelimiter + "*",      blockCommentEnd: "*" + rightDelimiter    };  });  CodeMirror.defineMIME("text/x-smarty", "smarty");});
 |