Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support to abbreviations, definition lists and subscript/superscript text #2346

Merged
merged 11 commits into from
Nov 8, 2018
58 changes: 56 additions & 2 deletions browser/components/markdown.styl
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ for name, val in admonition_types
.admonition.{name}
@extend $admonition
border-left-color: val[color]

.admonition.{name}>.admonition-title
@extend $admonition-title
border-bottom-color: .1rem solid rgba(val[color], 0.2)
Expand All @@ -372,6 +372,36 @@ for name, val in admonition_types
color: val[color]
content: val[icon]

dl
margin 2em 0
padding 0
display flex
width 100%
flex-wrap wrap
align-items flex-start
border-bottom 1px solid borderColor
background-color tableHeadBgColor

dt
border-top 1px solid borderColor
font-weight bold
text-align right
overflow hidden
flex-basis 20%
padding 6px 13px
box-sizing border-box

dd
border-top 1px solid borderColor
flex-basis 80%
padding 6px 13px
min-height 2.5em
background-color $ui-noteDetail-backgroundColor
box-sizing border-box

dd + dd
margin-left 20%

themeDarkBackground = darken(#21252B, 10%)
themeDarkText = #f9f9f9
themeDarkBorder = lighten(themeDarkBackground, 20%)
Expand Down Expand Up @@ -422,6 +452,14 @@ body[data-theme="dark"]
kbd
background-color themeDarkBorder
color themeDarkText
dl
border-color themeDarkBorder
background-color themeDarkTableHead
dt
border-color themeDarkBorder
dd
border-color themeDarkBorder
background-color themeDarkPreview

themeSolarizedDarkTableOdd = $ui-solarized-dark-noteDetail-backgroundColor
themeSolarizedDarkTableEven = darken($ui-solarized-dark-noteDetail-backgroundColor, 10%)
Expand Down Expand Up @@ -449,6 +487,14 @@ body[data-theme="solarized-dark"]
border-color themeSolarizedDarkTableBorder
&:last-child
border-right solid 1px themeSolarizedDarkTableBorder
dl
border-color themeDarkBorder
background-color themeSolarizedDarkTableHead
dt
border-color themeDarkBorder
dd
border-color themeDarkBorder
background-color $ui-solarized-dark-noteDetail-backgroundColor

themeMonokaiTableOdd = $ui-monokai-noteDetail-backgroundColor
themeMonokaiTableEven = darken($ui-monokai-noteDetail-backgroundColor, 10%)
Expand Down Expand Up @@ -477,4 +523,12 @@ body[data-theme="monokai"]
&:last-child
border-right solid 1px themeMonokaiTableBorder
kbd
background-color themeDarkBackground
background-color themeDarkBackground
dl
border-color themeDarkBorder
background-color themeMonokaiTableHead
dt
border-color themeDarkBorder
dd
border-color themeDarkBorder
background-color $ui-monokai-noteDetail-backgroundColor
232 changes: 232 additions & 0 deletions browser/lib/markdown-it-deflist.js
Original file line number Diff line number Diff line change
@@ -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 = [ nextLine, 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' ] })
}
4 changes: 4 additions & 0 deletions browser/lib/markdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@ class Markdown {
})
this.md.use(require('markdown-it-kbd'))
this.md.use(require('markdown-it-admonition'))
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'))

const deflate = require('markdown-it-plantuml/lib/deflate')
this.md.use(require('markdown-it-plantuml'), '', {
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
"lodash": "^4.11.1",
"lodash-move": "^1.1.1",
"markdown-it": "^6.0.1",
"markdown-it-abbr": "^1.0.4",
"markdown-it-admonition": "^1.0.4",
"markdown-it-emoji": "^1.1.1",
"markdown-it-footnote": "^3.0.0",
Expand All @@ -80,6 +81,8 @@
"markdown-it-named-headers": "^0.0.4",
"markdown-it-plantuml": "^1.1.0",
"markdown-it-smartarrows": "^1.0.1",
"markdown-it-sub": "^1.0.0",
"markdown-it-sup": "^1.0.0",
"mdurl": "^1.0.1",
"mermaid": "^8.0.0-rc.8",
"moment": "^2.10.3",
Expand Down
12 changes: 12 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5723,6 +5723,10 @@ map-visit@^1.0.0:
dependencies:
object-visit "^1.0.0"

markdown-it-abbr@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/markdown-it-abbr/-/markdown-it-abbr-1.0.4.tgz#d66b5364521cbb3dd8aa59dadfba2fb6865c8fd8"

markdown-it-admonition@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/markdown-it-admonition/-/markdown-it-admonition-1.0.4.tgz#d7bbc7eb1fe6168fc8cc304de7a9d8c993acb2f5"
Expand Down Expand Up @@ -5763,6 +5767,14 @@ markdown-it-smartarrows@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/markdown-it-smartarrows/-/markdown-it-smartarrows-1.0.1.tgz#b570e9c0ff9812e0db6ace19afa5ba12b64bb9a7"

markdown-it-sub@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/markdown-it-sub/-/markdown-it-sub-1.0.0.tgz#375fd6026eae7ddcb012497f6411195ea1e3afe8"

markdown-it-sup@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/markdown-it-sup/-/markdown-it-sup-1.0.0.tgz#cb9c9ff91a5255ac08f3fd3d63286e15df0a1fc3"

markdown-it@^5.0.3:
version "5.1.0"
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-5.1.0.tgz#25286b8465bac496f3f1b77eed544643e9bd718d"
Expand Down