diff --git a/docs/packages/transformers.md b/docs/packages/transformers.md index 08581fd91..c55b83555 100644 --- a/docs/packages/transformers.md +++ b/docs/packages/transformers.md @@ -404,6 +404,37 @@ pre.shiki .indent::before { --- +### `transformerRenderLineNumber` + +Render line numbers as individual spans, with class `line-number`. + +```ts +import { transformerRenderLineNumber } from '@shikijs/transformers' + +const html = await codeToHtml(code, { + transformers: [ + transformerRenderLineNumber(), + ], +}) +``` + +Options: + +- `start`: Start number. Default `1`. +- `classLineNumber`: Class for line number. Default `'line-number'`. + +With some additional CSS rules, you can make it look like this: + +```css +pre.shiki .line-number { + user-select: none; + opacity: 0.5; + margin-right: 1em; +} +``` + +--- + ### `transformerMetaHighlight` Highlight lines based on the [meta string](/guide/transformers#meta) provided on the code snippet. diff --git a/packages/transformers/src/index.ts b/packages/transformers/src/index.ts index 7bc630870..ed6f0932b 100644 --- a/packages/transformers/src/index.ts +++ b/packages/transformers/src/index.ts @@ -13,5 +13,6 @@ export * from './transformers/remove-comments' export * from './transformers/remove-line-breaks' export * from './transformers/remove-notation-escape' export * from './transformers/render-indent-guides' +export * from './transformers/render-line-number' export * from './transformers/render-whitespace' export * from './transformers/style-to-class' diff --git a/packages/transformers/src/transformers/render-line-number.ts b/packages/transformers/src/transformers/render-line-number.ts new file mode 100644 index 000000000..cc4e42799 --- /dev/null +++ b/packages/transformers/src/transformers/render-line-number.ts @@ -0,0 +1,45 @@ +import type { ShikiTransformer } from '@shikijs/types' + +export interface TransformerRenderLineNumberOptions { + /** + * Class for line number + * @default 'line-number' + */ + classLineNumber?: string + /** + * Start number + * @default 1 + */ + start?: number +} + +/** + * Render line number as separate tokens. + * + * @param options + */ +export function transformerRenderLineNumber( + options: TransformerRenderLineNumberOptions = {}, +): ShikiTransformer { + const { + classLineNumber = 'line-number', + start = 1, + } = options + + return { + name: '@shikijs/transformers:render-line-number', + line(node, line) { + if (node.tagName === 'span') { + const num = start + line - 1 + node.children.unshift({ + type: 'element', + tagName: 'span', + properties: { + class: classLineNumber, + }, + children: [{ type: 'text', value: String(num) }], + }) + } + }, + } +} diff --git a/packages/transformers/test/fixtures.test.ts b/packages/transformers/test/fixtures.test.ts index 75b4184bc..dadcb3f8d 100644 --- a/packages/transformers/test/fixtures.test.ts +++ b/packages/transformers/test/fixtures.test.ts @@ -13,6 +13,7 @@ import { transformerRemoveComments, transformerRemoveLineBreak, transformerRemoveNotationEscape, + transformerRenderLineNumber, transformerRenderWhitespace, } from '../src' @@ -193,6 +194,22 @@ suite( '.leading', ) +suite( + 'line-number', + import.meta.glob('./fixtures/line-number/*.*', { query: '?raw', import: 'default', eager: true }), + [ + transformerRenderLineNumber(), + ], + code => `${code} +`, +) + suite( 'all', import.meta.glob('./fixtures/all/*.*', { query: '?raw', import: 'default', eager: true }), diff --git a/packages/transformers/test/fixtures/line-number/basic.js b/packages/transformers/test/fixtures/line-number/basic.js new file mode 100644 index 000000000..14a5b9d4d --- /dev/null +++ b/packages/transformers/test/fixtures/line-number/basic.js @@ -0,0 +1,5 @@ +function hello() { + console.log('line 1') + console.log('line 2') + console.log('line 3') +} diff --git a/packages/transformers/test/fixtures/line-number/basic.js.output.html b/packages/transformers/test/fixtures/line-number/basic.js.output.html new file mode 100644 index 000000000..7f66591eb --- /dev/null +++ b/packages/transformers/test/fixtures/line-number/basic.js.output.html @@ -0,0 +1,13 @@ +
1function hello() {
+2 console.log('line 1')
+3 console.log('line 2')
+4 console.log('line 3')
+5}
+6
+
\ No newline at end of file
diff --git a/test/exports/@shikijs/transformers.yaml b/test/exports/@shikijs/transformers.yaml
index c4bf27d20..71b844ff1 100644
--- a/test/exports/@shikijs/transformers.yaml
+++ b/test/exports/@shikijs/transformers.yaml
@@ -16,5 +16,6 @@
transformerRemoveLineBreak: function
transformerRemoveNotationEscape: function
transformerRenderIndentGuides: function
+ transformerRenderLineNumber: function
transformerRenderWhitespace: function
transformerStyleToClass: function