其实上次写 http://wdicc.com/how-i-became-a-emacser 的时候,是想写一点 eslisp 入门的东西的,结果总觉得好像也写不出来什么,就写成另一篇了,呵呵。(看这篇前最好先看看那个吧,那个更入门。)
不过我还是觉得,用 emacs 如果不会一点 elisp,那基本你是用不住的。记那些无聊的快捷键有什么意思,有意思的是你能让 emacs 用你希望的模式工作。今天 twitter 上面看到一个词"计算姬",感觉很有点意思,呵呵,小蜜就是给你干活的嘛,不要被她折磨就好。
其实主要是我自我感觉目前了解的 elisp 的东西,好像基本就够用了,所以才想写出来,给比我还糊涂的指条明路。
1 数据类型。
elisp 是有类型在里面的,我看好像有什么 sequence, number 之类,具体有哪些不重要,重要的是你使用的时候,比如比较的时候,切记要弄明白他们是什么类型。我找到一个 format 函数,感觉很好用,可以转类型,具体可以查文档,可以多用用。
2 调试
调一个程序的时候,我觉得最基本的就是 print 和 message 这两个函数了吧,加上上面的 format,基本应该能搞定了。在一段 elisp 后面使用 C-x C-e 就能直接执行他,执行之后就能在当前的 emacs 里面起作用,不过对我等菜鸟来说,有时候会遇到一些奇怪的问题,不行就还是再启动一个 emacs 来验证结果吧。
3 emacs 简单设置
掌握了上面两个,基本就可以定义自己的东西了。一般用的是 setq,比如下面这个
;; 防止页面滚动时跳动, scroll-margin 3 可以在靠近屏幕边沿3行时就开始滚动,可以很好的看到上下文。
(setq scroll-margin 3
            scroll-conservatively 10000)
(set-terminal-coding-system 'utf-8)
(add-to-list 'auto-mode-alist '("\\.py\\'" . python-mode))

可以看到他一次设置了两个变量,其实写两个括号也是可以的。
还有下面的两行,他是执行了一个函数,这个函数里面干的什么,他接受什么参数,直接在 emacs 里面按 C-h f 然后输入你要查的函数的名字,就会显示 help 信息,很方便吧。
4 hook
下面稍微高级一点,了解下 hook 怎么用。hook 这个东西翻译过来应该是钩子的意思吧,其实就是别人的程序预留的一些接口,可以让你在他的程序里面插入一些你自己的程序。比如下面这几个。
(add-hook 'weblogger-start-edit-entry-hook (lambda()
    (auto-fill-mode -1)
    (abbrev-mode -1)
    (auto-complete-mode 1)
    ))
(add-hook 'cperl-mode-hook (lambda () (abbrev-mode -1)))
(add-hook 'view-mode-hook 'view-mode-keybinding-hook)

(defun weblogger-edit-entry (&optional entry)
  "Edit a entry.  If ENTRY is specified, then use that entry.
Otherwise, open a new entry."
   ...........
  (run-hooks 'weblogger-start-edit-entry-hook)
)

第一个是在 weblogger.el 开始编辑文件的时候,把那些 mode 关掉。第二个是 cperl-mode 启用的时候,把 abbrev-mode 关掉。第三个是在 view-mode-hook 执行的时候,执行那个函数。
最后是在实际代码里面这个 hook 是怎么执行的,能看到当调用 weblogger-edit-entry 的时候,就会在这里面某个时候去执行之前设置的 hook,这样个性化设置的目的就达到了。
eamcs 的各种 mode 一般都有各种的 hook,这应该能完全达到个性化的目的了,可有些时候想定制的地方没有 hook 怎么办?暴力一点,直接改他的程序好了。。。温柔一点的,那就看下面这个。
5 defadvice
defadvice 在文档里面写的很清楚,大概应该是可以在一个已有函数执行前或后执行你定义的东西。比如下面这个。
;; use this to auto cancel notify
;; (add-hook 'erc-send-pre-hook
;;           (lambda(s)
;;             (erc-tray-change-state nil)))
(eval-after-load 'erc
  '(progn
     (defadvice erc-send-input (before change-tray-status activate)
       (erc-tray-change-state nil))))

我设置了 erc 在收到消息的时候会发送 notify 到 tray,我想做到只要我在 erc 里面输入了一些东西(即使是空的),就把 tray 的状态标记为已读,就不用继续提醒我了。
erc 有个 erc-send-pre-hook,可以在发送一条消息前执行 hook,可是如果输入的是空行,是不会触发这个 hook 的,使用 defadvice 可以解决这个,具体使用方法还是看文档吧,我突然觉得我很罗嗦。。。。屁大点东西也能发一篇?。。。
我会的基本就说完了,其它高级玩意有需要的时候应该可以从文档里面去看吧,目前来看,会用 hook 和 defadvice 我就知足了,不行就来 irc 里面找牛人问一个,经过提示后,应该还是能解决的吧。反正不求能自己去写一个 mode,当时最少也要能看明白别人的那点东西,然后自己能改一下吧,要不用 emacs 会很痛苦的。