Skip to content

Commit 78b8b45

Browse files
authored
docs: use shiki for syntax highlighting (#65)
* docs: document reference escaping, writing and version conversion - references: local references are JSON pointers in a URI, so "/" and "~" in a key are escaped as "~1" and "~0", and the pointer is percent-decoded; add how references are written, including inlining references whose target the written document does not have. - version conversion: list which references stay references and which are written inline, how V2 channel references map to V3 channel keys, and the operations and messages a downgrade drops. - README: drop the JsonPointer.Net attribution, which is no longer a dependency, and fix the ReferenceResolutionSetting name and a server reference example. * docs: highlight code with Shiki Prism's C# grammar has no raw string literals, so the AsyncAPI documents embedded in examples were highlighted as C# code, and as a regex-based grammar it leaves identifiers and properties plain. Its themes also gave types the same color as numbers and booleans. Code blocks now use Shiki with Visual Studio Code's grammars and its Light+ and Dark+ themes, through a swizzled CodeBlock/Content that keeps the theme's line rendering, so line numbers, highlighted lines and the copy button still work. Highlighting is synchronous, so pages render the same on the server and in the browser. C#, JSON, YAML and shell are loaded; other languages render as plain text.
1 parent c686e65 commit 78b8b45

7 files changed

Lines changed: 342 additions & 3 deletions

File tree

‎website/docusaurus.config.js‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ const config = {
4242
],
4343
copyright: `Copyright © ${new Date().getFullYear()} ByteBardOrg.`,
4444
},
45-
prism: {theme: prismThemes.github, darkTheme: prismThemes.dracula, additionalLanguages: ['csharp']},
45+
// Code is highlighted with Shiki (src/theme/CodeBlock/Content); these Prism themes only color the code block
46+
// around it, and match the background of Shiki's Visual Studio Code themes.
47+
prism: {theme: prismThemes.vsLight, darkTheme: prismThemes.vsDark},
4648
},
4749
};
4850

‎website/package-lock.json‎

Lines changed: 185 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎website/package.json‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
"clsx": "^2.1.1",
1717
"prism-react-renderer": "^2.4.1",
1818
"react": "^18.0.0",
19-
"react-dom": "^18.0.0"
19+
"react-dom": "^18.0.0",
20+
"shiki": "^4.5.0"
2021
},
2122
"devDependencies": {
2223
"@docusaurus/module-type-aliases": "^3.8.1",

‎website/src/css/custom.css‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,18 @@ html[data-theme='dark'] .navbar__items--right .navbar__link:hover {color: #a87ef
153153
html:not([data-theme='dark']) .navbar-sidebar .menu__link--active,
154154
html[data-theme='dark'] .navbar-sidebar .menu__link--active {color: #a87efc}
155155
}
156+
157+
/* Code tokens carry both color modes' styles as CSS variables (src/theme/CodeBlock/Content/shiki.js). */
158+
.shiki-token {
159+
color: var(--shiki-light);
160+
font-style: var(--shiki-light-font-style);
161+
font-weight: var(--shiki-light-font-weight);
162+
text-decoration: var(--shiki-light-text-decoration);
163+
}
164+
165+
html[data-theme='dark'] .shiki-token {
166+
color: var(--shiki-dark);
167+
font-style: var(--shiki-dark-font-style);
168+
font-weight: var(--shiki-dark-font-weight);
169+
text-decoration: var(--shiki-dark-text-decoration);
170+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/**
2+
* Swizzled from @docusaurus/theme-classic to highlight code with Shiki instead of Prism. The Prism-shaped
3+
* line and token props are kept, so the theme's Line component still renders line numbers and highlighted lines.
4+
*/
5+
import React, {useMemo} from 'react';
6+
import clsx from 'clsx';
7+
import {useCodeBlockContext} from '@docusaurus/theme-common/internal';
8+
import Line from '@theme/CodeBlock/Line';
9+
import {highlight} from './shiki';
10+
import styles from './styles.module.css';
11+
12+
const Pre = React.forwardRef((props, ref) => {
13+
return (
14+
<pre
15+
ref={ref}
16+
/* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */
17+
tabIndex={0}
18+
{...props}
19+
className={clsx(props.className, styles.codeBlock, 'thin-scrollbar')}
20+
/>
21+
);
22+
});
23+
24+
function Code(props) {
25+
const {metadata} = useCodeBlockContext();
26+
return (
27+
<code
28+
{...props}
29+
className={clsx(
30+
props.className,
31+
styles.codeBlockLines,
32+
metadata.lineNumbersStart !== undefined && styles.codeBlockLinesWithNumbering,
33+
)}
34+
style={{
35+
...props.style,
36+
counterReset: metadata.lineNumbersStart === undefined ? undefined : `line-count ${metadata.lineNumbersStart - 1}`,
37+
}}
38+
/>
39+
);
40+
}
41+
42+
function getLineProps({className}) {
43+
return {className: clsx('token-line', className)};
44+
}
45+
46+
function getTokenProps({token}) {
47+
return {className: 'token shiki-token', style: token.style, children: token.content};
48+
}
49+
50+
export default function CodeBlockContent({className}) {
51+
const {metadata, wordWrap} = useCodeBlockContext();
52+
const {code, language, lineNumbersStart, lineClassNames} = metadata;
53+
const lines = useMemo(
54+
() => highlight(code, language).map((line) => line.map((token) => ({content: token.content, style: token.htmlStyle}))),
55+
[code, language],
56+
);
57+
58+
return (
59+
<Pre ref={wordWrap.codeBlockRef} className={clsx(className, `language-${language}`)}>
60+
<Code>
61+
{lines.map((line, i) => (
62+
<Line
63+
key={i}
64+
line={line}
65+
getLineProps={getLineProps}
66+
getTokenProps={getTokenProps}
67+
classNames={lineClassNames[i]}
68+
showLineNumbers={lineNumbersStart !== undefined}
69+
/>
70+
))}
71+
</Code>
72+
</Pre>
73+
);
74+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import {createHighlighterCoreSync} from 'shiki/core';
2+
import {createJavaScriptRegexEngine} from 'shiki/engine/javascript';
3+
import csharp from '@shikijs/langs/csharp';
4+
import json from '@shikijs/langs/json';
5+
import shellscript from '@shikijs/langs/shellscript';
6+
import yaml from '@shikijs/langs/yaml';
7+
import darkPlus from '@shikijs/themes/dark-plus';
8+
import lightPlus from '@shikijs/themes/light-plus';
9+
10+
// The Visual Studio Code themes, matching prismThemes.vsLight and prismThemes.vsDark in docusaurus.config.js,
11+
// which style the rest of the code block.
12+
const themes = {light: 'light-plus', dark: 'dark-plus'};
13+
14+
// Synchronous, so code blocks render the same on the server and in the browser.
15+
const highlighter = createHighlighterCoreSync({
16+
themes: [lightPlus, darkPlus],
17+
langs: [csharp, json, shellscript, yaml],
18+
engine: createJavaScriptRegexEngine(),
19+
});
20+
21+
/**
22+
* Tokenizes code into lines of tokens, each styled with both themes' colors as CSS variables
23+
* (--shiki-light and --shiki-dark), which custom.css applies for the current color mode.
24+
*/
25+
export function highlight(code, language) {
26+
const lang = highlighter.getLoadedLanguages().includes(language) ? language : 'text';
27+
return highlighter.codeToTokens(code, {lang, themes, defaultColor: false}).tokens;
28+
}

0 commit comments

Comments
 (0)