openrat-cms

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

smarty.js (6828B)


      1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
      2 // Distributed under an MIT license: http://codemirror.net/LICENSE
      3 
      4 /**
      5  * Smarty 2 and 3 mode.
      6  */
      7 
      8 (function(mod) {
      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
     14     mod(CodeMirror);
     15 })(function(CodeMirror) {
     16   "use strict";
     17 
     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");
     23 
     24     var keyFunctions = ["debug", "extends", "function", "include", "literal"];
     25     var regs = {
     26       operatorChars: /[+\-*&%=<>!?]/,
     27       validIdentifier: /[a-zA-Z0-9_]/,
     28       stringChar: /['"]/
     29     };
     30 
     31     var last;
     32     function cont(style, lastType) {
     33       last = lastType;
     34       return style;
     35     }
     36 
     37     function chain(stream, state, parser) {
     38       state.tokenize = parser;
     39       return parser(stream, state);
     40     }
     41 
     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)));
     47     }
     48 
     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;
     55       }
     56       if (nextMatch == stream.pos) {
     57         stream.match(leftDelimiter);
     58         if (stream.eat("*")) {
     59           return chain(stream, state, tokenBlock("comment", "*" + rightDelimiter));
     60         } else {
     61           state.depth++;
     62           state.tokenize = tokenSmarty;
     63           last = "startTag";
     64           return "tag";
     65         }
     66       }
     67 
     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;
     71       return token;
     72     }
     73 
     74     // parsing Smarty content
     75     function tokenSmarty(stream, state) {
     76       if (stream.match(rightDelimiter, true)) {
     77         if (version === 3) {
     78           state.depth--;
     79           if (state.depth <= 0) {
     80             state.tokenize = tokenTop;
     81           }
     82         } else {
     83           state.tokenize = tokenTop;
     84         }
     85         return cont("tag", null);
     86       }
     87 
     88       if (stream.match(leftDelimiter, true)) {
     89         state.depth++;
     90         return cont("tag", "startTag");
     91       }
     92 
     93       var ch = stream.next();
     94       if (ch == "$") {
     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");
    114       } else {
    115 
    116         if (state.last == "variable") {
    117           if (ch == "@") {
    118             stream.eatWhile(regs.validIdentifier);
    119             return cont("property", "property");
    120           } else if (ch == "|") {
    121             stream.eatWhile(regs.validIdentifier);
    122             return cont("qualifier", "modifier");
    123           }
    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)) {
    134           last = "whitespace";
    135           return null;
    136         }
    137 
    138         var str = "";
    139         if (ch != "/") {
    140           str += ch;
    141         }
    142         var c = null;
    143         while (c = stream.eat(regs.validIdentifier)) {
    144           str += c;
    145         }
    146         for (var i=0, j=keyFunctions.length; i<j; i++) {
    147           if (keyFunctions[i] == str) {
    148             return cont("keyword", "keyword");
    149           }
    150         }
    151         if (/\s/.test(ch)) {
    152           return null;
    153         }
    154         return cont("tag", "tag");
    155       }
    156     }
    157 
    158     function tokenAttribute(quote) {
    159       return function(stream, state) {
    160         var prevChar = null;
    161         var currChar = null;
    162         while (!stream.eol()) {
    163           currChar = stream.peek();
    164           if (stream.next() == quote && prevChar !== '\\') {
    165             state.tokenize = tokenSmarty;
    166             break;
    167           }
    168           prevChar = currChar;
    169         }
    170         return "string";
    171       };
    172     }
    173 
    174     function tokenBlock(style, terminator) {
    175       return function(stream, state) {
    176         while (!stream.eol()) {
    177           if (stream.match(terminator)) {
    178             state.tokenize = tokenTop;
    179             break;
    180           }
    181           stream.next();
    182         }
    183         return style;
    184       };
    185     }
    186 
    187     return {
    188       startState: function() {
    189         return {
    190           base: CodeMirror.startState(baseMode),
    191           tokenize: tokenTop,
    192           last: null,
    193           depth: 0
    194         };
    195       },
    196       copyState: function(state) {
    197         return {
    198           base: CodeMirror.copyState(baseMode, state.base),
    199           tokenize: state.tokenize,
    200           last: state.last,
    201           depth: state.depth
    202         };
    203       },
    204       innerMode: function(state) {
    205         if (state.tokenize == tokenTop)
    206           return {mode: baseMode, state: state.base};
    207       },
    208       token: function(stream, state) {
    209         var style = state.tokenize(stream, state);
    210         state.last = last;
    211         return style;
    212       },
    213       indent: function(state, text) {
    214         if (state.tokenize == tokenTop && baseMode.indent)
    215           return baseMode.indent(state.base, text);
    216         else
    217           return CodeMirror.Pass;
    218       },
    219       blockCommentStart: leftDelimiter + "*",
    220       blockCommentEnd: "*" + rightDelimiter
    221     };
    222   });
    223 
    224   CodeMirror.defineMIME("text/x-smarty", "smarty");
    225 });