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 //}}}