mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-11-04 15:11:31 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			253 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			253 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
// CodeMirror, copyright (c) by Marijn Haverbeke and others
 | 
						|
// Distributed under an MIT license: https://codemirror.net/LICENSE
 | 
						|
 | 
						|
(function(mod) {
 | 
						|
  if (typeof exports == "object" && typeof module == "object") // CommonJS
 | 
						|
    mod(require("../../lib/codemirror"));
 | 
						|
  else if (typeof define == "function" && define.amd) // AMD
 | 
						|
    define(["../../lib/codemirror"], mod);
 | 
						|
  else // Plain browser env
 | 
						|
    mod(CodeMirror);
 | 
						|
})(function(CodeMirror) {
 | 
						|
"use strict";
 | 
						|
 | 
						|
CodeMirror.defineMode("oz", function (conf) {
 | 
						|
 | 
						|
  function wordRegexp(words) {
 | 
						|
    return new RegExp("^((" + words.join(")|(") + "))\\b");
 | 
						|
  }
 | 
						|
 | 
						|
  var singleOperators = /[\^@!\|<>#~\.\*\-\+\\/,=]/;
 | 
						|
  var doubleOperators = /(<-)|(:=)|(=<)|(>=)|(<=)|(<:)|(>:)|(=:)|(\\=)|(\\=:)|(!!)|(==)|(::)/;
 | 
						|
  var tripleOperators = /(:::)|(\.\.\.)|(=<:)|(>=:)/;
 | 
						|
 | 
						|
  var middle = ["in", "then", "else", "of", "elseof", "elsecase", "elseif", "catch",
 | 
						|
    "finally", "with", "require", "prepare", "import", "export", "define", "do"];
 | 
						|
  var end = ["end"];
 | 
						|
 | 
						|
  var atoms = wordRegexp(["true", "false", "nil", "unit"]);
 | 
						|
  var commonKeywords = wordRegexp(["andthen", "at", "attr", "declare", "feat", "from", "lex",
 | 
						|
    "mod", "div", "mode", "orelse", "parser", "prod", "prop", "scanner", "self", "syn", "token"]);
 | 
						|
  var openingKeywords = wordRegexp(["local", "proc", "fun", "case", "class", "if", "cond", "or", "dis",
 | 
						|
    "choice", "not", "thread", "try", "raise", "lock", "for", "suchthat", "meth", "functor"]);
 | 
						|
  var middleKeywords = wordRegexp(middle);
 | 
						|
  var endKeywords = wordRegexp(end);
 | 
						|
 | 
						|
  // Tokenizers
 | 
						|
  function tokenBase(stream, state) {
 | 
						|
    if (stream.eatSpace()) {
 | 
						|
      return null;
 | 
						|
    }
 | 
						|
 | 
						|
    // Brackets
 | 
						|
    if(stream.match(/[{}]/)) {
 | 
						|
      return "bracket";
 | 
						|
    }
 | 
						|
 | 
						|
    // Special [] keyword
 | 
						|
    if (stream.match(/(\[])/)) {
 | 
						|
        return "keyword"
 | 
						|
    }
 | 
						|
 | 
						|
    // Operators
 | 
						|
    if (stream.match(tripleOperators) || stream.match(doubleOperators)) {
 | 
						|
      return "operator";
 | 
						|
    }
 | 
						|
 | 
						|
    // Atoms
 | 
						|
    if(stream.match(atoms)) {
 | 
						|
      return 'atom';
 | 
						|
    }
 | 
						|
 | 
						|
    // Opening keywords
 | 
						|
    var matched = stream.match(openingKeywords);
 | 
						|
    if (matched) {
 | 
						|
      if (!state.doInCurrentLine)
 | 
						|
        state.currentIndent++;
 | 
						|
      else
 | 
						|
        state.doInCurrentLine = false;
 | 
						|
 | 
						|
      // Special matching for signatures
 | 
						|
      if(matched[0] == "proc" || matched[0] == "fun")
 | 
						|
        state.tokenize = tokenFunProc;
 | 
						|
      else if(matched[0] == "class")
 | 
						|
        state.tokenize = tokenClass;
 | 
						|
      else if(matched[0] == "meth")
 | 
						|
        state.tokenize = tokenMeth;
 | 
						|
 | 
						|
      return 'keyword';
 | 
						|
    }
 | 
						|
 | 
						|
    // Middle and other keywords
 | 
						|
    if (stream.match(middleKeywords) || stream.match(commonKeywords)) {
 | 
						|
      return "keyword"
 | 
						|
    }
 | 
						|
 | 
						|
    // End keywords
 | 
						|
    if (stream.match(endKeywords)) {
 | 
						|
      state.currentIndent--;
 | 
						|
      return 'keyword';
 | 
						|
    }
 | 
						|
 | 
						|
    // Eat the next char for next comparisons
 | 
						|
    var ch = stream.next();
 | 
						|
 | 
						|
    // Strings
 | 
						|
    if (ch == '"' || ch == "'") {
 | 
						|
      state.tokenize = tokenString(ch);
 | 
						|
      return state.tokenize(stream, state);
 | 
						|
    }
 | 
						|
 | 
						|
    // Numbers
 | 
						|
    if (/[~\d]/.test(ch)) {
 | 
						|
      if (ch == "~") {
 | 
						|
        if(! /^[0-9]/.test(stream.peek()))
 | 
						|
          return null;
 | 
						|
        else if (( stream.next() == "0" && stream.match(/^[xX][0-9a-fA-F]+/)) || stream.match(/^[0-9]*(\.[0-9]+)?([eE][~+]?[0-9]+)?/))
 | 
						|
          return "number";
 | 
						|
      }
 | 
						|
 | 
						|
      if ((ch == "0" && stream.match(/^[xX][0-9a-fA-F]+/)) || stream.match(/^[0-9]*(\.[0-9]+)?([eE][~+]?[0-9]+)?/))
 | 
						|
        return "number";
 | 
						|
 | 
						|
      return null;
 | 
						|
    }
 | 
						|
 | 
						|
    // Comments
 | 
						|
    if (ch == "%") {
 | 
						|
      stream.skipToEnd();
 | 
						|
      return 'comment';
 | 
						|
    }
 | 
						|
    else if (ch == "/") {
 | 
						|
      if (stream.eat("*")) {
 | 
						|
        state.tokenize = tokenComment;
 | 
						|
        return tokenComment(stream, state);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    // Single operators
 | 
						|
    if(singleOperators.test(ch)) {
 | 
						|
      return "operator";
 | 
						|
    }
 | 
						|
 | 
						|
    // If nothing match, we skip the entire alphanumerical block
 | 
						|
    stream.eatWhile(/\w/);
 | 
						|
 | 
						|
    return "variable";
 | 
						|
  }
 | 
						|
 | 
						|
  function tokenClass(stream, state) {
 | 
						|
    if (stream.eatSpace()) {
 | 
						|
      return null;
 | 
						|
    }
 | 
						|
    stream.match(/([A-Z][A-Za-z0-9_]*)|(`.+`)/);
 | 
						|
    state.tokenize = tokenBase;
 | 
						|
    return "variable-3"
 | 
						|
  }
 | 
						|
 | 
						|
  function tokenMeth(stream, state) {
 | 
						|
    if (stream.eatSpace()) {
 | 
						|
      return null;
 | 
						|
    }
 | 
						|
    stream.match(/([a-zA-Z][A-Za-z0-9_]*)|(`.+`)/);
 | 
						|
    state.tokenize = tokenBase;
 | 
						|
    return "def"
 | 
						|
  }
 | 
						|
 | 
						|
  function tokenFunProc(stream, state) {
 | 
						|
    if (stream.eatSpace()) {
 | 
						|
      return null;
 | 
						|
    }
 | 
						|
 | 
						|
    if(!state.hasPassedFirstStage && stream.eat("{")) {
 | 
						|
      state.hasPassedFirstStage = true;
 | 
						|
      return "bracket";
 | 
						|
    }
 | 
						|
    else if(state.hasPassedFirstStage) {
 | 
						|
      stream.match(/([A-Z][A-Za-z0-9_]*)|(`.+`)|\$/);
 | 
						|
      state.hasPassedFirstStage = false;
 | 
						|
      state.tokenize = tokenBase;
 | 
						|
      return "def"
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      state.tokenize = tokenBase;
 | 
						|
      return null;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  function tokenComment(stream, state) {
 | 
						|
    var maybeEnd = false, ch;
 | 
						|
    while (ch = stream.next()) {
 | 
						|
      if (ch == "/" && maybeEnd) {
 | 
						|
        state.tokenize = tokenBase;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      maybeEnd = (ch == "*");
 | 
						|
    }
 | 
						|
    return "comment";
 | 
						|
  }
 | 
						|
 | 
						|
  function tokenString(quote) {
 | 
						|
    return function (stream, state) {
 | 
						|
      var escaped = false, next, end = false;
 | 
						|
      while ((next = stream.next()) != null) {
 | 
						|
        if (next == quote && !escaped) {
 | 
						|
          end = true;
 | 
						|
          break;
 | 
						|
        }
 | 
						|
        escaped = !escaped && next == "\\";
 | 
						|
      }
 | 
						|
      if (end || !escaped)
 | 
						|
        state.tokenize = tokenBase;
 | 
						|
      return "string";
 | 
						|
    };
 | 
						|
  }
 | 
						|
 | 
						|
  function buildElectricInputRegEx() {
 | 
						|
    // Reindentation should occur on [] or on a match of any of
 | 
						|
    // the block closing keywords, at the end of a line.
 | 
						|
    var allClosings = middle.concat(end);
 | 
						|
    return new RegExp("[\\[\\]]|(" + allClosings.join("|") + ")$");
 | 
						|
  }
 | 
						|
 | 
						|
  return {
 | 
						|
 | 
						|
    startState: function () {
 | 
						|
      return {
 | 
						|
        tokenize: tokenBase,
 | 
						|
        currentIndent: 0,
 | 
						|
        doInCurrentLine: false,
 | 
						|
        hasPassedFirstStage: false
 | 
						|
      };
 | 
						|
    },
 | 
						|
 | 
						|
    token: function (stream, state) {
 | 
						|
      if (stream.sol())
 | 
						|
        state.doInCurrentLine = 0;
 | 
						|
 | 
						|
      return state.tokenize(stream, state);
 | 
						|
    },
 | 
						|
 | 
						|
    indent: function (state, textAfter) {
 | 
						|
      var trueText = textAfter.replace(/^\s+|\s+$/g, '');
 | 
						|
 | 
						|
      if (trueText.match(endKeywords) || trueText.match(middleKeywords) || trueText.match(/(\[])/))
 | 
						|
        return conf.indentUnit * (state.currentIndent - 1);
 | 
						|
 | 
						|
      if (state.currentIndent < 0)
 | 
						|
        return 0;
 | 
						|
 | 
						|
      return state.currentIndent * conf.indentUnit;
 | 
						|
    },
 | 
						|
    fold: "indent",
 | 
						|
    electricInput: buildElectricInputRegEx(),
 | 
						|
    lineComment: "%",
 | 
						|
    blockCommentStart: "/*",
 | 
						|
    blockCommentEnd: "*/"
 | 
						|
  };
 | 
						|
});
 | 
						|
 | 
						|
CodeMirror.defineMIME("text/x-oz", "oz");
 | 
						|
 | 
						|
});
 |