Skip to content

Commit

Permalink
feat(theme-classic): allow line numbering to code blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
lex111 committed Mar 25, 2022
1 parent fa50d09 commit 0de49c3
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 7 deletions.
1 change: 1 addition & 0 deletions packages/docusaurus-theme-classic/src/theme-classic.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ declare module '@theme/CodeBlock' {
readonly metastring?: string;
readonly title?: string;
readonly language?: string;
readonly showLineNumbers?: boolean;
}

export default function CodeBlock(props: Props): JSX.Element;
Expand Down
19 changes: 17 additions & 2 deletions packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
parseCodeBlockTitle,
parseLanguage,
parseLines,
containsLineNumbers,
ThemeClassNames,
usePrismTheme,
} from '@docusaurus/theme-common';
Expand All @@ -26,6 +27,7 @@ export default function CodeBlock({
className: blockClassName = '',
metastring,
title,
showLineNumbers,
language: languageProp,
}: Props): JSX.Element {
const {prism} = useThemeConfig();
Expand Down Expand Up @@ -87,6 +89,8 @@ export default function CodeBlock({
const language =
languageProp ?? parseLanguage(blockClassName) ?? prism.defaultLanguage;
const {highlightLines, code} = parseLines(content, metastring, language);
const shouldShowLineNumbers =
showLineNumbers || containsLineNumbers(metastring);

return (
<Highlight
Expand Down Expand Up @@ -118,20 +122,31 @@ export default function CodeBlock({
/* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */
tabIndex={0}
className={clsx(className, styles.codeBlock, 'thin-scrollbar')}>
<code className={styles.codeBlockLines}>
<code
className={clsx(
styles.codeBlockLines,
shouldShowLineNumbers && styles.codeBlockLinesWithNumbering,
)}>
{tokens.map((line, i) => {
if (line.length === 1 && line[0]!.content === '\n') {
line[0]!.content = '';
}

const lineProps = getLineProps({line, key: i});
const lineProps = getLineProps({
line,
key: i,
...(shouldShowLineNumbers && {className: styles.codeLine}),
});

if (highlightLines.includes(i)) {
lineProps.className += ' docusaurus-highlight-code-line';
}

return (
<span key={i} {...lineProps}>
{shouldShowLineNumbers && (
<span className={styles.codeLineNumber} />
)}
{line.map((token, key) => (
<span key={key} {...getTokenProps({token, key})} />
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
margin: 0;
padding: 0;
border-radius: var(--ifm-global-radius);
background-color: inherit;
--ifm-pre-background: inherit;
}

.codeBlockTitle + .codeBlockContent .codeBlock {
Expand All @@ -45,14 +45,40 @@

.codeBlockLines {
font: inherit;
background: var(--ifm-pre-background);
/* rtl:ignore */
float: left;
min-width: 100%;
padding: var(--ifm-pre-padding);
}

.codeBlockLinesWithNumbering {
padding-left: 0;
}

@media print {
.codeBlockLines {
white-space: pre-wrap;
}
}

.codeLine {
counter-increment: line-count;
}

.codeLineNumber {
display: inline-block;
position: sticky;
left: 0;
padding: 0 var(--ifm-pre-padding);
background: var(--ifm-pre-background);
}

.codeLineNumber::before {
content: counter(line-count);
opacity: 0.4;
}

:global(.docusaurus-highlight-code-line) .codeLineNumber::before {
opacity: 0.8;
}
1 change: 1 addition & 0 deletions packages/docusaurus-theme-common/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export {
parseCodeBlockTitle,
parseLanguage,
parseLines,
containsLineNumbers,
} from './utils/codeBlockUtils';

export {
Expand Down
4 changes: 4 additions & 0 deletions packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ export function parseCodeBlockTitle(metastring?: string): string {
return metastring?.match(codeBlockTitleRegex)?.groups!.title ?? '';
}

export function containsLineNumbers(metastring?: string): boolean {
return metastring?.includes('showLineNumbers') || false;
}

/**
* Gets the language name from the class name (set by MDX).
* e.g. `"language-javascript"` => `"javascript"`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,28 @@ function HelloCodeTitle(props) {

</BrowserWindow>

## Code line numbering

You can enable line numbering for your code block by using `showLineNumbers` key within the language meta string (don't forget to add space directly before the key).

````md
```jsx showLineNumbers
function PageLayout(props) {
return <Layout title="Awesome Docusaurus page" description="Just one more awesome page on my Docusaurus site">;
}
```
````

<BrowserWindow>

```jsx showLineNumbers
function PageLayout(props) {
return <Layout title="Awesome Docusaurus page" description="Just one more awesome page on my Docusaurus site">;
}
```

</BrowserWindow>

## Syntax highlighting {#syntax-highlighting}

Code blocks are text blocks wrapped around by strings of 3 backticks. You may check out [this reference](https://github.com/mdx-js/specification) for the specifications of MDX.
Expand Down Expand Up @@ -590,7 +612,10 @@ export default function MyReactPage() {
return (
<div>
{/* highlight-start */}
<CodeBlock language="jsx" title="/src/components/HelloCodeTitle.js">
<CodeBlock
language="jsx"
title="/src/components/HelloCodeTitle.js"
showLineNumbers>
{`function HelloCodeTitle(props) {
return <h1>Hello, {props.name}</h1>;
}`}
Expand All @@ -602,15 +627,18 @@ export default function MyReactPage() {
```

<BrowserWindow>
<CodeBlock language="jsx" title="/src/components/HelloCodeTitle.js">
<CodeBlock
language="jsx"
title="/src/components/HelloCodeTitle.js"
showLineNumbers>
{`function HelloCodeTitle(props) {
return <h1>Hello, {props.name}</h1>;
}`}
</CodeBlock>
</BrowserWindow>

The props accepted are `language` and `title`, in the same way as you write Markdown code blocks.
The props accepted are `language`, `title` and `showLineNumbers`, in the same way as you write Markdown code blocks.

Although discouraged, you can also pass in a `metastring` prop like `metastring='{1-2} title="/src/components/HelloCodeTitle.js"'`, which is how Markdown code blocks are handled under the hood. However, we recommend you [use comments for highlighting lines](#highlighting-with-comments).
Although discouraged, you can also pass in a `metastring` prop like `metastring='{1-2} title="/src/components/HelloCodeTitle.js" showLineNumbers'`, which is how Markdown code blocks are handled under the hood. However, we recommend you [use comments for highlighting lines](#highlighting-with-comments).

As [previously stated](#using-jsx-markup), syntax highlighting is only applied when the children is a simple string.

0 comments on commit 0de49c3

Please sign in to comment.