forked from Gitlink/forgeplus-react
123 lines
3.0 KiB
JavaScript
123 lines
3.0 KiB
JavaScript
import marked from 'marked'
|
|
import { escape, unescape } from 'marked/src/helpers'
|
|
import { renderToString } from 'katex';
|
|
|
|
const latexRegex = /\$+([^\$\n]+?)\$+/g
|
|
//兼容之前的 ##标题式写法
|
|
const headingRegex = /^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/
|
|
let toc = []
|
|
let ctx = ["<ul>"]
|
|
|
|
export function cleanToc() {
|
|
toc = []
|
|
ctx = ["<ul>"]
|
|
}
|
|
|
|
function buildToc(coll, k, level, ctx) {
|
|
if (k >= coll.length || coll[k].level <= level) { return k }
|
|
var node = coll[k]
|
|
ctx.push("<li><a href='#" + node.anchor + "'>" + node.text + "</a>")
|
|
k++
|
|
var childCtx = []
|
|
k = buildToc(coll, k, node.level, childCtx)
|
|
if (childCtx.length > 0) {
|
|
ctx.push("<ul>")
|
|
childCtx.forEach(function (idm) {
|
|
ctx.push(idm)
|
|
});
|
|
ctx.push("</ul>")
|
|
}
|
|
ctx.push("</li>")
|
|
k = buildToc(coll, k, level, ctx)
|
|
return k
|
|
}
|
|
|
|
export function getTocContent() {
|
|
buildToc(toc, 0, 0, ctx)
|
|
ctx.push("</ul>")
|
|
return ctx.join("")
|
|
}
|
|
|
|
const tokenizer = {
|
|
heading(src) {
|
|
const cap = headingRegex.exec(src);
|
|
if (cap) {
|
|
return {
|
|
type: 'heading',
|
|
raw: cap[0],
|
|
depth: cap[1].length,
|
|
text: cap[2]
|
|
};
|
|
}
|
|
},
|
|
codespan(src) {
|
|
const cap = this.rules.inline.code.exec(src);
|
|
if (cap) {
|
|
let text = cap[2].replace(/\n/g, ' ');
|
|
const hasNonSpaceChars = /[^ ]/.test(text);
|
|
const hasSpaceCharsOnBothEnds = text.startsWith(' ') && text.endsWith(' ');
|
|
if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) {
|
|
text = text.substring(1, text.length - 1)
|
|
}
|
|
let match = text.match(latexRegex)
|
|
if (match) {
|
|
text = text.replace(latexRegex, (_, $1) => {
|
|
return renderToString(unescape($1))
|
|
})
|
|
} else {
|
|
text = escape(text, true);
|
|
}
|
|
return {
|
|
type: 'codespan',
|
|
raw: cap[0],
|
|
text
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const renderer = {
|
|
code(code, infostring, escaped) {
|
|
const lang = (infostring || '').match(/\S*/)[0];
|
|
if (!lang) {
|
|
return '<pre class="prettyprint linenums"><code>'
|
|
+ (escaped ? code : escape(code, true))
|
|
+ '</code></pre>';
|
|
}
|
|
|
|
if (['latex', 'katex', 'math'].indexOf(lang) >= 0) {
|
|
return `<p class='editormd-tex'>${renderToString(unescape(code))}</p>`
|
|
} else {
|
|
return `<pre class="prettyprint linenums"><code class="language-${infostring}">${escaped ? code : escape(code, true)}</code></pre>\n`
|
|
}
|
|
}
|
|
, paragraph(text) {
|
|
let match = text.match(latexRegex)
|
|
if (match) {
|
|
text = text.replace(latexRegex, (_, $1) => {
|
|
return renderToString(unescape($1))
|
|
})
|
|
}
|
|
return '<p>' + text + '</p>\n';
|
|
},
|
|
heading(text, level, raw, slugger) {
|
|
let anchor = this.options.headerPrefix + raw.toLowerCase().replace(/[^\w\\u4e00-\\u9fa5]]+/g, '-');
|
|
toc.push({
|
|
anchor: anchor,
|
|
level: level,
|
|
text: text
|
|
})
|
|
return '<h' + level + ' id="' + anchor + '">' + text + '</h' + level + '>'
|
|
}
|
|
}
|
|
|
|
marked.setOptions({
|
|
silent: true,
|
|
smartypants: true,
|
|
gfm: true,
|
|
pedantic: false
|
|
})
|
|
|
|
marked.use({ tokenizer, renderer });
|
|
|
|
export default marked |