【问题标题】:Static html generation with prismjs - how to enable line-numbers?使用 prismjs 生成静态 html - 如何启用行号?
【发布时间】:2019-12-28 05:34:00
【问题描述】:

我正在使用 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 插件,但不知道如何使它工作。我的&lt;pre&gt;line-numbers 类,我的左边距更大,但没有行号。

【问题讨论】:

  • 也许你会发现这个链接有帮助github.com/PrismJS/prism/issues/1420
  • 不,不是这样。我认为这是因为 line-numbers 实际上使用 Javascript 来修改 DOM。 IOW,它无法在没有 Javascript 的静态页面中工作。
  • 是的,我认为这就是原因。 Prism.highlight(..) 函数仅处理在您提供的源代码中突出显示特定语言语法。行号插件在页面中的 块加载到浏览器后对其起作用。您可以从 Prism 文档中给出的示例中看到,您可以将行号应用于未经过 highlight(..) 的纯文本块。
  • @JohnRC 我有能力修改highlight 生成的HTML。我想知道是否可以在每一行的开头注入正确的 HTML?我认为这就是您的建议,但是从阅读 Prism 文档中我看不到它明显。你能扩展你的建议吗?
  • 你包含 css 对吗?

标签: node.js prismjs


【解决方案1】:

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

Prism.highlight 仅运行 2 个挂钩,before-tokenizeafter-tokenize。我们将使用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 元素中使用该输出,我们将得到正确的行号结果。检查这个只有themes/prism.cssplugins/line-numbers/prism-line-numbers.cssCodepen,并用上面输出的代码正确显示行号。

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

更新

如果您不依赖 CSS 并且只希望在每行之前添加一个行号,那么您可以通过拆分所有行来添加一个,并在开头使用 padStart 添加每个带有空格填充的 index + 1

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>

【讨论】:

  • 英雄。事实证明 litehtml 不支持 CSS content: counter 所以我别无选择,只能使用你的第二个建议的变体。但你的答案是我正在寻找的细节。我的 javascript/node 太生锈了,我无法自己轻松解码 Prism.highlight 中的代码。享受赏金;-)
  • @tig 太可惜了,因为最好的方法是使用 CSS 并且对复制友好。但我想了想,我意识到您可能需要一种方法来直接在每行前面添加静态行号。您可以更改行号格式,但最重要的部分是缩进。感谢您的赏金!
【解决方案2】:

我有一个带有代码 sn-ps 的 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>
    );
};

然后我决定添加行号插件,我很难弄清楚如何使它与 Node.js 和 React 一起工作。问题是行号使用了 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>
    );
};

【讨论】:

    【解决方案3】:

    也许这对你有帮助:

    Codepen 出错:

    link

    (codepen 行超出了堆栈溢出的限制!)

    Codepen 工作正常:

    link

    (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;
    }

    【讨论】:

    • 如果你禁用 Javascript,这似乎不起作用,这是我需要的(我使用的 html 渲染器不支持 Javascript)。
    • 一个(“我使用的 html 渲染器不支持 Javascript”)是一个很好的了解...
    • 当我在上面写“静态html文件”时,我认为这很清楚。但是,我可以看到它是多么模棱两可。我已经更新了我的问题以更清楚。不过,我很感谢您尝试提供帮助。
    猜你喜欢
    • 2018-06-12
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-26
    • 2023-03-12
    • 1970-01-01
    相关资源
    最近更新 更多