使用 highlight.js 高亮 Org mode

Table of Contents


背景

Org mode 代码的默认导出使用的是 htmlize 效果不是很好看,而 highlight.js 却有各种各样的配色,但是 Org mode 却不支持。下面解决的问题就是如何通过 highlight.js 来高亮 org mode 导出的 HTML 代码片段。

方案

由于 org mode 在 export 代码的时候不支持 highlight.js,而使用 htmlize 来高亮又不是很好看。所以看了下 ox-html.el 的代码改了部分的内容,使得导出的 html 中代码能够通过 highlight.js 来高亮。

  1. M-x customize 然后输入 htmlize
  2. 找到 'Org Html Htmlize Output Type' 并且改变它的值为 css
  3. 找到 elpa/org 目录下的 ox-html.el
  4. 在 ox-html.el 下找到 'org-html-src-block' 并且修改最后一行为

    (format "<pre><code class=\"%s\"%s>%s</code></pre>"
                        lang label code)
    
  5. 将下面的代码放到你的配置文件中,我的是放到了 org-html-head-extra 中。

    <link href="http://apps.bdimg.com/libs/highlight.js/9.1.0/styles/default.min.css" rel="stylesheet">
    <script src="http://apps.bdimg.com/libs/highlight.js/9.1.0/highlight.min.js"></script>
    <script>hljs.initHighlightingOnLoad();</script>
    

问题

上面的方法基本能够解决问题,但是处理方式却很不好。首先,它对 org library 做了 hack,如果下次更新又需要手动再改动。 另外,难于发现问题。一个推荐的处理方式是不改变原来库的行为模式,改用 advice 来处理:

(defun org-html-src-block2 (src-block _contents info)
  "Transcode a SRC-BLOCK element from Org to HTML.
CONTENTS holds the contents of the item.  INFO is a plist holding
contextual information."
  (if (org-export-read-attribute :attr_html src-block :textarea)
      (org-html--textarea-block src-block)
    (let ((lang (org-element-property :language src-block))
          (code (org-html-format-code src-block info))
          (label (let ((lbl (and (org-element-property :name src-block)
                                 (org-export-get-reference src-block info))))
                   (if lbl (format " id=\"%s\"" lbl) ""))))
      (if (not lang) (format "<pre><code class=\"example\"%s>\n%s</code></pre>" label code)
        (format "<div class=\"container\">\n%s%s\n</div>"
                ;; Build caption.
                (let ((caption (org-export-get-caption src-block)))
                  (if (not caption) ""
                    (let ((listing-number
                           (format
                            "<span class=\"listing-number\">%s </span>"
                            (format
                             (org-html--translate "Listing %d:" info)
                             (org-export-get-ordinal
                              src-block info nil #'org-html--has-caption-p)))))
                      (format "<label class=\"org-src-name\">%s%s</label>"
                              listing-number
                              (org-trim (org-export-data caption info))))))
                ;; Contents.
                (format "<pre><code class=\"%s\"%s>%s</code></pre>"
                        lang label code))))))

(advice-add 'org-html-src-block :override 'org-html-src-block2)

简单解释,就是写一个函数 org-html-src-block2 来覆盖原来的函数。我们 C-h f 看下原来的函数:

20190523_092445_15212Pkv.png

可以看到它已经被 advice 处理过了。