mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-13 01:36:22 +00:00
131 lines
3.2 KiB
JavaScript
131 lines
3.2 KiB
JavaScript
'use strict'
|
|
|
|
module.exports = function (md, renderers, defaultRenderer) {
|
|
function fence (state, startLine, endLine) {
|
|
let pos = state.bMarks[startLine] + state.tShift[startLine]
|
|
let max = state.eMarks[startLine]
|
|
|
|
if (state.sCount[startLine] - state.blkIndent >= 4 || pos + 3 > max) {
|
|
return false
|
|
}
|
|
|
|
const marker = state.src.charCodeAt(pos)
|
|
if (!(marker === 96 || marker === 126)) {
|
|
return false
|
|
}
|
|
|
|
let mem = pos
|
|
pos = state.skipChars(pos, marker)
|
|
|
|
let len = pos - mem
|
|
if (len < 3) {
|
|
return false
|
|
}
|
|
|
|
const markup = state.src.slice(mem, pos)
|
|
const params = state.src.slice(pos, max)
|
|
|
|
let nextLine = startLine
|
|
let haveEndMarker = false
|
|
|
|
while (true) {
|
|
nextLine++
|
|
if (nextLine >= endLine) {
|
|
break
|
|
}
|
|
|
|
pos = mem = state.bMarks[nextLine] + state.tShift[nextLine]
|
|
max = state.eMarks[nextLine]
|
|
|
|
if (pos < max && state.sCount[nextLine] < state.blkIndent) {
|
|
break
|
|
}
|
|
if (state.src.charCodeAt(pos) !== marker || state.sCount[nextLine] - state.blkIndent >= 4) {
|
|
continue
|
|
}
|
|
|
|
pos = state.skipChars(pos, marker)
|
|
|
|
if (pos - mem < len) {
|
|
continue
|
|
}
|
|
|
|
pos = state.skipSpaces(pos)
|
|
|
|
if (pos >= max) {
|
|
haveEndMarker = true
|
|
break
|
|
}
|
|
}
|
|
|
|
len = state.sCount[startLine]
|
|
state.line = nextLine + (haveEndMarker ? 1 : 0)
|
|
|
|
const parameters = {}
|
|
let langType = ''
|
|
let fileName = ''
|
|
let firstLineNumber = 0
|
|
|
|
let match = /^(\w[-\w]*)?(?:\(((?:\s*\w[-\w]*(?:=(?:'(?:.*?[^\\])?'|"(?:.*?[^\\])?"|(?:[^'"][^\s]*)))?)*)\))?(?::([^:]*)(?::(\d+))?)?\s*$/.exec(params)
|
|
if (match) {
|
|
if (match[1]) {
|
|
langType = match[1]
|
|
}
|
|
if (match[3]) {
|
|
fileName = match[3]
|
|
}
|
|
if (match[4]) {
|
|
firstLineNumber = parseInt(match[4], 10)
|
|
}
|
|
|
|
if (match[2]) {
|
|
const params = match[2]
|
|
const regex = /(\w[-\w]*)(?:=(?:'(.*?[^\\])?'|"(.*?[^\\])?"|([^'"][^\s]*)))?/g
|
|
|
|
let name, value
|
|
while ((match = regex.exec(params))) {
|
|
name = match[1]
|
|
value = match[2] || match[3] || match[4] || null
|
|
|
|
const height = /^(\d+)h$/.exec(name)
|
|
if (height && !value) {
|
|
parameters.height = height[1]
|
|
} else {
|
|
parameters[name] = value
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
let token
|
|
if (renderers[langType]) {
|
|
token = state.push(`${langType}_fence`, 'div', 0)
|
|
} else {
|
|
token = state.push('_fence', 'code', 0)
|
|
}
|
|
|
|
token.langType = langType
|
|
token.fileName = fileName
|
|
token.firstLineNumber = firstLineNumber
|
|
token.parameters = parameters
|
|
|
|
token.content = state.getLines(startLine + 1, nextLine, len, true)
|
|
token.markup = markup
|
|
token.map = [startLine, state.line]
|
|
|
|
return true
|
|
}
|
|
|
|
md.block.ruler.before('fence', '_fence', fence, {
|
|
alt: ['paragraph', 'reference', 'blockquote', 'list']
|
|
})
|
|
|
|
for (let name in renderers) {
|
|
md.renderer.rules[`${name}_fence`] = (tokens, index) => renderers[name](tokens[index])
|
|
}
|
|
|
|
if (defaultRenderer) {
|
|
md.renderer.rules['_fence'] = (tokens, index) => defaultRenderer(tokens[index])
|
|
}
|
|
}
|