使用prismjs 生成静态html - 如何启用行号?

tig*_*tig 4 node.js prismjs

我正在使用 node.js从代码生成静态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');
Run Code Online (Sandbox Code Playgroud)

这很好用。但是我想使用该line-numbers插件并且不知道如何使其工作。我<pre>line-numbers课,我得到了更大的左边距,但没有行号。

Chr*_*ras 5

PrismJS需要 DOM 才能让大多数插件工作。查看plugins/line-numbers/prism-line-numbers.js#L109 中的代码后,我们可以看到行号只是一个span元素,class="line-numbers-rows"其中span每行都包含一个空。我们可以在没有 DOM 的情况下模拟这种行为,只需使用prism-line-numbers用于获取行号的相同正则表达式,然后组合一个包含 html 代码的字符串,并为每一行span.line-numbers-rows添加一个空字符串<span></span>

Prism.highlight只运行 2 个钩子,before-tokenize并且after-tokenize. 我们将使用after-tokenize组成一个lineNumbersWrapper包含span.line-numbers-rows元素和空span行元素的字符串:

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);
Run Code Online (Sandbox Code Playgroud)

这将输出:

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>
Run Code Online (Sandbox Code Playgroud)

最后有span.line-numbers-rows

<span aria-hidden="true" class="line-numbers-rows">
  <span></span>
  <span></span>
</span>
Run Code Online (Sandbox Code Playgroud)

现在,如果我们在pre.language-csharp.line-numbers code.language-csharp元素中使用该输出,我们将获得正确的行号结果。检查此Codepen仅具有themes/prism.cssplugins/line-numbers/prism-line-numbers.css与上述输出代码并正确显示行号。

请注意,每一行(除了第一行)都必须是用于代码正确显示的标记,这是因为我们在一个pre.code块内,但我想您已经知道了。

更新

如果您不依赖 CSS 并且只需要在每一行之前添加一个行号,那么您可以通过拆分所有行来添加一个行号,并index + 1在开始时使用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);
Run Code Online (Sandbox Code Playgroud)

将输出:

   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>
Run Code Online (Sandbox Code Playgroud)