Hexo 集成 Shiki 代码高亮

使用 Pcrab/hexo-highlight-shiki 很简单,但是文档有些错误 😑,Hexo 配置文件得设置到 enable 里

_config.yml
syntax_highlighter: "shiki"
highlight: 
  enable: false
prismjs: 
  enable: false

另外 NexT 配置文件中需要关闭 language

_config.next.yml
codeblock:
  theme:
    light: github
    dark: github-dark
  copy_button:
    enable: true
    style: mac
  # Display language name
  # 如果启用了 shiki 这里的语言名称会固定为错误的 SHIKI 
  language: false

然后这么一搞,丢失了 Hexo 自带的给代码块添加 title 的功能,像 Editor & Terminal Frames | Expressive CodeRehype Pretty Code | Rehype Pretty 都支持。

看上去 hexo/lib/plugins/filter/before_post_render/backtick_code_block.ts at master · hexojs/hexo 是解析 Markdown 的 codeblock 相关逻辑,按 Syntax Highlighting | Hexo 解析 triple backtick 后面的 [language] [title] [url] [link text] [additional options] 格式。

node_modules/.pnpm_patches/hexo-highlight-shiki/src/index.ts
hexo.extend.highlight.register(HIGHLIGHTER_NAME, (code, options) => {
    const { caption, firstLineNumber } = options;
    let title = caption;
    if (caption === '<span>title</span>' && typeof firstLineNumber === 'string') {
        const noquote = firstLineNumber.replace(/["]/g, '');
        title = caption.replace('title', noquote);
    }
    try {
        const codeHtml = hl.codeToHtml(code, {
            ...("theme" in config
                ? { theme: config.theme }
                : { themes: config.themes }),
            lang: options.lang as string,
        });
        if (caption) {
            // mermaid class to bypass copy button generation by hexo-theme-next
            return `<pre><div class="caption mermaid">${title}</div><code>${codeHtml}</code></pre>`;
        }
        return codeHtml;
    } catch (e) {
        if (e instanceof Error) {
            console.error(e.message);
        } else {
            console.error(e);
        }
        return `<pre><code>${code}</code></pre>`;
    }
});

注意这里的格式和 expressive code 等习惯的 title="xxx" 不同,title 就是普通字符串,引号的处理方式不同。firstLineNumber 才存放真正放在引号里的 title。
另外 caption 有个 mermaid class,用来避免 hexo-theme-next/source/js/utils.js at master · next-theme/hexo-theme-next 为标题创建 copy button。