tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

coffeescript.js (10091B)


      1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
      2 // Distributed under an MIT license: https://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("resource://devtools/client/shared/sourceeditor/codemirror/lib/codemirror.js"));
     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 });