// CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: https://codemirror.net/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) // Plain browser env else 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') })