diff --git a/plugins/markdown/plugin-shiki/src/node/markdown/highlightLinesPlugin.ts b/plugins/markdown/plugin-shiki/src/node/markdown/highlightLinesPlugin.ts new file mode 100644 index 0000000000..478f1d6778 --- /dev/null +++ b/plugins/markdown/plugin-shiki/src/node/markdown/highlightLinesPlugin.ts @@ -0,0 +1,48 @@ +// Modified from https://github.com/egoist/markdown-it-highlight-lines +// Now this plugin is only used to normalize line attrs. +// The else part of line highlights logic is in './highlight.ts'. + +import type { Markdown } from 'vuepress/markdown' + +const HIGHLIGHT_LINES_REGEXP = /{([\d,-]+)}/ + +export const highlightLinePlugin = (md: Markdown): void => { + const fence = md.renderer.rules.fence! + md.renderer.rules.fence = (...args) => { + const [tokens, idx] = args + const token = tokens[idx] + + // due to use of markdown-it-attrs, the {0} syntax would have been + // converted to attrs on the token + const attr = token.attrs?.[0] + + let lines: string | null = null + + if (!attr) { + // markdown-it-attrs maybe disabled + const rawInfo = token.info + + if (!rawInfo || !HIGHLIGHT_LINES_REGEXP.test(rawInfo)) { + return fence(...args) + } + + const langName = rawInfo.replace(HIGHLIGHT_LINES_REGEXP, '').trim() + + // ensure the next plugin get the correct lang + token.info = langName + + lines = HIGHLIGHT_LINES_REGEXP.exec(rawInfo)![1] + } + + if (!lines) { + lines = attr![0] + + if (!lines || !/[\d,-]+/.test(lines)) { + return fence(...args) + } + } + + token.info += ` ${lines}` + return fence(...args) + } +} diff --git a/plugins/markdown/plugin-shiki/src/node/markdown/index.ts b/plugins/markdown/plugin-shiki/src/node/markdown/index.ts index 03663eee68..bf490a7d37 100644 --- a/plugins/markdown/plugin-shiki/src/node/markdown/index.ts +++ b/plugins/markdown/plugin-shiki/src/node/markdown/index.ts @@ -1,2 +1,3 @@ export * from './highlighter/index.js' export * from './preWrapperPlugin.js' +export * from './highlightLinesPlugin.js' diff --git a/plugins/markdown/plugin-shiki/src/node/shikiPlugin.ts b/plugins/markdown/plugin-shiki/src/node/shikiPlugin.ts index 59099a0f1e..e3fca2b77b 100644 --- a/plugins/markdown/plugin-shiki/src/node/shikiPlugin.ts +++ b/plugins/markdown/plugin-shiki/src/node/shikiPlugin.ts @@ -17,6 +17,7 @@ import type { MarkdownItPreWrapperOptions } from './markdown/index.js' import { createShikiHighlighter, getHighLightFunction, + highlightLinePlugin, preWrapperPlugin, } from './markdown/index.js' import type { ShikiPluginOptions } from './options.js' @@ -112,7 +113,7 @@ export const shikiPlugin = (options: ShikiPluginOptions = {}): Plugin => { loadLang, markdownFilePathGetter, ) - + md.use(highlightLinePlugin) md.use(preWrapperPlugin, { preWrapper }) if (preWrapper) { md.use(lineNumbersPlugin, { diff --git a/plugins/markdown/plugin-shiki/src/node/utils.ts b/plugins/markdown/plugin-shiki/src/node/utils.ts index 067fd3220b..3f294f802c 100644 --- a/plugins/markdown/plugin-shiki/src/node/utils.ts +++ b/plugins/markdown/plugin-shiki/src/node/utils.ts @@ -47,9 +47,7 @@ export const resolveLanguage = (info: string): string => * @returns Line options array / 行选项数组 */ export const attrsToLines = (attrs: string): TransformerCompactLineOption[] => { - const attrsContent = attrs - .replace(/^(?:\[.*?\])?.*?\{([\d,-]+)\}.*/, '$1') - .trim() + const attrsContent = attrs.replace(/^(?:\[.*?\])?.*?([\d,-]+).*/, '$1').trim() const result: number[] = [] if (!attrsContent) { diff --git a/plugins/markdown/plugin-shiki/tests/__snapshots__/shiki-preWrapper.spec.ts.snap b/plugins/markdown/plugin-shiki/tests/__snapshots__/shiki-preWrapper.spec.ts.snap index 7b768b8069..ed59675179 100644 --- a/plugins/markdown/plugin-shiki/tests/__snapshots__/shiki-preWrapper.spec.ts.snap +++ b/plugins/markdown/plugin-shiki/tests/__snapshots__/shiki-preWrapper.spec.ts.snap @@ -301,13 +301,13 @@ exports[`@vuepress/plugin-shiki > fence preWrapper > :line-numbers / :no-line-nu function bar () { return 1024 } -
const foo = 'foo'
-
+
const foo = 'foo'
+
 function bar () {
   return 1024
 }
-
const foo = 'foo'
-
+
const foo = 'foo'
+
 function bar () {
   return 1024
 }
@@ -315,8 +315,8 @@ exports[`@vuepress/plugin-shiki > fence preWrapper > :line-numbers / :no-line-nu
config/foo.ts
-
const foo = 'foo'
-
+  
const foo = 'foo'
+
 function bar () {
   return 1024
 }
@@ -343,13 +343,13 @@ exports[`@vuepress/plugin-shiki > fence preWrapper > :line-numbers / :no-line-nu function bar () { return 1024 }
-
const foo = 'foo'
-
+
const foo = 'foo'
+
 function bar () {
   return 1024
 }
-
const foo = 'foo'
-
+
const foo = 'foo'
+
 function bar () {
   return 1024
 }
@@ -357,8 +357,8 @@ exports[`@vuepress/plugin-shiki > fence preWrapper > :line-numbers / :no-line-nu
config/foo.ts
-
const foo = 'foo'
-
+  
const foo = 'foo'
+
 function bar () {
   return 1024
 }
@@ -385,13 +385,13 @@ exports[`@vuepress/plugin-shiki > fence preWrapper > :line-numbers / :no-line-nu function bar () { return 1024 }
-
const foo = 'foo'
-
+
const foo = 'foo'
+
 function bar () {
   return 1024
 }
-
const foo = 'foo'
-
+
const foo = 'foo'
+
 function bar () {
   return 1024
 }
@@ -399,8 +399,8 @@ exports[`@vuepress/plugin-shiki > fence preWrapper > :line-numbers / :no-line-nu
config/foo.ts
-
const foo = 'foo'
-
+  
const foo = 'foo'
+
 function bar () {
   return 1024
 }
@@ -412,14 +412,14 @@ exports[`@vuepress/plugin-shiki > fence preWrapper > :line-numbers=number > shou "
const line2 = 'line 2'
 const line3 = 'line 3'
const line3 = 'line 3'
-const line4 = 'line 4'
-const line5 = 'line 5'
+const line4 = 'line 4' +const line5 = 'line 5'
config/foo.ts
-
const line10 = 'line 10'
-const line11 = 'line 11'
+
const line10 = 'line 10'
+const line11 = 'line 11'
" `; @@ -428,14 +428,14 @@ exports[`@vuepress/plugin-shiki > fence preWrapper > :line-numbers=number > shou "
const line2 = 'line 2'
 const line3 = 'line 3'
const line3 = 'line 3'
-const line4 = 'line 4'
-const line5 = 'line 5'
+const line4 = 'line 4' +const line5 = 'line 5'
config/foo.ts
-
const line10 = 'line 10'
-const line11 = 'line 11'
+
const line10 = 'line 10'
+const line11 = 'line 11'
" `; @@ -444,14 +444,14 @@ exports[`@vuepress/plugin-shiki > fence preWrapper > :line-numbers=number > shou "
const line2 = 'line 2'
 const line3 = 'line 3'
const line3 = 'line 3'
-const line4 = 'line 4'
-const line5 = 'line 5'
+const line4 = 'line 4' +const line5 = 'line 5'
config/foo.ts
-
const line10 = 'line 10'
-const line11 = 'line 11'
+
const line10 = 'line 10'
+const line11 = 'line 11'
" `; @@ -511,8 +511,8 @@ exports[`@vuepress/plugin-shiki > fence preWrapper > plugin options > should dis function bar () { return 1024 } -
const foo = 'foo'
-
+
const foo = 'foo'
+
 function bar () {
   return 1024
 }
@@ -542,8 +542,8 @@ exports[`@vuepress/plugin-shiki > fence preWrapper > plugin options > should dis function bar () { return 1024 } -
const foo = 'foo'
-
+
const foo = 'foo'
+
 function bar () {
   return 1024
 }
@@ -568,8 +568,8 @@ exports[`@vuepress/plugin-shiki > fence preWrapper > plugin options > should ena function bar () { return 1024 }
-
const foo = 'foo'
-
+
const foo = 'foo'
+
 function bar () {
   return 1024
 }
@@ -599,8 +599,8 @@ exports[`@vuepress/plugin-shiki > fence preWrapper > plugin options > should pro function bar () { return 1024 } -
const foo = 'foo'
-
+
const foo = 'foo'
+
 function bar () {
   return 1024
 }
diff --git a/plugins/markdown/plugin-shiki/tests/shiki-preWrapper.spec.ts b/plugins/markdown/plugin-shiki/tests/shiki-preWrapper.spec.ts index 3b3ae06eab..cb8238f873 100644 --- a/plugins/markdown/plugin-shiki/tests/shiki-preWrapper.spec.ts +++ b/plugins/markdown/plugin-shiki/tests/shiki-preWrapper.spec.ts @@ -16,6 +16,7 @@ import { createMarkdownFilePathGetter, createShikiHighlighter, getHighLightFunction, + highlightLinePlugin, preWrapperPlugin, } from '../src/node/markdown/index.js' import type { ShikiPluginOptions } from '../src/node/options.js' @@ -41,6 +42,7 @@ const createMarkdown = ({ markdownFilePathGetter, ) + md.use(highlightLinePlugin) md.use(preWrapperPlugin, { preWrapper }) if (preWrapper) { md.use(lineNumbersPlugin, {