|
- // 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('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");
-
- });
|