perf(plugin-md-power): optimize collapsed-lines (#180)

This commit is contained in:
pengzhanbo 2024-09-15 02:13:49 +08:00 committed by GitHub
parent be47c9a025
commit 0f1ffc7532
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 88 additions and 27 deletions

View File

@ -0,0 +1,61 @@
import type { Markdown } from 'vuepress/markdown'
import { resolveCollapsedLines } from '../utils/index.js'
export interface MarkdownItCollapsedLinesOptions {
/**
* Whether to collapse code blocks when they exceed a certain number of lines,
*
* - If `number`, collapse starts from line `number`.
* - If `true`, collapse starts from line 15 by default.
* - If `false`, disable collapse.
* @default false
*/
collapsedLines?: boolean | number
}
export function collapsedLinesPlugin(md: Markdown, {
collapsedLines: collapsedLinesOptions = false,
}: MarkdownItCollapsedLinesOptions = {}): void {
const rawFence = md.renderer.rules.fence!
md.renderer.rules.fence = (...args) => {
const [tokens, index] = args
const token = tokens[index]
// get token info
const info = token.info ? md.utils.unescapeAll(token.info).trim() : ''
const code = rawFence(...args)
// resolve collapsed-lines mark from token info
const collapsedLinesInfo
= resolveCollapsedLines(info) ?? collapsedLinesOptions
if (collapsedLinesInfo === false) {
return code
}
const lines
= code.slice(code.indexOf('<code>'), code.indexOf('</code>')).split('\n').length
const startLines
= typeof collapsedLinesInfo === 'number' ? collapsedLinesInfo : 15
if (lines < startLines) {
return code
}
const collapsedLinesCode = `<div class="collapsed-lines"></div>`
const styles = `--vp-collapsed-lines:${startLines};`
const finalCode = code
.replace(/<\/div>$/, `${collapsedLinesCode}</div>`)
.replace(/"(language-[^"]*)"/, '"$1 has-collapsed collapsed"')
.replace(/^<div[^>]*>/, (match) => {
if (!match.includes('style=')) {
return `${match.slice(0, -1)} style="${styles}">`
}
return match.replace(/(style=")/, `$1${styles}`)
})
return finalCode
}
}

View File

@ -1,3 +1,4 @@
export * from './collapsedLinesPlugin.js'
export * from './highlightLinesPlugin.js'
export * from './lineNumberPlugin.js'
export * from './preWrapperPlugin.js'

View File

@ -1,12 +1,12 @@
// markdown-it plugin for generating line numbers.
// v-pre block logic is in `../highlight.ts`
import type { Markdown } from 'vuepress/markdown'
import { resolveAttr, resolveCollapsedLines, resolveLanguage } from '../utils/index.js'
import { resolveAttr, resolveLanguage } from '../utils/index.js'
import type { PreWrapperOptions } from '../types.js'
export function preWrapperPlugin(
md: Markdown,
{ preWrapper = true, collapsedLines = false }: PreWrapperOptions = {},
{ preWrapper = true }: PreWrapperOptions = {},
): void {
const rawFence = md.renderer.rules.fence!
@ -33,12 +33,6 @@ export function preWrapperPlugin(
`data-ext="${lang}"`,
`data-title="${title}"`,
]
const collapsed = resolveCollapsedLines(info, collapsedLines)
if (collapsed) {
classes.push('has-collapsed', 'collapsed')
attrs.push(`style="--vp-collapsed-lines:${collapsed}"`)
result += `<div class="collapsed-lines"></div>`
}
return `<div class="${classes.join(' ')}" ${attrs.join(' ')}>${result}</div>`
}

View File

@ -3,6 +3,7 @@ import type { Plugin } from 'vuepress/core'
import { copyCodeButtonPlugin } from './copy-code-button/index.js'
import { highlight } from './highlight/index.js'
import {
collapsedLinesPlugin,
highlightLinesPlugin,
lineNumberPlugin,
preWrapperPlugin,
@ -53,14 +54,12 @@ export function shikiPlugin({
md.options.highlight = await highlight(theme, options)
md.use(highlightLinesPlugin)
md.use(preWrapperPlugin, {
preWrapper,
collapsedLines,
})
md.use(preWrapperPlugin, { preWrapper })
if (preWrapper) {
copyCodeButtonPlugin(md, app, copyCode)
md.use<LineNumberOptions>(lineNumberPlugin, { lineNumbers })
md.use(lineNumberPlugin, { lineNumbers })
md.use(collapsedLinesPlugin, { collapsedLines })
}
},

View File

@ -1,18 +1,24 @@
export const COLLAPSED_LINES_REGEXP = /:collapsed-lines(?:=(\d+))?\b/
export const NO_COLLAPSED_LINES_REGEXP = /:no-collapsed-lines\b/
const COLLAPSED_LINES_REGEXP = /:collapsed-lines\b/
const COLLAPSED_LINES_START_REGEXP = /:collapsed-lines=(\d+)\b/
const NO_COLLAPSED_LINES_REGEXP = /:no-collapsed-lines\b/
const DEFAULT_LINES = 15
/**
* Resolve the `:collapsed-lines` `:collapsed-lines=num` / `:no-collapsed-lines` mark from token info
*/
export function resolveCollapsedLines(info: string): boolean | number | null {
const lines = COLLAPSED_LINES_START_REGEXP.exec(info)?.[1]
export function resolveCollapsedLines(info: string, defaultLines: boolean | number): number | false {
if (NO_COLLAPSED_LINES_REGEXP.test(info))
return false
const lines = defaultLines === true ? DEFAULT_LINES : defaultLines
const match = info.match(COLLAPSED_LINES_REGEXP)
if (match) {
return Number(match[1]) || lines || DEFAULT_LINES
if (lines) {
return Number(lines)
}
return lines ?? false
if (COLLAPSED_LINES_REGEXP.test(info)) {
return true
}
if (NO_COLLAPSED_LINES_REGEXP.test(info)) {
return false
}
return null
}