all repos — NoPaste @ 29b774f090102303e43cf939b38ac2083e62d9f1

Resurrected - The PussTheCat.org fork of NoPaste

scripts/CodeMirror/mode/tiki/tiki.js (view raw)

  1// CodeMirror, copyright (c) by Marijn Haverbeke and others
  2// Distributed under an MIT license: https://codemirror.net/LICENSE
  3
  4(function(mod) {
  5  if (typeof exports == "object" && typeof module == "object") // CommonJS
  6    mod(require("../../lib/codemirror"));
  7  else if (typeof define == "function" && define.amd) // AMD
  8    define(["../../lib/codemirror"], mod);
  9  else // Plain browser env
 10    mod(CodeMirror);
 11})(function(CodeMirror) {
 12"use strict";
 13
 14CodeMirror.defineMode('tiki', function(config) {
 15  function inBlock(style, terminator, returnTokenizer) {
 16    return function(stream, state) {
 17      while (!stream.eol()) {
 18        if (stream.match(terminator)) {
 19          state.tokenize = inText;
 20          break;
 21        }
 22        stream.next();
 23      }
 24
 25      if (returnTokenizer) state.tokenize = returnTokenizer;
 26
 27      return style;
 28    };
 29  }
 30
 31  function inLine(style) {
 32    return function(stream, state) {
 33      while(!stream.eol()) {
 34        stream.next();
 35      }
 36      state.tokenize = inText;
 37      return style;
 38    };
 39  }
 40
 41  function inText(stream, state) {
 42    function chain(parser) {
 43      state.tokenize = parser;
 44      return parser(stream, state);
 45    }
 46
 47    var sol = stream.sol();
 48    var ch = stream.next();
 49
 50    //non start of line
 51    switch (ch) { //switch is generally much faster than if, so it is used here
 52    case "{": //plugin
 53      stream.eat("/");
 54      stream.eatSpace();
 55      stream.eatWhile(/[^\s\u00a0=\"\'\/?(}]/);
 56      state.tokenize = inPlugin;
 57      return "tag";
 58    case "_": //bold
 59      if (stream.eat("_"))
 60        return chain(inBlock("strong", "__", inText));
 61      break;
 62    case "'": //italics
 63      if (stream.eat("'"))
 64        return chain(inBlock("em", "''", inText));
 65      break;
 66    case "(":// Wiki Link
 67      if (stream.eat("("))
 68        return chain(inBlock("variable-2", "))", inText));
 69      break;
 70    case "[":// Weblink
 71      return chain(inBlock("variable-3", "]", inText));
 72      break;
 73    case "|": //table
 74      if (stream.eat("|"))
 75        return chain(inBlock("comment", "||"));
 76      break;
 77    case "-":
 78      if (stream.eat("=")) {//titleBar
 79        return chain(inBlock("header string", "=-", inText));
 80      } else if (stream.eat("-")) {//deleted
 81        return chain(inBlock("error tw-deleted", "--", inText));
 82      }
 83      break;
 84    case "=": //underline
 85      if (stream.match("=="))
 86        return chain(inBlock("tw-underline", "===", inText));
 87      break;
 88    case ":":
 89      if (stream.eat(":"))
 90        return chain(inBlock("comment", "::"));
 91      break;
 92    case "^": //box
 93      return chain(inBlock("tw-box", "^"));
 94      break;
 95    case "~": //np
 96      if (stream.match("np~"))
 97        return chain(inBlock("meta", "~/np~"));
 98      break;
 99    }
100
101    //start of line types
102    if (sol) {
103      switch (ch) {
104      case "!": //header at start of line
105        if (stream.match('!!!!!')) {
106          return chain(inLine("header string"));
107        } else if (stream.match('!!!!')) {
108          return chain(inLine("header string"));
109        } else if (stream.match('!!!')) {
110          return chain(inLine("header string"));
111        } else if (stream.match('!!')) {
112          return chain(inLine("header string"));
113        } else {
114          return chain(inLine("header string"));
115        }
116        break;
117      case "*": //unordered list line item, or <li /> at start of line
118      case "#": //ordered list line item, or <li /> at start of line
119      case "+": //ordered list line item, or <li /> at start of line
120        return chain(inLine("tw-listitem bracket"));
121        break;
122      }
123    }
124
125    //stream.eatWhile(/[&{]/); was eating up plugins, turned off to act less like html and more like tiki
126    return null;
127  }
128
129  var indentUnit = config.indentUnit;
130
131  // Return variables for tokenizers
132  var pluginName, type;
133  function inPlugin(stream, state) {
134    var ch = stream.next();
135    var peek = stream.peek();
136
137    if (ch == "}") {
138      state.tokenize = inText;
139      //type = ch == ")" ? "endPlugin" : "selfclosePlugin"; inPlugin
140      return "tag";
141    } else if (ch == "(" || ch == ")") {
142      return "bracket";
143    } else if (ch == "=") {
144      type = "equals";
145
146      if (peek == ">") {
147        stream.next();
148        peek = stream.peek();
149      }
150
151      //here we detect values directly after equal character with no quotes
152      if (!/[\'\"]/.test(peek)) {
153        state.tokenize = inAttributeNoQuote();
154      }
155      //end detect values
156
157      return "operator";
158    } else if (/[\'\"]/.test(ch)) {
159      state.tokenize = inAttribute(ch);
160      return state.tokenize(stream, state);
161    } else {
162      stream.eatWhile(/[^\s\u00a0=\"\'\/?]/);
163      return "keyword";
164    }
165  }
166
167  function inAttribute(quote) {
168    return function(stream, state) {
169      while (!stream.eol()) {
170        if (stream.next() == quote) {
171          state.tokenize = inPlugin;
172          break;
173        }
174      }
175      return "string";
176    };
177  }
178
179  function inAttributeNoQuote() {
180    return function(stream, state) {
181      while (!stream.eol()) {
182        var ch = stream.next();
183        var peek = stream.peek();
184        if (ch == " " || ch == "," || /[ )}]/.test(peek)) {
185      state.tokenize = inPlugin;
186      break;
187    }
188  }
189  return "string";
190};
191                     }
192
193var curState, setStyle;
194function pass() {
195  for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]);
196}
197
198function cont() {
199  pass.apply(null, arguments);
200  return true;
201}
202
203function pushContext(pluginName, startOfLine) {
204  var noIndent = curState.context && curState.context.noIndent;
205  curState.context = {
206    prev: curState.context,
207    pluginName: pluginName,
208    indent: curState.indented,
209    startOfLine: startOfLine,
210    noIndent: noIndent
211  };
212}
213
214function popContext() {
215  if (curState.context) curState.context = curState.context.prev;
216}
217
218function element(type) {
219  if (type == "openPlugin") {curState.pluginName = pluginName; return cont(attributes, endplugin(curState.startOfLine));}
220  else if (type == "closePlugin") {
221    var err = false;
222    if (curState.context) {
223      err = curState.context.pluginName != pluginName;
224      popContext();
225    } else {
226      err = true;
227    }
228    if (err) setStyle = "error";
229    return cont(endcloseplugin(err));
230  }
231  else if (type == "string") {
232    if (!curState.context || curState.context.name != "!cdata") pushContext("!cdata");
233    if (curState.tokenize == inText) popContext();
234    return cont();
235  }
236  else return cont();
237}
238
239function endplugin(startOfLine) {
240  return function(type) {
241    if (
242      type == "selfclosePlugin" ||
243        type == "endPlugin"
244    )
245      return cont();
246    if (type == "endPlugin") {pushContext(curState.pluginName, startOfLine); return cont();}
247    return cont();
248  };
249}
250
251function endcloseplugin(err) {
252  return function(type) {
253    if (err) setStyle = "error";
254    if (type == "endPlugin") return cont();
255    return pass();
256  };
257}
258
259function attributes(type) {
260  if (type == "keyword") {setStyle = "attribute"; return cont(attributes);}
261  if (type == "equals") return cont(attvalue, attributes);
262  return pass();
263}
264function attvalue(type) {
265  if (type == "keyword") {setStyle = "string"; return cont();}
266  if (type == "string") return cont(attvaluemaybe);
267  return pass();
268}
269function attvaluemaybe(type) {
270  if (type == "string") return cont(attvaluemaybe);
271  else return pass();
272}
273return {
274  startState: function() {
275    return {tokenize: inText, cc: [], indented: 0, startOfLine: true, pluginName: null, context: null};
276  },
277  token: function(stream, state) {
278    if (stream.sol()) {
279      state.startOfLine = true;
280      state.indented = stream.indentation();
281    }
282    if (stream.eatSpace()) return null;
283
284    setStyle = type = pluginName = null;
285    var style = state.tokenize(stream, state);
286    if ((style || type) && style != "comment") {
287      curState = state;
288      while (true) {
289        var comb = state.cc.pop() || element;
290        if (comb(type || style)) break;
291      }
292    }
293    state.startOfLine = false;
294    return setStyle || style;
295  },
296  indent: function(state, textAfter) {
297    var context = state.context;
298    if (context && context.noIndent) return 0;
299    if (context && /^{\//.test(textAfter))
300        context = context.prev;
301    while (context && !context.startOfLine)
302        context = context.prev;
303    if (context) return context.indent + indentUnit;
304    else return 0;
305  },
306  electricChars: "/"
307};
308});
309
310CodeMirror.defineMIME("text/tiki", "tiki");
311
312});