mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-10-27 01:51:34 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			265 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			265 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| // CodeMirror, copyright (c) by Marijn Haverbeke and others
 | |
| // Distributed under an MIT license: https://codemirror.net/5/LICENSE
 | |
| 
 | |
| /*
 | |
|  * Author: Constantin Jucovschi (c.jucovschi@jacobs-university.de)
 | |
|  * Licence: MIT
 | |
|  */
 | |
| 
 | |
| (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("stex", function(_config, parserConfig) {
 | |
|     "use strict";
 | |
| 
 | |
|     function pushCommand(state, command) {
 | |
|       state.cmdState.push(command);
 | |
|     }
 | |
| 
 | |
|     function peekCommand(state) {
 | |
|       if (state.cmdState.length > 0) {
 | |
|         return state.cmdState[state.cmdState.length - 1];
 | |
|       } else {
 | |
|         return null;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     function popCommand(state) {
 | |
|       var plug = state.cmdState.pop();
 | |
|       if (plug) {
 | |
|         plug.closeBracket();
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     // returns the non-default plugin closest to the end of the list
 | |
|     function getMostPowerful(state) {
 | |
|       var context = state.cmdState;
 | |
|       for (var i = context.length - 1; i >= 0; i--) {
 | |
|         var plug = context[i];
 | |
|         if (plug.name == "DEFAULT") {
 | |
|           continue;
 | |
|         }
 | |
|         return plug;
 | |
|       }
 | |
|       return { styleIdentifier: function() { return null; } };
 | |
|     }
 | |
| 
 | |
|     function addPluginPattern(pluginName, cmdStyle, styles) {
 | |
|       return function () {
 | |
|         this.name = pluginName;
 | |
|         this.bracketNo = 0;
 | |
|         this.style = cmdStyle;
 | |
|         this.styles = styles;
 | |
|         this.argument = null;   // \begin and \end have arguments that follow. These are stored in the plugin
 | |
| 
 | |
|         this.styleIdentifier = function() {
 | |
|           return this.styles[this.bracketNo - 1] || null;
 | |
|         };
 | |
|         this.openBracket = function() {
 | |
|           this.bracketNo++;
 | |
|           return "bracket";
 | |
|         };
 | |
|         this.closeBracket = function() {};
 | |
|       };
 | |
|     }
 | |
| 
 | |
|     var plugins = {};
 | |
| 
 | |
|     plugins["importmodule"] = addPluginPattern("importmodule", "tag", ["string", "builtin"]);
 | |
|     plugins["documentclass"] = addPluginPattern("documentclass", "tag", ["", "atom"]);
 | |
|     plugins["usepackage"] = addPluginPattern("usepackage", "tag", ["atom"]);
 | |
|     plugins["begin"] = addPluginPattern("begin", "tag", ["atom"]);
 | |
|     plugins["end"] = addPluginPattern("end", "tag", ["atom"]);
 | |
| 
 | |
|     plugins["label"    ] = addPluginPattern("label"    , "tag", ["atom"]);
 | |
|     plugins["ref"      ] = addPluginPattern("ref"      , "tag", ["atom"]);
 | |
|     plugins["eqref"    ] = addPluginPattern("eqref"    , "tag", ["atom"]);
 | |
|     plugins["cite"     ] = addPluginPattern("cite"     , "tag", ["atom"]);
 | |
|     plugins["bibitem"  ] = addPluginPattern("bibitem"  , "tag", ["atom"]);
 | |
|     plugins["Bibitem"  ] = addPluginPattern("Bibitem"  , "tag", ["atom"]);
 | |
|     plugins["RBibitem" ] = addPluginPattern("RBibitem" , "tag", ["atom"]);
 | |
| 
 | |
|     plugins["DEFAULT"] = function () {
 | |
|       this.name = "DEFAULT";
 | |
|       this.style = "tag";
 | |
| 
 | |
|       this.styleIdentifier = this.openBracket = this.closeBracket = function() {};
 | |
|     };
 | |
| 
 | |
|     function setState(state, f) {
 | |
|       state.f = f;
 | |
|     }
 | |
| 
 | |
|     // called when in a normal (no environment) context
 | |
|     function normal(source, state) {
 | |
|       var plug;
 | |
|       // Do we look like '\command' ?  If so, attempt to apply the plugin 'command'
 | |
|       if (source.match(/^\\[a-zA-Z@]+/)) {
 | |
|         var cmdName = source.current().slice(1);
 | |
|         plug = plugins.hasOwnProperty(cmdName) ? plugins[cmdName] : plugins["DEFAULT"];
 | |
|         plug = new plug();
 | |
|         pushCommand(state, plug);
 | |
|         setState(state, beginParams);
 | |
|         return plug.style;
 | |
|       }
 | |
| 
 | |
|       // escape characters
 | |
|       if (source.match(/^\\[$&%#{}_]/)) {
 | |
|         return "tag";
 | |
|       }
 | |
| 
 | |
|       // white space control characters
 | |
|       if (source.match(/^\\[,;!\/\\]/)) {
 | |
|         return "tag";
 | |
|       }
 | |
| 
 | |
|       // find if we're starting various math modes
 | |
|       if (source.match("\\[")) {
 | |
|         setState(state, function(source, state){ return inMathMode(source, state, "\\]"); });
 | |
|         return "keyword";
 | |
|       }
 | |
|       if (source.match("\\(")) {
 | |
|         setState(state, function(source, state){ return inMathMode(source, state, "\\)"); });
 | |
|         return "keyword";
 | |
|       }
 | |
|       if (source.match("$$")) {
 | |
|         setState(state, function(source, state){ return inMathMode(source, state, "$$"); });
 | |
|         return "keyword";
 | |
|       }
 | |
|       if (source.match("$")) {
 | |
|         setState(state, function(source, state){ return inMathMode(source, state, "$"); });
 | |
|         return "keyword";
 | |
|       }
 | |
| 
 | |
|       var ch = source.next();
 | |
|       if (ch == "%") {
 | |
|         source.skipToEnd();
 | |
|         return "comment";
 | |
|       } else if (ch == '}' || ch == ']') {
 | |
|         plug = peekCommand(state);
 | |
|         if (plug) {
 | |
|           plug.closeBracket(ch);
 | |
|           setState(state, beginParams);
 | |
|         } else {
 | |
|           return "error";
 | |
|         }
 | |
|         return "bracket";
 | |
|       } else if (ch == '{' || ch == '[') {
 | |
|         plug = plugins["DEFAULT"];
 | |
|         plug = new plug();
 | |
|         pushCommand(state, plug);
 | |
|         return "bracket";
 | |
|       } else if (/\d/.test(ch)) {
 | |
|         source.eatWhile(/[\w.%]/);
 | |
|         return "atom";
 | |
|       } else {
 | |
|         source.eatWhile(/[\w\-_]/);
 | |
|         plug = getMostPowerful(state);
 | |
|         if (plug.name == 'begin') {
 | |
|           plug.argument = source.current();
 | |
|         }
 | |
|         return plug.styleIdentifier();
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     function inMathMode(source, state, endModeSeq) {
 | |
|       if (source.eatSpace()) {
 | |
|         return null;
 | |
|       }
 | |
|       if (endModeSeq && source.match(endModeSeq)) {
 | |
|         setState(state, normal);
 | |
|         return "keyword";
 | |
|       }
 | |
|       if (source.match(/^\\[a-zA-Z@]+/)) {
 | |
|         return "tag";
 | |
|       }
 | |
|       if (source.match(/^[a-zA-Z]+/)) {
 | |
|         return "variable-2";
 | |
|       }
 | |
|       // escape characters
 | |
|       if (source.match(/^\\[$&%#{}_]/)) {
 | |
|         return "tag";
 | |
|       }
 | |
|       // white space control characters
 | |
|       if (source.match(/^\\[,;!\/]/)) {
 | |
|         return "tag";
 | |
|       }
 | |
|       // special math-mode characters
 | |
|       if (source.match(/^[\^_&]/)) {
 | |
|         return "tag";
 | |
|       }
 | |
|       // non-special characters
 | |
|       if (source.match(/^[+\-<>|=,\/@!*:;'"`~#?]/)) {
 | |
|         return null;
 | |
|       }
 | |
|       if (source.match(/^(\d+\.\d*|\d*\.\d+|\d+)/)) {
 | |
|         return "number";
 | |
|       }
 | |
|       var ch = source.next();
 | |
|       if (ch == "{" || ch == "}" || ch == "[" || ch == "]" || ch == "(" || ch == ")") {
 | |
|         return "bracket";
 | |
|       }
 | |
| 
 | |
|       if (ch == "%") {
 | |
|         source.skipToEnd();
 | |
|         return "comment";
 | |
|       }
 | |
|       return "error";
 | |
|     }
 | |
| 
 | |
|     function beginParams(source, state) {
 | |
|       var ch = source.peek(), lastPlug;
 | |
|       if (ch == '{' || ch == '[') {
 | |
|         lastPlug = peekCommand(state);
 | |
|         lastPlug.openBracket(ch);
 | |
|         source.eat(ch);
 | |
|         setState(state, normal);
 | |
|         return "bracket";
 | |
|       }
 | |
|       if (/[ \t\r]/.test(ch)) {
 | |
|         source.eat(ch);
 | |
|         return null;
 | |
|       }
 | |
|       setState(state, normal);
 | |
|       popCommand(state);
 | |
| 
 | |
|       return normal(source, state);
 | |
|     }
 | |
| 
 | |
|     return {
 | |
|       startState: function() {
 | |
|         var f = parserConfig.inMathMode ? function(source, state){ return inMathMode(source, state); } : normal;
 | |
|         return {
 | |
|           cmdState: [],
 | |
|           f: f
 | |
|         };
 | |
|       },
 | |
|       copyState: function(s) {
 | |
|         return {
 | |
|           cmdState: s.cmdState.slice(),
 | |
|           f: s.f
 | |
|         };
 | |
|       },
 | |
|       token: function(stream, state) {
 | |
|         return state.f(stream, state);
 | |
|       },
 | |
|       blankLine: function(state) {
 | |
|         state.f = normal;
 | |
|         state.cmdState.length = 0;
 | |
|       },
 | |
|       lineComment: "%"
 | |
|     };
 | |
|   });
 | |
| 
 | |
|   CodeMirror.defineMIME("text/x-stex", "stex");
 | |
|   CodeMirror.defineMIME("text/x-latex", "stex");
 | |
| 
 | |
| });
 | 
