|
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 'linkhref'; |
|
} |
|
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) { |
|
return state.token(stream, state); |
|
} |
|
} |
|
}); |
|
|