tor-browser

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

clike.js (35779B)


      1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
      2 // Distributed under an MIT license: https://codemirror.net/LICENSE
      3 
      4 (function(mod) {
      5  if (typeof exports == "object" && typeof module == "object") // CommonJS
      6    mod(require("resource://devtools/client/shared/sourceeditor/codemirror/lib/codemirror.js"));
      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 function Context(indented, column, type, info, align, prev) {
     15  this.indented = indented;
     16  this.column = column;
     17  this.type = type;
     18  this.info = info;
     19  this.align = align;
     20  this.prev = prev;
     21 }
     22 function pushContext(state, col, type, info) {
     23  var indent = state.indented;
     24  if (state.context && state.context.type == "statement" && type != "statement")
     25    indent = state.context.indented;
     26  return state.context = new Context(indent, col, type, info, null, state.context);
     27 }
     28 function popContext(state) {
     29  var t = state.context.type;
     30  if (t == ")" || t == "]" || t == "}")
     31    state.indented = state.context.indented;
     32  return state.context = state.context.prev;
     33 }
     34 
     35 function typeBefore(stream, state, pos) {
     36  if (state.prevToken == "variable" || state.prevToken == "type") return true;
     37  if (/\S(?:[^- ]>|[*\]])\s*$|\*$/.test(stream.string.slice(0, pos))) return true;
     38  if (state.typeAtEndOfLine && stream.column() == stream.indentation()) return true;
     39 }
     40 
     41 function isTopScope(context) {
     42  for (;;) {
     43    if (!context || context.type == "top") return true;
     44    if (context.type == "}" && context.prev.info != "namespace") return false;
     45    context = context.prev;
     46  }
     47 }
     48 
     49 CodeMirror.defineMode("clike", function(config, parserConfig) {
     50  var indentUnit = config.indentUnit,
     51      statementIndentUnit = parserConfig.statementIndentUnit || indentUnit,
     52      dontAlignCalls = parserConfig.dontAlignCalls,
     53      keywords = parserConfig.keywords || {},
     54      types = parserConfig.types || {},
     55      builtin = parserConfig.builtin || {},
     56      blockKeywords = parserConfig.blockKeywords || {},
     57      defKeywords = parserConfig.defKeywords || {},
     58      atoms = parserConfig.atoms || {},
     59      hooks = parserConfig.hooks || {},
     60      multiLineStrings = parserConfig.multiLineStrings,
     61      indentStatements = parserConfig.indentStatements !== false,
     62      indentSwitch = parserConfig.indentSwitch !== false,
     63      namespaceSeparator = parserConfig.namespaceSeparator,
     64      isPunctuationChar = parserConfig.isPunctuationChar || /[\[\]{}\(\),;\:\.]/,
     65      numberStart = parserConfig.numberStart || /[\d\.]/,
     66      number = parserConfig.number || /^(?:0x[a-f\d]+|0b[01]+|(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?)(u|ll?|l|f)?/i,
     67      isOperatorChar = parserConfig.isOperatorChar || /[+\-*&%=<>!?|\/]/,
     68      isIdentifierChar = parserConfig.isIdentifierChar || /[\w\$_\xa1-\uffff]/,
     69      // An optional function that takes a {string} token and returns true if it
     70      // should be treated as a builtin.
     71      isReservedIdentifier = parserConfig.isReservedIdentifier || false;
     72 
     73  var curPunc, isDefKeyword;
     74 
     75  function tokenBase(stream, state) {
     76    var ch = stream.next();
     77    if (hooks[ch]) {
     78      var result = hooks[ch](stream, state);
     79      if (result !== false) return result;
     80    }
     81    if (ch == '"' || ch == "'") {
     82      state.tokenize = tokenString(ch);
     83      return state.tokenize(stream, state);
     84    }
     85    if (isPunctuationChar.test(ch)) {
     86      curPunc = ch;
     87      return null;
     88    }
     89    if (numberStart.test(ch)) {
     90      stream.backUp(1)
     91      if (stream.match(number)) return "number"
     92      stream.next()
     93    }
     94    if (ch == "/") {
     95      if (stream.eat("*")) {
     96        state.tokenize = tokenComment;
     97        return tokenComment(stream, state);
     98      }
     99      if (stream.eat("/")) {
    100        stream.skipToEnd();
    101        return "comment";
    102      }
    103    }
    104    if (isOperatorChar.test(ch)) {
    105      while (!stream.match(/^\/[\/*]/, false) && stream.eat(isOperatorChar)) {}
    106      return "operator";
    107    }
    108    stream.eatWhile(isIdentifierChar);
    109    if (namespaceSeparator) while (stream.match(namespaceSeparator))
    110      stream.eatWhile(isIdentifierChar);
    111 
    112    var cur = stream.current();
    113    if (contains(keywords, cur)) {
    114      if (contains(blockKeywords, cur)) curPunc = "newstatement";
    115      if (contains(defKeywords, cur)) isDefKeyword = true;
    116      return "keyword";
    117    }
    118    if (contains(types, cur)) return "type";
    119    if (contains(builtin, cur)
    120        || (isReservedIdentifier && isReservedIdentifier(cur))) {
    121      if (contains(blockKeywords, cur)) curPunc = "newstatement";
    122      return "builtin";
    123    }
    124    if (contains(atoms, cur)) return "atom";
    125    return "variable";
    126  }
    127 
    128  function tokenString(quote) {
    129    return function(stream, state) {
    130      var escaped = false, next, end = false;
    131      while ((next = stream.next()) != null) {
    132        if (next == quote && !escaped) {end = true; break;}
    133        escaped = !escaped && next == "\\";
    134      }
    135      if (end || !(escaped || multiLineStrings))
    136        state.tokenize = null;
    137      return "string";
    138    };
    139  }
    140 
    141  function tokenComment(stream, state) {
    142    var maybeEnd = false, ch;
    143    while (ch = stream.next()) {
    144      if (ch == "/" && maybeEnd) {
    145        state.tokenize = null;
    146        break;
    147      }
    148      maybeEnd = (ch == "*");
    149    }
    150    return "comment";
    151  }
    152 
    153  function maybeEOL(stream, state) {
    154    if (parserConfig.typeFirstDefinitions && stream.eol() && isTopScope(state.context))
    155      state.typeAtEndOfLine = typeBefore(stream, state, stream.pos)
    156  }
    157 
    158  // Interface
    159 
    160  return {
    161    startState: function(basecolumn) {
    162      return {
    163        tokenize: null,
    164        context: new Context((basecolumn || 0) - indentUnit, 0, "top", null, false),
    165        indented: 0,
    166        startOfLine: true,
    167        prevToken: null
    168      };
    169    },
    170 
    171    token: function(stream, state) {
    172      var ctx = state.context;
    173      if (stream.sol()) {
    174        if (ctx.align == null) ctx.align = false;
    175        state.indented = stream.indentation();
    176        state.startOfLine = true;
    177      }
    178      if (stream.eatSpace()) { maybeEOL(stream, state); return null; }
    179      curPunc = isDefKeyword = null;
    180      var style = (state.tokenize || tokenBase)(stream, state);
    181      if (style == "comment" || style == "meta") return style;
    182      if (ctx.align == null) ctx.align = true;
    183 
    184      if (curPunc == ";" || curPunc == ":" || (curPunc == "," && stream.match(/^\s*(?:\/\/.*)?$/, false)))
    185        while (state.context.type == "statement") popContext(state);
    186      else if (curPunc == "{") pushContext(state, stream.column(), "}");
    187      else if (curPunc == "[") pushContext(state, stream.column(), "]");
    188      else if (curPunc == "(") pushContext(state, stream.column(), ")");
    189      else if (curPunc == "}") {
    190        while (ctx.type == "statement") ctx = popContext(state);
    191        if (ctx.type == "}") ctx = popContext(state);
    192        while (ctx.type == "statement") ctx = popContext(state);
    193      }
    194      else if (curPunc == ctx.type) popContext(state);
    195      else if (indentStatements &&
    196               (((ctx.type == "}" || ctx.type == "top") && curPunc != ";") ||
    197                (ctx.type == "statement" && curPunc == "newstatement"))) {
    198        pushContext(state, stream.column(), "statement", stream.current());
    199      }
    200 
    201      if (style == "variable" &&
    202          ((state.prevToken == "def" ||
    203            (parserConfig.typeFirstDefinitions && typeBefore(stream, state, stream.start) &&
    204             isTopScope(state.context) && stream.match(/^\s*\(/, false)))))
    205        style = "def";
    206 
    207      if (hooks.token) {
    208        var result = hooks.token(stream, state, style);
    209        if (result !== undefined) style = result;
    210      }
    211 
    212      if (style == "def" && parserConfig.styleDefs === false) style = "variable";
    213 
    214      state.startOfLine = false;
    215      state.prevToken = isDefKeyword ? "def" : style || curPunc;
    216      maybeEOL(stream, state);
    217      return style;
    218    },
    219 
    220    indent: function(state, textAfter) {
    221      if (state.tokenize != tokenBase && state.tokenize != null || state.typeAtEndOfLine) return CodeMirror.Pass;
    222      var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
    223      var closing = firstChar == ctx.type;
    224      if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev;
    225      if (parserConfig.dontIndentStatements)
    226        while (ctx.type == "statement" && parserConfig.dontIndentStatements.test(ctx.info))
    227          ctx = ctx.prev
    228      if (hooks.indent) {
    229        var hook = hooks.indent(state, ctx, textAfter, indentUnit);
    230        if (typeof hook == "number") return hook
    231      }
    232      var switchBlock = ctx.prev && ctx.prev.info == "switch";
    233      if (parserConfig.allmanIndentation && /[{(]/.test(firstChar)) {
    234        while (ctx.type != "top" && ctx.type != "}") ctx = ctx.prev
    235        return ctx.indented
    236      }
    237      if (ctx.type == "statement")
    238        return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit);
    239      if (ctx.align && (!dontAlignCalls || ctx.type != ")"))
    240        return ctx.column + (closing ? 0 : 1);
    241      if (ctx.type == ")" && !closing)
    242        return ctx.indented + statementIndentUnit;
    243 
    244      return ctx.indented + (closing ? 0 : indentUnit) +
    245        (!closing && switchBlock && !/^(?:case|default)\b/.test(textAfter) ? indentUnit : 0);
    246    },
    247 
    248    electricInput: indentSwitch ? /^\s*(?:case .*?:|default:|\{\}?|\})$/ : /^\s*[{}]$/,
    249    blockCommentStart: "/*",
    250    blockCommentEnd: "*/",
    251    blockCommentContinue: " * ",
    252    lineComment: "//",
    253    fold: "brace"
    254  };
    255 });
    256 
    257  function words(str) {
    258    var obj = {}, words = str.split(" ");
    259    for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
    260    return obj;
    261  }
    262  function contains(words, word) {
    263    if (typeof words === "function") {
    264      return words(word);
    265    } else {
    266      return words.propertyIsEnumerable(word);
    267    }
    268  }
    269  var cKeywords = "auto if break case register continue return default do sizeof " +
    270    "static else struct switch extern typedef union for goto while enum const " +
    271    "volatile inline restrict asm fortran";
    272 
    273  // Do not use this. Use the cTypes function below. This is global just to avoid
    274  // excessive calls when cTypes is being called multiple times during a parse.
    275  var basicCTypes = words("int long char short double float unsigned signed " +
    276    "void bool");
    277 
    278  // Do not use this. Use the objCTypes function below. This is global just to avoid
    279  // excessive calls when objCTypes is being called multiple times during a parse.
    280  var basicObjCTypes = words("SEL instancetype id Class Protocol BOOL");
    281 
    282  // Returns true if identifier is a "C" type.
    283  // C type is defined as those that are reserved by the compiler (basicTypes),
    284  // and those that end in _t (Reserved by POSIX for types)
    285  // http://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html
    286  function cTypes(identifier) {
    287    return contains(basicCTypes, identifier) || /.+_t$/.test(identifier);
    288  }
    289 
    290  // Returns true if identifier is a "Objective C" type.
    291  function objCTypes(identifier) {
    292    return cTypes(identifier) || contains(basicObjCTypes, identifier);
    293  }
    294 
    295  var cBlockKeywords = "case do else for if switch while struct enum union";
    296  var cDefKeywords = "struct enum union";
    297 
    298  function cppHook(stream, state) {
    299    if (!state.startOfLine) return false
    300    for (var ch, next = null; ch = stream.peek();) {
    301      if (ch == "\\" && stream.match(/^.$/)) {
    302        next = cppHook
    303        break
    304      } else if (ch == "/" && stream.match(/^\/[\/\*]/, false)) {
    305        break
    306      }
    307      stream.next()
    308    }
    309    state.tokenize = next
    310    return "meta"
    311  }
    312 
    313  function pointerHook(_stream, state) {
    314    if (state.prevToken == "type") return "type";
    315    return false;
    316  }
    317 
    318  // For C and C++ (and ObjC): identifiers starting with __
    319  // or _ followed by a capital letter are reserved for the compiler.
    320  function cIsReservedIdentifier(token) {
    321    if (!token || token.length < 2) return false;
    322    if (token[0] != '_') return false;
    323    return (token[1] == '_') || (token[1] !== token[1].toLowerCase());
    324  }
    325 
    326  function cpp14Literal(stream) {
    327    stream.eatWhile(/[\w\.']/);
    328    return "number";
    329  }
    330 
    331  function cpp11StringHook(stream, state) {
    332    stream.backUp(1);
    333    // Raw strings.
    334    if (stream.match(/(R|u8R|uR|UR|LR)/)) {
    335      var match = stream.match(/"([^\s\\()]{0,16})\(/);
    336      if (!match) {
    337        return false;
    338      }
    339      state.cpp11RawStringDelim = match[1];
    340      state.tokenize = tokenRawString;
    341      return tokenRawString(stream, state);
    342    }
    343    // Unicode strings/chars.
    344    if (stream.match(/(u8|u|U|L)/)) {
    345      if (stream.match(/["']/, /* eat */ false)) {
    346        return "string";
    347      }
    348      return false;
    349    }
    350    // Ignore this hook.
    351    stream.next();
    352    return false;
    353  }
    354 
    355  function cppLooksLikeConstructor(word) {
    356    var lastTwo = /(\w+)::~?(\w+)$/.exec(word);
    357    return lastTwo && lastTwo[1] == lastTwo[2];
    358  }
    359 
    360  // C#-style strings where "" escapes a quote.
    361  function tokenAtString(stream, state) {
    362    var next;
    363    while ((next = stream.next()) != null) {
    364      if (next == '"' && !stream.eat('"')) {
    365        state.tokenize = null;
    366        break;
    367      }
    368    }
    369    return "string";
    370  }
    371 
    372  // C++11 raw string literal is <prefix>"<delim>( anything )<delim>", where
    373  // <delim> can be a string up to 16 characters long.
    374  function tokenRawString(stream, state) {
    375    // Escape characters that have special regex meanings.
    376    var delim = state.cpp11RawStringDelim.replace(/[^\w\s]/g, '\\$&');
    377    var match = stream.match(new RegExp(".*?\\)" + delim + '"'));
    378    if (match)
    379      state.tokenize = null;
    380    else
    381      stream.skipToEnd();
    382    return "string";
    383  }
    384 
    385  function def(mimes, mode) {
    386    if (typeof mimes == "string") mimes = [mimes];
    387    var words = [];
    388    function add(obj) {
    389      if (obj) for (var prop in obj) if (obj.hasOwnProperty(prop))
    390        words.push(prop);
    391    }
    392    add(mode.keywords);
    393    add(mode.types);
    394    add(mode.builtin);
    395    add(mode.atoms);
    396    if (words.length) {
    397      mode.helperType = mimes[0];
    398      CodeMirror.registerHelper("hintWords", mimes[0], words);
    399    }
    400 
    401    for (var i = 0; i < mimes.length; ++i)
    402      CodeMirror.defineMIME(mimes[i], mode);
    403  }
    404 
    405  def(["text/x-csrc", "text/x-c", "text/x-chdr"], {
    406    name: "clike",
    407    keywords: words(cKeywords),
    408    types: cTypes,
    409    blockKeywords: words(cBlockKeywords),
    410    defKeywords: words(cDefKeywords),
    411    typeFirstDefinitions: true,
    412    atoms: words("NULL true false"),
    413    isReservedIdentifier: cIsReservedIdentifier,
    414    hooks: {
    415      "#": cppHook,
    416      "*": pointerHook,
    417    },
    418    modeProps: {fold: ["brace", "include"]}
    419  });
    420 
    421  def(["text/x-c++src", "text/x-c++hdr"], {
    422    name: "clike",
    423    // Keywords from https://en.cppreference.com/w/cpp/keyword includes C++20.
    424    keywords: words(cKeywords + "alignas alignof and and_eq audit axiom bitand bitor catch " +
    425                    "class compl concept constexpr const_cast decltype delete dynamic_cast " +
    426                    "explicit export final friend import module mutable namespace new noexcept " +
    427                    "not not_eq operator or or_eq override private protected public " +
    428                    "reinterpret_cast requires static_assert static_cast template this " +
    429                    "thread_local throw try typeid typename using virtual xor xor_eq"),
    430    types: cTypes,
    431    blockKeywords: words(cBlockKeywords + " class try catch"),
    432    defKeywords: words(cDefKeywords + " class namespace"),
    433    typeFirstDefinitions: true,
    434    atoms: words("true false NULL nullptr"),
    435    dontIndentStatements: /^template$/,
    436    isIdentifierChar: /[\w\$_~\xa1-\uffff]/,
    437    isReservedIdentifier: cIsReservedIdentifier,
    438    hooks: {
    439      "#": cppHook,
    440      "*": pointerHook,
    441      "u": cpp11StringHook,
    442      "U": cpp11StringHook,
    443      "L": cpp11StringHook,
    444      "R": cpp11StringHook,
    445      "0": cpp14Literal,
    446      "1": cpp14Literal,
    447      "2": cpp14Literal,
    448      "3": cpp14Literal,
    449      "4": cpp14Literal,
    450      "5": cpp14Literal,
    451      "6": cpp14Literal,
    452      "7": cpp14Literal,
    453      "8": cpp14Literal,
    454      "9": cpp14Literal,
    455      token: function(stream, state, style) {
    456        if (style == "variable" && stream.peek() == "(" &&
    457            (state.prevToken == ";" || state.prevToken == null ||
    458             state.prevToken == "}") &&
    459            cppLooksLikeConstructor(stream.current()))
    460          return "def";
    461      }
    462    },
    463    namespaceSeparator: "::",
    464    modeProps: {fold: ["brace", "include"]}
    465  });
    466 
    467  def("text/x-java", {
    468    name: "clike",
    469    keywords: words("abstract assert break case catch class const continue default " +
    470                    "do else enum extends final finally for goto if implements import " +
    471                    "instanceof interface native new package private protected public " +
    472                    "return static strictfp super switch synchronized this throw throws transient " +
    473                    "try volatile while @interface"),
    474    types: words("byte short int long float double boolean char void Boolean Byte Character Double Float " +
    475                 "Integer Long Number Object Short String StringBuffer StringBuilder Void"),
    476    blockKeywords: words("catch class do else finally for if switch try while"),
    477    defKeywords: words("class interface enum @interface"),
    478    typeFirstDefinitions: true,
    479    atoms: words("true false null"),
    480    number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+\.?\d*|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i,
    481    hooks: {
    482      "@": function(stream) {
    483        // Don't match the @interface keyword.
    484        if (stream.match('interface', false)) return false;
    485 
    486        stream.eatWhile(/[\w\$_]/);
    487        return "meta";
    488      }
    489    },
    490    modeProps: {fold: ["brace", "import"]}
    491  });
    492 
    493  def("text/x-csharp", {
    494    name: "clike",
    495    keywords: words("abstract as async await base break case catch checked class const continue" +
    496                    " default delegate do else enum event explicit extern finally fixed for" +
    497                    " foreach goto if implicit in interface internal is lock namespace new" +
    498                    " operator out override params private protected public readonly ref return sealed" +
    499                    " sizeof stackalloc static struct switch this throw try typeof unchecked" +
    500                    " unsafe using virtual void volatile while add alias ascending descending dynamic from get" +
    501                    " global group into join let orderby partial remove select set value var yield"),
    502    types: words("Action Boolean Byte Char DateTime DateTimeOffset Decimal Double Func" +
    503                 " Guid Int16 Int32 Int64 Object SByte Single String Task TimeSpan UInt16 UInt32" +
    504                 " UInt64 bool byte char decimal double short int long object"  +
    505                 " sbyte float string ushort uint ulong"),
    506    blockKeywords: words("catch class do else finally for foreach if struct switch try while"),
    507    defKeywords: words("class interface namespace struct var"),
    508    typeFirstDefinitions: true,
    509    atoms: words("true false null"),
    510    hooks: {
    511      "@": function(stream, state) {
    512        if (stream.eat('"')) {
    513          state.tokenize = tokenAtString;
    514          return tokenAtString(stream, state);
    515        }
    516        stream.eatWhile(/[\w\$_]/);
    517        return "meta";
    518      }
    519    }
    520  });
    521 
    522  function tokenTripleString(stream, state) {
    523    var escaped = false;
    524    while (!stream.eol()) {
    525      if (!escaped && stream.match('"""')) {
    526        state.tokenize = null;
    527        break;
    528      }
    529      escaped = stream.next() == "\\" && !escaped;
    530    }
    531    return "string";
    532  }
    533 
    534  function tokenNestedComment(depth) {
    535    return function (stream, state) {
    536      var ch
    537      while (ch = stream.next()) {
    538        if (ch == "*" && stream.eat("/")) {
    539          if (depth == 1) {
    540            state.tokenize = null
    541            break
    542          } else {
    543            state.tokenize = tokenNestedComment(depth - 1)
    544            return state.tokenize(stream, state)
    545          }
    546        } else if (ch == "/" && stream.eat("*")) {
    547          state.tokenize = tokenNestedComment(depth + 1)
    548          return state.tokenize(stream, state)
    549        }
    550      }
    551      return "comment"
    552    }
    553  }
    554 
    555  def("text/x-scala", {
    556    name: "clike",
    557    keywords: words(
    558      /* scala */
    559      "abstract case catch class def do else extends final finally for forSome if " +
    560      "implicit import lazy match new null object override package private protected return " +
    561      "sealed super this throw trait try type val var while with yield _ " +
    562 
    563      /* package scala */
    564      "assert assume require print println printf readLine readBoolean readByte readShort " +
    565      "readChar readInt readLong readFloat readDouble"
    566    ),
    567    types: words(
    568      "AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either " +
    569      "Enumeration Equiv Error Exception Fractional Function IndexedSeq Int Integral Iterable " +
    570      "Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering " +
    571      "Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder " +
    572      "StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector " +
    573 
    574      /* package java.lang */
    575      "Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " +
    576      "Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " +
    577      "Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " +
    578      "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void"
    579    ),
    580    multiLineStrings: true,
    581    blockKeywords: words("catch class enum do else finally for forSome if match switch try while"),
    582    defKeywords: words("class enum def object package trait type val var"),
    583    atoms: words("true false null"),
    584    indentStatements: false,
    585    indentSwitch: false,
    586    isOperatorChar: /[+\-*&%=<>!?|\/#:@]/,
    587    hooks: {
    588      "@": function(stream) {
    589        stream.eatWhile(/[\w\$_]/);
    590        return "meta";
    591      },
    592      '"': function(stream, state) {
    593        if (!stream.match('""')) return false;
    594        state.tokenize = tokenTripleString;
    595        return state.tokenize(stream, state);
    596      },
    597      "'": function(stream) {
    598        stream.eatWhile(/[\w\$_\xa1-\uffff]/);
    599        return "atom";
    600      },
    601      "=": function(stream, state) {
    602        var cx = state.context
    603        if (cx.type == "}" && cx.align && stream.eat(">")) {
    604          state.context = new Context(cx.indented, cx.column, cx.type, cx.info, null, cx.prev)
    605          return "operator"
    606        } else {
    607          return false
    608        }
    609      },
    610 
    611      "/": function(stream, state) {
    612        if (!stream.eat("*")) return false
    613        state.tokenize = tokenNestedComment(1)
    614        return state.tokenize(stream, state)
    615      }
    616    },
    617    modeProps: {closeBrackets: {pairs: '()[]{}""', triples: '"'}}
    618  });
    619 
    620  function tokenKotlinString(tripleString){
    621    return function (stream, state) {
    622      var escaped = false, next, end = false;
    623      while (!stream.eol()) {
    624        if (!tripleString && !escaped && stream.match('"') ) {end = true; break;}
    625        if (tripleString && stream.match('"""')) {end = true; break;}
    626        next = stream.next();
    627        if(!escaped && next == "$" && stream.match('{'))
    628          stream.skipTo("}");
    629        escaped = !escaped && next == "\\" && !tripleString;
    630      }
    631      if (end || !tripleString)
    632        state.tokenize = null;
    633      return "string";
    634    }
    635  }
    636 
    637  def("text/x-kotlin", {
    638    name: "clike",
    639    keywords: words(
    640      /*keywords*/
    641      "package as typealias class interface this super val operator " +
    642      "var fun for is in This throw return annotation " +
    643      "break continue object if else while do try when !in !is as? " +
    644 
    645      /*soft keywords*/
    646      "file import where by get set abstract enum open inner override private public internal " +
    647      "protected catch finally out final vararg reified dynamic companion constructor init " +
    648      "sealed field property receiver param sparam lateinit data inline noinline tailrec " +
    649      "external annotation crossinline const operator infix suspend actual expect setparam"
    650    ),
    651    types: words(
    652      /* package java.lang */
    653      "Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " +
    654      "Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " +
    655      "Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " +
    656      "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void Annotation Any BooleanArray " +
    657      "ByteArray Char CharArray DeprecationLevel DoubleArray Enum FloatArray Function Int IntArray Lazy " +
    658      "LazyThreadSafetyMode LongArray Nothing ShortArray Unit"
    659    ),
    660    intendSwitch: false,
    661    indentStatements: false,
    662    multiLineStrings: true,
    663    number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+(\.\d+)?|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i,
    664    blockKeywords: words("catch class do else finally for if where try while enum"),
    665    defKeywords: words("class val var object interface fun"),
    666    atoms: words("true false null this"),
    667    hooks: {
    668      "@": function(stream) {
    669        stream.eatWhile(/[\w\$_]/);
    670        return "meta";
    671      },
    672      '*': function(_stream, state) {
    673        return state.prevToken == '.' ? 'variable' : 'operator';
    674      },
    675      '"': function(stream, state) {
    676        state.tokenize = tokenKotlinString(stream.match('""'));
    677        return state.tokenize(stream, state);
    678      },
    679      "/": function(stream, state) {
    680        if (!stream.eat("*")) return false;
    681        state.tokenize = tokenNestedComment(1);
    682        return state.tokenize(stream, state)
    683      },
    684      indent: function(state, ctx, textAfter, indentUnit) {
    685        var firstChar = textAfter && textAfter.charAt(0);
    686        if ((state.prevToken == "}" || state.prevToken == ")") && textAfter == "")
    687          return state.indented;
    688        if ((state.prevToken == "operator" && textAfter != "}" && state.context.type != "}") ||
    689          state.prevToken == "variable" && firstChar == "." ||
    690          (state.prevToken == "}" || state.prevToken == ")") && firstChar == ".")
    691          return indentUnit * 2 + ctx.indented;
    692        if (ctx.align && ctx.type == "}")
    693          return ctx.indented + (state.context.type == (textAfter || "").charAt(0) ? 0 : indentUnit);
    694      }
    695    },
    696    modeProps: {closeBrackets: {triples: '"'}}
    697  });
    698 
    699  def(["x-shader/x-vertex", "x-shader/x-fragment"], {
    700    name: "clike",
    701    keywords: words("sampler1D sampler2D sampler3D samplerCube " +
    702                    "sampler1DShadow sampler2DShadow " +
    703                    "const attribute uniform varying " +
    704                    "break continue discard return " +
    705                    "for while do if else struct " +
    706                    "in out inout"),
    707    types: words("float int bool void " +
    708                 "vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 " +
    709                 "mat2 mat3 mat4"),
    710    blockKeywords: words("for while do if else struct"),
    711    builtin: words("radians degrees sin cos tan asin acos atan " +
    712                    "pow exp log exp2 sqrt inversesqrt " +
    713                    "abs sign floor ceil fract mod min max clamp mix step smoothstep " +
    714                    "length distance dot cross normalize ftransform faceforward " +
    715                    "reflect refract matrixCompMult " +
    716                    "lessThan lessThanEqual greaterThan greaterThanEqual " +
    717                    "equal notEqual any all not " +
    718                    "texture1D texture1DProj texture1DLod texture1DProjLod " +
    719                    "texture2D texture2DProj texture2DLod texture2DProjLod " +
    720                    "texture3D texture3DProj texture3DLod texture3DProjLod " +
    721                    "textureCube textureCubeLod " +
    722                    "shadow1D shadow2D shadow1DProj shadow2DProj " +
    723                    "shadow1DLod shadow2DLod shadow1DProjLod shadow2DProjLod " +
    724                    "dFdx dFdy fwidth " +
    725                    "noise1 noise2 noise3 noise4"),
    726    atoms: words("true false " +
    727                "gl_FragColor gl_SecondaryColor gl_Normal gl_Vertex " +
    728                "gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 " +
    729                "gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 " +
    730                "gl_FogCoord gl_PointCoord " +
    731                "gl_Position gl_PointSize gl_ClipVertex " +
    732                "gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor " +
    733                "gl_TexCoord gl_FogFragCoord " +
    734                "gl_FragCoord gl_FrontFacing " +
    735                "gl_FragData gl_FragDepth " +
    736                "gl_ModelViewMatrix gl_ProjectionMatrix gl_ModelViewProjectionMatrix " +
    737                "gl_TextureMatrix gl_NormalMatrix gl_ModelViewMatrixInverse " +
    738                "gl_ProjectionMatrixInverse gl_ModelViewProjectionMatrixInverse " +
    739                "gl_TexureMatrixTranspose gl_ModelViewMatrixInverseTranspose " +
    740                "gl_ProjectionMatrixInverseTranspose " +
    741                "gl_ModelViewProjectionMatrixInverseTranspose " +
    742                "gl_TextureMatrixInverseTranspose " +
    743                "gl_NormalScale gl_DepthRange gl_ClipPlane " +
    744                "gl_Point gl_FrontMaterial gl_BackMaterial gl_LightSource gl_LightModel " +
    745                "gl_FrontLightModelProduct gl_BackLightModelProduct " +
    746                "gl_TextureColor gl_EyePlaneS gl_EyePlaneT gl_EyePlaneR gl_EyePlaneQ " +
    747                "gl_FogParameters " +
    748                "gl_MaxLights gl_MaxClipPlanes gl_MaxTextureUnits gl_MaxTextureCoords " +
    749                "gl_MaxVertexAttribs gl_MaxVertexUniformComponents gl_MaxVaryingFloats " +
    750                "gl_MaxVertexTextureImageUnits gl_MaxTextureImageUnits " +
    751                "gl_MaxFragmentUniformComponents gl_MaxCombineTextureImageUnits " +
    752                "gl_MaxDrawBuffers"),
    753    indentSwitch: false,
    754    hooks: {"#": cppHook},
    755    modeProps: {fold: ["brace", "include"]}
    756  });
    757 
    758  def("text/x-nesc", {
    759    name: "clike",
    760    keywords: words(cKeywords + " as atomic async call command component components configuration event generic " +
    761                    "implementation includes interface module new norace nx_struct nx_union post provides " +
    762                    "signal task uses abstract extends"),
    763    types: cTypes,
    764    blockKeywords: words(cBlockKeywords),
    765    atoms: words("null true false"),
    766    hooks: {"#": cppHook},
    767    modeProps: {fold: ["brace", "include"]}
    768  });
    769 
    770  def("text/x-objectivec", {
    771    name: "clike",
    772    keywords: words(cKeywords + " bycopy byref in inout oneway out self super atomic nonatomic retain copy " +
    773                    "readwrite readonly strong weak assign typeof nullable nonnull null_resettable _cmd " +
    774                    "@interface @implementation @end @protocol @encode @property @synthesize @dynamic @class " +
    775                    "@public @package @private @protected @required @optional @try @catch @finally @import " +
    776                    "@selector @encode @defs @synchronized @autoreleasepool @compatibility_alias @available"),
    777    types: objCTypes,
    778    builtin: words("FOUNDATION_EXPORT FOUNDATION_EXTERN NS_INLINE NS_FORMAT_FUNCTION NS_RETURNS_RETAINED " +
    779                   "NS_ERROR_ENUM NS_RETURNS_NOT_RETAINED NS_RETURNS_INNER_POINTER NS_DESIGNATED_INITIALIZER " +
    780                   "NS_ENUM NS_OPTIONS NS_REQUIRES_NIL_TERMINATION NS_ASSUME_NONNULL_BEGIN " +
    781                   "NS_ASSUME_NONNULL_END NS_SWIFT_NAME NS_REFINED_FOR_SWIFT"),
    782    blockKeywords: words(cBlockKeywords + " @synthesize @try @catch @finally @autoreleasepool @synchronized"),
    783    defKeywords: words(cDefKeywords + " @interface @implementation @protocol @class"),
    784    dontIndentStatements: /^@.*$/,
    785    typeFirstDefinitions: true,
    786    atoms: words("YES NO NULL Nil nil true false nullptr"),
    787    isReservedIdentifier: cIsReservedIdentifier,
    788    hooks: {
    789      "#": cppHook,
    790      "*": pointerHook,
    791    },
    792    modeProps: {fold: ["brace", "include"]}
    793  });
    794 
    795  def("text/x-squirrel", {
    796    name: "clike",
    797    keywords: words("base break clone continue const default delete enum extends function in class" +
    798                    " foreach local resume return this throw typeof yield constructor instanceof static"),
    799    types: cTypes,
    800    blockKeywords: words("case catch class else for foreach if switch try while"),
    801    defKeywords: words("function local class"),
    802    typeFirstDefinitions: true,
    803    atoms: words("true false null"),
    804    hooks: {"#": cppHook},
    805    modeProps: {fold: ["brace", "include"]}
    806  });
    807 
    808  // Ceylon Strings need to deal with interpolation
    809  var stringTokenizer = null;
    810  function tokenCeylonString(type) {
    811    return function(stream, state) {
    812      var escaped = false, next, end = false;
    813      while (!stream.eol()) {
    814        if (!escaped && stream.match('"') &&
    815              (type == "single" || stream.match('""'))) {
    816          end = true;
    817          break;
    818        }
    819        if (!escaped && stream.match('``')) {
    820          stringTokenizer = tokenCeylonString(type);
    821          end = true;
    822          break;
    823        }
    824        next = stream.next();
    825        escaped = type == "single" && !escaped && next == "\\";
    826      }
    827      if (end)
    828          state.tokenize = null;
    829      return "string";
    830    }
    831  }
    832 
    833  def("text/x-ceylon", {
    834    name: "clike",
    835    keywords: words("abstracts alias assembly assert assign break case catch class continue dynamic else" +
    836                    " exists extends finally for function given if import in interface is let module new" +
    837                    " nonempty object of out outer package return satisfies super switch then this throw" +
    838                    " try value void while"),
    839    types: function(word) {
    840        // In Ceylon all identifiers that start with an uppercase are types
    841        var first = word.charAt(0);
    842        return (first === first.toUpperCase() && first !== first.toLowerCase());
    843    },
    844    blockKeywords: words("case catch class dynamic else finally for function if interface module new object switch try while"),
    845    defKeywords: words("class dynamic function interface module object package value"),
    846    builtin: words("abstract actual aliased annotation by default deprecated doc final formal late license" +
    847                   " native optional sealed see serializable shared suppressWarnings tagged throws variable"),
    848    isPunctuationChar: /[\[\]{}\(\),;\:\.`]/,
    849    isOperatorChar: /[+\-*&%=<>!?|^~:\/]/,
    850    numberStart: /[\d#$]/,
    851    number: /^(?:#[\da-fA-F_]+|\$[01_]+|[\d_]+[kMGTPmunpf]?|[\d_]+\.[\d_]+(?:[eE][-+]?\d+|[kMGTPmunpf]|)|)/i,
    852    multiLineStrings: true,
    853    typeFirstDefinitions: true,
    854    atoms: words("true false null larger smaller equal empty finished"),
    855    indentSwitch: false,
    856    styleDefs: false,
    857    hooks: {
    858      "@": function(stream) {
    859        stream.eatWhile(/[\w\$_]/);
    860        return "meta";
    861      },
    862      '"': function(stream, state) {
    863          state.tokenize = tokenCeylonString(stream.match('""') ? "triple" : "single");
    864          return state.tokenize(stream, state);
    865        },
    866      '`': function(stream, state) {
    867          if (!stringTokenizer || !stream.match('`')) return false;
    868          state.tokenize = stringTokenizer;
    869          stringTokenizer = null;
    870          return state.tokenize(stream, state);
    871        },
    872      "'": function(stream) {
    873        stream.eatWhile(/[\w\$_\xa1-\uffff]/);
    874        return "atom";
    875      },
    876      token: function(_stream, state, style) {
    877          if ((style == "variable" || style == "type") &&
    878              state.prevToken == ".") {
    879            return "variable-2";
    880          }
    881        }
    882    },
    883    modeProps: {
    884        fold: ["brace", "import"],
    885        closeBrackets: {triples: '"'}
    886    }
    887  });
    888 
    889 });