perf(plugin-md-power): optimize collapsed-lines (#180)
This commit is contained in:
parent
be47c9a025
commit
0f1ffc7532
@ -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
|
||||
}
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
export * from './collapsedLinesPlugin.js'
|
||||
export * from './highlightLinesPlugin.js'
|
||||
export * from './lineNumberPlugin.js'
|
||||
export * from './preWrapperPlugin.js'
|
||||
|
||||
@ -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>`
|
||||
}
|
||||
|
||||
@ -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 })
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user