openrat-cms

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

coffeescript.js (10035B)


      1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
      2 // Distributed under an MIT license: http://codemirror.net/LICENSE
      3 
      4 /**
      5  * Link to the project's GitHub page:
      6  * https://github.com/pickhardt/coffeescript-codemirror-mode
      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("coffeescript", function(conf, parserConf) {
     19   var ERRORCLASS = "error";
     20 
     21   function wordRegexp(words) {
     22     return new RegExp("^((" + words.join(")|(") + "))\\b");
     23   }
     24 
     25   var operators = /^(?:->|=>|\+[+=]?|-[\-=]?|\*[\*=]?|\/[\/=]?|[=!]=|<[><]?=?|>>?=?|%=?|&=?|\|=?|\^=?|\~|!|\?|(or|and|\|\||&&|\?)=)/;
     26   var delimiters = /^(?:[()\[\]{},:`=;]|\.\.?\.?)/;
     27   var identifiers = /^[_A-Za-z$][_A-Za-z$0-9]*/;
     28   var atProp = /^@[_A-Za-z$][_A-Za-z$0-9]*/;
     29 
     30   var wordOperators = wordRegexp(["and", "or", "not",
     31                                   "is", "isnt", "in",
     32                                   "instanceof", "typeof"]);
     33   var indentKeywords = ["for", "while", "loop", "if", "unless", "else",
     34                         "switch", "try", "catch", "finally", "class"];
     35   var commonKeywords = ["break", "by", "continue", "debugger", "delete",
     36                         "do", "in", "of", "new", "return", "then",
     37                         "this", "@", "throw", "when", "until", "extends"];
     38 
     39   var keywords = wordRegexp(indentKeywords.concat(commonKeywords));
     40 
     41   indentKeywords = wordRegexp(indentKeywords);
     42 
     43 
     44   var stringPrefixes = /^('{3}|\"{3}|['\"])/;
     45   var regexPrefixes = /^(\/{3}|\/)/;
     46   var commonConstants = ["Infinity", "NaN", "undefined", "null", "true", "false", "on", "off", "yes", "no"];
     47   var constants = wordRegexp(commonConstants);
     48 
     49   // Tokenizers
     50   function tokenBase(stream, state) {
     51     // Handle scope changes
     52     if (stream.sol()) {
     53       if (state.scope.align === null) state.scope.align = false;
     54       var scopeOffset = state.scope.offset;
     55       if (stream.eatSpace()) {
     56         var lineOffset = stream.indentation();
     57         if (lineOffset > scopeOffset && state.scope.type == "coffee") {
     58           return "indent";
     59         } else if (lineOffset < scopeOffset) {
     60           return "dedent";
     61         }
     62         return null;
     63       } else {
     64         if (scopeOffset > 0) {
     65           dedent(stream, state);
     66         }
     67       }
     68     }
     69     if (stream.eatSpace()) {
     70       return null;
     71     }
     72 
     73     var ch = stream.peek();
     74 
     75     // Handle docco title comment (single line)
     76     if (stream.match("####")) {
     77       stream.skipToEnd();
     78       return "comment";
     79     }
     80 
     81     // Handle multi line comments
     82     if (stream.match("###")) {
     83       state.tokenize = longComment;
     84       return state.tokenize(stream, state);
     85     }
     86 
     87     // Single line comment
     88     if (ch === "#") {
     89       stream.skipToEnd();
     90       return "comment";
     91     }
     92 
     93     // Handle number literals
     94     if (stream.match(/^-?[0-9\.]/, false)) {
     95       var floatLiteral = false;
     96       // Floats
     97       if (stream.match(/^-?\d*\.\d+(e[\+\-]?\d+)?/i)) {
     98         floatLiteral = true;
     99       }
    100       if (stream.match(/^-?\d+\.\d*/)) {
    101         floatLiteral = true;
    102       }
    103       if (stream.match(/^-?\.\d+/)) {
    104         floatLiteral = true;
    105       }
    106 
    107       if (floatLiteral) {
    108         // prevent from getting extra . on 1..
    109         if (stream.peek() == "."){
    110           stream.backUp(1);
    111         }
    112         return "number";
    113       }
    114       // Integers
    115       var intLiteral = false;
    116       // Hex
    117       if (stream.match(/^-?0x[0-9a-f]+/i)) {
    118         intLiteral = true;
    119       }
    120       // Decimal
    121       if (stream.match(/^-?[1-9]\d*(e[\+\-]?\d+)?/)) {
    122         intLiteral = true;
    123       }
    124       // Zero by itself with no other piece of number.
    125       if (stream.match(/^-?0(?![\dx])/i)) {
    126         intLiteral = true;
    127       }
    128       if (intLiteral) {
    129         return "number";
    130       }
    131     }
    132 
    133     // Handle strings
    134     if (stream.match(stringPrefixes)) {
    135       state.tokenize = tokenFactory(stream.current(), false, "string");
    136       return state.tokenize(stream, state);
    137     }
    138     // Handle regex literals
    139     if (stream.match(regexPrefixes)) {
    140       if (stream.current() != "/" || stream.match(/^.*\//, false)) { // prevent highlight of division
    141         state.tokenize = tokenFactory(stream.current(), true, "string-2");
    142         return state.tokenize(stream, state);
    143       } else {
    144         stream.backUp(1);
    145       }
    146     }
    147 
    148 
    149 
    150     // Handle operators and delimiters
    151     if (stream.match(operators) || stream.match(wordOperators)) {
    152       return "operator";
    153     }
    154     if (stream.match(delimiters)) {
    155       return "punctuation";
    156     }
    157 
    158     if (stream.match(constants)) {
    159       return "atom";
    160     }
    161 
    162     if (stream.match(atProp) || state.prop && stream.match(identifiers)) {
    163       return "property";
    164     }
    165 
    166     if (stream.match(keywords)) {
    167       return "keyword";
    168     }
    169 
    170     if (stream.match(identifiers)) {
    171       return "variable";
    172     }
    173 
    174     // Handle non-detected items
    175     stream.next();
    176     return ERRORCLASS;
    177   }
    178 
    179   function tokenFactory(delimiter, singleline, outclass) {
    180     return function(stream, state) {
    181       while (!stream.eol()) {
    182         stream.eatWhile(/[^'"\/\\]/);
    183         if (stream.eat("\\")) {
    184           stream.next();
    185           if (singleline && stream.eol()) {
    186             return outclass;
    187           }
    188         } else if (stream.match(delimiter)) {
    189           state.tokenize = tokenBase;
    190           return outclass;
    191         } else {
    192           stream.eat(/['"\/]/);
    193         }
    194       }
    195       if (singleline) {
    196         if (parserConf.singleLineStringErrors) {
    197           outclass = ERRORCLASS;
    198         } else {
    199           state.tokenize = tokenBase;
    200         }
    201       }
    202       return outclass;
    203     };
    204   }
    205 
    206   function longComment(stream, state) {
    207     while (!stream.eol()) {
    208       stream.eatWhile(/[^#]/);
    209       if (stream.match("###")) {
    210         state.tokenize = tokenBase;
    211         break;
    212       }
    213       stream.eatWhile("#");
    214     }
    215     return "comment";
    216   }
    217 
    218   function indent(stream, state, type) {
    219     type = type || "coffee";
    220     var offset = 0, align = false, alignOffset = null;
    221     for (var scope = state.scope; scope; scope = scope.prev) {
    222       if (scope.type === "coffee" || scope.type == "}") {
    223         offset = scope.offset + conf.indentUnit;
    224         break;
    225       }
    226     }
    227     if (type !== "coffee") {
    228       align = null;
    229       alignOffset = stream.column() + stream.current().length;
    230     } else if (state.scope.align) {
    231       state.scope.align = false;
    232     }
    233     state.scope = {
    234       offset: offset,
    235       type: type,
    236       prev: state.scope,
    237       align: align,
    238       alignOffset: alignOffset
    239     };
    240   }
    241 
    242   function dedent(stream, state) {
    243     if (!state.scope.prev) return;
    244     if (state.scope.type === "coffee") {
    245       var _indent = stream.indentation();
    246       var matched = false;
    247       for (var scope = state.scope; scope; scope = scope.prev) {
    248         if (_indent === scope.offset) {
    249           matched = true;
    250           break;
    251         }
    252       }
    253       if (!matched) {
    254         return true;
    255       }
    256       while (state.scope.prev && state.scope.offset !== _indent) {
    257         state.scope = state.scope.prev;
    258       }
    259       return false;
    260     } else {
    261       state.scope = state.scope.prev;
    262       return false;
    263     }
    264   }
    265 
    266   function tokenLexer(stream, state) {
    267     var style = state.tokenize(stream, state);
    268     var current = stream.current();
    269 
    270     // Handle scope changes.
    271     if (current === "return") {
    272       state.dedent = true;
    273     }
    274     if (((current === "->" || current === "=>") && stream.eol())
    275         || style === "indent") {
    276       indent(stream, state);
    277     }
    278     var delimiter_index = "[({".indexOf(current);
    279     if (delimiter_index !== -1) {
    280       indent(stream, state, "])}".slice(delimiter_index, delimiter_index+1));
    281     }
    282     if (indentKeywords.exec(current)){
    283       indent(stream, state);
    284     }
    285     if (current == "then"){
    286       dedent(stream, state);
    287     }
    288 
    289 
    290     if (style === "dedent") {
    291       if (dedent(stream, state)) {
    292         return ERRORCLASS;
    293       }
    294     }
    295     delimiter_index = "])}".indexOf(current);
    296     if (delimiter_index !== -1) {
    297       while (state.scope.type == "coffee" && state.scope.prev)
    298         state.scope = state.scope.prev;
    299       if (state.scope.type == current)
    300         state.scope = state.scope.prev;
    301     }
    302     if (state.dedent && stream.eol()) {
    303       if (state.scope.type == "coffee" && state.scope.prev)
    304         state.scope = state.scope.prev;
    305       state.dedent = false;
    306     }
    307 
    308     return style;
    309   }
    310 
    311   var external = {
    312     startState: function(basecolumn) {
    313       return {
    314         tokenize: tokenBase,
    315         scope: {offset:basecolumn || 0, type:"coffee", prev: null, align: false},
    316         prop: false,
    317         dedent: 0
    318       };
    319     },
    320 
    321     token: function(stream, state) {
    322       var fillAlign = state.scope.align === null && state.scope;
    323       if (fillAlign && stream.sol()) fillAlign.align = false;
    324 
    325       var style = tokenLexer(stream, state);
    326       if (style && style != "comment") {
    327         if (fillAlign) fillAlign.align = true;
    328         state.prop = style == "punctuation" && stream.current() == "."
    329       }
    330 
    331       return style;
    332     },
    333 
    334     indent: function(state, text) {
    335       if (state.tokenize != tokenBase) return 0;
    336       var scope = state.scope;
    337       var closer = text && "])}".indexOf(text.charAt(0)) > -1;
    338       if (closer) while (scope.type == "coffee" && scope.prev) scope = scope.prev;
    339       var closes = closer && scope.type === text.charAt(0);
    340       if (scope.align)
    341         return scope.alignOffset - (closes ? 1 : 0);
    342       else
    343         return (closes ? scope.prev : scope).offset;
    344     },
    345 
    346     lineComment: "#",
    347     fold: "indent"
    348   };
    349   return external;
    350 });
    351 
    352 // IANA registered media type
    353 // https://www.iana.org/assignments/media-types/
    354 CodeMirror.defineMIME("application/vnd.coffeescript", "coffeescript");
    355 
    356 CodeMirror.defineMIME("text/x-coffeescript", "coffeescript");
    357 CodeMirror.defineMIME("text/coffeescript", "coffeescript");
    358 
    359 });