org2blog hack: 显示章节编号

在org-mode中,如果在文件头部写上`#OPTIONS: num:t’,导出的各种格式的文件就会有章节
编号。但用org2blog(punchagan commit 387217f792)生成博客,做同样的设置,却没有效
果。

在github上开了个issue,但等了很久也不见作者或者其他人尝试解决(开源项目中,这种事
儿很常见),于是我自己写了段很丑的Emacs Lisp来解决这个问题。

我想要的效果是,org文件里这样的“代码”:

#+BEGIN_SRC Language

1 Hello

1.1 World

1.2 Emacs

#+END_SRC

导出之后,变成:

1 Hello
1.1 World
1.2 Emacs

2 定位bug

以前除了修改配置文件之外,基本没有接触过Emacs Lisp,所以定位bug花了很长时间。

定位的过程就是跟着代码一步步看,找到出错的位置,最后发现跟org2blog没啥关系。

`org2blog/wp-post-buffer’(把博客发到WordPress)会调用
`org2blog/wp-parse-entry’把org文件转换成HTML,以便发布。

而在`org2blog/wp-parse-entry’中,会调用`org-export-as-html’。

我发现在`org-export-as-html’之前,一切都没问题,但等到`org-export-as-html’把内
容返回来之后,里边却没有章节编号。

于是我按”C-h f RET org-export-as-html”,调出`org-export-as-html’的文档:

org-export-as-html is an interactive autoloaded compiled Lisp function in
`org-html.el'.

(org-export-as-html ARG &optional EXT-PLIST TO-BUFFER BODY-ONLY PUB-DIR)

Export the outline as a pretty HTML file.
...
...
...
When BODY-ONLY is set, don't produce the file header and footer, simply return
the content of <body>...</body>, without even the body tags themselves.  When
PUB-DIR is set, use this as the publishing directory.

`org2blog’调用`org-export-as-html’的时候,传入的`BODY-ONLY’参数值为`t’,所以只会
返回 <body></body> 之间的内容,而不是整个页面。

我自己试了试,发现传入的`BODY-ONLY’为`nil’的时候,章节编号没问题;但
`BODY-ONLY’为`t’的时候,章节编号就不显示了。

所以整了半天,这其实是org-mode的bug。

经过这一趟,对 edebug 用的比较熟了。

3 修改

org-mode比较巨大,代码写得很丑很复杂,注释又特别稀少,我实在不想碰,于是投机取
巧,直接在org2blog里改。

我想,既然`org-export-as-html’生成完整的HTML的时候没有问题,那就先生成完整的
HTML,然后再从里面截取需要的部分。

写个函数抓取 <body></body> 之间的内容。

(defun org2blog/wp-retrieve-html-body (html-text)
  "Retrieve the content between <body> and </body> from the HTML
string generated by org-export-as-html"
  (substring html-text
             (string-match "<body>" html-text)
             (string-match "</body>" html-text)))

然后修改`org2blog/wp-parse-entry’,让它调用这个函数

(setq html-text
      ;;Starting with org-mode 7.9.3, org-export-as-html
      ;;takes 4 optional args instead of 5.
      (condition-case nil
          (org2blog/wp-retrieve-html-body
           (org-export-as-html nil nil nil 'string nil nil))
        (wrong-number-of-arguments
         (org2blog/wp-retrieve-html-body
          (org-export-as-html nil nil 'string nil nil)))))

这样”num:t”的`org-mode’文件转成的博客,就是带有章节编号的了,同时也带着
postamble(这个可以很容易地去掉,不过我挺喜欢现在这样的)。

4 (心中的)更好的解决方案

这个解决方法其实有很多问题:

  • 这是`org-mode’的bug,应该去`org-mode’里边解决。
  • `string-match’是有隐患的,如果文章正文里有 </body> ,可能导出的博客就会变短。
    最安全的方式是对HTML进行解析之后再进行处理。

最好的办法,是把这个bug提交给`org-mode’的开发团队,或者直接改好了给他们发补丁,
不过暂时能用,就懒得做了。

5 获取代码

可以clone我的fork:

$ git clone git@github.com:RenWenshan/org2blog.git

或者加一个upstream,然后pull(请自行查阅git手册)。

或者直接把下载我的`org2blog.el’,把现有的替换掉:
https://raw.github.com/RenWenshan/org2blog/master/org2blog.el

Happy Hacking!


Leave a Reply