如何使用 highlight.js (React) 正确地逐行突出显示代码?
How can I correctly highlight a line by line code, using highlight.js (React)?
我需要突出显示一段代码,但同时,我需要将代码放在单独的编号行中,为每行代码留下注释,就像在 [=14 上所做的那样=].我设法做到了这一点,但因为我突出显示了每一行的代码,所以多行上的“SQL”代码将无法正确突出显示(仅突出显示第一行)并且我无法修复此问题。你有什么建议吗?
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));
}
您不能简单地拆分 \n
上的输出,因为跨度可以跨越线边界:
var x = <span class="string>"This is a
really long string
that spans multiple lines
super annoying"</span>
您必须编写代码将其变成:
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,在任何时候你都必须跟踪所有打开的标签并在一行结束时关闭它们,然后在下一行开始之前打开它们。
可以这么说,这并不是 Highlight.js 的典型用例,因此您可以自己构建它。
没有简单的方法可以做到这一点,但是如果您访问原始解析树(而不是生成的 HTML),您可以编写一些遍历它的东西逐个节点并找出线条的位置。如何访问解析树对象(发射器):
highlight(code).__emitter
或者您可以简单地将发射器替换为您自己的自定义发射器。查看源文件以了解您需要实现的 API:
https://github.com/highlightjs/highlight.js/blob/master/src/lib/token_tree.js
然后你必须遍历树,跟踪哪些标签是打开的,当你找到一行结束时你需要关闭标签...... re-opening 下一个线。 IE,你几乎需要从解析树开始写你自己的 HTML 渲染引擎。
请注意:整个 __emitter
API 不被视为 public API 的一部分,可能会在未来的更新中随时更改或中断 - 虽然通常只要您确保测试新版本,就应该“相当安全”地使用它。我没有计划在不久的将来对其进行重大更改。
[免责声明:我是当前的 Highlight.js 维护者。]
我们最近不得不实现行号,这是我们在 Typescript 中将其添加为插件的实现:
hljs.addPlugin({
"after:highlight": (params: { value: string; }) => {
const openTags: string[] = [];
params.value = params.value.replace(/(<span [^>]+>)|(<\/span>)|(\n)/g, match => {
if (match === "\n") {
return "</span>".repeat(openTags.length) + "\n" + openTags.join("");
}
if (match === "</span>") {
openTags.pop();
} else {
openTags.push(match);
}
return match;
});
},
});
这会将 highlightjs
输出的字符串更改为可以很容易地被 \n
拆分的字符串。
如果您在客户端执行此操作,则可能需要使用 "after:highlightBlock"
或 "after:highlightElement"
,具体取决于 highlightjs
.
的版本
或者您可以只在输出上调用该函数,然后将其拆分为 \n
。
我需要突出显示一段代码,但同时,我需要将代码放在单独的编号行中,为每行代码留下注释,就像在 [=14 上所做的那样=].我设法做到了这一点,但因为我突出显示了每一行的代码,所以多行上的“SQL”代码将无法正确突出显示(仅突出显示第一行)并且我无法修复此问题。你有什么建议吗?
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));
}
您不能简单地拆分 \n
上的输出,因为跨度可以跨越线边界:
var x = <span class="string>"This is a
really long string
that spans multiple lines
super annoying"</span>
您必须编写代码将其变成:
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,在任何时候你都必须跟踪所有打开的标签并在一行结束时关闭它们,然后在下一行开始之前打开它们。
可以这么说,这并不是 Highlight.js 的典型用例,因此您可以自己构建它。
没有简单的方法可以做到这一点,但是如果您访问原始解析树(而不是生成的 HTML),您可以编写一些遍历它的东西逐个节点并找出线条的位置。如何访问解析树对象(发射器):
highlight(code).__emitter
或者您可以简单地将发射器替换为您自己的自定义发射器。查看源文件以了解您需要实现的 API:
https://github.com/highlightjs/highlight.js/blob/master/src/lib/token_tree.js
然后你必须遍历树,跟踪哪些标签是打开的,当你找到一行结束时你需要关闭标签...... re-opening 下一个线。 IE,你几乎需要从解析树开始写你自己的 HTML 渲染引擎。
请注意:整个 __emitter
API 不被视为 public API 的一部分,可能会在未来的更新中随时更改或中断 - 虽然通常只要您确保测试新版本,就应该“相当安全”地使用它。我没有计划在不久的将来对其进行重大更改。
[免责声明:我是当前的 Highlight.js 维护者。]
我们最近不得不实现行号,这是我们在 Typescript 中将其添加为插件的实现:
hljs.addPlugin({
"after:highlight": (params: { value: string; }) => {
const openTags: string[] = [];
params.value = params.value.replace(/(<span [^>]+>)|(<\/span>)|(\n)/g, match => {
if (match === "\n") {
return "</span>".repeat(openTags.length) + "\n" + openTags.join("");
}
if (match === "</span>") {
openTags.pop();
} else {
openTags.push(match);
}
return match;
});
},
});
这会将 highlightjs
输出的字符串更改为可以很容易地被 \n
拆分的字符串。
如果您在客户端执行此操作,则可能需要使用 "after:highlightBlock"
或 "after:highlightElement"
,具体取决于 highlightjs
.
或者您可以只在输出上调用该函数,然后将其拆分为 \n
。