Mercurial
comparison .cms/lib/codemirror/mode/tiddlywiki/tiddlywiki.js @ 0:78edf6b517a0 draft
24.10
author | Coffee CMS <info@coffee-cms.ru> |
---|---|
date | Fri, 11 Oct 2024 22:40:23 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:78edf6b517a0 |
---|---|
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others | |
2 // Distributed under an MIT license: https://codemirror.net/5/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''|https://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 (function(mod) { | |
21 if (typeof exports == "object" && typeof module == "object") // CommonJS | |
22 mod(require("../../lib/codemirror")); | |
23 else if (typeof define == "function" && define.amd) // AMD | |
24 define(["../../lib/codemirror"], mod); | |
25 else // Plain browser env | |
26 mod(CodeMirror); | |
27 })(function(CodeMirror) { | |
28 "use strict"; | |
29 | |
30 CodeMirror.defineMode("tiddlywiki", function () { | |
31 // Tokenizer | |
32 var textwords = {}; | |
33 | |
34 var keywords = { | |
35 "allTags": true, "closeAll": true, "list": true, | |
36 "newJournal": true, "newTiddler": true, | |
37 "permaview": true, "saveChanges": true, | |
38 "search": true, "slider": true, "tabs": true, | |
39 "tag": true, "tagging": true, "tags": true, | |
40 "tiddler": true, "timeline": true, | |
41 "today": true, "version": true, "option": true, | |
42 "with": true, "filter": true | |
43 }; | |
44 | |
45 var isSpaceName = /[\w_\-]/i, | |
46 reHR = /^\-\-\-\-+$/, // <hr> | |
47 reWikiCommentStart = /^\/\*\*\*$/, // /*** | |
48 reWikiCommentStop = /^\*\*\*\/$/, // ***/ | |
49 reBlockQuote = /^<<<$/, | |
50 | |
51 reJsCodeStart = /^\/\/\{\{\{$/, // //{{{ js block start | |
52 reJsCodeStop = /^\/\/\}\}\}$/, // //}}} js stop | |
53 reXmlCodeStart = /^<!--\{\{\{-->$/, // xml block start | |
54 reXmlCodeStop = /^<!--\}\}\}-->$/, // xml stop | |
55 | |
56 reCodeBlockStart = /^\{\{\{$/, // {{{ TW text div block start | |
57 reCodeBlockStop = /^\}\}\}$/, // }}} TW text stop | |
58 | |
59 reUntilCodeStop = /.*?\}\}\}/; | |
60 | |
61 function chain(stream, state, f) { | |
62 state.tokenize = f; | |
63 return f(stream, state); | |
64 } | |
65 | |
66 function tokenBase(stream, state) { | |
67 var sol = stream.sol(), ch = stream.peek(); | |
68 | |
69 state.block = false; // indicates the start of a code block. | |
70 | |
71 // check start of blocks | |
72 if (sol && /[<\/\*{}\-]/.test(ch)) { | |
73 if (stream.match(reCodeBlockStart)) { | |
74 state.block = true; | |
75 return chain(stream, state, twTokenCode); | |
76 } | |
77 if (stream.match(reBlockQuote)) | |
78 return 'quote'; | |
79 if (stream.match(reWikiCommentStart) || stream.match(reWikiCommentStop)) | |
80 return 'comment'; | |
81 if (stream.match(reJsCodeStart) || stream.match(reJsCodeStop) || stream.match(reXmlCodeStart) || stream.match(reXmlCodeStop)) | |
82 return 'comment'; | |
83 if (stream.match(reHR)) | |
84 return 'hr'; | |
85 } | |
86 | |
87 stream.next(); | |
88 if (sol && /[\/\*!#;:>|]/.test(ch)) { | |
89 if (ch == "!") { // tw header | |
90 stream.skipToEnd(); | |
91 return "header"; | |
92 } | |
93 if (ch == "*") { // tw list | |
94 stream.eatWhile('*'); | |
95 return "comment"; | |
96 } | |
97 if (ch == "#") { // tw numbered list | |
98 stream.eatWhile('#'); | |
99 return "comment"; | |
100 } | |
101 if (ch == ";") { // definition list, term | |
102 stream.eatWhile(';'); | |
103 return "comment"; | |
104 } | |
105 if (ch == ":") { // definition list, description | |
106 stream.eatWhile(':'); | |
107 return "comment"; | |
108 } | |
109 if (ch == ">") { // single line quote | |
110 stream.eatWhile(">"); | |
111 return "quote"; | |
112 } | |
113 if (ch == '|') | |
114 return 'header'; | |
115 } | |
116 | |
117 if (ch == '{' && stream.match('{{')) | |
118 return chain(stream, state, twTokenCode); | |
119 | |
120 // rudimentary html:// file:// link matching. TW knows much more ... | |
121 if (/[hf]/i.test(ch) && | |
122 /[ti]/i.test(stream.peek()) && | |
123 stream.match(/\b(ttps?|tp|ile):\/\/[\-A-Z0-9+&@#\/%?=~_|$!:,.;]*[A-Z0-9+&@#\/%=~_|$]/i)) | |
124 return "link"; | |
125 | |
126 // just a little string indicator, don't want to have the whole string covered | |
127 if (ch == '"') | |
128 return 'string'; | |
129 | |
130 if (ch == '~') // _no_ CamelCase indicator should be bold | |
131 return 'brace'; | |
132 | |
133 if (/[\[\]]/.test(ch) && stream.match(ch)) // check for [[..]] | |
134 return 'brace'; | |
135 | |
136 if (ch == "@") { // check for space link. TODO fix @@...@@ highlighting | |
137 stream.eatWhile(isSpaceName); | |
138 return "link"; | |
139 } | |
140 | |
141 if (/\d/.test(ch)) { // numbers | |
142 stream.eatWhile(/\d/); | |
143 return "number"; | |
144 } | |
145 | |
146 if (ch == "/") { // tw invisible comment | |
147 if (stream.eat("%")) { | |
148 return chain(stream, state, twTokenComment); | |
149 } else if (stream.eat("/")) { // | |
150 return chain(stream, state, twTokenEm); | |
151 } | |
152 } | |
153 | |
154 if (ch == "_" && stream.eat("_")) // tw underline | |
155 return chain(stream, state, twTokenUnderline); | |
156 | |
157 // strikethrough and mdash handling | |
158 if (ch == "-" && stream.eat("-")) { | |
159 // if strikethrough looks ugly, change CSS. | |
160 if (stream.peek() != ' ') | |
161 return chain(stream, state, twTokenStrike); | |
162 // mdash | |
163 if (stream.peek() == ' ') | |
164 return 'brace'; | |
165 } | |
166 | |
167 if (ch == "'" && stream.eat("'")) // tw bold | |
168 return chain(stream, state, twTokenStrong); | |
169 | |
170 if (ch == "<" && stream.eat("<")) // tw macro | |
171 return chain(stream, state, twTokenMacro); | |
172 | |
173 // core macro handling | |
174 stream.eatWhile(/[\w\$_]/); | |
175 return textwords.propertyIsEnumerable(stream.current()) ? "keyword" : null | |
176 } | |
177 | |
178 // tw invisible comment | |
179 function twTokenComment(stream, state) { | |
180 var maybeEnd = false, ch; | |
181 while (ch = stream.next()) { | |
182 if (ch == "/" && maybeEnd) { | |
183 state.tokenize = tokenBase; | |
184 break; | |
185 } | |
186 maybeEnd = (ch == "%"); | |
187 } | |
188 return "comment"; | |
189 } | |
190 | |
191 // tw strong / bold | |
192 function twTokenStrong(stream, state) { | |
193 var maybeEnd = false, | |
194 ch; | |
195 while (ch = stream.next()) { | |
196 if (ch == "'" && maybeEnd) { | |
197 state.tokenize = tokenBase; | |
198 break; | |
199 } | |
200 maybeEnd = (ch == "'"); | |
201 } | |
202 return "strong"; | |
203 } | |
204 | |
205 // tw code | |
206 function twTokenCode(stream, state) { | |
207 var sb = state.block; | |
208 | |
209 if (sb && stream.current()) { | |
210 return "comment"; | |
211 } | |
212 | |
213 if (!sb && stream.match(reUntilCodeStop)) { | |
214 state.tokenize = tokenBase; | |
215 return "comment"; | |
216 } | |
217 | |
218 if (sb && stream.sol() && stream.match(reCodeBlockStop)) { | |
219 state.tokenize = tokenBase; | |
220 return "comment"; | |
221 } | |
222 | |
223 stream.next(); | |
224 return "comment"; | |
225 } | |
226 | |
227 // tw em / italic | |
228 function twTokenEm(stream, state) { | |
229 var maybeEnd = false, | |
230 ch; | |
231 while (ch = stream.next()) { | |
232 if (ch == "/" && maybeEnd) { | |
233 state.tokenize = tokenBase; | |
234 break; | |
235 } | |
236 maybeEnd = (ch == "/"); | |
237 } | |
238 return "em"; | |
239 } | |
240 | |
241 // tw underlined text | |
242 function twTokenUnderline(stream, state) { | |
243 var maybeEnd = false, | |
244 ch; | |
245 while (ch = stream.next()) { | |
246 if (ch == "_" && maybeEnd) { | |
247 state.tokenize = tokenBase; | |
248 break; | |
249 } | |
250 maybeEnd = (ch == "_"); | |
251 } | |
252 return "underlined"; | |
253 } | |
254 | |
255 // tw strike through text looks ugly | |
256 // change CSS if needed | |
257 function twTokenStrike(stream, state) { | |
258 var maybeEnd = false, ch; | |
259 | |
260 while (ch = stream.next()) { | |
261 if (ch == "-" && maybeEnd) { | |
262 state.tokenize = tokenBase; | |
263 break; | |
264 } | |
265 maybeEnd = (ch == "-"); | |
266 } | |
267 return "strikethrough"; | |
268 } | |
269 | |
270 // macro | |
271 function twTokenMacro(stream, state) { | |
272 if (stream.current() == '<<') { | |
273 return 'macro'; | |
274 } | |
275 | |
276 var ch = stream.next(); | |
277 if (!ch) { | |
278 state.tokenize = tokenBase; | |
279 return null; | |
280 } | |
281 if (ch == ">") { | |
282 if (stream.peek() == '>') { | |
283 stream.next(); | |
284 state.tokenize = tokenBase; | |
285 return "macro"; | |
286 } | |
287 } | |
288 | |
289 stream.eatWhile(/[\w\$_]/); | |
290 return keywords.propertyIsEnumerable(stream.current()) ? "keyword" : null | |
291 } | |
292 | |
293 // Interface | |
294 return { | |
295 startState: function () { | |
296 return {tokenize: tokenBase}; | |
297 }, | |
298 | |
299 token: function (stream, state) { | |
300 if (stream.eatSpace()) return null; | |
301 var style = state.tokenize(stream, state); | |
302 return style; | |
303 } | |
304 }; | |
305 }); | |
306 | |
307 CodeMirror.defineMIME("text/x-tiddlywiki", "tiddlywiki"); | |
308 }); |