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

feat: support KaTex in notes #2024

Merged
merged 2 commits into from
Jan 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions packages/client/setup/code-runners.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,10 @@ function runJavaScript(code: string): CodeRunnerOutputs {
// JSON.stringify omits any keys with a value of undefined. To get around this, we replace undefined with the text __undefined__ and then do a global replace using regex back to keyword undefined
textRep
= prefix
+ JSON.stringify(arg, (_, value) => (value === undefined ? '__undefined__' : value), 2).replace(
/"__undefined__"/g,
'undefined',
)
+ JSON.stringify(arg, (_, value) => (value === undefined ? '__undefined__' : value), 2).replace(
/"__undefined__"/g,
'undefined',
)

textRep = String(textRep)
}
Expand Down
2 changes: 2 additions & 0 deletions packages/slidev/node/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { getThemeMeta, resolveTheme } from './integrations/themes'
import { parser } from './parser'
import { getRoots, resolveEntry, toAtFS } from './resolver'
import setupIndexHtml from './setups/indexHtml'
import setupKatex from './setups/katex'
import setupShiki from './setups/shiki'

const debug = Debug('slidev:options')
Expand Down Expand Up @@ -82,6 +83,7 @@ export async function createDataUtils(resolved: Omit<ResolvedSlidevOptions, 'uti

return {
...await setupShiki(resolved.roots),
katexOptions: await setupKatex(resolved.roots),
indexHtml: setupIndexHtml(resolved),
define: getDefine(resolved),
iconsResolvePath: [resolved.clientRoot, ...resolved.roots].reverse(),
Expand Down
2 changes: 1 addition & 1 deletion packages/slidev/node/resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ export async function getRoots(entry?: string): Promise<RootsInfo> {
const userRoot = dirname(entry)
isInstalledGlobally.value
= slash(relative(userRoot, process.argv[1])).includes('/.pnpm/')
|| (await import('is-installed-globally')).default
|| (await import('is-installed-globally')).default
const clientRoot = await findPkgRoot('@slidev/client', cliRoot, true)
const closestPkgRoot = dirname(await findClosestPkgJsonPath(userRoot) || userRoot)
const userPkgJson = getUserPkgJson(closestPkgRoot)
Expand Down
5 changes: 2 additions & 3 deletions packages/slidev/node/syntax/markdown-it/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@ import { taskLists as MarkdownItTaskList } from '@hedgedoc/markdown-it-plugins'
// @ts-expect-error missing types
import MarkdownItFootnote from 'markdown-it-footnote'
import MarkdownItMdc from 'markdown-it-mdc'
import setupKatex from '../../setups/katex'
import MarkdownItEscapeInlineCode from './markdown-it-escape-code'
import MarkdownItKatex from './markdown-it-katex'
import MarkdownItLink from './markdown-it-link'
import MarkdownItShiki from './markdown-it-shiki'
import MarkdownItVDrag from './markdown-it-v-drag'

export async function useMarkdownItPlugins(md: MarkdownIt, options: ResolvedSlidevOptions, markdownTransformMap: Map<string, MagicString>) {
const { roots, data: { features, config } } = options
const { data: { features, config }, utils: { katexOptions } } = options

if (config.highlighter === 'shiki') {
md.use(await MarkdownItShiki(options))
Expand All @@ -24,7 +23,7 @@ export async function useMarkdownItPlugins(md: MarkdownIt, options: ResolvedSlid
md.use(MarkdownItFootnote)
md.use(MarkdownItTaskList, { enabled: true, lineNumber: true, label: true })
if (features.katex)
md.use(MarkdownItKatex, await setupKatex(roots))
md.use(MarkdownItKatex, katexOptions)
md.use(MarkdownItVDrag, markdownTransformMap)
if (config.mdc)
md.use(MarkdownItMdc)
Expand Down
4 changes: 2 additions & 2 deletions packages/slidev/node/syntax/markdown-it/markdown-it-katex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,8 @@ function math_block(state: any, start: number, end: number, silent: boolean) {
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 : '')
+ state.getLines(start + 1, next, state.tShift[start], true)
+ (lastLine && lastLine.trim() ? lastLine : '')
token.map = [start, state.line]
token.markup = '$$'
return true
Expand Down
49 changes: 28 additions & 21 deletions packages/slidev/node/vite/loaders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import type { Plugin, ViteDevServer } from 'vite'
import { notNullish, range } from '@antfu/utils'
import * as parser from '@slidev/parser/fs'
import equal from 'fast-deep-equal'
import MarkdownIt from 'markdown-it'
import YAML from 'yaml'
import { sharedMd } from '../commands/shared'
import { createDataUtils } from '../options'
import MarkdownItKatex from '../syntax/markdown-it/markdown-it-katex'
import markdownItLink from '../syntax/markdown-it/markdown-it-link'
import { getBodyJson, updateFrontmatterPatch } from '../utils'
import { templates } from '../virtual'
import { templateConfigs } from '../virtual/configs'
Expand All @@ -16,32 +18,17 @@ import { templateSlides, VIRTUAL_SLIDE_PREFIX } from '../virtual/slides'
import { templateTitleRendererMd } from '../virtual/titles'
import { regexSlideFacadeId, regexSlideReqPath, regexSlideSourceId } from './common'

function renderNote(text: string = '') {
let clickCount = 0
const html = sharedMd.render(text
// replace [click] marker with span
.replace(/\[click(?::(\d+))?\]/gi, (_, count = 1) => {
clickCount += Number(count)
return `<span class="slidev-note-click-mark" data-clicks="${clickCount}"></span>`
}),
)

return html
}

function withRenderedNote(data: SlideInfo): SlideInfo {
return {
...data,
noteHTML: renderNote(data?.note),
}
}

export function createSlidesLoader(
options: ResolvedSlidevOptions,
serverOptions: SlidevServerOptions,
): Plugin {
const { data, mode, utils } = options

const notesMd = MarkdownIt({ html: true })
notesMd.use(markdownItLink)
if (data.features.katex)
notesMd.use(MarkdownItKatex, utils.katexOptions)

const hmrSlidesIndexes = new Set<number>()
let server: ViteDevServer | undefined
let skipHmr: { filePath: string, fileContent: string } | null = null
Expand Down Expand Up @@ -374,4 +361,24 @@ export function createSlidesLoader(
return ''
},
}

function renderNote(text: string = '') {
let clickCount = 0
const html = notesMd.render(text
// replace [click] marker with span
.replace(/\[click(?::(\d+))?\]/gi, (_, count = 1) => {
clickCount += Number(count)
return `<span class="slidev-note-click-mark" data-clicks="${clickCount}"></span>`
}),
)

return html
}

function withRenderedNote(data: SlideInfo): SlideInfo {
return {
...data,
noteHTML: renderNote(data?.note),
}
}
}
2 changes: 2 additions & 0 deletions packages/types/src/options.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { MarkdownItShikiOptions } from '@shikijs/markdown-it/index.mjs'
import type { KatexOptions } from 'katex'
import type { HighlighterGeneric } from 'shiki/types.mjs'
import type { SlidevData } from './types'

Expand Down Expand Up @@ -53,6 +54,7 @@ export interface ResolvedSlidevOptions extends RootsInfo, SlidevEntryOptions {
export interface ResolvedSlidevUtils {
shiki: HighlighterGeneric<any, any>
shikiOptions: MarkdownItShikiOptions
katexOptions: KatexOptions | null
indexHtml: string
define: Record<string, string>
iconsResolvePath: string[]
Expand Down
Loading