diff options
Diffstat (limited to 'imports/codemirror/mode/tiddlywiki/tiddlywiki.js')
-rwxr-xr-x | imports/codemirror/mode/tiddlywiki/tiddlywiki.js | 374 |
1 files changed, 374 insertions, 0 deletions
diff --git a/imports/codemirror/mode/tiddlywiki/tiddlywiki.js b/imports/codemirror/mode/tiddlywiki/tiddlywiki.js new file mode 100755 index 00000000..e07124c2 --- /dev/null +++ b/imports/codemirror/mode/tiddlywiki/tiddlywiki.js | |||
@@ -0,0 +1,374 @@ | |||
1 | /*** | ||
2 | |''Name''|tiddlywiki.js| | ||
3 | |''Description''|Enables TiddlyWikiy syntax highlighting using CodeMirror2| | ||
4 | |''Author''|PMario| | ||
5 | |''Version''|0.1.6| | ||
6 | |''Status''|''beta''| | ||
7 | |''Source''|[[GitHub|https://github.com/pmario/CodeMirror2/blob/tw-syntax/mode/tiddlywiki]]| | ||
8 | |''Documentation''|http://codemirror.tiddlyspace.com/| | ||
9 | |''License''|[[MIT License|http://www.opensource.org/licenses/mit-license.php]]| | ||
10 | |''CoreVersion''|2.5.0| | ||
11 | |''Requires''|codemirror.js| | ||
12 | |''Keywords''|syntax highlighting color code mirror codemirror| | ||
13 | ! Info | ||
14 | CoreVersion parameter is needed for TiddlyWiki only! | ||
15 | ***/ | ||
16 | //{{{ | ||
17 | CodeMirror.defineMode("tiddlywiki", function (config, parserConfig) { | ||
18 | var indentUnit = config.indentUnit; | ||
19 | |||
20 | // Tokenizer | ||
21 | var textwords = function () { | ||
22 | function kw(type) { | ||
23 | return { | ||
24 | type: type, | ||
25 | style: "text" | ||
26 | }; | ||
27 | } | ||
28 | return {}; | ||
29 | }(); | ||
30 | |||
31 | var keywords = function () { | ||
32 | function kw(type) { | ||
33 | return { type: type, style: "macro"}; | ||
34 | } | ||
35 | return { | ||
36 | "allTags": kw('allTags'), "closeAll": kw('closeAll'), "list": kw('list'), | ||
37 | "newJournal": kw('newJournal'), "newTiddler": kw('newTiddler'), | ||
38 | "permaview": kw('permaview'), "saveChanges": kw('saveChanges'), | ||
39 | "search": kw('search'), "slider": kw('slider'), "tabs": kw('tabs'), | ||
40 | "tag": kw('tag'), "tagging": kw('tagging'), "tags": kw('tags'), | ||
41 | "tiddler": kw('tiddler'), "timeline": kw('timeline'), | ||
42 | "today": kw('today'), "version": kw('version'), "option": kw('option'), | ||
43 | |||
44 | "with": kw('with'), | ||
45 | "filter": kw('filter') | ||
46 | }; | ||
47 | }(); | ||
48 | |||
49 | var isSpaceName = /[\w_\-]/i, | ||
50 | reHR = /^\-\-\-\-+$/, | ||
51 | reWikiCommentStart = /^\/\*\*\*$/, // /*** | ||
52 | reWikiCommentStop = /^\*\*\*\/$/, // ***/ | ||
53 | reBlockQuote = /^<<<$/, | ||
54 | |||
55 | reJsCodeStart = /^\/\/\{\{\{$/, // //{{{ | ||
56 | reJsCodeStop = /^\/\/\}\}\}$/, // //}}} | ||
57 | reXmlCodeStart = /^<!--\{\{\{-->$/, | ||
58 | reXmlCodeStop = /^<!--\}\}\}-->$/, | ||
59 | |||
60 | reCodeBlockStart = /^\{\{\{$/, | ||
61 | reCodeBlockStop = /^\}\}\}$/, | ||
62 | |||
63 | reCodeStart = /\{\{\{/, | ||
64 | reUntilCodeStop = /.*?\}\}\}/; | ||
65 | |||
66 | function chain(stream, state, f) { | ||
67 | state.tokenize = f; | ||
68 | return f(stream, state); | ||
69 | } | ||
70 | |||
71 | // used for strings | ||
72 | function nextUntilUnescaped(stream, end) { | ||
73 | var escaped = false, | ||
74 | next; | ||
75 | while ((next = stream.next()) != null) { | ||
76 | if (next == end && !escaped) return false; | ||
77 | escaped = !escaped && next == "\\"; | ||
78 | } | ||
79 | return escaped; | ||
80 | } | ||
81 | |||
82 | // Used as scratch variables to communicate multiple values without | ||
83 | // consing up tons of objects. | ||
84 | var type, content; | ||
85 | |||
86 | function ret(tp, style, cont) { | ||
87 | type = tp; | ||
88 | content = cont; | ||
89 | return style; | ||
90 | } | ||
91 | |||
92 | function jsTokenBase(stream, state) { | ||
93 | var sol = stream.sol(), | ||
94 | ch, tch; | ||
95 | |||
96 | state.block = false; // indicates the start of a code block. | ||
97 | |||
98 | ch = stream.peek(); // don't eat, to make match simpler | ||
99 | |||
100 | // check start of blocks | ||
101 | if (sol && /[<\/\*{}\-]/.test(ch)) { | ||
102 | if (stream.match(reCodeBlockStart)) { | ||
103 | state.block = true; | ||
104 | return chain(stream, state, twTokenCode); | ||
105 | } | ||
106 | if (stream.match(reBlockQuote)) { | ||
107 | return ret('quote', 'quote'); | ||
108 | } | ||
109 | if (stream.match(reWikiCommentStart) || stream.match(reWikiCommentStop)) { | ||
110 | return ret('code', 'code'); | ||
111 | } | ||
112 | if (stream.match(reJsCodeStart) || stream.match(reJsCodeStop) || stream.match(reXmlCodeStart) || stream.match(reXmlCodeStop)) { | ||
113 | return ret('code', 'code'); | ||
114 | } | ||
115 | if (stream.match(reHR)) { | ||
116 | return ret('hr', 'hr'); | ||
117 | } | ||
118 | } // sol | ||
119 | var ch = stream.next(); | ||
120 | |||
121 | if (sol && /[\/\*!#;:>|]/.test(ch)) { | ||
122 | if (ch == "!") { // tw header | ||
123 | stream.skipToEnd(); | ||
124 | return ret("header", "header"); | ||
125 | } | ||
126 | if (ch == "*") { // tw list | ||
127 | stream.eatWhile('*'); | ||
128 | return ret("list", "list"); | ||
129 | } | ||
130 | if (ch == "#") { // tw numbered list | ||
131 | stream.eatWhile('#'); | ||
132 | return ret("list", "list"); | ||
133 | } | ||
134 | if (ch == ";") { // tw list | ||
135 | stream.eatWhile(';'); | ||
136 | return ret("list", "list"); | ||
137 | } | ||
138 | if (ch == ":") { // tw list | ||
139 | stream.eatWhile(':'); | ||
140 | return ret("list", "list"); | ||
141 | } | ||
142 | if (ch == ">") { // single line quote | ||
143 | stream.eatWhile(">"); | ||
144 | return ret("quote", "quote"); | ||
145 | } | ||
146 | if (ch == '|') { | ||
147 | return ret('table', 'table'); | ||
148 | } | ||
149 | } | ||
150 | |||
151 | if (ch == '{' && stream.match(/\{\{/)) { | ||
152 | return chain(stream, state, twTokenCode); | ||
153 | } | ||
154 | |||
155 | // rudimentary html:// file:// link matching. TW knows much more ... | ||
156 | if (/[hf]/i.test(ch)) { | ||
157 | if (/[ti]/i.test(stream.peek()) && stream.match(/\b(ttps?|tp|ile):\/\/[\-A-Z0-9+&@#\/%?=~_|$!:,.;]*[A-Z0-9+&@#\/%=~_|$]/i)) { | ||
158 | return ret("link-external", "link-external"); | ||
159 | } | ||
160 | } | ||
161 | // just a little string indicator, don't want to have the whole string covered | ||
162 | if (ch == '"') { | ||
163 | return ret('string', 'string'); | ||
164 | } | ||
165 | if (/[\[\]]/.test(ch)) { // check for [[..]] | ||
166 | if (stream.peek() == ch) { | ||
167 | stream.next(); | ||
168 | return ret('brace', 'brace'); | ||
169 | } | ||
170 | } | ||
171 | if (ch == "@") { // check for space link. TODO fix @@...@@ highlighting | ||
172 | stream.eatWhile(isSpaceName); | ||
173 | return ret("link-external", "link-external"); | ||
174 | } | ||
175 | if (/\d/.test(ch)) { // numbers | ||
176 | stream.eatWhile(/\d/); | ||
177 | return ret("number", "number"); | ||
178 | } | ||
179 | if (ch == "/") { // tw invisible comment | ||
180 | if (stream.eat("%")) { | ||
181 | return chain(stream, state, twTokenComment); | ||
182 | } | ||
183 | else if (stream.eat("/")) { // | ||
184 | return chain(stream, state, twTokenEm); | ||
185 | } | ||
186 | } | ||
187 | if (ch == "_") { // tw underline | ||
188 | if (stream.eat("_")) { | ||
189 | return chain(stream, state, twTokenUnderline); | ||
190 | } | ||
191 | } | ||
192 | if (ch == "-") { // tw strikethrough TODO looks ugly .. different handling see below; | ||
193 | if (stream.eat("-")) { | ||
194 | return chain(stream, state, twTokenStrike); | ||
195 | } | ||
196 | } | ||
197 | if (ch == "'") { // tw bold | ||
198 | if (stream.eat("'")) { | ||
199 | return chain(stream, state, twTokenStrong); | ||
200 | } | ||
201 | } | ||
202 | if (ch == "<") { // tw macro | ||
203 | if (stream.eat("<")) { | ||
204 | return chain(stream, state, twTokenMacro); | ||
205 | } | ||
206 | } | ||
207 | else { | ||
208 | return ret(ch); | ||
209 | } | ||
210 | |||
211 | stream.eatWhile(/[\w\$_]/); | ||
212 | var word = stream.current(), | ||
213 | known = textwords.propertyIsEnumerable(word) && textwords[word]; | ||
214 | |||
215 | return known ? ret(known.type, known.style, word) : ret("text", null, word); | ||
216 | |||
217 | } // jsTokenBase() | ||