我的 GNU Emacs 配置“程序” 续 一

keybindings.el

再接下来是 "=keybindings.el=" 。这个文件定义所有的按键绑定。通常我们定义 key binding 的时候都是使用 =(global-set-key (kbd "C-c x) 'some-function)= 问题是 =global-set-key= 没有像 =setq= 那么方便的 =list= 处理方式。怎么办? 那就写一个吧。还能怎么办呢? 这就是 =set-key-bindings=

 

 

(defun set-key-bindings (action bindingList)
""
(mapcar (lambda(lst)
""
(let ((x (car lst))
(y (car (last lst))))
(funcall action x y))) bindingList ))

 

这个 =set-key-bindings= 接收一个函数作为指令,告诉它需要做什么,然后再接收一个 =list= ,作为数据。然后通过 =mapcar= 遍历这个 =list= ,对其中的每一个元素执行接受到的指令。

 

这就是 Lisp语言非常精彩的地方。Lisp 不仅仅能够处理 list,更重要的是它能够像传递数据一样简单方便的传递指令(函数)。这个强大的特性使得我可以不必把 =global-set-key= 硬性的写在 =set-key-bindings= 里面。为什么要这样呢?还用说吗?如果我想要做 =local-set-key= 我会怎么做? 我不许要去修改 =set-key-bindings= ,我只需要把 =local-set-key= 作为指令传递给它就行了。换句话说我可以传递任何指令给它,告诉它做任何事,而不需要再做任何修改。在 Lisp的世界里,没有无聊的 =case sth in something= 。

 

扯远了,让我们还回到按键绑定上来。现在就可以把按键和功能写成一个简单的 =list= ,交给 =set-key-bindings= 去处理了。

 

代码
(set-key-bindings 'global-set-key
(list
'([f2] calendar)
'([(shift f2)] remember)
'([f5] revert-buffer)
'([f10] rename-buffer)
'([f11] query-replace)
'([(shift f11)] query-replace-regexp)
; ... ... ... ... 按键太多,中间省略
;; copy paste operations
(list (kbd
"C-=") 'set-mark-command)
(list (kbd "C-c l") 'copy-line)
(list (kbd "C-c w") 'copy-word)
(list (kbd "C-S-k") (lambda() " " (interactive) (kill-visual-line -1)))
(list (kbd
"C-c s") 'thing-copy-string-to-mark)
(list (kbd "C-c a") 'thing-copy-parenthesis-to-mark)
(list (kbd "C-c p") 'copy-paragraph)
(list (kbd "C-x a d") 'delete-region)
; ... ... ... ... 按键太多,中间省略
(list (kbd
"C-c c") '(lambda() " " (interactive) (if emaci-mode (emaci-mode-off) (emaci-mode-on))))
(list (kbd "M-DEL")
(lambda(
&optional arg)
"Act as the obsolete dove-backward-kill-word "
(interactive
"P")
(
if arg
(let ((arg (
- 0 arg))) (dove-forward-kill-word arg))
(dove
-forward-kill-word -1))))

))

 

plugins.el

 =plugins.el= 的作用是引用各种网上下载的第三方扩展。简单来说就是成堆成堆的 =(require 'something)= 。由于 =require= 函数只需要一个参数,这意味着我们将只需要一个一维的 =list= ,这样会比 keybinding.el 的情况更简单一些。下面是 =require-extensions= 函数。

 

(defun require-extensions (action lst)
""
(mapcar (lambda(ext)
"" (funcall action ext)) lst))

有了这个函数,我们就可以进行非常简单的工作了——删掉 =require= ,换成 =list= 。

 

 

代码
(require-extensions 'require
(list
'tabbar
'switch-window
'thing-edit
'second-sel
'browse-kill-ring+
'bbdb
'gnuplot
'muse-mode
'ibuffer
'w3m-load
'rect-mark
'ido
'multi-term
'lusty-explorer
'oddmuse
'emaci
'move-text
'uniquify
'hide-region
))

 

至于每一个扩展的个别配置,就分别写在文件的后面了。

 

可以看到,我用的扩展并不多。因为每天工作当中基本就在 =shell-mode= , =sh-mode= 和 =org-mode= 这几个模式当中打转转。下班之后大概是用 =emacs-lisp-mode= 。

outline-minor-mode

在这里比较值得一提的还有一个 =outline-minor-mode= 的设置。这个模式实在是一个很有用的东西。甚至在 =shell-mode= 里面我都会打开它。但是针对每一个不同的 mode 设置各自的 =outline-regexp= , 对,我是想说是挺烦人的。也许你们要比我 nice,好让人羡慕啊。 好,言归正传,我选择写一个函数来搞定它。我叫它 =set-outline-minor-mode-regexp= 。 只是,这次,事情稍微有点复杂。

 

首先这个函数的环境比较特殊,所以相对来说就会比较复杂。因为他是用在 =add-hook= 函数当中的,这意味着我没有机会直接传递我要的数据给 =set-outline-minor-mode-regexp= 。我需要绕一下,用一个全局变量 =outline-minor-mode-list= 来存储数据,并且这次的数据会是一个二维的 =list= ,所以处理也会复杂一些。

 

(setq outline-minor-mode-list
(list
'(emacs-lisp-mode "(defun")
'(shell-mode ".*[bB]ash.*[#\$] ")
'(sh-mode "function")

))

这里就是我说的这个函数,也许你们可以帮我把它写的更简单一些。

 

 

代码
(defun set-outline-minor-mode-regexp ()
""
(outline
-minor-mode 1)
(let ((regexp
-list (append outline-minor-mode-list nil))
(find
-regexp
(lambda (lst)
""
(let ((innerList (car lst)))
(
if innerList
(
if (string= (car innerList) major-mode)
(car (cdr innerList))
(progn (pop lst)
(funcall find
-regexp lst))))
))))
(make
-local-variable 'outline-regexp)
(setq outline-regexp (funcall find-regexp regexp-list)))

(
set-key-bindings 'local-set-key
(list
(list (kbd
"C-c C-t") 'hide-body)
(list (kbd "C-c C-a") 'show-all)
(list (kbd "C-c C-e") 'show-entry)
; (kbd "C-c C-d") 和 shell-mode 冲突,所以继续沿用 C-c @ C-d,不做自定义
))
)

然后针对每一个需要的模式添加 hook就行了。

 

 

(add-hook 'shell-mode-hook 'set-outline-minor-mode-regexp t)
(add
-hook 'sh-mode-hook 'set-outline-minor-mode-regexp t)
(add
-hook 'emacs-lisp-mode-hook 'set-outline-minor-mode-regexp t)

最后在 函数里面还要提到的一点是 =(make-local-variable 'outline-regexp)= 。我在这里显式的把 =outline-regexp= 作成 buffer local 了。如果不这样做的话, =sh-mode= 中的 =outline-regexp= 赋值会很诡异的覆盖掉 =shell-mode= 里面的值。虽然我还不太清楚为什么在别的 mode 里面就没有问题。灵异中……

 

未完待续 …… ……

 

posted on 2010-11-06 12:18  David Young 杨博华  阅读(1163)  评论(0编辑  收藏  举报

导航