diff --git a/packages/docusaurus-theme-classic/package.json b/packages/docusaurus-theme-classic/package.json index 581c181970..13b7dc4dbc 100644 --- a/packages/docusaurus-theme-classic/package.json +++ b/packages/docusaurus-theme-classic/package.json @@ -41,7 +41,6 @@ "globby": "^11.0.2", "infima": "0.2.0-alpha.34", "lodash": "^4.17.20", - "parse-numeric-range": "^1.3.0", "postcss": "^8.3.7", "prism-react-renderer": "^1.2.1", "prismjs": "^1.23.0", diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx b/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx index bd7d49ac24..a616579e24 100644 --- a/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx @@ -5,100 +5,22 @@ * LICENSE file in the root directory of this source tree. */ -import React, {useEffect, useState, useRef} from 'react'; +import React, {useEffect, useState} from 'react'; import clsx from 'clsx'; import Highlight, {defaultProps, Language} from 'prism-react-renderer'; import copy from 'copy-text-to-clipboard'; -import rangeParser from 'parse-numeric-range'; +import Translate, {translate} from '@docusaurus/Translate'; +import { + useThemeConfig, + parseCodeBlockTitle, + parseLanguage, + parseLines, +} from '@docusaurus/theme-common'; import usePrismTheme from '@theme/hooks/usePrismTheme'; import type {Props} from '@theme/CodeBlock'; -import Translate, {translate} from '@docusaurus/Translate'; import styles from './styles.module.css'; -import {useThemeConfig, parseCodeBlockTitle} from '@docusaurus/theme-common'; - -const HighlightLinesRangeRegex = /{([\d,-]+)}/; - -const HighlightLanguages = ['js', 'jsBlock', 'jsx', 'python', 'html'] as const; -type HighlightLanguage = typeof HighlightLanguages[number]; - -type HighlightLanguageConfig = { - start: string; - end: string; -}; - -// Supported types of highlight comments -const HighlightComments: Record = { - js: { - start: '\\/\\/', - end: '', - }, - jsBlock: { - start: '\\/\\*', - end: '\\*\\/', - }, - jsx: { - start: '\\{\\s*\\/\\*', - end: '\\*\\/\\s*\\}', - }, - python: { - start: '#', - end: '', - }, - html: { - start: '', - }, -}; - -// Supported highlight directives -const HighlightDirectives = [ - 'highlight-next-line', - 'highlight-start', - 'highlight-end', -]; - -const getHighlightDirectiveRegex = ( - languages: readonly HighlightLanguage[] = HighlightLanguages, -) => { - // to be more reliable, the opening and closing comment must match - const commentPattern = languages - .map((lang) => { - const {start, end} = HighlightComments[lang]; - return `(?:${start}\\s*(${HighlightDirectives.join('|')})\\s*${end})`; - }) - .join('|'); - // white space is allowed, but otherwise it should be on it's own line - return new RegExp(`^\\s*(?:${commentPattern})\\s*$`); -}; - -// select comment styles based on language -const highlightDirectiveRegex = (lang: string) => { - switch (lang) { - case 'js': - case 'javascript': - case 'ts': - case 'typescript': - return getHighlightDirectiveRegex(['js', 'jsBlock']); - - case 'jsx': - case 'tsx': - return getHighlightDirectiveRegex(['js', 'jsBlock', 'jsx']); - - case 'html': - return getHighlightDirectiveRegex(['js', 'jsBlock', 'html']); - - case 'python': - case 'py': - return getHighlightDirectiveRegex(['python']); - - default: - // all comment types - return getHighlightDirectiveRegex(); - } -}; - export default function CodeBlock({ children, className: blockClassName, @@ -124,10 +46,6 @@ export default function CodeBlock({ // so we probably don't need to parse the metastring // (note: title="xyz" => title prop still has the quotes) const codeBlockTitle = parseCodeBlockTitle(metastring) || title; - - const button = useRef(null); - let highlightLines: number[] = []; - const prismTheme = usePrismTheme(); // In case interleaved Markdown (e.g. when using CodeBlock as standalone component). @@ -135,67 +53,9 @@ export default function CodeBlock({ ? children.join('') : (children as string); - if (metastring && HighlightLinesRangeRegex.test(metastring)) { - // Tested above - const highlightLinesRange = metastring.match(HighlightLinesRangeRegex)![1]; - highlightLines = rangeParser(highlightLinesRange).filter((n) => n > 0); - } - - const languageClassName = blockClassName - ?.split(' ') - .find((str) => str.startsWith('language-')); - let language = languageClassName?.replace(/language-/, '') as Language; - - if (!language && prism.defaultLanguage) { - language = prism.defaultLanguage as Language; - } - - // only declaration OR directive highlight can be used for a block - let code = content.replace(/\n$/, ''); - if (highlightLines.length === 0 && language !== undefined) { - let range = ''; - const directiveRegex = highlightDirectiveRegex(language); - // go through line by line - const lines = content.replace(/\n$/, '').split('\n'); - let blockStart: number; - // loop through lines - for (let index = 0; index < lines.length; ) { - const line = lines[index]; - // adjust for 0-index - const lineNumber = index + 1; - const match = line.match(directiveRegex); - if (match !== null) { - const directive = match - .slice(1) - .reduce( - (final: string | undefined, item) => final || item, - undefined, - ); - switch (directive) { - case 'highlight-next-line': - range += `${lineNumber},`; - break; - - case 'highlight-start': - blockStart = lineNumber; - break; - - case 'highlight-end': - range += `${blockStart!}-${lineNumber - 1},`; - break; - - default: - break; - } - lines.splice(index, 1); - } else { - // lines without directives are unchanged - index += 1; - } - } - highlightLines = rangeParser(range); - code = lines.join('\n'); - } + const language = + parseLanguage(blockClassName) ?? (prism.defaultLanguage as Language); + const {highlightLines, code} = parseLines(content, metastring, language); const handleCopyCode = () => { copy(code); @@ -212,11 +72,7 @@ export default function CodeBlock({ code={code} language={language}> {({className, style, tokens, getLineProps, getTokenProps}) => ( -
+
{codeBlockTitle && (
{codeBlockTitle} @@ -236,7 +92,7 @@ export default function CodeBlock({ const lineProps = getLineProps({line, key: i}); - if (highlightLines.includes(i + 1)) { + if (highlightLines.includes(i)) { lineProps.className += ' docusaurus-highlight-code-line'; } @@ -253,7 +109,6 @@ export default function CodeBlock({