Fix code highlighting

This commit is contained in:
Marcus Blättermann 2022-12-20 08:51:10 +01:00
parent f1a54563f1
commit de3e2080b9
No known key found for this signature in database
GPG Key ID: A1E1F04008AC450D
7 changed files with 42 additions and 64 deletions

View File

@ -2,13 +2,11 @@ import MDX from '@next/mdx'
import PWA from 'next-pwa' import PWA from 'next-pwa'
import remarkPlugins from './plugins/index.mjs' import remarkPlugins from './plugins/index.mjs'
import rehypePlugins from './plugins/rehypePlugins.mjs'
const withMDX = MDX({ const withMDX = MDX({
extension: /\.mdx?$/, extension: /\.mdx?$/,
options: { options: {
remarkPlugins, remarkPlugins,
rehypePlugins,
providerImportSource: '@mdx-js/react', providerImportSource: '@mdx-js/react',
}, },
experimental: { experimental: {

View File

@ -5,7 +5,6 @@ import { MDXRemote, MDXRemoteSerializeResult } from 'next-mdx-remote'
import path from 'path' import path from 'path'
import Layout from '../src/templates' import Layout from '../src/templates'
import remarkPlugins from '../plugins/index.mjs' import remarkPlugins from '../plugins/index.mjs'
import rehypePlugins from '../plugins/rehypePlugins.mjs'
import recordSection from '../meta/recordSections' import recordSection from '../meta/recordSections'
import { sidebarUsageFlat } from '../meta/sidebarFlat' import { sidebarUsageFlat } from '../meta/sidebarFlat'
@ -94,10 +93,7 @@ export const getStaticProps: GetStaticProps<PropsPage, ParsedUrlQuery> = async (
const mdx = await serialize(fs.readFileSync(pathFileWithIndexAndExtension, 'utf-8'), { const mdx = await serialize(fs.readFileSync(pathFileWithIndexAndExtension, 'utf-8'), {
parseFrontmatter: true, parseFrontmatter: true,
mdxOptions: { mdxOptions: { remarkPlugins },
remarkPlugins,
rehypePlugins,
},
}) })
if (!mdx.frontmatter) { if (!mdx.frontmatter) {

View File

@ -1,5 +0,0 @@
import rehypePrism from '@mapbox/rehype-prism'
const rehypePlugins = [rehypePrism]
export default rehypePlugins

View File

@ -54,32 +54,6 @@ function remarkCodeBlocks(userOptions = {}) {
const meta = getProps(Parser.parse(node.meta, { ecmaVersion: 'latest' })) const meta = getProps(Parser.parse(node.meta, { ecmaVersion: 'latest' }))
node.data.hProperties = Object.assign({}, hProps, attrs, meta) node.data.hProperties = Object.assign({}, hProps, attrs, meta)
if (meta.executable) {
node.type = 'mdxJsxFlowElement'
node.name = 'CodeBlock'
node.attributes = [
{
type: 'mdxJsxAttribute',
name: 'lang',
value: 'python',
},
{
type: 'mdxJsxAttribute',
name: 'executable',
value: true,
},
// Adding the children like this makes sure
// they don't get further formatted by Remark
{
type: 'mdxJsxAttribute',
name: 'children',
value: node.value,
},
]
node.data['_mdxExplicitJsx'] = true
}
} }
}) })

View File

@ -2,10 +2,17 @@ import React, { Fragment, useEffect, useState } from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import classNames from 'classnames' import classNames from 'classnames'
import rangeParser from 'parse-numeric-range' import rangeParser from 'parse-numeric-range'
import { window } from 'browser-monads'
import Prism from 'prismjs' import Prism from 'prismjs'
// We manually load all the languages that are needed, which are currently only those:
import 'prismjs/components/prism-diff.min.js'
import 'prismjs/components/prism-bash.min.js'
import 'prismjs/components/prism-ini.min.js'
import 'prismjs/components/prism-jsx.min.js'
import 'prismjs/components/prism-json.min.js'
import 'prismjs/components/prism-markdown.min.js'
import 'prismjs/components/prism-python.min.js' import 'prismjs/components/prism-python.min.js'
import 'prismjs/components/prism-yaml.min.js'
import CUSTOM_TYPES from '../../meta/type-annotations.json' import CUSTOM_TYPES from '../../meta/type-annotations.json'
import { isString, htmlToReact } from './util' import { isString, htmlToReact } from './util'
@ -197,12 +204,7 @@ const checkoutForComment = (line) => {
) )
} }
const convertLine = (line, prompt) => { const handlePromot = ({ lineFlat, prompt }) => {
const lineFlat = flattenReact(line).join('')
if (!lineFlat.startsWith(`${prompt} `)) {
return line
}
const lineWithoutPrompt = lineFlat.slice(prompt.length + 1) const lineWithoutPrompt = lineFlat.slice(prompt.length + 1)
const cliRegex = /^python -m spacy/ const cliRegex = /^python -m spacy/
@ -244,6 +246,23 @@ const convertLine = (line, prompt) => {
) )
} }
const convertLine = ({ line, prompt, lang }) => {
const lineFlat = flattenReact(line).join('')
if (lineFlat.startsWith(`${prompt} `)) {
return handlePromot({ lineFlat, prompt })
}
return lang === 'none' || !lineFlat ? (
lineFlat
) : (
<span
dangerouslySetInnerHTML={{
__html: Prism.highlight(lineFlat, Prism.languages[lang], lang),
}}
/>
)
}
const addLineHighlight = (children, highlight) => { const addLineHighlight = (children, highlight) => {
if (!highlight) { if (!highlight) {
return children return children
@ -269,18 +288,18 @@ const addLineHighlight = (children, highlight) => {
}) })
} }
const CodeHighlighted = ({ children, highlight }) => { export const CodeHighlighted = ({ children, highlight, lang }) => {
const [html, setHtml] = useState() const [html, setHtml] = useState()
useEffect( useEffect(
() => () =>
setHtml( setHtml(
addLineHighlight( addLineHighlight(
splitLines(children).map((line) => convertLine(line, '$')), splitLines(children).map((line) => convertLine({ line, prompt: '$', lang })),
highlight highlight
) )
), ),
[children, highlight] [children, highlight, lang]
) )
return <>{html}</> return <>{html}</>
@ -304,8 +323,7 @@ export class Code extends React.Component {
} }
render() { render() {
const { lang, title, executable, github, prompt, wrap, highlight, className, children } = const { lang, title, executable, github, wrap, highlight, className, children } = this.props
this.props
const codeClassNames = classNames(classes['code'], className, `language-${lang}`, { const codeClassNames = classNames(classes['code'], className, `language-${lang}`, {
[classes['wrap']]: !!highlight || !!wrap || lang === 'cli', [classes['wrap']]: !!highlight || !!wrap || lang === 'cli',
[classes['cli']]: lang === 'cli', [classes['cli']]: lang === 'cli',
@ -327,7 +345,9 @@ export class Code extends React.Component {
<> <>
{title && <h4 className={classes['title']}>{title}</h4>} {title && <h4 className={classes['title']}>{title}</h4>}
<code className={codeClassNames}> <code className={codeClassNames}>
<CodeHighlighted highlight={highlight}>{children}</CodeHighlighted> <CodeHighlighted highlight={highlight} lang={lang}>
{children}
</CodeHighlighted>
</code> </code>
</> </>
) )

View File

@ -1,17 +1,11 @@
import React, { useState, useEffect } from 'react' import React, { useState, useEffect } from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import classNames from 'classnames' import classNames from 'classnames'
import Prism from 'prismjs'
// We manually load all the languages that are needed, which are currently only those:
import 'prismjs/components/prism-json.min.js'
import 'prismjs/components/prism-python.min.js'
import 'prismjs/components/prism-yaml.min.js'
import 'prismjs/components/prism-ini.min.js'
import Icon from './icon' import Icon from './icon'
import Link from './link' import Link from './link'
import classes from '../styles/code.module.sass' import classes from '../styles/code.module.sass'
import { Code } from './code'
const defaultErrorMsg = `Can't fetch code example from GitHub :( const defaultErrorMsg = `Can't fetch code example from GitHub :(
@ -45,9 +39,6 @@ const GitHubCode = ({ url, lang, errorMsg = defaultErrorMsg, className }) => {
} }
}, [initialized, rawUrl, errorMsg]) }, [initialized, rawUrl, errorMsg])
const highlighted =
lang === 'none' || !code ? code : Prism.highlight(code, Prism.languages[lang], lang)
return ( return (
<> <>
<header className={classes.header}> <header className={classes.header}>
@ -60,7 +51,11 @@ const GitHubCode = ({ url, lang, errorMsg = defaultErrorMsg, className }) => {
</code> </code>
</Link> </Link>
</header> </header>
<code className={codeClassNames} dangerouslySetInnerHTML={{ __html: highlighted }} /> {code && (
<Code className={codeClassNames} lang={lang}>
{code}
</Code>
)}
</> </>
) )
} }

View File

@ -298,8 +298,8 @@ const Model = ({
{name} {name}
</H2> </H2>
<Aside title="Installation"> <Aside title="Installation">
<CodeBlock lang="cli" prompt="$"> <CodeBlock lang="bash" prompt="$">
python -m spacy download {name} $ python -m spacy download {name}
</CodeBlock> </CodeBlock>
</Aside> </Aside>
{meta.description && <MarkdownToReact markdown={meta.description} />} {meta.description && <MarkdownToReact markdown={meta.description} />}