Skip to content
This repository has been archived by the owner on Feb 7, 2024. It is now read-only.

Commit

Permalink
feat(transformers): introduce transformerMetaHighlight transformer
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed Jan 14, 2024
1 parent be23651 commit aa81a47
Show file tree
Hide file tree
Showing 14 changed files with 181 additions and 63 deletions.
1 change: 1 addition & 0 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { DefaultTheme } from 'vitepress'
import { defineConfig } from 'vitepress'
import { bundledThemes } from 'shikiji'
import { defaultHoverInfoProcessor, transformerTwoslash } from 'vitepress-plugin-twoslash'
import { transformerRenderWhitespace } from 'shikiji-transformers'

Check failure on line 5 in docs/.vitepress/config.ts

View workflow job for this annotation

GitHub Actions / lint

'transformerRenderWhitespace' is defined but never used
import { version } from '../../package.json'
import vite from './vite.config'

Expand Down
17 changes: 17 additions & 0 deletions docs/.vitepress/theme/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -181,3 +181,20 @@
.DocSearch {
--docsearch-primary-color: var(--vp-c-brand-1) !important;
}

.vp-code .tab,
.vp-code .space {
position: relative;
}

.vp-code .tab::before {
content: '⇥';
position: absolute;
opacity: 0.3;
}

.vp-code .space::before {
content: '·';
position: absolute;
opacity: 0.3;
}
70 changes: 69 additions & 1 deletion docs/packages/transformers.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ export function foo() {
}
```

::: details HTML Output

```html
<!-- Output (stripped of `style` attributes for clarity) -->
<pre class="shiki has-diff"> <!-- Notice `has-diff` -->
Expand All @@ -78,6 +80,10 @@ export function foo() {
</pre>
```

:::

---

### `transformerNotationHighlight`

Use `[!code highlight]` to highlight a line (adding `highlighted` class).
Expand All @@ -88,6 +94,10 @@ export function foo() {
}
```

Alternatively, you can use the [`transformerMetaHighlight`](#transformermetahighlight) to highlight lines based on the meta string.

---

### `transformerNotationFocus`

Use `[!code focus]` to focus a line (adding `focused` class).
Expand All @@ -98,6 +108,8 @@ export function foo() {
}
```

---

### `transformerNotationErrorLevel`

Use `[!code error]`, `[!code warning]`, to mark a line with an error level (adding `highlighted error`, `highlighted warning` class).
Expand All @@ -109,18 +121,74 @@ export function foo() {
}
```

---

### `transformerRenderWhitespace`

Render whitespaces (tabs and spaces) as individual spans, with classes `tab` and `space`.

With some CSS, you can make it look like this:

<img width="293" alt="image" src="https://github.com/antfu/shikiji/assets/11247099/01b7c4ba-6d63-4e74-8fd7-68a9f901f3de">
<div class="language-js vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre v-pre class="shiki shiki-themes vitesse-light vitesse-dark vp-code" style="--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212;" tabindex="0"><code><span class="line"><span style="--shiki-light:#AB5959;--shiki-dark:#CB7676;">function</span><span class="space"> </span><span style="--shiki-light:#59873A;--shiki-dark:#80A665;">block</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">(</span><span class="space"> </span><span style="--shiki-light:#999999;--shiki-dark:#666666;">)</span><span class="space"> </span><span style="--shiki-light:#999999;--shiki-dark:#666666;">{</span></span>
<span class="line"><span class="space"> </span><span class="space"> </span><span style="--shiki-light:#59873A;--shiki-dark:#80A665;">space</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">(</span><span class="space"> </span><span style="--shiki-light:#999999;--shiki-dark:#666666;">)</span></span>
<span class="line"><span class="tab">&#9;</span><span class="tab">&#9;</span><span style="--shiki-light:#59873A;--shiki-dark:#80A665;">table</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">(</span><span class="space"> </span><span style="--shiki-light:#999999;--shiki-dark:#666666;">)</span><span style="--shiki-light:#393A34;--shiki-dark:#DBD7CAEE;"> </span></span>
<span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;">}</span></span></code></pre></div>

::: details Example CSS

```css
.vp-code .tab,
.vp-code .space {
position: relative;
}

.vp-code .tab::before {
content: '';
position: absolute;
opacity: 0.3;
}

.vp-code .space::before {
content: '·';
position: absolute;
opacity: 0.3;
}
```

:::

---

### `transformerMetaHighlight`

Highlight lines based on the meta string provided on the code snippet. Requires integrations supports.

````md
```js {1,3-4}
console.log('1')
console.log('2')
console.log('3')
console.log('4')
```
````

Results in

```js {1,3-4}
console.log('1')
console.log('2')
console.log('3')
console.log('4')
```

---

### `transformerCompactLineOptions`

Support for `shiki`'s `lineOptions` that is removed in `shikiji`.

---

### `transformerRemoveLineBreak`

Remove line breaks between `<span class="line">`. Useful when you set `display: block` to `.line` in CSS.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"rollup-plugin-esbuild": "^6.1.0",
"rollup-plugin-typescript2": "^0.36.0",
"shikiji": "workspace:*",
"shikiji-transformers": "workspace:*",
"simple-git-hooks": "^2.9.0",
"taze": "^0.13.1",
"typescript": "^5.3.3",
Expand Down
3 changes: 2 additions & 1 deletion packages/markdown-it-shikiji/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@
},
"dependencies": {
"markdown-it": "^14.0.0",
"shikiji": "workspace:*"
"shikiji": "workspace:*",
"shikiji-transformers": "workspace:*"
},
"devDependencies": {
"@types/markdown-it": "^13.0.7"
Expand Down
25 changes: 8 additions & 17 deletions packages/markdown-it-shikiji/src/core.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type MarkdownIt from 'markdown-it'
import { addClassToHast } from 'shikiji/core'
import type { BuiltinTheme, CodeOptionsMeta, CodeOptionsThemes, CodeToHastOptions, HighlighterGeneric, ShikijiTransformer, TransformerOptions } from 'shikiji'
import { parseHighlightLines } from '../../shared/line-highlight'
import { transformerMetaHighlight } from 'shikiji-transformers'

export interface MarkdownItShikijiExtraOptions {
/**
Expand Down Expand Up @@ -54,21 +53,13 @@ export function setupMarkdownIt(
const builtInTransformer: ShikijiTransformer[] = []

if (highlightLines) {
const lines = parseHighlightLines(attrs)
if (lines) {
const className = highlightLines === true
? 'highlighted'
: highlightLines

builtInTransformer.push({
name: 'markdown-it-shikiji:line-class',
line(node, line) {
if (lines.includes(line))
addClassToHast(node, className)
return node
},
})
}
builtInTransformer.push(
transformerMetaHighlight({
className: highlightLines === true
? 'highlighted'
: highlightLines,
}),
)
}

builtInTransformer.push({
Expand Down
1 change: 1 addition & 0 deletions packages/rehype-shikiji/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"@types/hast": "^3.0.3",
"hast-util-to-string": "^3.0.0",
"shikiji": "workspace:*",
"shikiji-transformers": "workspace:*",
"unified": "^11.0.4",
"unist-util-visit": "^5.0.0"
},
Expand Down
26 changes: 9 additions & 17 deletions packages/rehype-shikiji/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { BuiltinTheme } from 'shikiji'
import type { Plugin } from 'unified'
import { toString } from 'hast-util-to-string'
import { visit } from 'unist-util-visit'
import { parseHighlightLines } from '../../shared/line-highlight'
import { transformerMetaHighlight } from 'shikiji-transformers'

export interface MapLike<K = any, V = any> {
get(key: K): V | undefined
Expand Down Expand Up @@ -133,22 +133,14 @@ const rehypeShikijiFromHighlighter: Plugin<[HighlighterGeneric<any, any>, Rehype
}

if (highlightLines && typeof attrs === 'string') {
const lines = parseHighlightLines(attrs)
if (lines) {
const className = highlightLines === true
? 'highlighted'
: highlightLines

codeOptions.transformers ||= []
codeOptions.transformers.push({
name: 'rehype-shikiji:line-class',
line(node, line) {
if (lines.includes(line))
addClassToHast(node, className)
return node
},
})
}
codeOptions.transformers ||= []
codeOptions.transformers.push(
transformerMetaHighlight({
className: highlightLines === true
? 'highlighted'
: highlightLines,
}),
)
}

try {
Expand Down
17 changes: 0 additions & 17 deletions packages/shared/line-highlight.ts

This file was deleted.

10 changes: 0 additions & 10 deletions packages/shared/test/line-highlight.test.ts

This file was deleted.

1 change: 1 addition & 0 deletions packages/shikiji-transformers/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export * from './transformers/notation-focus'
export * from './transformers/notation-highlight'
export * from './transformers/notation-diff'
export * from './transformers/notation-error-level'
export * from './transformers/transformer-meta-highlight'
export * from './utils'
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { type ShikijiTransformer, addClassToHast } from 'shikiji'

export function parseMetaHighlightString(meta: string) {
if (!meta)
return null
const match = meta.match(/{([\d,-]+)}/)
if (!match)
return null
const lines = match[1].split(',')
.flatMap((v) => {
const num = v.split('-').map(v => Number.parseInt(v, 10))
if (num.length === 1)
return [num[0]]
else
return Array.from({ length: num[1] - num[0] + 1 }, (_, i) => i + num[0])
})
return lines
}

export interface TransformerMetaHighlightOptions {
/**
* Class for highlighted lines
*
* @default 'highlighted'
*/
className?: string
}

const symbol = Symbol('highlighted-lines')

/**
* Allow using `{1,3-5}` in the code snippet meta to mark highlighted lines.
*/
export function transformerMetaHighlight(
options: TransformerMetaHighlightOptions = {},
): ShikijiTransformer {
const {
className = 'highlighted',
} = options

return {
name: 'shikiji-transformers:meta-highlight',
line(node, line) {
if (!this.options.meta?.__raw)
return
;(this.meta as any)[symbol] ||= parseMetaHighlightString(this.options.meta.__raw)
const lines: number[] = (this.meta as any)[symbol] || []
if (lines.includes(line))
addClassToHast(node, className)
return node
},
}
}
10 changes: 10 additions & 0 deletions packages/shikiji-transformers/test/meta-line-highlight.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { expect, it } from 'vitest'
import { parseMetaHighlightString } from '../src/transformers/transformer-meta-highlight'

it('parseHighlightLines', () => {
expect(parseMetaHighlightString('')).toBe(null)
expect(parseMetaHighlightString('{1}')).toEqual([1])
expect(parseMetaHighlightString('{1,2}')).toEqual([1, 2])
expect(parseMetaHighlightString('{1,2-4,5}')).toEqual([1, 2, 3, 4, 5])
expect(parseMetaHighlightString('{1-1}')).toEqual([1])
})
9 changes: 9 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit aa81a47

Please sign in to comment.