github.com/elliott5/community@v0.14.1-0.20160709191136-823126fb026a/app/public/codemirror/mode/tiddlywiki/tiddlywiki.js (about)

     1  // CodeMirror, copyright (c) by Marijn Haverbeke and others
     2  // Distributed under an MIT license: http://codemirror.net/LICENSE
     3  
     4  /***
     5      |''Name''|tiddlywiki.js|
     6      |''Description''|Enables TiddlyWikiy syntax highlighting using CodeMirror|
     7      |''Author''|PMario|
     8      |''Version''|0.1.7|
     9      |''Status''|''stable''|
    10      |''Source''|[[GitHub|https://github.com/pmario/CodeMirror2/blob/tw-syntax/mode/tiddlywiki]]|
    11      |''Documentation''|http://codemirror.tiddlyspace.com/|
    12      |''License''|[[MIT License|http://www.opensource.org/licenses/mit-license.php]]|
    13      |''CoreVersion''|2.5.0|
    14      |''Requires''|codemirror.js|
    15      |''Keywords''|syntax highlighting color code mirror codemirror|
    16      ! Info
    17      CoreVersion parameter is needed for TiddlyWiki only!
    18  ***/
    19  //{{{
    20  
    21  (function(mod) {
    22    if (typeof exports == "object" && typeof module == "object") // CommonJS
    23      mod(require("../../lib/codemirror"));
    24    else if (typeof define == "function" && define.amd) // AMD
    25      define(["../../lib/codemirror"], mod);
    26    else // Plain browser env
    27      mod(CodeMirror);
    28  })(function(CodeMirror) {
    29  "use strict";
    30  
    31  CodeMirror.defineMode("tiddlywiki", function () {
    32    // Tokenizer
    33    var textwords = {};
    34  
    35    var keywords = function () {
    36      function kw(type) {
    37        return { type: type, style: "macro"};
    38      }
    39      return {
    40        "allTags": kw('allTags'), "closeAll": kw('closeAll'), "list": kw('list'),
    41        "newJournal": kw('newJournal'), "newTiddler": kw('newTiddler'),
    42        "permaview": kw('permaview'), "saveChanges": kw('saveChanges'),
    43        "search": kw('search'), "slider": kw('slider'),   "tabs": kw('tabs'),
    44        "tag": kw('tag'), "tagging": kw('tagging'),       "tags": kw('tags'),
    45        "tiddler": kw('tiddler'), "timeline": kw('timeline'),
    46        "today": kw('today'), "version": kw('version'),   "option": kw('option'),
    47  
    48        "with": kw('with'),
    49        "filter": kw('filter')
    50      };
    51    }();
    52  
    53    var isSpaceName = /[\w_\-]/i,
    54    reHR = /^\-\-\-\-+$/,                                 // <hr>
    55    reWikiCommentStart = /^\/\*\*\*$/,            // /***
    56    reWikiCommentStop = /^\*\*\*\/$/,             // ***/
    57    reBlockQuote = /^<<<$/,
    58  
    59    reJsCodeStart = /^\/\/\{\{\{$/,                       // //{{{ js block start
    60    reJsCodeStop = /^\/\/\}\}\}$/,                        // //}}} js stop
    61    reXmlCodeStart = /^<!--\{\{\{-->$/,           // xml block start
    62    reXmlCodeStop = /^<!--\}\}\}-->$/,            // xml stop
    63  
    64    reCodeBlockStart = /^\{\{\{$/,                        // {{{ TW text div block start
    65    reCodeBlockStop = /^\}\}\}$/,                 // }}} TW text stop
    66  
    67    reUntilCodeStop = /.*?\}\}\}/;
    68  
    69    function chain(stream, state, f) {
    70      state.tokenize = f;
    71      return f(stream, state);
    72    }
    73  
    74    function jsTokenBase(stream, state) {
    75      var sol = stream.sol(), ch;
    76  
    77      state.block = false;        // indicates the start of a code block.
    78  
    79      ch = stream.peek();         // don't eat, to make matching simpler
    80  
    81      // check start of  blocks
    82      if (sol && /[<\/\*{}\-]/.test(ch)) {
    83        if (stream.match(reCodeBlockStart)) {
    84          state.block = true;
    85          return chain(stream, state, twTokenCode);
    86        }
    87        if (stream.match(reBlockQuote)) {
    88          return 'quote';
    89        }
    90        if (stream.match(reWikiCommentStart) || stream.match(reWikiCommentStop)) {
    91          return 'comment';
    92        }
    93        if (stream.match(reJsCodeStart) || stream.match(reJsCodeStop) || stream.match(reXmlCodeStart) || stream.match(reXmlCodeStop)) {
    94          return 'comment';
    95        }
    96        if (stream.match(reHR)) {
    97          return 'hr';
    98        }
    99      } // sol
   100      ch = stream.next();
   101  
   102      if (sol && /[\/\*!#;:>|]/.test(ch)) {
   103        if (ch == "!") { // tw header
   104          stream.skipToEnd();
   105          return "header";
   106        }
   107        if (ch == "*") { // tw list
   108          stream.eatWhile('*');
   109          return "comment";
   110        }
   111        if (ch == "#") { // tw numbered list
   112          stream.eatWhile('#');
   113          return "comment";
   114        }
   115        if (ch == ";") { // definition list, term
   116          stream.eatWhile(';');
   117          return "comment";
   118        }
   119        if (ch == ":") { // definition list, description
   120          stream.eatWhile(':');
   121          return "comment";
   122        }
   123        if (ch == ">") { // single line quote
   124          stream.eatWhile(">");
   125          return "quote";
   126        }
   127        if (ch == '|') {
   128          return 'header';
   129        }
   130      }
   131  
   132      if (ch == '{' && stream.match(/\{\{/)) {
   133        return chain(stream, state, twTokenCode);
   134      }
   135  
   136      // rudimentary html:// file:// link matching. TW knows much more ...
   137      if (/[hf]/i.test(ch)) {
   138        if (/[ti]/i.test(stream.peek()) && stream.match(/\b(ttps?|tp|ile):\/\/[\-A-Z0-9+&@#\/%?=~_|$!:,.;]*[A-Z0-9+&@#\/%=~_|$]/i)) {
   139          return "link";
   140        }
   141      }
   142      // just a little string indicator, don't want to have the whole string covered
   143      if (ch == '"') {
   144        return 'string';
   145      }
   146      if (ch == '~') {    // _no_ CamelCase indicator should be bold
   147        return 'brace';
   148      }
   149      if (/[\[\]]/.test(ch)) { // check for [[..]]
   150        if (stream.peek() == ch) {
   151          stream.next();
   152          return 'brace';
   153        }
   154      }
   155      if (ch == "@") {    // check for space link. TODO fix @@...@@ highlighting
   156        stream.eatWhile(isSpaceName);
   157        return "link";
   158      }
   159      if (/\d/.test(ch)) {        // numbers
   160        stream.eatWhile(/\d/);
   161        return "number";
   162      }
   163      if (ch == "/") { // tw invisible comment
   164        if (stream.eat("%")) {
   165          return chain(stream, state, twTokenComment);
   166        }
   167        else if (stream.eat("/")) { //
   168          return chain(stream, state, twTokenEm);
   169        }
   170      }
   171      if (ch == "_") { // tw underline
   172        if (stream.eat("_")) {
   173          return chain(stream, state, twTokenUnderline);
   174        }
   175      }
   176      // strikethrough and mdash handling
   177      if (ch == "-") {
   178        if (stream.eat("-")) {
   179          // if strikethrough looks ugly, change CSS.
   180          if (stream.peek() != ' ')
   181            return chain(stream, state, twTokenStrike);
   182          // mdash
   183          if (stream.peek() == ' ')
   184            return 'brace';
   185        }
   186      }
   187      if (ch == "'") { // tw bold
   188        if (stream.eat("'")) {
   189          return chain(stream, state, twTokenStrong);
   190        }
   191      }
   192      if (ch == "<") { // tw macro
   193        if (stream.eat("<")) {
   194          return chain(stream, state, twTokenMacro);
   195        }
   196      }
   197      else {
   198        return null;
   199      }
   200  
   201      // core macro handling
   202      stream.eatWhile(/[\w\$_]/);
   203      var word = stream.current(),
   204      known = textwords.propertyIsEnumerable(word) && textwords[word];
   205  
   206      return known ? known.style : null;
   207    } // jsTokenBase()
   208  
   209    // tw invisible comment
   210    function twTokenComment(stream, state) {
   211      var maybeEnd = false,
   212      ch;
   213      while (ch = stream.next()) {
   214        if (ch == "/" && maybeEnd) {
   215          state.tokenize = jsTokenBase;
   216          break;
   217        }
   218        maybeEnd = (ch == "%");
   219      }
   220      return "comment";
   221    }
   222  
   223    // tw strong / bold
   224    function twTokenStrong(stream, state) {
   225      var maybeEnd = false,
   226      ch;
   227      while (ch = stream.next()) {
   228        if (ch == "'" && maybeEnd) {
   229          state.tokenize = jsTokenBase;
   230          break;
   231        }
   232        maybeEnd = (ch == "'");
   233      }
   234      return "strong";
   235    }
   236  
   237    // tw code
   238    function twTokenCode(stream, state) {
   239      var sb = state.block;
   240  
   241      if (sb && stream.current()) {
   242        return "comment";
   243      }
   244  
   245      if (!sb && stream.match(reUntilCodeStop)) {
   246        state.tokenize = jsTokenBase;
   247        return "comment";
   248      }
   249  
   250      if (sb && stream.sol() && stream.match(reCodeBlockStop)) {
   251        state.tokenize = jsTokenBase;
   252        return "comment";
   253      }
   254  
   255      stream.next();
   256      return "comment";
   257    }
   258  
   259    // tw em / italic
   260    function twTokenEm(stream, state) {
   261      var maybeEnd = false,
   262      ch;
   263      while (ch = stream.next()) {
   264        if (ch == "/" && maybeEnd) {
   265          state.tokenize = jsTokenBase;
   266          break;
   267        }
   268        maybeEnd = (ch == "/");
   269      }
   270      return "em";
   271    }
   272  
   273    // tw underlined text
   274    function twTokenUnderline(stream, state) {
   275      var maybeEnd = false,
   276      ch;
   277      while (ch = stream.next()) {
   278        if (ch == "_" && maybeEnd) {
   279          state.tokenize = jsTokenBase;
   280          break;
   281        }
   282        maybeEnd = (ch == "_");
   283      }
   284      return "underlined";
   285    }
   286  
   287    // tw strike through text looks ugly
   288    // change CSS if needed
   289    function twTokenStrike(stream, state) {
   290      var maybeEnd = false, ch;
   291  
   292      while (ch = stream.next()) {
   293        if (ch == "-" && maybeEnd) {
   294          state.tokenize = jsTokenBase;
   295          break;
   296        }
   297        maybeEnd = (ch == "-");
   298      }
   299      return "strikethrough";
   300    }
   301  
   302    // macro
   303    function twTokenMacro(stream, state) {
   304      var ch, word, known;
   305  
   306      if (stream.current() == '<<') {
   307        return 'macro';
   308      }
   309  
   310      ch = stream.next();
   311      if (!ch) {
   312        state.tokenize = jsTokenBase;
   313        return null;
   314      }
   315      if (ch == ">") {
   316        if (stream.peek() == '>') {
   317          stream.next();
   318          state.tokenize = jsTokenBase;
   319          return "macro";
   320        }
   321      }
   322  
   323      stream.eatWhile(/[\w\$_]/);
   324      word = stream.current();
   325      known = keywords.propertyIsEnumerable(word) && keywords[word];
   326  
   327      if (known) {
   328        return known.style, word;
   329      }
   330      else {
   331        return null, word;
   332      }
   333    }
   334  
   335    // Interface
   336    return {
   337      startState: function () {
   338        return {
   339          tokenize: jsTokenBase,
   340          indented: 0,
   341          level: 0
   342        };
   343      },
   344  
   345      token: function (stream, state) {
   346        if (stream.eatSpace()) return null;
   347        var style = state.tokenize(stream, state);
   348        return style;
   349      },
   350  
   351      electricChars: ""
   352    };
   353  });
   354  
   355  CodeMirror.defineMIME("text/x-tiddlywiki", "tiddlywiki");
   356  });
   357  
   358  //}}}