mirror of
				https://github.com/zadam/trilium.git
				synced 2025-11-04 05:28:59 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			313 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			313 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
// CodeMirror, copyright (c) by Marijn Haverbeke and others
 | 
						|
// Distributed under an MIT license: https://codemirror.net/5/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('tiki', function(config) {
 | 
						|
  function inBlock(style, terminator, returnTokenizer) {
 | 
						|
    return function(stream, state) {
 | 
						|
      while (!stream.eol()) {
 | 
						|
        if (stream.match(terminator)) {
 | 
						|
          state.tokenize = inText;
 | 
						|
          break;
 | 
						|
        }
 | 
						|
        stream.next();
 | 
						|
      }
 | 
						|
 | 
						|
      if (returnTokenizer) state.tokenize = returnTokenizer;
 | 
						|
 | 
						|
      return style;
 | 
						|
    };
 | 
						|
  }
 | 
						|
 | 
						|
  function inLine(style) {
 | 
						|
    return function(stream, state) {
 | 
						|
      while(!stream.eol()) {
 | 
						|
        stream.next();
 | 
						|
      }
 | 
						|
      state.tokenize = inText;
 | 
						|
      return style;
 | 
						|
    };
 | 
						|
  }
 | 
						|
 | 
						|
  function inText(stream, state) {
 | 
						|
    function chain(parser) {
 | 
						|
      state.tokenize = parser;
 | 
						|
      return parser(stream, state);
 | 
						|
    }
 | 
						|
 | 
						|
    var sol = stream.sol();
 | 
						|
    var ch = stream.next();
 | 
						|
 | 
						|
    //non start of line
 | 
						|
    switch (ch) { //switch is generally much faster than if, so it is used here
 | 
						|
    case "{": //plugin
 | 
						|
      stream.eat("/");
 | 
						|
      stream.eatSpace();
 | 
						|
      stream.eatWhile(/[^\s\u00a0=\"\'\/?(}]/);
 | 
						|
      state.tokenize = inPlugin;
 | 
						|
      return "tag";
 | 
						|
    case "_": //bold
 | 
						|
      if (stream.eat("_"))
 | 
						|
        return chain(inBlock("strong", "__", inText));
 | 
						|
      break;
 | 
						|
    case "'": //italics
 | 
						|
      if (stream.eat("'"))
 | 
						|
        return chain(inBlock("em", "''", inText));
 | 
						|
      break;
 | 
						|
    case "(":// Wiki Link
 | 
						|
      if (stream.eat("("))
 | 
						|
        return chain(inBlock("variable-2", "))", inText));
 | 
						|
      break;
 | 
						|
    case "[":// Weblink
 | 
						|
      return chain(inBlock("variable-3", "]", inText));
 | 
						|
      break;
 | 
						|
    case "|": //table
 | 
						|
      if (stream.eat("|"))
 | 
						|
        return chain(inBlock("comment", "||"));
 | 
						|
      break;
 | 
						|
    case "-":
 | 
						|
      if (stream.eat("=")) {//titleBar
 | 
						|
        return chain(inBlock("header string", "=-", inText));
 | 
						|
      } else if (stream.eat("-")) {//deleted
 | 
						|
        return chain(inBlock("error tw-deleted", "--", inText));
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    case "=": //underline
 | 
						|
      if (stream.match("=="))
 | 
						|
        return chain(inBlock("tw-underline", "===", inText));
 | 
						|
      break;
 | 
						|
    case ":":
 | 
						|
      if (stream.eat(":"))
 | 
						|
        return chain(inBlock("comment", "::"));
 | 
						|
      break;
 | 
						|
    case "^": //box
 | 
						|
      return chain(inBlock("tw-box", "^"));
 | 
						|
      break;
 | 
						|
    case "~": //np
 | 
						|
      if (stream.match("np~"))
 | 
						|
        return chain(inBlock("meta", "~/np~"));
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //start of line types
 | 
						|
    if (sol) {
 | 
						|
      switch (ch) {
 | 
						|
      case "!": //header at start of line
 | 
						|
        if (stream.match('!!!!!')) {
 | 
						|
          return chain(inLine("header string"));
 | 
						|
        } else if (stream.match('!!!!')) {
 | 
						|
          return chain(inLine("header string"));
 | 
						|
        } else if (stream.match('!!!')) {
 | 
						|
          return chain(inLine("header string"));
 | 
						|
        } else if (stream.match('!!')) {
 | 
						|
          return chain(inLine("header string"));
 | 
						|
        } else {
 | 
						|
          return chain(inLine("header string"));
 | 
						|
        }
 | 
						|
        break;
 | 
						|
      case "*": //unordered list line item, or <li /> at start of line
 | 
						|
      case "#": //ordered list line item, or <li /> at start of line
 | 
						|
      case "+": //ordered list line item, or <li /> at start of line
 | 
						|
        return chain(inLine("tw-listitem bracket"));
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    //stream.eatWhile(/[&{]/); was eating up plugins, turned off to act less like html and more like tiki
 | 
						|
    return null;
 | 
						|
  }
 | 
						|
 | 
						|
  var indentUnit = config.indentUnit;
 | 
						|
 | 
						|
  // Return variables for tokenizers
 | 
						|
  var pluginName, type;
 | 
						|
  function inPlugin(stream, state) {
 | 
						|
    var ch = stream.next();
 | 
						|
    var peek = stream.peek();
 | 
						|
 | 
						|
    if (ch == "}") {
 | 
						|
      state.tokenize = inText;
 | 
						|
      //type = ch == ")" ? "endPlugin" : "selfclosePlugin"; inPlugin
 | 
						|
      return "tag";
 | 
						|
    } else if (ch == "(" || ch == ")") {
 | 
						|
      return "bracket";
 | 
						|
    } else if (ch == "=") {
 | 
						|
      type = "equals";
 | 
						|
 | 
						|
      if (peek == ">") {
 | 
						|
        stream.next();
 | 
						|
        peek = stream.peek();
 | 
						|
      }
 | 
						|
 | 
						|
      //here we detect values directly after equal character with no quotes
 | 
						|
      if (!/[\'\"]/.test(peek)) {
 | 
						|
        state.tokenize = inAttributeNoQuote();
 | 
						|
      }
 | 
						|
      //end detect values
 | 
						|
 | 
						|
      return "operator";
 | 
						|
    } else if (/[\'\"]/.test(ch)) {
 | 
						|
      state.tokenize = inAttribute(ch);
 | 
						|
      return state.tokenize(stream, state);
 | 
						|
    } else {
 | 
						|
      stream.eatWhile(/[^\s\u00a0=\"\'\/?]/);
 | 
						|
      return "keyword";
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  function inAttribute(quote) {
 | 
						|
    return function(stream, state) {
 | 
						|
      while (!stream.eol()) {
 | 
						|
        if (stream.next() == quote) {
 | 
						|
          state.tokenize = inPlugin;
 | 
						|
          break;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      return "string";
 | 
						|
    };
 | 
						|
  }
 | 
						|
 | 
						|
  function inAttributeNoQuote() {
 | 
						|
    return function(stream, state) {
 | 
						|
      while (!stream.eol()) {
 | 
						|
        var ch = stream.next();
 | 
						|
        var peek = stream.peek();
 | 
						|
        if (ch == " " || ch == "," || /[ )}]/.test(peek)) {
 | 
						|
      state.tokenize = inPlugin;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return "string";
 | 
						|
};
 | 
						|
                     }
 | 
						|
 | 
						|
var curState, setStyle;
 | 
						|
function pass() {
 | 
						|
  for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]);
 | 
						|
}
 | 
						|
 | 
						|
function cont() {
 | 
						|
  pass.apply(null, arguments);
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
function pushContext(pluginName, startOfLine) {
 | 
						|
  var noIndent = curState.context && curState.context.noIndent;
 | 
						|
  curState.context = {
 | 
						|
    prev: curState.context,
 | 
						|
    pluginName: pluginName,
 | 
						|
    indent: curState.indented,
 | 
						|
    startOfLine: startOfLine,
 | 
						|
    noIndent: noIndent
 | 
						|
  };
 | 
						|
}
 | 
						|
 | 
						|
function popContext() {
 | 
						|
  if (curState.context) curState.context = curState.context.prev;
 | 
						|
}
 | 
						|
 | 
						|
function element(type) {
 | 
						|
  if (type == "openPlugin") {curState.pluginName = pluginName; return cont(attributes, endplugin(curState.startOfLine));}
 | 
						|
  else if (type == "closePlugin") {
 | 
						|
    var err = false;
 | 
						|
    if (curState.context) {
 | 
						|
      err = curState.context.pluginName != pluginName;
 | 
						|
      popContext();
 | 
						|
    } else {
 | 
						|
      err = true;
 | 
						|
    }
 | 
						|
    if (err) setStyle = "error";
 | 
						|
    return cont(endcloseplugin(err));
 | 
						|
  }
 | 
						|
  else if (type == "string") {
 | 
						|
    if (!curState.context || curState.context.name != "!cdata") pushContext("!cdata");
 | 
						|
    if (curState.tokenize == inText) popContext();
 | 
						|
    return cont();
 | 
						|
  }
 | 
						|
  else return cont();
 | 
						|
}
 | 
						|
 | 
						|
function endplugin(startOfLine) {
 | 
						|
  return function(type) {
 | 
						|
    if (
 | 
						|
      type == "selfclosePlugin" ||
 | 
						|
        type == "endPlugin"
 | 
						|
    )
 | 
						|
      return cont();
 | 
						|
    if (type == "endPlugin") {pushContext(curState.pluginName, startOfLine); return cont();}
 | 
						|
    return cont();
 | 
						|
  };
 | 
						|
}
 | 
						|
 | 
						|
function endcloseplugin(err) {
 | 
						|
  return function(type) {
 | 
						|
    if (err) setStyle = "error";
 | 
						|
    if (type == "endPlugin") return cont();
 | 
						|
    return pass();
 | 
						|
  };
 | 
						|
}
 | 
						|
 | 
						|
function attributes(type) {
 | 
						|
  if (type == "keyword") {setStyle = "attribute"; return cont(attributes);}
 | 
						|
  if (type == "equals") return cont(attvalue, attributes);
 | 
						|
  return pass();
 | 
						|
}
 | 
						|
function attvalue(type) {
 | 
						|
  if (type == "keyword") {setStyle = "string"; return cont();}
 | 
						|
  if (type == "string") return cont(attvaluemaybe);
 | 
						|
  return pass();
 | 
						|
}
 | 
						|
function attvaluemaybe(type) {
 | 
						|
  if (type == "string") return cont(attvaluemaybe);
 | 
						|
  else return pass();
 | 
						|
}
 | 
						|
return {
 | 
						|
  startState: function() {
 | 
						|
    return {tokenize: inText, cc: [], indented: 0, startOfLine: true, pluginName: null, context: null};
 | 
						|
  },
 | 
						|
  token: function(stream, state) {
 | 
						|
    if (stream.sol()) {
 | 
						|
      state.startOfLine = true;
 | 
						|
      state.indented = stream.indentation();
 | 
						|
    }
 | 
						|
    if (stream.eatSpace()) return null;
 | 
						|
 | 
						|
    setStyle = type = pluginName = null;
 | 
						|
    var style = state.tokenize(stream, state);
 | 
						|
    if ((style || type) && style != "comment") {
 | 
						|
      curState = state;
 | 
						|
      while (true) {
 | 
						|
        var comb = state.cc.pop() || element;
 | 
						|
        if (comb(type || style)) break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    state.startOfLine = false;
 | 
						|
    return setStyle || style;
 | 
						|
  },
 | 
						|
  indent: function(state, textAfter) {
 | 
						|
    var context = state.context;
 | 
						|
    if (context && context.noIndent) return 0;
 | 
						|
    if (context && /^{\//.test(textAfter))
 | 
						|
        context = context.prev;
 | 
						|
    while (context && !context.startOfLine)
 | 
						|
        context = context.prev;
 | 
						|
    if (context) return context.indent + indentUnit;
 | 
						|
    else return 0;
 | 
						|
  },
 | 
						|
  electricChars: "/"
 | 
						|
};
 | 
						|
});
 | 
						|
 | 
						|
CodeMirror.defineMIME("text/tiki", "tiki");
 | 
						|
 | 
						|
});
 |