github.com/elliott5/community@v0.14.1-0.20160709191136-823126fb026a/app/public/codemirror/mode/velocity/velocity.js (about)

     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.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  });