1
CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
3
var htmlMode = CodeMirror.getMode(cmCfg, { name: 'xml', htmlMode: true });
14
, emstrong = 'emstrong';
16
var hrRE = /^([*\-=_])(?:\s*\1){2,}\s*$/
18
, olRE = /^[0-9]+\.\s+/
19
, headerRE = /^(?:\={3,}|-{3,})$/
20
, textRE = /^[^\[*_\\<>`]+/;
22
function switchInline(stream, state, f) {
23
state.f = state.inline = f;
24
return f(stream, state);
27
function switchBlock(stream, state, f) {
28
state.f = state.block = f;
29
return f(stream, state);
35
function blankLine(state) {
43
function blockNormal(stream, state) {
45
if (state.indentationDiff >= 4) {
46
state.indentation -= state.indentationDiff;
49
} else if (stream.eatSpace()) {
51
} else if (stream.peek() === '#' || stream.match(headerRE)) {
53
} else if (stream.eat('>')) {
56
} else if (stream.peek() === '[') {
57
return switchInline(stream, state, footnoteLink);
58
} else if (stream.match(hrRE, true)) {
60
} else if (match = stream.match(ulRE, true) || stream.match(olRE, true)) {
61
state.indentation += match[0].length;
65
return switchInline(stream, state, state.inline);
68
function htmlBlock(stream, state) {
69
var style = htmlMode.token(stream, state.htmlState);
70
if (style === 'tag' && state.htmlState.type !== 'openTag' && !state.htmlState.context) {
71
state.f = inlineNormal;
72
state.block = blockNormal;
79
function getType(state) {
82
if (state.strong) { styles.push(state.em ? emstrong : strong); }
83
else if (state.em) { styles.push(em); }
85
if (state.header) { styles.push(header); }
86
if (state.quote) { styles.push(quote); }
88
return styles.length ? styles.join(' ') : null;
91
function handleText(stream, state) {
92
if (stream.match(textRE, true)) {
93
return getType(state);
98
function inlineNormal(stream, state) {
99
var style = state.text(stream, state)
100
if (typeof style !== 'undefined')
103
var ch = stream.next();
107
return getType(state);
110
return switchInline(stream, state, inlineElement(code, '`'));
113
return switchInline(stream, state, linkText);
115
if (ch === '<' && stream.match(/^\w/, false)) {
117
return switchBlock(stream, state, htmlBlock);
120
var t = getType(state);
121
if (ch === '*' || ch === '_') {
122
if (stream.eat(ch)) {
123
return (state.strong = !state.strong) ? getType(state) : t;
125
return (state.em = !state.em) ? getType(state) : t;
128
return getType(state);
131
function linkText(stream, state) {
132
while (!stream.eol()) {
133
var ch = stream.next();
134
if (ch === '\\') stream.next();
136
state.inline = state.f = linkHref;
143
function linkHref(stream, state) {
145
var ch = stream.next();
146
if (ch === '(' || ch === '[') {
147
return switchInline(stream, state, inlineElement(linkhref, ch === '(' ? ')' : ']'));
152
function footnoteLink(stream, state) {
153
if (stream.match(/^[^\]]*\]:/, true)) {
154
state.f = footnoteUrl;
157
return switchInline(stream, state, inlineNormal);
160
function footnoteUrl(stream, state) {
162
stream.match(/^[^\s]+/, true);
163
state.f = state.inline = inlineNormal;
167
function inlineRE(endChar) {
168
if (!inlineRE[endChar]) {
169
// match any not-escaped-non-endChar and any escaped char
170
// then match endChar or eol
171
inlineRE[endChar] = new RegExp('^(?:[^\\\\\\' + endChar + ']|\\\\.)*(?:\\' + endChar + '|$)');
173
return inlineRE[endChar];
176
function inlineElement(type, endChar, next) {
177
next = next || inlineNormal;
178
return function(stream, state) {
179
stream.match(inlineRE(endChar));
180
state.inline = state.f = next;
186
startState: function() {
191
htmlState: htmlMode.startState(),
194
inline: inlineNormal,
203
copyState: function(s) {
208
htmlState: CodeMirror.copyState(htmlMode, s.htmlState),
209
indentation: s.indentation,
220
token: function(stream, state) {
222
if (stream.match(/^\s*$/, true)) { return blankLine(state); }
224
// Reset state.header
225
state.header = false;
229
state.f = state.block;
230
var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, ' ').length;
231
state.indentationDiff = indentation - state.indentation;
232
state.indentation = indentation;
233
if (indentation > 0) { return null; }
235
return state.f(stream, state);
238
blankLine: blankLine,
245
CodeMirror.defineMIME("text/x-markdown", "markdown");