Extending Emacs bookmark

GNU Emacs带有一个简单实用的书签管理工具——bookmark。

简单地说,它有四个主要的元素:

  • filename: 书签所对应的文件名
  • position: 书签在对应文件里的位置
  • bookmark-set: 在当前buffer的当前光标位置设置书签
  • bookmark-jump: 跳到相应的书签位置

bookmark还提供了一定的扩展功能,如果上述四个概念不足以实现某种特定的书签,可以在其基础上扩展。

doc-view是GNU Emacs用来查看PDF文件的工具,它首先把PDF转换成图片,每页一张图,然后把图片显示出来。对于doc-view来说,书签定义的位置是页,而不是某个字符的位置,所以doc-view必须通过扩展才能使用bookmark。

扩展方式很简单,首先为doc-view-mode定义一个单独的书签创建函数,在书签创建时两条额外的信息

  • 页数
  • 以及一个处理该书签的函数,以跳到相应的页数
(defun doc-view-bookmark-make-record ()
  (nconc (bookmark-make-record-default)
         `((page     . ,(doc-view-current-page))
           (handler  . doc-view-bookmark-jump))))

;;;###autoload
(defun doc-view-bookmark-jump (bmk)
  ;; This implements the `handler' function interface for record type
  ;; returned by `doc-view-bookmark-make-record', which see.
  (prog1 (bookmark-default-handler bmk)
    (let ((page (bookmark-prop-get bmk 'page)))
      (when (not (eq major-mode 'doc-view-mode))
        (doc-view-toggle-display))
      (with-selected-window
          (or (get-buffer-window (current-buffer) 0)
              (selected-window))
        (doc-view-goto-page page)))))

然后用该函数替换掉默认的书签创建函数。具体实现参见doc-view.el文件。

(set (make-local-variable 'bookmark-make-record-function)
     'doc-view-bookmark-make-record)

然而,doc-view提供的书签有一点小小的缺陷,就是没有保存解析度(doc-view-resolution)。doc-view本身提高缩放功能,但是如果缩放比例没有保存的话,使用书签后PDF将以默认比例打开,阅读体验不太友好。

修改的方式和前面几乎一样,唯一的区别是在doc-view-mode-hook里面替换掉doc-view-mode原来的书签创建函数,改用自己写的那个。代码部分摘录如下,具体参见我的wl-ebook-viewer.el中关于doc-view的部分(其中还包括了自动设置书签和打开PDF时自动跳到书签位置的代码,用于模拟定位上次阅读位置功能)。

(defun wl-doc-view-bookmark-make-record ()
  (nconc (bookmark-make-record-default)
         `((page . ,(doc-view-current-page))
           (resolution . ,doc-view-resolution)
           (handler . wl-doc-view-bookmark-jump))))

(defun wl-bookmark-get-resolution (bookmark)
  "Get doc view resolution."
  (or (bookmark-prop-get bookmark 'resolution)
      (default-value 'doc-view-resolution)))

(defun wl-doc-view-bookmark-jump (bookmark)
  (prog1 (doc-view-bookmark-jump bookmark)
    (let ((resolution (wl-bookmark-get-resolution bookmark)))
      (assert (> resolution 0))
      (when (/= doc-view-resolution resolution)
        (set (make-local-variable 'doc-view-resolution) resolution)
        (doc-view-reconvert-doc)))))

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据