部分围栏代码块的自动高亮失效

这种情况发生在我的开发环境中,也出现在实时的 Discourse 论坛 https://discourse.gohugo.io/ 以及 Discourse 演示站点上。

通常,当围栏代码块未设置语言时,我们会进行自动检测。在常规的 Highlight.js 使用场景(Node.js 或浏览器)中,这总能成功,因为它总会选中某种语言。

Discourse 似乎将此类代码块保存为 <code class="lang-auto">,这并不是一个有效的语言标识符 :wink:

我与 AI-Bot ask.discourse.cm…30386 进行了交流:
它指出你们在运行时进行了一些“魔法”操作,移除 “lang-auto” 后让 highlight.js 重新执行自动检测。看起来这个更新并非总是在 highlight.js 处理代码之前发生。因此,这似乎是 Discourse 中 highlight.js 集成和自动检测实现的一个小缺陷。

取消设置默认语言也不起作用,因为这样 “移除 lang-auto” 的操作就会失效,而且看起来 Discourse 的方式不会重新执行自动检测。

  • 手动设置语言始终有效——无论是内置语言,还是通过 PluginAPI (registerHLJSLanguage) 作为主题组件添加的自定义语言(hugo-templates)。
  • 如果不设置语言,结果取决于 content() 的竞态条件和时序,导致失败。

将默认语言设置为 “text” 也不是办法,因为我们希望代码被高亮显示,并且为了可用性需要自动检测功能(而且它是有效的…)

下面是一个 Markdown 示例,其中第二个代码块会失败(当然,前提是默认语言设置为 “auto”)。在 https://try.discourse.org/ 上使用以下 Markdown 可以轻松复现:

并在 24 小时内:Failed Discourse Autodetection breaks rendering of fenced code blocks - support - Discourse Demo

# 这个有效

```
{{ $currentPagemd5 := md5 $currentPage.File.Path }}
    {{ $currentPagemd5ext := (print $currentPagemd5 ".json")}}
```

# 这个失败并分配了 "lang-auto"

```
{{ $currentPage := . }}
{{ $jsonFile := "" }}
{{ with $currentPage.File }}
    {{ $currentPagemd5 := md5 $currentPage.File.Path }}
    {{ $currentPagemd5ext := (print $currentPagemd5 ".json")}}
    {{ $files := readDir "data/commits/" }}
    {{if gt (len $files ) 0}}
        <div class="bord-bas"></div>
        <div>
        <details>
            <summary>页面变更</summary>
            <div>
            {{ range $files }}
                {{ if eq .Name $currentPagemd5ext }}
                    {{ $jsonFile := $currentPagemd5 }}
                    {{ $data := index $.Site.Data.commits $jsonFile }}
                    <ul>
                    {{ range $data }}
                        <li>
                            {{ dateFormat "02/01/2006" .commit_date }} : {{ trim .message "\n" }} ({{ .author }})
                        </li>
                    {{ end }}
                    </ul>
                {{ end }}
            {{ end }}
            </div>
        </details>
        </div>
    {{ end }}
{{ end }}
```

也许只是 Discourse 和 HighlightJS 无法识别该语言,因此将其视为此类。

重点在于 Discourse Highlight.JS

  • Highlight.JS 单独使用时总是能识别并选择语言

  • 而在 Discourse 中,如果没有 lang 属性,运行时并不总是能识别语言。

Hugo 论坛:57307 帖 6:

这是论坛中的一个帖子:Proposal: Add highlighting support for Go/Hugo templates to Discourse - #6 by irkode - Meta - HUGO

  • 第一个代码块以 ```hugo-html 开头。
    结果是 <code="lang-hugo-html>
  • 第二个块以 ```
    结果是 <code=“lang-auto”>

两种情况都能正确高亮显示。

Hugo 论坛:57367 帖 2:

这里还有一个不起作用的例子:How to capture/generate revisions of page? - #2 by Welsh - support - HUGO

这里也分配了 “lang-auto”,但运行时的自动识别不起作用。

所以这似乎与 Discourse 的实现方式有关——可能因内容而异,涉及超时、promises 等……

也许我理解错了,但这是我在你发布的第一个链接中看到的:

两者都没有显示 lang-auto,并且两者的突出显示方式相同,尽管你没有为第二个代码块指定语言。

这是开发者控制台——它显示的是 highlight.js 成功自动检测之后的代码。

你需要查看页面源代码(Ctrl+u),在那里你会看到 lang-auto

然后这会触发 Discourse 的自动高亮方式,通过移除 lang-auto 并再次尝试检查我链接的第二个帖子,情况相同,但那里的检测失败了。

是的——没有 Discourse 框架围绕它,它是可以工作的

在迁移到裸版 Highlight.JS 时:

  • 除非我们有针对 “auto” 的语言规则,否则包裹在 <code class="lang-auto"> 中的代码将不会被高亮显示 :wink:

  • 我们可以为使用插件的用户重新启动自动检测:

    hljs.addPlugin({
       'before:highlight': (ctx) => {
          if (ctx.language === 'auto') {
             result = hljs.highlightAuto(ctx.code);
             ctx.language = result.language
             ctx.result = result
          }
       }
    });
    

由于插件和语言规则与 API 的集成方式,以及 highlight.js 引擎和方法的 DOM 封装特性,我无法在 Discourse 中使其正常工作;此外,如果这样做,可能会与 Discourse 默认的实时渲染产生竞态条件。

1 个赞