openrat-cms

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

velocity.js (7098B)


      1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
      2 // Distributed under an MIT license: http://codemirror.net/LICENSE
      3 
      4 (function(mod) {
      5   if (typeof exports == "object" && typeof module == "object") // CommonJS
      6     mod(require("../../lib/codemirror"));
      7   else if (typeof define == "function" && define.amd) // AMD
      8     define(["../../lib/codemirror"], mod);
      9   else // Plain browser env
     10     mod(CodeMirror);
     11 })(function(CodeMirror) {
     12 "use strict";
     13 
     14 CodeMirror.defineMode("velocity", function() {
     15     function parseWords(str) {
     16         var obj = {}, words = str.split(" ");
     17         for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
     18         return obj;
     19     }
     20 
     21     var keywords = parseWords("#end #else #break #stop #[[ #]] " +
     22                               "#{end} #{else} #{break} #{stop}");
     23     var functions = parseWords("#if #elseif #foreach #set #include #parse #macro #define #evaluate " +
     24                                "#{if} #{elseif} #{foreach} #{set} #{include} #{parse} #{macro} #{define} #{evaluate}");
     25     var specials = parseWords("$foreach.count $foreach.hasNext $foreach.first $foreach.last $foreach.topmost $foreach.parent.count $foreach.parent.hasNext $foreach.parent.first $foreach.parent.last $foreach.parent $velocityCount $!bodyContent $bodyContent");
     26     var isOperatorChar = /[+\-*&%=<>!?:\/|]/;
     27 
     28     function chain(stream, state, f) {
     29         state.tokenize = f;
     30         return f(stream, state);
     31     }
     32     function tokenBase(stream, state) {
     33         var beforeParams = state.beforeParams;
     34         state.beforeParams = false;
     35         var ch = stream.next();
     36         // start of unparsed string?
     37         if ((ch == "'") && !state.inString && state.inParams) {
     38             state.lastTokenWasBuiltin = false;
     39             return chain(stream, state, tokenString(ch));
     40         }
     41         // start of parsed string?
     42         else if ((ch == '"')) {
     43             state.lastTokenWasBuiltin = false;
     44             if (state.inString) {
     45                 state.inString = false;
     46                 return "string";
     47             }
     48             else if (state.inParams)
     49                 return chain(stream, state, tokenString(ch));
     50         }
     51         // is it one of the special signs []{}().,;? Seperator?
     52         else if (/[\[\]{}\(\),;\.]/.test(ch)) {
     53             if (ch == "(" && beforeParams)
     54                 state.inParams = true;
     55             else if (ch == ")") {
     56                 state.inParams = false;
     57                 state.lastTokenWasBuiltin = true;
     58             }
     59             return null;
     60         }
     61         // start of a number value?
     62         else if (/\d/.test(ch)) {
     63             state.lastTokenWasBuiltin = false;
     64             stream.eatWhile(/[\w\.]/);
     65             return "number";
     66         }
     67         // multi line comment?
     68         else if (ch == "#" && stream.eat("*")) {
     69             state.lastTokenWasBuiltin = false;
     70             return chain(stream, state, tokenComment);
     71         }
     72         // unparsed content?
     73         else if (ch == "#" && stream.match(/ *\[ *\[/)) {
     74             state.lastTokenWasBuiltin = false;
     75             return chain(stream, state, tokenUnparsed);
     76         }
     77         // single line comment?
     78         else if (ch == "#" && stream.eat("#")) {
     79             state.lastTokenWasBuiltin = false;
     80             stream.skipToEnd();
     81             return "comment";
     82         }
     83         // variable?
     84         else if (ch == "$") {
     85             stream.eatWhile(/[\w\d\$_\.{}]/);
     86             // is it one of the specials?
     87             if (specials && specials.propertyIsEnumerable(stream.current())) {
     88                 return "keyword";
     89             }
     90             else {
     91                 state.lastTokenWasBuiltin = true;
     92                 state.beforeParams = true;
     93                 return "builtin";
     94             }
     95         }
     96         // is it a operator?
     97         else if (isOperatorChar.test(ch)) {
     98             state.lastTokenWasBuiltin = false;
     99             stream.eatWhile(isOperatorChar);
    100             return "operator";
    101         }
    102         else {
    103             // get the whole word
    104             stream.eatWhile(/[\w\$_{}@]/);
    105             var word = stream.current();
    106             // is it one of the listed keywords?
    107             if (keywords && keywords.propertyIsEnumerable(word))
    108                 return "keyword";
    109             // is it one of the listed functions?
    110             if (functions && functions.propertyIsEnumerable(word) ||
    111                     (stream.current().match(/^#@?[a-z0-9_]+ *$/i) && stream.peek()=="(") &&
    112                      !(functions && functions.propertyIsEnumerable(word.toLowerCase()))) {
    113                 state.beforeParams = true;
    114                 state.lastTokenWasBuiltin = false;
    115                 return "keyword";
    116             }
    117             if (state.inString) {
    118                 state.lastTokenWasBuiltin = false;
    119                 return "string";
    120             }
    121             if (stream.pos > word.length && stream.string.charAt(stream.pos-word.length-1)=="." && state.lastTokenWasBuiltin)
    122                 return "builtin";
    123             // default: just a "word"
    124             state.lastTokenWasBuiltin = false;
    125             return null;
    126         }
    127     }
    128 
    129     function tokenString(quote) {
    130         return function(stream, state) {
    131             var escaped = false, next, end = false;
    132             while ((next = stream.next()) != null) {
    133                 if ((next == quote) && !escaped) {
    134                     end = true;
    135                     break;
    136                 }
    137                 if (quote=='"' && stream.peek() == '$' && !escaped) {
    138                     state.inString = true;
    139                     end = true;
    140                     break;
    141                 }
    142                 escaped = !escaped && next == "\\";
    143             }
    144             if (end) state.tokenize = tokenBase;
    145             return "string";
    146         };
    147     }
    148 
    149     function tokenComment(stream, state) {
    150         var maybeEnd = false, ch;
    151         while (ch = stream.next()) {
    152             if (ch == "#" && maybeEnd) {
    153                 state.tokenize = tokenBase;
    154                 break;
    155             }
    156             maybeEnd = (ch == "*");
    157         }
    158         return "comment";
    159     }
    160 
    161     function tokenUnparsed(stream, state) {
    162         var maybeEnd = 0, ch;
    163         while (ch = stream.next()) {
    164             if (ch == "#" && maybeEnd == 2) {
    165                 state.tokenize = tokenBase;
    166                 break;
    167             }
    168             if (ch == "]")
    169                 maybeEnd++;
    170             else if (ch != " ")
    171                 maybeEnd = 0;
    172         }
    173         return "meta";
    174     }
    175     // Interface
    176 
    177     return {
    178         startState: function() {
    179             return {
    180                 tokenize: tokenBase,
    181                 beforeParams: false,
    182                 inParams: false,
    183                 inString: false,
    184                 lastTokenWasBuiltin: false
    185             };
    186         },
    187 
    188         token: function(stream, state) {
    189             if (stream.eatSpace()) return null;
    190             return state.tokenize(stream, state);
    191         },
    192         blockCommentStart: "#*",
    193         blockCommentEnd: "*#",
    194         lineComment: "##",
    195         fold: "velocity"
    196     };
    197 });
    198 
    199 CodeMirror.defineMIME("text/velocity", "velocity");
    200 
    201 });