使用 prismjs 生成静态 html - 如何启用行号?
Static html generation with prismjs - how to enable line-numbers?
我正在使用 node.js 从代码生成 static html 文件,并使用 prismjs 对其进行格式化。在我的应用程序中,我无法访问支持 Javascript 的 HTML 渲染器(我正在使用 'htmllite')。所以我需要能够生成不需要 Javascript.
的 HTML
const Prism = require('prismjs');
const loadLanguages = require('prismjs/components/');
loadLanguages(['csharp']);
const code = '<a bunch of C# code>';
const html = Prism.highlight(code, Prism.languages.csharp, 'csharp');
效果很好。但是我想使用 line-numbers
插件,但不知道如何让它工作。我的 <pre>
有 line-numbers
class,我的左边距更大,但没有行号。
也许这对你有帮助:
Codepen 有错误:
(codepen 行数超过了堆栈溢出的限制!)
Codepen 工作正常:
(codepen 行数超过了堆栈溢出的限制!)
两者之间的变化:
pre.line-numbers {
position: relative;
padding-left: 3.8em;
counter-reset: linenumber;
}
pre.line-numbers>code {
position: relative;
}
.line-numbers .line-numbers-rows {
position: absolute;
pointer-events: none;
top: 0;
font-size: 100%;
left: -3.8em;
width: 3em;
/* works for line-numbers below 1000 lines */
letter-spacing: -1px;
border-right: 1px solid #999;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.line-numbers-rows>span {
pointer-events: none;
display: block;
counter-increment: linenumber;
}
.line-numbers-rows>span:before {
content: counter(linenumber);
color: #999;
display: block;
padding-right: 0.8em;
text-align: right;
}
PrismJS needs DOM for most plugins to work. After looking at the code inside plugins/line-numbers/prism-line-numbers.js#L109,我们可以看到行号只是一个 span
元素,其中 class="line-numbers-rows"
每行包含一个空的 span
。我们可以在没有 DOM 的情况下模拟这种行为,只需使用 prism-line-numbers
用于获取行号的相同正则表达式,然后组成一个具有 span.line-numbers-rows
的 html 代码的字符串] 并为每一行添加一个空字符串 <span></span>
。
Prism.highlight
runs only 2 hooks, before-tokenize
and after-tokenize
. We'll use after-tokenize
组成包含 span.line-numbers-rows
元素和空 span
行元素的 lineNumbersWrapper
字符串:
const Prism = require('prismjs');
const loadLanguages = require('prismjs/components/');
loadLanguages(['csharp']);
const code = `Console.WriteLine();
Console.WriteLine("Demo: Prism line-numbers plugin with nodejs");`;
// https://github.com/PrismJS/prism/blob/master/plugins/line-numbers/prism-line-numbers.js#L109
var NEW_LINE_EXP = /\n(?!$)/g;
var lineNumbersWrapper;
Prism.hooks.add('after-tokenize', function (env) {
var match = env.code.match(NEW_LINE_EXP);
var linesNum = match ? match.length + 1 : 1;
var lines = new Array(linesNum + 1).join('<span></span>');
lineNumbersWrapper = `<span aria-hidden="true" class="line-numbers-rows">${lines}</span>`;
});
const formated = Prism.highlight(code, Prism.languages.csharp, 'csharp');
const html = formated + lineNumbersWrapper;
console.log(html);
这将输出:
Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token string">"Demo: Generate invalid numbers"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span>
结尾有span.line-numbers-rows
:
<span aria-hidden="true" class="line-numbers-rows">
<span></span>
<span></span>
</span>
现在,如果我们在 pre.language-csharp.line-numbers code.language-csharp
元素中使用该输出,我们将获得正确的行号结果。检查此 Codepen,它只有 themes/prism.css
和 plugins/line-numbers/prism-line-numbers.css
,并正确显示带有上述输出代码的行号。
请注意,每一行(第一行除外)都必须是旨在使代码正确显示的标记,这是因为我们在 pre.code
块内,但我想您已经知道了。
更新
如果您不依赖 CSS 并且您只想在每行之前添加一个行号,那么您可以通过拆分所有行来添加一个行,并在每个 index + 1
中添加一个 space 开始使用 padStart
填充:
const Prism = require('prismjs');
const loadLanguages = require('prismjs/components/');
loadLanguages(['csharp']);
const code = `Console.WriteLine();
Console.WriteLine("Demo: Prism line-numbers plugin with nodejs");`;
const formated = Prism.highlight(code, Prism.languages.csharp, 'csharp');
const html = formated
.split('\n')
.map((line, num) => `${(num + 1).toString().padStart(4, ' ')}. ${line}`)
.join('\n');
console.log(html);
将输出:
1. Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
2. Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token string">"Demo: Prism line-numbers plugin with nodejs"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
我有一个带有代码片段的 React 网站,我使用了这样的 prismjs 节点模块:
SourceCode.js
import * as Prism from "prismjs";
export default function SourceCode(props) {
return (
<div>
<div style={{ maxWidth: 900 }}>
<pre className="language-javascript" style={{ backgroundColor: "#272822", fontSize: "0.8em" }}>
<code
style={{ fontFamily: "Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace" }}
dangerouslySetInnerHTML={{
__html: Prism.highlight(props.code, Prism.languages.javascript, "javascript"),
}}
/>
</pre>
</div>
</div>
);
};
然后我决定添加 line-numbers 插件,但我很难弄清楚如何让它与 Node.js 和 React 一起工作。问题是 line-numbers 使用了 DOM,而不是简单地在 Node.js.
中使用 DOM
我终于做到了。我卸载了 prismjs 模块并以一种老式的方式完成了:)。
index.html
<html lang="en-us">
<head>
<meta charset="utf-8" />
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<title>SciChart Web Demo</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.21.0/themes/prism-okaidia.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.21.0/plugins/line-numbers/prism-line-numbers.min.css" />
<script async type="text/javascript" src="bundle.js"></script>
</head>
<body>
<div id="react-root"></div>
<script>
window.Prism = window.Prism || {};
Prism.manual = true;
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.21.0/prism.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.21.0/plugins/line-numbers/prism-line-numbers.min.js"></script>
</body>
</html>
SourceCode.js
import * as React from "react";
export default function SourceCode(props) {
React.useEffect(() => {
window.Prism.highlightAll();
}, []);
return (
<div>
<div style={{ maxWidth: 900 }}>
<pre
className="language-javascript line-numbers"
style={{ backgroundColor: "#272822", fontSize: "0.8em" }}
>
<code style={{ fontFamily: "Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace" }}>
{props.code}
</code>
</pre>
</div>
</div>
);
};
我正在使用 node.js 从代码生成 static html 文件,并使用 prismjs 对其进行格式化。在我的应用程序中,我无法访问支持 Javascript 的 HTML 渲染器(我正在使用 'htmllite')。所以我需要能够生成不需要 Javascript.
的 HTMLconst Prism = require('prismjs');
const loadLanguages = require('prismjs/components/');
loadLanguages(['csharp']);
const code = '<a bunch of C# code>';
const html = Prism.highlight(code, Prism.languages.csharp, 'csharp');
效果很好。但是我想使用 line-numbers
插件,但不知道如何让它工作。我的 <pre>
有 line-numbers
class,我的左边距更大,但没有行号。
也许这对你有帮助:
Codepen 有错误:
(codepen 行数超过了堆栈溢出的限制!)
Codepen 工作正常:
(codepen 行数超过了堆栈溢出的限制!)
两者之间的变化:
pre.line-numbers {
position: relative;
padding-left: 3.8em;
counter-reset: linenumber;
}
pre.line-numbers>code {
position: relative;
}
.line-numbers .line-numbers-rows {
position: absolute;
pointer-events: none;
top: 0;
font-size: 100%;
left: -3.8em;
width: 3em;
/* works for line-numbers below 1000 lines */
letter-spacing: -1px;
border-right: 1px solid #999;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.line-numbers-rows>span {
pointer-events: none;
display: block;
counter-increment: linenumber;
}
.line-numbers-rows>span:before {
content: counter(linenumber);
color: #999;
display: block;
padding-right: 0.8em;
text-align: right;
}
PrismJS needs DOM for most plugins to work. After looking at the code inside plugins/line-numbers/prism-line-numbers.js#L109,我们可以看到行号只是一个 span
元素,其中 class="line-numbers-rows"
每行包含一个空的 span
。我们可以在没有 DOM 的情况下模拟这种行为,只需使用 prism-line-numbers
用于获取行号的相同正则表达式,然后组成一个具有 span.line-numbers-rows
的 html 代码的字符串] 并为每一行添加一个空字符串 <span></span>
。
Prism.highlight
runs only 2 hooks, before-tokenize
and after-tokenize
. We'll use after-tokenize
组成包含 span.line-numbers-rows
元素和空 span
行元素的 lineNumbersWrapper
字符串:
const Prism = require('prismjs');
const loadLanguages = require('prismjs/components/');
loadLanguages(['csharp']);
const code = `Console.WriteLine();
Console.WriteLine("Demo: Prism line-numbers plugin with nodejs");`;
// https://github.com/PrismJS/prism/blob/master/plugins/line-numbers/prism-line-numbers.js#L109
var NEW_LINE_EXP = /\n(?!$)/g;
var lineNumbersWrapper;
Prism.hooks.add('after-tokenize', function (env) {
var match = env.code.match(NEW_LINE_EXP);
var linesNum = match ? match.length + 1 : 1;
var lines = new Array(linesNum + 1).join('<span></span>');
lineNumbersWrapper = `<span aria-hidden="true" class="line-numbers-rows">${lines}</span>`;
});
const formated = Prism.highlight(code, Prism.languages.csharp, 'csharp');
const html = formated + lineNumbersWrapper;
console.log(html);
这将输出:
Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token string">"Demo: Generate invalid numbers"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span>
结尾有span.line-numbers-rows
:
<span aria-hidden="true" class="line-numbers-rows">
<span></span>
<span></span>
</span>
现在,如果我们在 pre.language-csharp.line-numbers code.language-csharp
元素中使用该输出,我们将获得正确的行号结果。检查此 Codepen,它只有 themes/prism.css
和 plugins/line-numbers/prism-line-numbers.css
,并正确显示带有上述输出代码的行号。
请注意,每一行(第一行除外)都必须是旨在使代码正确显示的标记,这是因为我们在 pre.code
块内,但我想您已经知道了。
更新
如果您不依赖 CSS 并且您只想在每行之前添加一个行号,那么您可以通过拆分所有行来添加一个行,并在每个 index + 1
中添加一个 space 开始使用 padStart
填充:
const Prism = require('prismjs');
const loadLanguages = require('prismjs/components/');
loadLanguages(['csharp']);
const code = `Console.WriteLine();
Console.WriteLine("Demo: Prism line-numbers plugin with nodejs");`;
const formated = Prism.highlight(code, Prism.languages.csharp, 'csharp');
const html = formated
.split('\n')
.map((line, num) => `${(num + 1).toString().padStart(4, ' ')}. ${line}`)
.join('\n');
console.log(html);
将输出:
1. Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
2. Console<span class="token punctuation">.</span><span class="token function">WriteLine</span><span class="token punctuation">(</span><span class="token string">"Demo: Prism line-numbers plugin with nodejs"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
我有一个带有代码片段的 React 网站,我使用了这样的 prismjs 节点模块:
SourceCode.js
import * as Prism from "prismjs";
export default function SourceCode(props) {
return (
<div>
<div style={{ maxWidth: 900 }}>
<pre className="language-javascript" style={{ backgroundColor: "#272822", fontSize: "0.8em" }}>
<code
style={{ fontFamily: "Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace" }}
dangerouslySetInnerHTML={{
__html: Prism.highlight(props.code, Prism.languages.javascript, "javascript"),
}}
/>
</pre>
</div>
</div>
);
};
然后我决定添加 line-numbers 插件,但我很难弄清楚如何让它与 Node.js 和 React 一起工作。问题是 line-numbers 使用了 DOM,而不是简单地在 Node.js.
中使用 DOM我终于做到了。我卸载了 prismjs 模块并以一种老式的方式完成了:)。
index.html
<html lang="en-us">
<head>
<meta charset="utf-8" />
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<title>SciChart Web Demo</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.21.0/themes/prism-okaidia.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.21.0/plugins/line-numbers/prism-line-numbers.min.css" />
<script async type="text/javascript" src="bundle.js"></script>
</head>
<body>
<div id="react-root"></div>
<script>
window.Prism = window.Prism || {};
Prism.manual = true;
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.21.0/prism.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.21.0/plugins/line-numbers/prism-line-numbers.min.js"></script>
</body>
</html>
SourceCode.js
import * as React from "react";
export default function SourceCode(props) {
React.useEffect(() => {
window.Prism.highlightAll();
}, []);
return (
<div>
<div style={{ maxWidth: 900 }}>
<pre
className="language-javascript line-numbers"
style={{ backgroundColor: "#272822", fontSize: "0.8em" }}
>
<code style={{ fontFamily: "Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace" }}>
{props.code}
</code>
</pre>
</div>
</div>
);
};