Skip to content

Commit

Permalink
fix: inline markdown-it-katex, fix #134
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed May 21, 2021
1 parent e277e9e commit e805063
Show file tree
Hide file tree
Showing 9 changed files with 224 additions and 22 deletions.
11 changes: 11 additions & 0 deletions demo/test/slides.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,14 @@ Current Page: {{$slidev.nav.currentPage}}
<div>
Hi
</div>

---

# Page 5

$$
\begin{aligned}
\frac{D \boldsymbol{v}}{D t}=&-\frac{1}{\rho} \operatorname{grad} p+\frac{\mu}{\rho} \Delta \boldsymbol{v}+\frac{\lambda+\mu}{\rho} \operatorname{grad} \Theta+\frac{\Theta}{\rho} \operatorname{grad}(\lambda+\mu) \\
&+\frac{1}{\rho} \operatorname{grad}(\boldsymbol{v} \cdot \operatorname{grad} \mu)+\frac{1}{\rho} \operatorname{rot}(\boldsymbol{v} \times \operatorname{grad} \mu)-\frac{1}{\rho} \boldsymbol{v} \Delta \mu+\boldsymbol{g}
\end{aligned}
$$
1 change: 1 addition & 0 deletions packages/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"file-saver": "^2.0.5",
"js-base64": "^3.6.0",
"js-yaml": "^4.1.0",
"katex": "^0.13.11",
"mermaid": "8.5.0",
"monaco-editor": "^0.24.0",
"nanoid": "^3.1.23",
Expand Down
3 changes: 0 additions & 3 deletions packages/slidev/node/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@ export async function getIndexHtml({ clientRoot, themeRoots, data, userRoot }: R
body += `\n${(index.match(/<body>([\s\S]*?)<\/body>/im)?.[1] || '').trim()}`
}

if (data.features.katex)
head += '\n<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.5.1/katex.min.css">'

if (data.features.tweet)
body += '\n<script src="https://platform.twitter.com/widgets.js"></script>'

Expand Down
3 changes: 3 additions & 0 deletions packages/slidev/node/plugins/loaders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,9 @@ export function createSlidesLoader(
}
}

if (data.features.katex)
imports.push('import "katex/dist/katex.min.css"')

return imports.join('\n')
}

Expand Down
198 changes: 198 additions & 0 deletions packages/slidev/node/plugins/markdown-it-katex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
// Ported from https://github.com/waylonflinn/markdown-it-katex

/* Process inline math */
/*
Like markdown-it-simplemath, this is a stripped down, simplified version of:
https://github.com/runarberg/markdown-it-math
It differs in that it takes (a subset of) LaTeX as input and relies on KaTeX
for rendering output.
*/

import katex, { KatexOptions } from 'katex'

// Test if potential opening or closing delimieter
// Assumes that there is a "$" at state.src[pos]
function isValidDelim(state: any, pos: number) {
const max = state.posMax
let can_open = true
let can_close = true

const prevChar = pos > 0 ? state.src.charCodeAt(pos - 1) : -1
const nextChar = pos + 1 <= max ? state.src.charCodeAt(pos + 1) : -1

// Check non-whitespace conditions for opening and closing, and
// check that closing delimeter isn't followed by a number
if (prevChar === 0x20/* " " */ || prevChar === 0x09
||/* \t */ (nextChar >= 0x30/* "0" */ && nextChar <= 0x39/* "9" */))
can_close = false

if (nextChar === 0x20/* " " */ || nextChar === 0x09/* \t */)
can_open = false

return {
can_open,
can_close,
}
}

function math_inline(state: any, silent: boolean) {
let match, token, res, pos

if (state.src[state.pos] !== '$') return false

res = isValidDelim(state, state.pos)
if (!res.can_open) {
if (!silent) state.pending += '$'
state.pos += 1
return true
}

// First check for and bypass all properly escaped delimieters
// This loop will assume that the first leading backtick can not
// be the first character in state.src, which is known since
// we have found an opening delimieter already.
const start = state.pos + 1
match = start
// eslint-disable-next-line no-cond-assign
while ((match = state.src.indexOf('$', match)) !== -1) {
// Found potential $, look for escapes, pos will point to
// first non escape when complete
pos = match - 1
while (state.src[pos] === '\\') pos -= 1

// Even number of escapes, potential closing delimiter found
if (((match - pos) % 2) === 1) break
match += 1
}

// No closing delimter found. Consume $ and continue.
if (match === -1) {
if (!silent) state.pending += '$'
state.pos = start
return true
}

// Check if we have empty content, ie: $$. Do not parse.
if (match - start === 0) {
if (!silent) state.pending += '$$'
state.pos = start + 1
return true
}

// Check for valid closing delimiter
res = isValidDelim(state, match)
if (!res.can_close) {
if (!silent) state.pending += '$'
state.pos = start
return true
}

if (!silent) {
token = state.push('math_inline', 'math', 0)
token.markup = '$'
token.content = state.src.slice(start, match)
}

state.pos = match + 1
return true
}

function math_block(state: any, start: number, end: number, silent: boolean) {
let firstLine; let lastLine; let next; let lastPos
let found = false
let pos = state.bMarks[start] + state.tShift[start]
let max = state.eMarks[start]

if (pos + 2 > max) return false
if (state.src.slice(pos, pos + 2) !== '$$') return false

pos += 2
firstLine = state.src.slice(pos, max)

if (silent) return true
if (firstLine.trim().slice(-2) === '$$') {
// Single line expression
firstLine = firstLine.trim().slice(0, -2)
found = true
}

for (next = start; !found;) {
next++

if (next >= end) break

pos = state.bMarks[next] + state.tShift[next]
max = state.eMarks[next]

if (pos < max && state.tShift[next] < state.blkIndent) {
// non-empty line with negative indent should stop the list:
break
}

if (state.src.slice(pos, max).trim().slice(-2) === '$$') {
lastPos = state.src.slice(0, max).lastIndexOf('$$')
lastLine = state.src.slice(pos, lastPos)
found = true
}
}

state.line = next + 1

const token = state.push('math_block', 'math', 0)
token.block = true
token.content = (firstLine && firstLine.trim() ? `${firstLine}\n` : '')
+ state.getLines(start + 1, next, state.tShift[start], true)
+ (lastLine && lastLine.trim() ? lastLine : '')
token.map = [start, state.line]
token.markup = '$$'
return true
}

export default function math_plugin(md: any, options: KatexOptions) {
// Default options

options = options || {}

// set KaTeX as the renderer for markdown-it-simplemath
const katexInline = function(latex: string) {
options.displayMode = false
try {
return katex.renderToString(latex, options)
}
catch (error) {
if (options.throwOnError)
// eslint-disable-next-line no-console
console.warn(error)
return latex
}
}

const inlineRenderer = function(tokens: any, idx: number) {
return katexInline(tokens[idx].content)
}

const katexBlock = function(latex: string) {
options.displayMode = true
try {
return `<p>${katex.renderToString(latex, options)}</p>`
}
catch (error) {
if (options.throwOnError)
// eslint-disable-next-line no-console
console.warn(error)
return latex
}
}

const blockRenderer = function(tokens: any, idx: number) {
return `${katexBlock(tokens[idx].content)}\n`
}

md.inline.ruler.after('escape', 'math_inline', math_inline)
md.block.ruler.after('blockquote', 'math_block', math_block, {
alt: ['paragraph', 'reference', 'blockquote', 'list'],
})
md.renderer.rules.math_inline = inlineRenderer
md.renderer.rules.math_block = blockRenderer
}
3 changes: 1 addition & 2 deletions packages/slidev/node/plugins/markdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ import base64 from 'js-base64'
import { slash } from '@antfu/utils'
// @ts-expect-error
import mila from 'markdown-it-link-attributes'
// @ts-expect-error
import Katex from 'markdown-it-katex'
import type { KatexOptions } from 'katex'
import { ResolvedSlidevOptions, SlidevPluginOptions } from '../options'
import Katex from './markdown-it-katex'
import { loadSetups } from './setupNode'
import Prism from './markdown-it-prism'
import Shiki, { resolveShikiOptions } from './markdown-it-shiki'
Expand Down
2 changes: 2 additions & 0 deletions packages/slidev/node/plugins/preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ const customElements = new Set([
'msqrt',
'mtr',
'semantics',
'mstyle',
'mtext',
])

export async function ViteSlidevPlugin(
Expand Down
2 changes: 1 addition & 1 deletion packages/slidev/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@
"fs-extra": "^10.0.0",
"jiti": "^1.9.2",
"js-base64": "^3.6.0",
"katex": "^0.13.11",
"kolorist": "^1.4.1",
"markdown-it": "^12.0.6",
"markdown-it-katex": "^2.0.3",
"markdown-it-link-attributes": "^3.0.0",
"monaco-editor": "^0.24.0",
"nanoid": "^3.1.23",
Expand Down
23 changes: 7 additions & 16 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit e805063

Please sign in to comment.