CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { var htmlMode = CodeMirror.getMode(cmCfg, { name: 'xml', htmlMode: true }); var header = 'header' , code = 'code' , quote = 'quote' , list = 'list' , hr = 'hr' , linktext = 'linktext' , linkhref = 'linkhref' , em = 'em' , strong = 'strong' , emstrong = 'emstrong'; var hrRE = /^[*-=_]/ , ulRE = /^[*-+]\s+/ , olRE = /^[0-9]\.\s+/ , headerRE = /^(?:\={3,}|-{3,})$/ , codeRE = /^(k:\t|\s{4,})/ , textRE = /^[^\[*_\\<>`]+/; function switchInline(stream, state, f) { state.f = state.inline = f; return f(stream, state); } function switchBlock(stream, state, f) { state.f = state.block = f; return f(stream, state); } // Blocks function blockNormal(stream, state) { if (stream.match(codeRE)) { stream.skipToEnd(); return code; } if (stream.eatSpace()) { return null; } if (stream.peek() === '#' || stream.match(headerRE)) { stream.skipToEnd(); return header; } if (stream.eat('>')) { state.indentation++; return quote; } if (stream.peek() === '<') { return switchBlock(stream, state, htmlBlock); } if (stream.peek() === '[') { return switchInline(stream, state, footnoteLink); } if (hrRE.test(stream.peek())) { var re = new RegExp('(?:\s*['+stream.peek()+']){3,}$'); if (stream.match(re, true)) { return hr; } } var match; if (match = stream.match(ulRE, true) || stream.match(olRE, true)) { state.indentation += match[0].length; return list; } return switchInline(stream, state, state.inline); } function htmlBlock(stream, state) { var type = htmlMode.token(stream, state.htmlState); if (stream.eol() && !state.htmlState.context) { state.block = blockNormal; } return type; } // Inline function inlineNormal(stream, state) { function getType() { return state.strong ? (state.em ? emstrong : strong) : (state.em ? em : null); } if (stream.match(textRE, true)) { return getType(); } var ch = stream.next(); if (ch === '\\') { stream.next(); return getType(); } if (ch === '`') { return switchInline(stream, state, inlineElement(code, '`')); } if (ch === '<') { return switchInline(stream, state, inlineElement(linktext, '>')); } if (ch === '[') { return switchInline(stream, state, linkText); } var t = getType(); if (ch === '*' || ch === '_') { if (stream.eat(ch)) { return (state.strong = !state.strong) ? getType() : t; } return (state.em = !state.em) ? getType() : t; } return getType(); } function linkText(stream, state) { while (!stream.eol()) { var ch = stream.next(); if (ch === '\\') stream.next(); if (ch === ']') { state.inline = state.f = linkHref; return linktext; } } return linktext; } function linkHref(stream, state) { stream.eatSpace(); var ch = stream.next(); if (ch === '(' || ch === '[') { return switchInline(stream, state, inlineElement(linkhref, ch === '(' ? ')' : ']')); } return 'error'; } function footnoteLink(stream, state) { if (stream.match(/^[^\]]*\]:/, true)) { state.f = footnoteUrl; return linktext; } return switchInline(stream, state, inlineNormal); } function footnoteUrl(stream, state) { stream.eatSpace(); stream.match(/^[^\s]+/, true); state.f = state.inline = inlineNormal; return linkhref; } function inlineElement(type, endChar, next) { next = next || inlineNormal; return function(stream, state) { while (!stream.eol()) { var ch = stream.next(); if (ch === '\\') stream.next(); if (ch === endChar) { state.inline = state.f = next; return type; } } return type; }; } return { startState: function() { return { f: blockNormal, block: blockNormal, htmlState: htmlMode.startState(), indentation: 0, inline: inlineNormal, em: false, strong: false }; }, copyState: function(s) { return { f: s.f, block: s.block, htmlState: CodeMirror.copyState(htmlMode, s.htmlState), indentation: s.indentation, inline: s.inline, em: s.em, strong: s.strong }; }, token: function(stream, state) { if (stream.sol()) { state.f = state.block; var previousIndentation = state.indentation , currentIndentation = 0; while (previousIndentation > 0) { if (stream.eat(' ')) { previousIndentation--; currentIndentation++; } else if (previousIndentation >= 4 && stream.eat('\t')) { previousIndentation -= 4; currentIndentation += 4; } else { break; } } state.indentation = currentIndentation; if (currentIndentation > 0) return null; } return state.f(stream, state); } }; }); CodeMirror.defineMIME("text/x-markdown", "markdown");