One Key 掌控键位

经常见到有人抱怨Emacs里有些键位不用就忘记了,结果想用的时候还得翻配置文件,去看看自己原来是咋定义的。当然,键位不常用就会遗忘,这是记忆的正常规律;除非很多常用按键,经过日积月累会形成肌肉记忆。所以,Emacs另外也提供menu bar和tool bar来辅助记忆,这样只需要点击鼠标就可以完成一些功能,这也是一般IDE的做法。

不过,menu bar和tool bar的定制不是很方便,另外在console里也有局限;所以,这里推荐一套好用的工具 one key来帮助我们记忆键位。是不是想起了one ring?是的,就像铭文所表的那样:

One Ring to rule them all, One Ring to find them.

使用one key能通过一个键位来寻找到你所有可能关心的键位。这里的精髓就是提示,利用提示来辅助记忆。具体做法是通过带提示的按键序列树,把所有零散的按键结合到了一起。既然每一步都有提示可循,那么你也就不会忘记你的键位了。

举个例子,比如你在vc模式下,Ctrl+x v = 是把你的工作拷贝和HEAD版本做diff,但是你可能记不清具体的按键序列,于是你先按下Ctrl+x v,这时one-key会在一个pop-up window里提示你接下来的所有可能的键位和相应说明,当然,接下来你就知道应该按下=完成你想要的操作。甚至,你可以配置成在按下Ctrl+x就出现下一步可能的键位提示。

one key我觉得有两种使用方法,对应两个主要的函数:

  • one-key-insert-template
  • one-key-menu

第一种是辅助记忆已经定义过的按键序列,比如前一段列举的Ctrl+x v =,有一小段函数可以把这些已有的按键序列变成附带提示的one key按键方式,它们被提供在 one-key-default.el 里。

(defun one-key-default-create-menu (key &rest depends)
  (ignore-errors
    (dolist (key depends)
      (let ((sym (intern (format "one-key-menu-%s"
                                 (replace-regexp-in-string " " "-" key)))))
        (one-key-default-set-key key sym)))
    (with-temp-buffer
      (one-key-insert-template key key)
      (eval-buffer))))

这个函数很巧妙的读取那些已定义的keymap,然后扔给one-key-insert-template处理,后者可以解析这些keymap,从而生成带提示的one key按键序列。所以像Ctrl+x 4Ctrl+x 5Ctrl+x n等等这些你平常可能也不常用的按键前缀,都可以丢给one-key-default-create-menu来处理,这样这些按键序列就都带提示了。具体可以参见 one-key-default.el 内的实现。

另外一种使用方式就是自定义按键序列,这里就可以直接自己用one-key-menu来定义按键序列了。这样灵活性更高一些,比如我定义了一个anything的按键序列(anything也是个好东西,随后我另写一篇介绍):

(defun one-key-menu-anything ()
    "The `one-key' menu for ANYTHING."
    (interactive)
    (require 'anything-config nil t)    ; lazy load
    (one-key-menu
     "ANYTHING"
     '(
       (("a" . "Anything") . anything)
       (("b" . "Buffers") . anything-buffers+)
       (("B" . "Bookmarks") . anything-c-pp-bookmarks)
       (("c" . "Commands") . anything-M-x)
       (("f" . "Files") . anything-for-files)
       (("i" . "Imenu") . anything-imenu)
       (("I" . "Info") . anything-info-emacs)
       (("k" . "Kill Ring") . anything-show-kill-ring)
       (("o" . "Occur") . anything-occur)
       (("r" . "Register") . anything-register)
       (("m" . "Man Pages") . anything-man-woman)
       (("SPC" . "Execute anything commands") . anything-execute-anything-command)
       ) t))

自定义按键序列的好处是可以精选一些你所关心的按键序列,因为有时候选择太多了也不是好事情 :) 另外,你可以做一些tweak,比如anything-config.el这个文件比较大,我不想在启动emacs的时候load它,而希望在使用anything的时候再加载它。

最后,把你新定义的按键序列 one-key-menu-anything 放到你的整个按键序列树的合适位置,你就再也不会“忘记”它了,这正达到了我们所期望的:

One Key to rule them all, One Key to find them.