From 84fd42a2a77020fc13c914ef5ae0d50b0f7caf4d Mon Sep 17 00:00:00 2001 From: Elvis Date: Tue, 24 Mar 2020 00:17:33 -0500 Subject: [PATCH 1/4] feat: support comments for code highlighting --- .../src/theme/CodeBlock/index.js | 115 +++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.js b/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.js index 4921105531aa..fefdcd228336 100644 --- a/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.js +++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.js @@ -17,6 +17,73 @@ import useThemeContext from '@theme/hooks/useThemeContext'; import styles from './styles.module.css'; const highlightLinesRangeRegex = /{([\d,-]+)}/; +const getHighlightDirectiveRegex = ( + languages = ['js', 'jsBlock', 'jsx', 'python', 'html'], +) => { + // supported types of comments + const comments = { + js: { + start: '\\/\\/', + end: '', + }, + jsBlock: { + start: '\\/\\*', + end: '\\*\\/', + }, + jsx: { + start: '\\{\\s*\\/\\*', + end: '\\*\\/\\s*\\}', + }, + python: { + start: '#', + end: '', + }, + html: { + start: '', + }, + }; + // supported directives + const directives = [ + 'highlight-next-line', + 'highlight-start', + 'highlight-end', + ].join('|'); + // to be more reliable, the opening and closing comment must match + const commentPattern = languages + .map( + lang => + `(?:${comments[lang].start}\\s*(${directives})\\s*${comments[lang].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 => { + 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 ({children, className: languageClassName, metastring}) => { const { @@ -75,6 +142,52 @@ export default ({children, className: languageClassName, metastring}) => { language = prism.defaultLanguage; } + // only declaration OR directive highlight can be used for a block + let code = children.replace(/\n$/, ''); + if (highlightLines.length === 0) { + let range = ''; + const directiveRegex = highlightDirectiveRegex(language); + // go through line by line + const lines = children.replace(/\n$/, '').split('\n'); + let blockStart; + // 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, item) => final || item, undefined); + console.log(lineNumber, directive); + 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; + } + } + console.log(range); + highlightLines = rangeParser.parse(range); + code = lines.join('\n'); + } + const handleCopyCode = () => { window.getSelection().empty(); setShowCopied(true); @@ -87,7 +200,7 @@ export default ({children, className: languageClassName, metastring}) => { {...defaultProps} key={mounted} theme={prismTheme} - code={children.replace(/\n$/, '')} + code={code} language={language}> {({className, style, tokens, getLineProps, getTokenProps}) => (

From 8356ed1a790869568e86e1d5745373890ae3c450 Mon Sep 17 00:00:00 2001
From: Elvis 
Date: Tue, 24 Mar 2020 01:56:44 -0500
Subject: [PATCH 2/4] docs(v2): demonstrate highlighting with comments

---
 website/docs/markdown-features.mdx | 45 ++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/website/docs/markdown-features.mdx b/website/docs/markdown-features.mdx
index 75269709203f..fdd3f6a38416 100644
--- a/website/docs/markdown-features.mdx
+++ b/website/docs/markdown-features.mdx
@@ -267,6 +267,51 @@ function HighlightSomeText(highlight) {
 }
 ```
 
+You can also use comments with `highlight-next-line`, `highlight-start`, and `highlight-end` to select which lines are highlighted.
+
+    ```jsx
+    function HighlightSomeText(highlight) {
+      if (highlight) {
+        // highlight-next-line
+        return 'This text is highlighted!';
+      }
+
+      return 'Nothing highlighted';
+    }
+
+    function HighlightMoreText(highlight) {
+      // highlight-start
+      if (highlight) {
+        return 'This range is highlighted!';
+      }
+      // highlight-end
+
+      return 'Nothing highlighted';
+    }
+    ```
+
+```jsx
+function HighlightSomeText(highlight) {
+  if (highlight) {
+    // highlight-next-line
+    return 'This text is highlighted!';
+  }
+  
+  return 'Nothing highlighted';
+}
+function HighlightMoreText(highlight) {
+  // highlight-start
+  if (highlight) {
+    return 'This range is highlighted!';
+  }
+  // highlight-end
+
+  return 'Nothing highlighted';
+}
+```
+
+JS style (`/* */` and `//`), JSX style (`{ /* */ }`), Python style (`# `), and HTML style (``) are supported.
+
 To accomplish this, Docusaurus adds the `docusaurus-highlight-code-line` class to the highlighted lines. You will need to define your own styling for this CSS, possibly in your `src/css/custom.css` with a custom background color which is dependent on your selected syntax highlighting theme. The color given below works for the default highlighting theme (Palenight), so if you are using another theme, you will have to tweak the color accordingly.
 
 ```css

From 11ef89d684afb6cead3fedc16945d88183a18630 Mon Sep 17 00:00:00 2001
From: Elvis 
Date: Tue, 24 Mar 2020 01:58:46 -0500
Subject: [PATCH 3/4] chore: remove debugging console.log

---
 packages/docusaurus-theme-classic/src/theme/CodeBlock/index.js | 2 --
 1 file changed, 2 deletions(-)

diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.js b/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.js
index fefdcd228336..f7825956aa5e 100644
--- a/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.js
+++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.js
@@ -160,7 +160,6 @@ export default ({children, className: languageClassName, metastring}) => {
         const directive = match
           .slice(1)
           .reduce((final, item) => final || item, undefined);
-        console.log(lineNumber, directive);
         switch (directive) {
           case 'highlight-next-line':
             range += `${lineNumber},`;
@@ -183,7 +182,6 @@ export default ({children, className: languageClassName, metastring}) => {
         index += 1;
       }
     }
-    console.log(range);
     highlightLines = rangeParser.parse(range);
     code = lines.join('\n');
   }

From dc5dfe18d5b1fc32e6bfc97016a59c17c66c8ecf Mon Sep 17 00:00:00 2001
From: Elvis 
Date: Tue, 24 Mar 2020 01:59:55 -0500
Subject: [PATCH 4/4] fix: disable when language is undefined

---
 packages/docusaurus-theme-classic/src/theme/CodeBlock/index.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.js b/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.js
index f7825956aa5e..46236067613b 100644
--- a/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.js
+++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.js
@@ -144,7 +144,7 @@ export default ({children, className: languageClassName, metastring}) => {
 
   // only declaration OR directive highlight can be used for a block
   let code = children.replace(/\n$/, '');
-  if (highlightLines.length === 0) {
+  if (highlightLines.length === 0 && language !== undefined) {
     let range = '';
     const directiveRegex = highlightDirectiveRegex(language);
     // go through line by line