1
|
|
|
// CodeMirror, copyright (c) by Marijn Haverbeke and others |
2
|
|
|
// Distributed under an MIT license: http://codemirror.net/LICENSE |
3
|
|
|
|
4
|
|
|
(function(mod) { |
5
|
|
|
if (typeof exports == "object" && typeof module == "object") // CommonJS |
6
|
|
|
mod(require("../../lib/codemirror"), require("../xml/xml"), require("../meta")); |
7
|
|
|
else if (typeof define == "function" && define.amd) // AMD |
|
|
|
|
8
|
|
|
define(["../../lib/codemirror", "../xml/xml", "../meta"], mod); |
9
|
|
|
else // Plain browser env |
10
|
|
|
mod(CodeMirror); |
|
|
|
|
11
|
|
|
})(function(CodeMirror) { |
12
|
|
|
"use strict"; |
13
|
|
|
|
14
|
|
|
CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { |
15
|
|
|
|
16
|
|
|
var htmlFound = CodeMirror.modes.hasOwnProperty("xml"); |
17
|
|
|
var htmlMode = CodeMirror.getMode(cmCfg, htmlFound ? {name: "xml", htmlMode: true} : "text/plain"); |
18
|
|
|
|
19
|
|
|
function getMode(name) { |
20
|
|
|
if (CodeMirror.findModeByName) { |
21
|
|
|
var found = CodeMirror.findModeByName(name); |
22
|
|
|
if (found) name = found.mime || found.mimes[0]; |
23
|
|
|
} |
24
|
|
|
var mode = CodeMirror.getMode(cmCfg, name); |
25
|
|
|
return mode.name == "null" ? null : mode; |
26
|
|
|
} |
27
|
|
|
|
28
|
|
|
// Should characters that affect highlighting be highlighted separate? |
29
|
|
|
// Does not include characters that will be output (such as `1.` and `-` for lists) |
30
|
|
|
if (modeCfg.highlightFormatting === undefined) |
31
|
|
|
modeCfg.highlightFormatting = false; |
32
|
|
|
|
33
|
|
|
// Maximum number of nested blockquotes. Set to 0 for infinite nesting. |
34
|
|
|
// Excess `>` will emit `error` token. |
35
|
|
|
if (modeCfg.maxBlockquoteDepth === undefined) |
36
|
|
|
modeCfg.maxBlockquoteDepth = 0; |
37
|
|
|
|
38
|
|
|
// Should underscores in words open/close em/strong? |
39
|
|
|
if (modeCfg.underscoresBreakWords === undefined) |
40
|
|
|
modeCfg.underscoresBreakWords = true; |
41
|
|
|
|
42
|
|
|
// Turn on fenced code blocks? ("```" to start/end) |
43
|
|
|
if (modeCfg.fencedCodeBlocks === undefined) modeCfg.fencedCodeBlocks = false; |
44
|
|
|
|
45
|
|
|
// Turn on task lists? ("- [ ] " and "- [x] ") |
46
|
|
|
if (modeCfg.taskLists === undefined) modeCfg.taskLists = false; |
47
|
|
|
|
48
|
|
|
// Turn on strikethrough syntax |
49
|
|
|
if (modeCfg.strikethrough === undefined) |
50
|
|
|
modeCfg.strikethrough = false; |
51
|
|
|
|
52
|
|
|
var codeDepth = 0; |
53
|
|
|
|
54
|
|
|
var header = 'header' |
55
|
|
|
, code = 'comment' |
56
|
|
|
, quote = 'quote' |
57
|
|
|
, list1 = 'variable-2' |
58
|
|
|
, list2 = 'variable-3' |
59
|
|
|
, list3 = 'keyword' |
60
|
|
|
, hr = 'hr' |
61
|
|
|
, image = 'tag' |
62
|
|
|
, formatting = 'formatting' |
63
|
|
|
, linkinline = 'link' |
64
|
|
|
, linkemail = 'link' |
65
|
|
|
, linktext = 'link' |
66
|
|
|
, linkhref = 'string' |
67
|
|
|
, em = 'em' |
68
|
|
|
, strong = 'strong' |
69
|
|
|
, strikethrough = 'strikethrough'; |
70
|
|
|
|
71
|
|
|
var hrRE = /^([*\-=_])(?:\s*\1){2,}\s*$/ |
72
|
|
|
, ulRE = /^[*\-+]\s+/ |
73
|
|
|
, olRE = /^[0-9]+\.\s+/ |
74
|
|
|
, taskListRE = /^\[(x| )\](?=\s)/ // Must follow ulRE or olRE |
75
|
|
|
, atxHeaderRE = /^#+/ |
76
|
|
|
, setextHeaderRE = /^(?:\={1,}|-{1,})$/ |
77
|
|
|
, textRE = /^[^#!\[\]*_\\<>` "'(~]+/; |
78
|
|
|
|
79
|
|
|
function switchInline(stream, state, f) { |
80
|
|
|
state.f = state.inline = f; |
81
|
|
|
return f(stream, state); |
82
|
|
|
} |
83
|
|
|
|
84
|
|
|
function switchBlock(stream, state, f) { |
85
|
|
|
state.f = state.block = f; |
86
|
|
|
return f(stream, state); |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
|
90
|
|
|
// Blocks |
91
|
|
|
|
92
|
|
|
function blankLine(state) { |
93
|
|
|
// Reset linkTitle state |
94
|
|
|
state.linkTitle = false; |
95
|
|
|
// Reset EM state |
96
|
|
|
state.em = false; |
97
|
|
|
// Reset STRONG state |
98
|
|
|
state.strong = false; |
99
|
|
|
// Reset strikethrough state |
100
|
|
|
state.strikethrough = false; |
101
|
|
|
// Reset state.quote |
102
|
|
|
state.quote = 0; |
103
|
|
|
if (!htmlFound && state.f == htmlBlock) { |
104
|
|
|
state.f = inlineNormal; |
105
|
|
|
state.block = blockNormal; |
106
|
|
|
} |
107
|
|
|
// Reset state.trailingSpace |
108
|
|
|
state.trailingSpace = 0; |
109
|
|
|
state.trailingSpaceNewLine = false; |
110
|
|
|
// Mark this line as blank |
111
|
|
|
state.thisLineHasContent = false; |
112
|
|
|
return null; |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
function blockNormal(stream, state) { |
116
|
|
|
|
117
|
|
|
var sol = stream.sol(); |
118
|
|
|
|
119
|
|
|
var prevLineIsList = (state.list !== false); |
120
|
|
|
if (state.list !== false && state.indentationDiff >= 0) { // Continued list |
121
|
|
|
if (state.indentationDiff < 4) { // Only adjust indentation if *not* a code block |
122
|
|
|
state.indentation -= state.indentationDiff; |
123
|
|
|
} |
124
|
|
|
state.list = null; |
125
|
|
|
} else if (state.list !== false && state.indentation > 0) { |
126
|
|
|
state.list = null; |
127
|
|
|
state.listDepth = Math.floor(state.indentation / 4); |
128
|
|
|
} else if (state.list !== false) { // No longer a list |
129
|
|
|
state.list = false; |
130
|
|
|
state.listDepth = 0; |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
var match = null; |
134
|
|
|
if (state.indentationDiff >= 4) { |
135
|
|
|
state.indentation -= 4; |
136
|
|
|
stream.skipToEnd(); |
137
|
|
|
return code; |
138
|
|
|
} else if (stream.eatSpace()) { |
139
|
|
|
return null; |
140
|
|
|
} else if (match = stream.match(atxHeaderRE)) { |
141
|
|
|
state.header = match[0].length <= 6 ? match[0].length : 6; |
142
|
|
|
if (modeCfg.highlightFormatting) state.formatting = "header"; |
143
|
|
|
state.f = state.inline; |
144
|
|
|
return getType(state); |
145
|
|
|
} else if (state.prevLineHasContent && (match = stream.match(setextHeaderRE))) { |
146
|
|
|
state.header = match[0].charAt(0) == '=' ? 1 : 2; |
147
|
|
|
if (modeCfg.highlightFormatting) state.formatting = "header"; |
148
|
|
|
state.f = state.inline; |
149
|
|
|
return getType(state); |
150
|
|
|
} else if (stream.eat('>')) { |
151
|
|
|
state.indentation++; |
152
|
|
|
state.quote = sol ? 1 : state.quote + 1; |
153
|
|
|
if (modeCfg.highlightFormatting) state.formatting = "quote"; |
154
|
|
|
stream.eatSpace(); |
155
|
|
|
return getType(state); |
156
|
|
|
} else if (stream.peek() === '[') { |
157
|
|
|
return switchInline(stream, state, footnoteLink); |
158
|
|
|
} else if (stream.match(hrRE, true)) { |
159
|
|
|
return hr; |
160
|
|
|
} else if ((!state.prevLineHasContent || prevLineIsList) && (stream.match(ulRE, false) || stream.match(olRE, false))) { |
161
|
|
|
var listType = null; |
|
|
|
|
162
|
|
|
if (stream.match(ulRE, true)) { |
163
|
|
|
listType = 'ul'; |
164
|
|
|
} else { |
165
|
|
|
stream.match(olRE, true); |
166
|
|
|
listType = 'ol'; |
167
|
|
|
} |
168
|
|
|
state.indentation += 4; |
169
|
|
|
state.list = true; |
170
|
|
|
state.listDepth++; |
171
|
|
|
if (modeCfg.taskLists && stream.match(taskListRE, false)) { |
172
|
|
|
state.taskList = true; |
173
|
|
|
} |
174
|
|
|
state.f = state.inline; |
175
|
|
|
if (modeCfg.highlightFormatting) state.formatting = ["list", "list-" + listType]; |
176
|
|
|
return getType(state); |
177
|
|
|
} else if (modeCfg.fencedCodeBlocks && stream.match(/^```[ \t]*([\w+#]*)/, true)) { |
178
|
|
|
// try switching mode |
179
|
|
|
state.localMode = getMode(RegExp.$1); |
180
|
|
|
if (state.localMode) state.localState = state.localMode.startState(); |
181
|
|
|
state.f = state.block = local; |
182
|
|
|
if (modeCfg.highlightFormatting) state.formatting = "code-block"; |
183
|
|
|
state.code = true; |
184
|
|
|
return getType(state); |
185
|
|
|
} |
186
|
|
|
|
187
|
|
|
return switchInline(stream, state, state.inline); |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
function htmlBlock(stream, state) { |
191
|
|
|
var style = htmlMode.token(stream, state.htmlState); |
192
|
|
|
if ((htmlFound && state.htmlState.tagStart === null && !state.htmlState.context) || |
193
|
|
|
(state.md_inside && stream.current().indexOf(">") > -1)) { |
194
|
|
|
state.f = inlineNormal; |
195
|
|
|
state.block = blockNormal; |
196
|
|
|
state.htmlState = null; |
197
|
|
|
} |
198
|
|
|
return style; |
199
|
|
|
} |
200
|
|
|
|
201
|
|
|
function local(stream, state) { |
202
|
|
|
if (stream.sol() && stream.match("```", false)) { |
203
|
|
|
state.localMode = state.localState = null; |
204
|
|
|
state.f = state.block = leavingLocal; |
205
|
|
|
return null; |
206
|
|
|
} else if (state.localMode) { |
207
|
|
|
return state.localMode.token(stream, state.localState); |
208
|
|
|
} else { |
209
|
|
|
stream.skipToEnd(); |
210
|
|
|
return code; |
211
|
|
|
} |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
function leavingLocal(stream, state) { |
215
|
|
|
stream.match("```"); |
216
|
|
|
state.block = blockNormal; |
217
|
|
|
state.f = inlineNormal; |
218
|
|
|
if (modeCfg.highlightFormatting) state.formatting = "code-block"; |
219
|
|
|
state.code = true; |
220
|
|
|
var returnType = getType(state); |
221
|
|
|
state.code = false; |
222
|
|
|
return returnType; |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
// Inline |
226
|
|
|
function getType(state) { |
227
|
|
|
var styles = []; |
228
|
|
|
|
229
|
|
|
if (state.formatting) { |
230
|
|
|
styles.push(formatting); |
231
|
|
|
|
232
|
|
|
if (typeof state.formatting === "string") state.formatting = [state.formatting]; |
233
|
|
|
|
234
|
|
|
for (var i = 0; i < state.formatting.length; i++) { |
235
|
|
|
styles.push(formatting + "-" + state.formatting[i]); |
236
|
|
|
|
237
|
|
|
if (state.formatting[i] === "header") { |
238
|
|
|
styles.push(formatting + "-" + state.formatting[i] + "-" + state.header); |
239
|
|
|
} |
240
|
|
|
|
241
|
|
|
// Add `formatting-quote` and `formatting-quote-#` for blockquotes |
242
|
|
|
// Add `error` instead if the maximum blockquote nesting depth is passed |
243
|
|
|
if (state.formatting[i] === "quote") { |
244
|
|
|
if (!modeCfg.maxBlockquoteDepth || modeCfg.maxBlockquoteDepth >= state.quote) { |
245
|
|
|
styles.push(formatting + "-" + state.formatting[i] + "-" + state.quote); |
246
|
|
|
} else { |
247
|
|
|
styles.push("error"); |
248
|
|
|
} |
249
|
|
|
} |
250
|
|
|
} |
251
|
|
|
} |
252
|
|
|
|
253
|
|
|
if (state.taskOpen) { |
254
|
|
|
styles.push("meta"); |
255
|
|
|
return styles.length ? styles.join(' ') : null; |
256
|
|
|
} |
257
|
|
|
if (state.taskClosed) { |
258
|
|
|
styles.push("property"); |
259
|
|
|
return styles.length ? styles.join(' ') : null; |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
if (state.linkHref) { |
263
|
|
|
styles.push(linkhref); |
264
|
|
|
return styles.length ? styles.join(' ') : null; |
265
|
|
|
} |
266
|
|
|
|
267
|
|
|
if (state.strong) { styles.push(strong); } |
268
|
|
|
if (state.em) { styles.push(em); } |
269
|
|
|
if (state.strikethrough) { styles.push(strikethrough); } |
270
|
|
|
|
271
|
|
|
if (state.linkText) { styles.push(linktext); } |
272
|
|
|
|
273
|
|
|
if (state.code) { styles.push(code); } |
274
|
|
|
|
275
|
|
|
if (state.header) { styles.push(header); styles.push(header + "-" + state.header); } |
276
|
|
|
|
277
|
|
|
if (state.quote) { |
278
|
|
|
styles.push(quote); |
279
|
|
|
|
280
|
|
|
// Add `quote-#` where the maximum for `#` is modeCfg.maxBlockquoteDepth |
281
|
|
|
if (!modeCfg.maxBlockquoteDepth || modeCfg.maxBlockquoteDepth >= state.quote) { |
282
|
|
|
styles.push(quote + "-" + state.quote); |
283
|
|
|
} else { |
284
|
|
|
styles.push(quote + "-" + modeCfg.maxBlockquoteDepth); |
285
|
|
|
} |
286
|
|
|
} |
287
|
|
|
|
288
|
|
|
if (state.list !== false) { |
289
|
|
|
var listMod = (state.listDepth - 1) % 3; |
290
|
|
|
if (!listMod) { |
291
|
|
|
styles.push(list1); |
292
|
|
|
} else if (listMod === 1) { |
293
|
|
|
styles.push(list2); |
294
|
|
|
} else { |
295
|
|
|
styles.push(list3); |
296
|
|
|
} |
297
|
|
|
} |
298
|
|
|
|
299
|
|
|
if (state.trailingSpaceNewLine) { |
300
|
|
|
styles.push("trailing-space-new-line"); |
301
|
|
|
} else if (state.trailingSpace) { |
302
|
|
|
styles.push("trailing-space-" + (state.trailingSpace % 2 ? "a" : "b")); |
303
|
|
|
} |
304
|
|
|
|
305
|
|
|
return styles.length ? styles.join(' ') : null; |
306
|
|
|
} |
307
|
|
|
|
308
|
|
|
function handleText(stream, state) { |
309
|
|
|
if (stream.match(textRE, true)) { |
310
|
|
|
return getType(state); |
311
|
|
|
} |
312
|
|
|
return undefined; |
313
|
|
|
} |
314
|
|
|
|
315
|
|
|
function inlineNormal(stream, state) { |
316
|
|
|
var style = state.text(stream, state); |
317
|
|
|
if (typeof style !== 'undefined') |
318
|
|
|
return style; |
319
|
|
|
|
320
|
|
|
if (state.list) { // List marker (*, +, -, 1., etc) |
321
|
|
|
state.list = null; |
322
|
|
|
return getType(state); |
323
|
|
|
} |
324
|
|
|
|
325
|
|
|
if (state.taskList) { |
326
|
|
|
var taskOpen = stream.match(taskListRE, true)[1] !== "x"; |
327
|
|
|
if (taskOpen) state.taskOpen = true; |
328
|
|
|
else state.taskClosed = true; |
329
|
|
|
if (modeCfg.highlightFormatting) state.formatting = "task"; |
330
|
|
|
state.taskList = false; |
331
|
|
|
return getType(state); |
332
|
|
|
} |
333
|
|
|
|
334
|
|
|
state.taskOpen = false; |
335
|
|
|
state.taskClosed = false; |
336
|
|
|
|
337
|
|
|
if (state.header && stream.match(/^#+$/, true)) { |
338
|
|
|
if (modeCfg.highlightFormatting) state.formatting = "header"; |
339
|
|
|
return getType(state); |
340
|
|
|
} |
341
|
|
|
|
342
|
|
|
// Get sol() value now, before character is consumed |
343
|
|
|
var sol = stream.sol(); |
344
|
|
|
|
345
|
|
|
var ch = stream.next(); |
346
|
|
|
|
347
|
|
|
if (ch === '\\') { |
348
|
|
|
stream.next(); |
349
|
|
|
if (modeCfg.highlightFormatting) { |
350
|
|
|
var type = getType(state); |
351
|
|
|
return type ? type + " formatting-escape" : "formatting-escape"; |
352
|
|
|
} |
353
|
|
|
} |
354
|
|
|
|
355
|
|
|
// Matches link titles present on next line |
356
|
|
|
if (state.linkTitle) { |
357
|
|
|
state.linkTitle = false; |
358
|
|
|
var matchCh = ch; |
359
|
|
|
if (ch === '(') { |
360
|
|
|
matchCh = ')'; |
361
|
|
|
} |
362
|
|
|
matchCh = (matchCh+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1"); |
363
|
|
|
var regex = '^\\s*(?:[^' + matchCh + '\\\\]+|\\\\\\\\|\\\\.)' + matchCh; |
364
|
|
|
if (stream.match(new RegExp(regex), true)) { |
365
|
|
|
return linkhref; |
366
|
|
|
} |
367
|
|
|
} |
368
|
|
|
|
369
|
|
|
// If this block is changed, it may need to be updated in GFM mode |
370
|
|
|
if (ch === '`') { |
371
|
|
|
var previousFormatting = state.formatting; |
372
|
|
|
if (modeCfg.highlightFormatting) state.formatting = "code"; |
373
|
|
|
var t = getType(state); |
374
|
|
|
var before = stream.pos; |
375
|
|
|
stream.eatWhile('`'); |
376
|
|
|
var difference = 1 + stream.pos - before; |
377
|
|
|
if (!state.code) { |
378
|
|
|
codeDepth = difference; |
379
|
|
|
state.code = true; |
380
|
|
|
return getType(state); |
381
|
|
|
} else { |
|
|
|
|
382
|
|
|
if (difference === codeDepth) { // Must be exact |
383
|
|
|
state.code = false; |
384
|
|
|
return t; |
385
|
|
|
} |
386
|
|
|
state.formatting = previousFormatting; |
387
|
|
|
return getType(state); |
388
|
|
|
} |
389
|
|
|
} else if (state.code) { |
390
|
|
|
return getType(state); |
391
|
|
|
} |
392
|
|
|
|
393
|
|
|
if (ch === '!' && stream.match(/\[[^\]]*\] ?(?:\(|\[)/, false)) { |
394
|
|
|
stream.match(/\[[^\]]*\]/); |
395
|
|
|
state.inline = state.f = linkHref; |
396
|
|
|
return image; |
397
|
|
|
} |
398
|
|
|
|
399
|
|
|
if (ch === '[' && stream.match(/.*\](\(.*\)| ?\[.*\])/, false)) { |
400
|
|
|
state.linkText = true; |
401
|
|
|
if (modeCfg.highlightFormatting) state.formatting = "link"; |
402
|
|
|
return getType(state); |
403
|
|
|
} |
404
|
|
|
|
405
|
|
|
if (ch === ']' && state.linkText && stream.match(/\(.*\)| ?\[.*\]/, false)) { |
406
|
|
|
if (modeCfg.highlightFormatting) state.formatting = "link"; |
407
|
|
|
var type = getType(state); |
|
|
|
|
408
|
|
|
state.linkText = false; |
409
|
|
|
state.inline = state.f = linkHref; |
410
|
|
|
return type; |
411
|
|
|
} |
412
|
|
|
|
413
|
|
|
if (ch === '<' && stream.match(/^(https?|ftps?):\/\/(?:[^\\>]|\\.)+>/, false)) { |
414
|
|
|
state.f = state.inline = linkInline; |
415
|
|
|
if (modeCfg.highlightFormatting) state.formatting = "link"; |
416
|
|
|
var type = getType(state); |
|
|
|
|
417
|
|
|
if (type){ |
418
|
|
|
type += " "; |
419
|
|
|
} else { |
420
|
|
|
type = ""; |
421
|
|
|
} |
422
|
|
|
return type + linkinline; |
423
|
|
|
} |
424
|
|
|
|
425
|
|
|
if (ch === '<' && stream.match(/^[^> \\]+@(?:[^\\>]|\\.)+>/, false)) { |
426
|
|
|
state.f = state.inline = linkInline; |
427
|
|
|
if (modeCfg.highlightFormatting) state.formatting = "link"; |
428
|
|
|
var type = getType(state); |
|
|
|
|
429
|
|
|
if (type){ |
430
|
|
|
type += " "; |
431
|
|
|
} else { |
432
|
|
|
type = ""; |
433
|
|
|
} |
434
|
|
|
return type + linkemail; |
435
|
|
|
} |
436
|
|
|
|
437
|
|
|
if (ch === '<' && stream.match(/^\w/, false)) { |
438
|
|
|
if (stream.string.indexOf(">") != -1) { |
439
|
|
|
var atts = stream.string.substring(1,stream.string.indexOf(">")); |
440
|
|
|
if (/markdown\s*=\s*('|"){0,1}1('|"){0,1}/.test(atts)) { |
441
|
|
|
state.md_inside = true; |
442
|
|
|
} |
443
|
|
|
} |
444
|
|
|
stream.backUp(1); |
445
|
|
|
state.htmlState = CodeMirror.startState(htmlMode); |
446
|
|
|
return switchBlock(stream, state, htmlBlock); |
447
|
|
|
} |
448
|
|
|
|
449
|
|
|
if (ch === '<' && stream.match(/^\/\w*?>/)) { |
450
|
|
|
state.md_inside = false; |
451
|
|
|
return "tag"; |
452
|
|
|
} |
453
|
|
|
|
454
|
|
|
var ignoreUnderscore = false; |
455
|
|
|
if (!modeCfg.underscoresBreakWords) { |
456
|
|
|
if (ch === '_' && stream.peek() !== '_' && stream.match(/(\w)/, false)) { |
457
|
|
|
var prevPos = stream.pos - 2; |
458
|
|
|
if (prevPos >= 0) { |
459
|
|
|
var prevCh = stream.string.charAt(prevPos); |
460
|
|
|
if (prevCh !== '_' && prevCh.match(/(\w)/, false)) { |
461
|
|
|
ignoreUnderscore = true; |
462
|
|
|
} |
463
|
|
|
} |
464
|
|
|
} |
465
|
|
|
} |
466
|
|
|
if (ch === '*' || (ch === '_' && !ignoreUnderscore)) { |
467
|
|
|
if (sol && stream.peek() === ' ') { |
|
|
|
|
468
|
|
|
// Do nothing, surrounded by newline and space |
469
|
|
|
} else if (state.strong === ch && stream.eat(ch)) { // Remove STRONG |
470
|
|
|
if (modeCfg.highlightFormatting) state.formatting = "strong"; |
471
|
|
|
var t = getType(state); |
|
|
|
|
472
|
|
|
state.strong = false; |
473
|
|
|
return t; |
474
|
|
|
} else if (!state.strong && stream.eat(ch)) { // Add STRONG |
475
|
|
|
state.strong = ch; |
476
|
|
|
if (modeCfg.highlightFormatting) state.formatting = "strong"; |
477
|
|
|
return getType(state); |
478
|
|
|
} else if (state.em === ch) { // Remove EM |
479
|
|
|
if (modeCfg.highlightFormatting) state.formatting = "em"; |
480
|
|
|
var t = getType(state); |
|
|
|
|
481
|
|
|
state.em = false; |
482
|
|
|
return t; |
483
|
|
|
} else if (!state.em) { // Add EM |
484
|
|
|
state.em = ch; |
485
|
|
|
if (modeCfg.highlightFormatting) state.formatting = "em"; |
486
|
|
|
return getType(state); |
487
|
|
|
} |
488
|
|
|
} else if (ch === ' ') { |
489
|
|
|
if (stream.eat('*') || stream.eat('_')) { // Probably surrounded by spaces |
490
|
|
|
if (stream.peek() === ' ') { // Surrounded by spaces, ignore |
491
|
|
|
return getType(state); |
492
|
|
|
} else { // Not surrounded by spaces, back up pointer |
|
|
|
|
493
|
|
|
stream.backUp(1); |
494
|
|
|
} |
495
|
|
|
} |
496
|
|
|
} |
497
|
|
|
|
498
|
|
|
if (modeCfg.strikethrough) { |
499
|
|
|
if (ch === '~' && stream.eatWhile(ch)) { |
500
|
|
|
if (state.strikethrough) {// Remove strikethrough |
501
|
|
|
if (modeCfg.highlightFormatting) state.formatting = "strikethrough"; |
502
|
|
|
var t = getType(state); |
|
|
|
|
503
|
|
|
state.strikethrough = false; |
504
|
|
|
return t; |
505
|
|
|
} else if (stream.match(/^[^\s]/, false)) {// Add strikethrough |
506
|
|
|
state.strikethrough = true; |
507
|
|
|
if (modeCfg.highlightFormatting) state.formatting = "strikethrough"; |
508
|
|
|
return getType(state); |
509
|
|
|
} |
510
|
|
|
} else if (ch === ' ') { |
511
|
|
|
if (stream.match(/^~~/, true)) { // Probably surrounded by space |
512
|
|
|
if (stream.peek() === ' ') { // Surrounded by spaces, ignore |
513
|
|
|
return getType(state); |
514
|
|
|
} else { // Not surrounded by spaces, back up pointer |
|
|
|
|
515
|
|
|
stream.backUp(2); |
516
|
|
|
} |
517
|
|
|
} |
518
|
|
|
} |
519
|
|
|
} |
520
|
|
|
|
521
|
|
|
if (ch === ' ') { |
522
|
|
|
if (stream.match(/ +$/, false)) { |
523
|
|
|
state.trailingSpace++; |
524
|
|
|
} else if (state.trailingSpace) { |
525
|
|
|
state.trailingSpaceNewLine = true; |
526
|
|
|
} |
527
|
|
|
} |
528
|
|
|
|
529
|
|
|
return getType(state); |
530
|
|
|
} |
531
|
|
|
|
532
|
|
|
function linkInline(stream, state) { |
533
|
|
|
var ch = stream.next(); |
534
|
|
|
|
535
|
|
|
if (ch === ">") { |
536
|
|
|
state.f = state.inline = inlineNormal; |
537
|
|
|
if (modeCfg.highlightFormatting) state.formatting = "link"; |
538
|
|
|
var type = getType(state); |
539
|
|
|
if (type){ |
540
|
|
|
type += " "; |
541
|
|
|
} else { |
542
|
|
|
type = ""; |
543
|
|
|
} |
544
|
|
|
return type + linkinline; |
545
|
|
|
} |
546
|
|
|
|
547
|
|
|
stream.match(/^[^>]+/, true); |
548
|
|
|
|
549
|
|
|
return linkinline; |
550
|
|
|
} |
551
|
|
|
|
552
|
|
|
function linkHref(stream, state) { |
553
|
|
|
// Check if space, and return NULL if so (to avoid marking the space) |
554
|
|
|
if(stream.eatSpace()){ |
555
|
|
|
return null; |
556
|
|
|
} |
557
|
|
|
var ch = stream.next(); |
558
|
|
|
if (ch === '(' || ch === '[') { |
559
|
|
|
state.f = state.inline = getLinkHrefInside(ch === "(" ? ")" : "]"); |
560
|
|
|
if (modeCfg.highlightFormatting) state.formatting = "link-string"; |
561
|
|
|
state.linkHref = true; |
562
|
|
|
return getType(state); |
563
|
|
|
} |
564
|
|
|
return 'error'; |
565
|
|
|
} |
566
|
|
|
|
567
|
|
|
function getLinkHrefInside(endChar) { |
568
|
|
|
return function(stream, state) { |
569
|
|
|
var ch = stream.next(); |
570
|
|
|
|
571
|
|
|
if (ch === endChar) { |
572
|
|
|
state.f = state.inline = inlineNormal; |
573
|
|
|
if (modeCfg.highlightFormatting) state.formatting = "link-string"; |
574
|
|
|
var returnState = getType(state); |
575
|
|
|
state.linkHref = false; |
576
|
|
|
return returnState; |
577
|
|
|
} |
578
|
|
|
|
579
|
|
|
if (stream.match(inlineRE(endChar), true)) { |
580
|
|
|
stream.backUp(1); |
581
|
|
|
} |
582
|
|
|
|
583
|
|
|
state.linkHref = true; |
584
|
|
|
return getType(state); |
585
|
|
|
}; |
586
|
|
|
} |
587
|
|
|
|
588
|
|
|
function footnoteLink(stream, state) { |
589
|
|
|
if (stream.match(/^[^\]]*\]:/, false)) { |
590
|
|
|
state.f = footnoteLinkInside; |
591
|
|
|
stream.next(); // Consume [ |
592
|
|
|
if (modeCfg.highlightFormatting) state.formatting = "link"; |
593
|
|
|
state.linkText = true; |
594
|
|
|
return getType(state); |
595
|
|
|
} |
596
|
|
|
return switchInline(stream, state, inlineNormal); |
597
|
|
|
} |
598
|
|
|
|
599
|
|
|
function footnoteLinkInside(stream, state) { |
600
|
|
|
if (stream.match(/^\]:/, true)) { |
601
|
|
|
state.f = state.inline = footnoteUrl; |
602
|
|
|
if (modeCfg.highlightFormatting) state.formatting = "link"; |
603
|
|
|
var returnType = getType(state); |
604
|
|
|
state.linkText = false; |
605
|
|
|
return returnType; |
606
|
|
|
} |
607
|
|
|
|
608
|
|
|
stream.match(/^[^\]]+/, true); |
609
|
|
|
|
610
|
|
|
return linktext; |
611
|
|
|
} |
612
|
|
|
|
613
|
|
|
function footnoteUrl(stream, state) { |
614
|
|
|
// Check if space, and return NULL if so (to avoid marking the space) |
615
|
|
|
if(stream.eatSpace()){ |
616
|
|
|
return null; |
617
|
|
|
} |
618
|
|
|
// Match URL |
619
|
|
|
stream.match(/^[^\s]+/, true); |
620
|
|
|
// Check for link title |
621
|
|
|
if (stream.peek() === undefined) { // End of line, set flag to check next line |
622
|
|
|
state.linkTitle = true; |
623
|
|
|
} else { // More content on line, check if link title |
624
|
|
|
stream.match(/^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?/, true); |
625
|
|
|
} |
626
|
|
|
state.f = state.inline = inlineNormal; |
627
|
|
|
return linkhref; |
628
|
|
|
} |
629
|
|
|
|
630
|
|
|
var savedInlineRE = []; |
631
|
|
|
function inlineRE(endChar) { |
632
|
|
|
if (!savedInlineRE[endChar]) { |
633
|
|
|
// Escape endChar for RegExp (taken from http://stackoverflow.com/a/494122/526741) |
634
|
|
|
endChar = (endChar+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1"); |
635
|
|
|
// Match any non-endChar, escaped character, as well as the closing |
636
|
|
|
// endChar. |
637
|
|
|
savedInlineRE[endChar] = new RegExp('^(?:[^\\\\]|\\\\.)*?(' + endChar + ')'); |
638
|
|
|
} |
639
|
|
|
return savedInlineRE[endChar]; |
640
|
|
|
} |
641
|
|
|
|
642
|
|
|
var mode = { |
643
|
|
|
startState: function() { |
644
|
|
|
return { |
645
|
|
|
f: blockNormal, |
646
|
|
|
|
647
|
|
|
prevLineHasContent: false, |
648
|
|
|
thisLineHasContent: false, |
649
|
|
|
|
650
|
|
|
block: blockNormal, |
651
|
|
|
htmlState: null, |
652
|
|
|
indentation: 0, |
653
|
|
|
|
654
|
|
|
inline: inlineNormal, |
655
|
|
|
text: handleText, |
656
|
|
|
|
657
|
|
|
formatting: false, |
658
|
|
|
linkText: false, |
659
|
|
|
linkHref: false, |
660
|
|
|
linkTitle: false, |
661
|
|
|
em: false, |
662
|
|
|
strong: false, |
663
|
|
|
header: 0, |
664
|
|
|
taskList: false, |
665
|
|
|
list: false, |
666
|
|
|
listDepth: 0, |
667
|
|
|
quote: 0, |
668
|
|
|
trailingSpace: 0, |
669
|
|
|
trailingSpaceNewLine: false, |
670
|
|
|
strikethrough: false |
671
|
|
|
}; |
672
|
|
|
}, |
673
|
|
|
|
674
|
|
|
copyState: function(s) { |
675
|
|
|
return { |
676
|
|
|
f: s.f, |
677
|
|
|
|
678
|
|
|
prevLineHasContent: s.prevLineHasContent, |
679
|
|
|
thisLineHasContent: s.thisLineHasContent, |
680
|
|
|
|
681
|
|
|
block: s.block, |
682
|
|
|
htmlState: s.htmlState && CodeMirror.copyState(htmlMode, s.htmlState), |
683
|
|
|
indentation: s.indentation, |
684
|
|
|
|
685
|
|
|
localMode: s.localMode, |
686
|
|
|
localState: s.localMode ? CodeMirror.copyState(s.localMode, s.localState) : null, |
687
|
|
|
|
688
|
|
|
inline: s.inline, |
689
|
|
|
text: s.text, |
690
|
|
|
formatting: false, |
691
|
|
|
linkTitle: s.linkTitle, |
692
|
|
|
em: s.em, |
693
|
|
|
strong: s.strong, |
694
|
|
|
strikethrough: s.strikethrough, |
695
|
|
|
header: s.header, |
696
|
|
|
taskList: s.taskList, |
697
|
|
|
list: s.list, |
698
|
|
|
listDepth: s.listDepth, |
699
|
|
|
quote: s.quote, |
700
|
|
|
trailingSpace: s.trailingSpace, |
701
|
|
|
trailingSpaceNewLine: s.trailingSpaceNewLine, |
702
|
|
|
md_inside: s.md_inside |
703
|
|
|
}; |
704
|
|
|
}, |
705
|
|
|
|
706
|
|
|
token: function(stream, state) { |
707
|
|
|
|
708
|
|
|
// Reset state.formatting |
709
|
|
|
state.formatting = false; |
710
|
|
|
|
711
|
|
|
if (stream.sol()) { |
712
|
|
|
var forceBlankLine = !!state.header; |
713
|
|
|
|
714
|
|
|
// Reset state.header |
715
|
|
|
state.header = 0; |
716
|
|
|
|
717
|
|
|
if (stream.match(/^\s*$/, true) || forceBlankLine) { |
718
|
|
|
state.prevLineHasContent = false; |
719
|
|
|
blankLine(state); |
720
|
|
|
return forceBlankLine ? this.token(stream, state) : null; |
721
|
|
|
} else { |
|
|
|
|
722
|
|
|
state.prevLineHasContent = state.thisLineHasContent; |
723
|
|
|
state.thisLineHasContent = true; |
724
|
|
|
} |
725
|
|
|
|
726
|
|
|
// Reset state.taskList |
727
|
|
|
state.taskList = false; |
728
|
|
|
|
729
|
|
|
// Reset state.code |
730
|
|
|
state.code = false; |
731
|
|
|
|
732
|
|
|
// Reset state.trailingSpace |
733
|
|
|
state.trailingSpace = 0; |
734
|
|
|
state.trailingSpaceNewLine = false; |
735
|
|
|
|
736
|
|
|
state.f = state.block; |
737
|
|
|
var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, ' ').length; |
738
|
|
|
var difference = Math.floor((indentation - state.indentation) / 4) * 4; |
739
|
|
|
if (difference > 4) difference = 4; |
740
|
|
|
var adjustedIndentation = state.indentation + difference; |
741
|
|
|
state.indentationDiff = adjustedIndentation - state.indentation; |
742
|
|
|
state.indentation = adjustedIndentation; |
743
|
|
|
if (indentation > 0) return null; |
744
|
|
|
} |
745
|
|
|
return state.f(stream, state); |
746
|
|
|
}, |
747
|
|
|
|
748
|
|
|
innerMode: function(state) { |
749
|
|
|
if (state.block == htmlBlock) return {state: state.htmlState, mode: htmlMode}; |
750
|
|
|
if (state.localState) return {state: state.localState, mode: state.localMode}; |
751
|
|
|
return {state: state, mode: mode}; |
752
|
|
|
}, |
753
|
|
|
|
754
|
|
|
blankLine: blankLine, |
755
|
|
|
|
756
|
|
|
getType: getType, |
757
|
|
|
|
758
|
|
|
fold: "markdown" |
759
|
|
|
}; |
760
|
|
|
return mode; |
761
|
|
|
}, "xml"); |
762
|
|
|
|
763
|
|
|
CodeMirror.defineMIME("text/x-markdown", "markdown"); |
764
|
|
|
|
765
|
|
|
}); |
766
|
|
|
|
This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.
To learn more about declaring variables in Javascript, see the MDN.