我的 GNU Emacs 配置“程序” 续 完
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 里面就没有问题。灵异中……
org-mode.el
最后是 =org-mode.el= , 我不知道再提到这个文件是不是还有必要。因为这里在没有什么神奇的地方了。这里只是一些关于 =org-mode= 的一些设置, 还有……一些 skeleton 定义。因为基本上 =org-mode= 的默认设置就已经蛮好用了(我用的是 7.01h 版),所以现在这个文件内的内容基本上就是 skeleton 定义。只是因为他们还没有变得足够多,所以我还没有把它们分成一个单独的文件来管理。那么就说说 skeleton 吧。最近比较常用的 skeleton 主要是以下这些:

(define-skeleton iexp
"Input #+BEGIN_EXAMPLE #+END_EXAMPLE in org-mode"
""
"#+BEGIN_EXAMPLE\n"
_ "\n"
"#+END_EXAMPLE"
)
(define-skeleton isrc
"Input #+begin_src #+end_src in org-mode"
""
"#+begin_src lisp \n"
_ "\n"
"#+end_src"
)
(define-skeleton iprop
"Input :PROPERTIES: :END: in org-mode"
""
":PROPERTIES:\n"
_ "\n"
":END:"
)
(define-skeleton insert-emacser-code
""
""
"#+BEGIN_HTML\n"
"<pre lang=\"lisp\" line=\"1\">\n"
_"\n"
"</pre>\n"
"#+END_HTML\n"
)
(define-abbrev org-mode-abbrev-table "iexp" "" 'iexp)
(define-abbrev org-mode-abbrev-table "isrc" "" 'isrc)
(define-abbrev org-mode-abbrev-table "iprop" "" 'iprop)
(define-abbrev org-mode-abbrev-table "ihtml" "" 'insert-emacser-code)
很容易看出来,有了这些东西以后,在写 =org= 文档的时候会很方便。并且,为了能够对已经存在的代码添加 =#+BEGIN_EXAMPLE= =#+begin_src= 等等定义,我还编写了几个扩展函数:

(defun i-babel-quote (beg end str1 str2)
(goto-char end)
(forward-line 1)
(insert str2)
(newline)
(goto-char beg)
(forward-line -1)
(newline)
(insert str1)
)
(defun iexp (St Ed)
" "
(interactive "r")
(let ((beg St) (end Ed))
(message "%s %s" beg end)
(i-babel-quote beg end "#+BEGIN_EXAMPLE" "#+END_EXAMPLE")))
(defun isrc (St Ed)
" "
(interactive "r")
(let ((beg St) (end Ed))
(message "%s %s" beg end)
(i-babel-quote beg end "#+begin_src " "#+end_src")))
(defun i= (St Ed)
""
(interactive "r")
(let ((beg St) (end Ed))
(goto-char end)
(insert "=")
(goto-char beg)
(insert "=")
(goto-char (+ end 2)))
)
最后呢,我把一些 Shell当中比较常用的命令也定义成了 skeleton 。之所以不在 Shell profile 当中定义它,一方面是因为在我的工作中每天都要接触到大量的 Unix/Linux机器,放在 Emacs 里面的话呢,所有的命令都只需要定义一次,就可以在任意一个机器上使用。另外一方面呢,就是 skeleton,包括 abbrev 都是 Emacs 内部的东西,也就是说他们只会把定义的命令扩展开来,而并不会直接的去执行他,只有当我看到扩展结果并且按下回车,comint.el才会把相应的命令转交给 shell process 去执行,这在很多时候要比 shell 本身的 alias 和 function 机制安全的多的多。以下是一些示例:

(define-skeleton kill-multiple-proces
"Build killing multiple process command list"
""
"ps -ef | grep -i " _ " | awk '{ print \"kill -9 \" $2 }'"
)
(define-abbrev shell-mode-abbrev-table "killps" "" 'kill-multiple-proces)
(define-skeleton gunzip-tar
"unzip .tar.gz package in where -z is not available"
""
"gunzip -cd " _ " | tar -xf - "
)
(define-skeleton def_listener
"Define a listener in a WMQ QMgr"
""
"DEF LISTENER(LST) TRPTYPE(TCP) PORT(" _ ") CONTROL(QMGR)\n"
)
(define-abbrev shell-mode-abbrev-table "deflst" "" 'def_listener)
(define-skeleton def_clusrcvr
"Define a Cluster Receiver Channel in a WMQ QMgr"
""
"DEF CHL(TO.QMCOD.4.FTECA) CHLTYPE(CLUSRCVR) CONNAME('" _ "') CLUSTER(FTECA)\n"
)
(define-abbrev shell-mode-abbrev-table "defclusrcvr" "" 'def_clusrcvr)
对于很多更简单的命令,直接就定义在 abbrev 里面了。
dove-ext.el
最后的最后,是 =dove-ext.el= 。这个文件的内容都是我自己编写的各种扩展函数。包括上面提到的部分和更多还没有被提到的。 你可以到 EmacsWiki上去浏览这些函数。
posted on 2010-11-13 14:43 David Young 杨博华 阅读(1829) 评论(3) 编辑 收藏 举报
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· [AI/GPT/综述] AI Agent的设计模式综述