1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-13 09:46:22 +00:00

Merge pull request #2346 from daiyam/text-deflist

add support to abbreviations, definition lists and subscript/superscript text
This commit is contained in:
Junyoung Choi (Sai)
2018-11-08 14:35:56 +09:00
committed by GitHub
9 changed files with 467 additions and 20 deletions

View File

@@ -0,0 +1,232 @@
'use strict'
module.exports = function definitionListPlugin (md) {
var isSpace = md.utils.isSpace
// Search `[:~][\n ]`, returns next pos after marker on success
// or -1 on fail.
function skipMarker (state, line) {
let start = state.bMarks[line] + state.tShift[line]
const max = state.eMarks[line]
if (start >= max) { return -1 }
// Check bullet
const marker = state.src.charCodeAt(start++)
if (marker !== 0x7E/* ~ */ && marker !== 0x3A/* : */) { return -1 }
const pos = state.skipSpaces(start)
// require space after ":"
if (start === pos) { return -1 }
return start
}
function markTightParagraphs (state, idx) {
const level = state.level + 2
let i
let l
for (i = idx + 2, l = state.tokens.length - 2; i < l; i++) {
if (state.tokens[i].level === level && state.tokens[i].type === 'paragraph_open') {
state.tokens[i + 2].hidden = true
state.tokens[i].hidden = true
i += 2
}
}
}
function deflist (state, startLine, endLine, silent) {
var ch,
contentStart,
ddLine,
dtLine,
itemLines,
listLines,
listTokIdx,
max,
newEndLine,
nextLine,
offset,
oldDDIndent,
oldIndent,
oldLineMax,
oldParentType,
oldSCount,
oldTShift,
oldTight,
pos,
prevEmptyEnd,
tight,
token
if (silent) {
// quirk: validation mode validates a dd block only, not a whole deflist
if (state.ddIndent < 0) { return false }
return skipMarker(state, startLine) >= 0
}
nextLine = startLine + 1
if (nextLine >= endLine) { return false }
if (state.isEmpty(nextLine)) {
nextLine++
if (nextLine >= endLine) { return false }
}
if (state.sCount[nextLine] < state.blkIndent) { return false }
contentStart = skipMarker(state, nextLine)
if (contentStart < 0) { return false }
// Start list
listTokIdx = state.tokens.length
tight = true
token = state.push('dl_open', 'dl', 1)
token.map = listLines = [ startLine, 0 ]
//
// Iterate list items
//
dtLine = startLine
ddLine = nextLine
// One definition list can contain multiple DTs,
// and one DT can be followed by multiple DDs.
//
// Thus, there is two loops here, and label is
// needed to break out of the second one
//
/* eslint no-labels:0,block-scoped-var:0 */
OUTER:
for (;;) {
prevEmptyEnd = false
token = state.push('dt_open', 'dt', 1)
token.map = [ dtLine, dtLine ]
token = state.push('inline', '', 0)
token.map = [ dtLine, dtLine ]
token.content = state.getLines(dtLine, dtLine + 1, state.blkIndent, false).trim()
token.children = []
token = state.push('dt_close', 'dt', -1)
for (;;) {
token = state.push('dd_open', 'dd', 1)
token.map = itemLines = [ ddLine, 0 ]
pos = contentStart
max = state.eMarks[ddLine]
offset = state.sCount[ddLine] + contentStart - (state.bMarks[ddLine] + state.tShift[ddLine])
while (pos < max) {
ch = state.src.charCodeAt(pos)
if (isSpace(ch)) {
if (ch === 0x09) {
offset += 4 - offset % 4
} else {
offset++
}
} else {
break
}
pos++
}
contentStart = pos
oldTight = state.tight
oldDDIndent = state.ddIndent
oldIndent = state.blkIndent
oldTShift = state.tShift[ddLine]
oldSCount = state.sCount[ddLine]
oldParentType = state.parentType
state.blkIndent = state.ddIndent = state.sCount[ddLine] + 2
state.tShift[ddLine] = contentStart - state.bMarks[ddLine]
state.sCount[ddLine] = offset
state.tight = true
state.parentType = 'deflist'
newEndLine = ddLine
while (++newEndLine < endLine && (state.sCount[newEndLine] >= state.sCount[ddLine] || state.isEmpty(newEndLine))) {
}
oldLineMax = state.lineMax
state.lineMax = newEndLine
state.md.block.tokenize(state, ddLine, newEndLine, true)
state.lineMax = oldLineMax
// If any of list item is tight, mark list as tight
if (!state.tight || prevEmptyEnd) {
tight = false
}
// Item become loose if finish with empty line,
// but we should filter last element, because it means list finish
prevEmptyEnd = (state.line - ddLine) > 1 && state.isEmpty(state.line - 1)
state.tShift[ddLine] = oldTShift
state.sCount[ddLine] = oldSCount
state.tight = oldTight
state.parentType = oldParentType
state.blkIndent = oldIndent
state.ddIndent = oldDDIndent
token = state.push('dd_close', 'dd', -1)
itemLines[1] = nextLine = state.line
if (nextLine >= endLine) { break OUTER }
if (state.sCount[nextLine] < state.blkIndent) { break OUTER }
contentStart = skipMarker(state, nextLine)
if (contentStart < 0) { break }
ddLine = nextLine
// go to the next loop iteration:
// insert DD tag and repeat checking
}
if (nextLine >= endLine) { break }
dtLine = nextLine
if (state.isEmpty(dtLine)) { break }
if (state.sCount[dtLine] < state.blkIndent) { break }
ddLine = dtLine + 1
if (ddLine >= endLine) { break }
if (state.isEmpty(ddLine)) { ddLine++ }
if (ddLine >= endLine) { break }
if (state.sCount[ddLine] < state.blkIndent) { break }
contentStart = skipMarker(state, ddLine)
if (contentStart < 0) { break }
// go to the next loop iteration:
// insert DT and DD tags and repeat checking
}
// Finilize list
token = state.push('dl_close', 'dl', -1)
listLines[1] = nextLine
state.line = nextLine
// mark paragraphs tight if needed
if (tight) {
markTightParagraphs(state, listTokIdx)
}
return true
}
md.block.ruler.before('paragraph', 'deflist', deflist, { alt: [ 'paragraph', 'reference' ] })
}

View File

@@ -127,8 +127,11 @@ class Markdown {
}
})
this.md.use(require('markdown-it-kbd'))
this.md.use(require('markdown-it-admonition'), {types: ['note', 'hint', 'attention', 'caution', 'danger', 'error']})
this.md.use(require('markdown-it-abbr'))
this.md.use(require('markdown-it-sub'))
this.md.use(require('markdown-it-sup'))
this.md.use(require('./markdown-it-deflist'))
this.md.use(require('./markdown-it-frontmatter'))
this.md.use(require('./markdown-it-fence'), {
@@ -268,9 +271,12 @@ class Markdown {
this.md.renderer.render = (tokens, options, env) => {
tokens.forEach((token) => {
switch (token.type) {
case 'heading_open':
case 'paragraph_open':
case 'blockquote_open':
case 'dd_open':
case 'dt_open':
case 'heading_open':
case 'list_item_open':
case 'paragraph_open':
case 'table_open':
token.attrPush(['data-line', token.map[0]])
}