gfm.js
144 lines
| 4.0 KiB
| application/javascript
|
JavascriptLexer
Matthias BUSSONNIER
|
r8053 | CodeMirror.defineMode("gfm", function(config, parserConfig) { | ||
var mdMode = CodeMirror.getMode(config, "markdown"); | ||||
var aliases = { | ||||
html: "htmlmixed", | ||||
js: "javascript", | ||||
json: "application/json", | ||||
c: "text/x-csrc", | ||||
"c++": "text/x-c++src", | ||||
java: "text/x-java", | ||||
csharp: "text/x-csharp", | ||||
"c#": "text/x-csharp" | ||||
}; | ||||
// make this lazy so that we don't need to load GFM last | ||||
var getMode = (function () { | ||||
var i, modes = {}, mimes = {}, mime; | ||||
var list = CodeMirror.listModes(); | ||||
for (i = 0; i < list.length; i++) { | ||||
modes[list[i]] = list[i]; | ||||
} | ||||
var mimesList = CodeMirror.listMIMEs(); | ||||
for (i = 0; i < mimesList.length; i++) { | ||||
mime = mimesList[i].mime; | ||||
mimes[mime] = mimesList[i].mime; | ||||
} | ||||
for (var a in aliases) { | ||||
if (aliases[a] in modes || aliases[a] in mimes) | ||||
modes[a] = aliases[a]; | ||||
} | ||||
return function (lang) { | ||||
return modes[lang] ? CodeMirror.getMode(config, modes[lang]) : null; | ||||
} | ||||
}()); | ||||
function markdown(stream, state) { | ||||
// intercept fenced code blocks | ||||
if (stream.sol() && stream.match(/^```([\w+#]*)/)) { | ||||
// try switching mode | ||||
state.localMode = getMode(RegExp.$1) | ||||
if (state.localMode) | ||||
state.localState = state.localMode.startState(); | ||||
state.token = local; | ||||
return 'code'; | ||||
} | ||||
return mdMode.token(stream, state.mdState); | ||||
} | ||||
function local(stream, state) { | ||||
if (stream.sol() && stream.match(/^```/)) { | ||||
state.localMode = state.localState = null; | ||||
state.token = markdown; | ||||
return 'code'; | ||||
} | ||||
else if (state.localMode) { | ||||
return state.localMode.token(stream, state.localState); | ||||
} else { | ||||
stream.skipToEnd(); | ||||
return 'code'; | ||||
} | ||||
} | ||||
// custom handleText to prevent emphasis in the middle of a word | ||||
// and add autolinking | ||||
function handleText(stream, mdState) { | ||||
var match; | ||||
if (stream.match(/^\w+:\/\/\S+/)) { | ||||
return 'link'; | ||||
} | ||||
if (stream.match(/^[^\[*\\<>` _][^\[*\\<>` ]*[^\[*\\<>` _]/)) { | ||||
return mdMode.getType(mdState); | ||||
} | ||||
if (match = stream.match(/^[^\[*\\<>` ]+/)) { | ||||
var word = match[0]; | ||||
if (word[0] === '_' && word[word.length-1] === '_') { | ||||
stream.backUp(word.length); | ||||
return undefined; | ||||
} | ||||
return mdMode.getType(mdState); | ||||
} | ||||
if (stream.eatSpace()) { | ||||
return null; | ||||
} | ||||
} | ||||
return { | ||||
startState: function() { | ||||
var mdState = mdMode.startState(); | ||||
mdState.text = handleText; | ||||
return {token: markdown, mode: "markdown", mdState: mdState, | ||||
localMode: null, localState: null}; | ||||
}, | ||||
copyState: function(state) { | ||||
return {token: state.token, mode: state.mode, mdState: CodeMirror.copyState(mdMode, state.mdState), | ||||
localMode: state.localMode, | ||||
localState: state.localMode ? CodeMirror.copyState(state.localMode, state.localState) : null}; | ||||
}, | ||||
token: function(stream, state) { | ||||
/* Parse GFM double bracket links */ | ||||
if ((ch = stream.peek()) != undefined && ch == '[') { | ||||
stream.next(); // Advance the stream | ||||
/* Only handle double bracket links */ | ||||
if ((ch = stream.peek()) == undefined || ch != '[') { | ||||
stream.backUp(1); | ||||
return state.token(stream, state); | ||||
} | ||||
while ((ch = stream.next()) != undefined && ch != ']') {} | ||||
if (ch == ']' && (ch = stream.next()) != undefined && ch == ']') | ||||
return 'link'; | ||||
/* If we did not find the second ']' */ | ||||
stream.backUp(1); | ||||
} | ||||
/* Match GFM latex formulas, as well as latex formulas within '$' */ | ||||
if (stream.match(/^\$[^\$]+\$/)) { | ||||
return "string"; | ||||
} | ||||
if (stream.match(/^\\\((.*?)\\\)/)) { | ||||
return "string"; | ||||
} | ||||
if (stream.match(/^\$\$[^\$]+\$\$/)) { | ||||
return "string"; | ||||
} | ||||
if (stream.match(/^\\\[(.*?)\\\]/)) { | ||||
return "string"; | ||||
} | ||||
return state.token(stream, state); | ||||
} | ||||
} | ||||
}, "markdown"); | ||||