Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I correctly highlight a line by line code, using highlight.js (React)?

I need to highlight a block of code but at the same time, I need the code to be placed on separate and numbered lines, to leave comments for each line of code, just as can be done on Github. I managed to do this but because I highlight the code for each line, the "SQL" code that is on several lines will not be highlighted correctly (only the first line is highlighted) and I fail to fix this. Do you have any suggestions?

       if (data.success === 1) {
          setCodeLanguage(translateLanguage(data.code.language));
          let rows = [];
          data.code.source_code.split("\n").forEach((line, index) => {
            rows.push(
              <tr key={index} className="line">
                <td className="line-number">{index + 1}</td>
                <td id={"plus" + index} className="plus-square-line">
                  <PlusSquareTwoTone className="plus-square" />
                </td>
                <td id={"codeblock" + index}
                  className={'language-' + codeLanguage} style={rowStyle}>
                  {line}
                </td>
              </tr>
            );
          });
          setCodeRows(rows);
          for (let i = 0; i < codeRows.length; ++i) {
            hljs.highlightBlock(document.getElementById("codeblock" + i));
          } 
like image 637
Alex Popa Avatar asked Oct 09 '20 13:10

Alex Popa


People also ask

How do you use react syntax highlighter?

You need to install prism–react–renderer from NPM to use it. Prism react renderer exposes Highlight as its main component and exports some default props, which you can pass to Highlight . You need to pass a render prop to the Highlight component as in the example below.


1 Answers

You can't simply split the output on \n because spans can cross line boundaries:

var x = <span class="string>"This is a
really long string
that spans multiple lines
super annoying"</span>

You have to write code to turn this into:

var x = <span class="string">"This is a</span>
<span class="string">really long string</span>
<span class="string">that spans multiple lines</span>
<span class="string">super annoying"</span>

IE, at any given moment you have to keep track of all open tags and close them when one line ends, then open them before the next line starts.

Suffice to say this is not really a typical use case for Highlight.js, so you can of have to build it all yourself.


There is no easy way to do this, but if you access the raw parse tree (rather than the generated HTML) you could write something that walked it node by node and figured out where the lines are. How to get access to the parse tree object (the emitter):

highlight(code).__emitter

Or you can simply replace the emitter with your own custom emitter. See the source file to learn about the API you'd need to implement:

https://github.com/highlightjs/highlight.js/blob/master/src/lib/token_tree.js

Then you'd have to walk the tree, keep track of which tags are open and when you found a line end you'd need to close the tags... re-opening them again on the next line. IE, pretty much you need to start from the parse tree and write your own HTML rendering engine.

Please note: The whole __emitter API is not considered part of the public API and could change or break at any time in future updates - though generally it should be "fairly safe" to use as long as you make sure to test new versions. I have no plans to change it significantly in the near future.

[Disclaim: I'm the current Highlight.js maintainer.]

like image 90
Josh Goebel Avatar answered Oct 10 '22 11:10

Josh Goebel