最近在移植代码过程中,需要在三个不同的gcc(FSF, Marvell和Android)源代码目录下,查看、比较文件。在另外的目录下打开同一个文件的操作比较繁琐,于是写了点Emacs Lisp代码,自动完成带开文件的操作。
方法很简单,有一个根目录列表,
(defvar wl-find-file-gcc-root-list (mapcar 'expand-file-name '("~/project/git/marvell-toolchain/src/gcc-src/" "~/project/git/fsf-gcc/" "~/project/android/toolchain/gcc/gcc-4.4.3/")))
然后通过比较根目录字符串,得到当前buffer对应文件的相对路径,在提示用户选择其它根目录,并打开该目录下的对应文件。
(defun wl-find-file-root (filename root-list) (find-if (lambda (dir) (when (> (length filename) (length dir)) (string-equal dir (substring filename 0 (length dir))))) root-list)) (defun wl-find-file-in-other-root (filename dir root-list) (let* ((root (wl-find-file-root filename root-list)) (relative-path (substring filename (length root)))) (find-file-existing (expand-file-name relative-path dir)))) (defun wl-iswitchb-completing-read (prompt choices &optional dummy require-match) "Use iswitchb completion functionality." (let ((iswitchb-make-buflist-hook (lambda () (setq iswitchb-temp-buflist (cond ((consp (car choices)) (mapcar 'car choices)) ((stringp (car choices)) choices) ((symbolp (car choices)) (mapcar 'symbol-name choices)) (t (error "Unknown type of choices."))))))) (iswitchb-read-buffer prompt nil require-match))) (defvar wl-find-file-completing-read-function 'wl-iswitchb-completing-read) (defun wl-gcc-find-buffer-file-in-other-root (dir) (interactive (list (let ((completion-ignore-case t) (root (wl-find-file-root (buffer-file-name) wl-find-file-gcc-root-list))) (funcall wl-find-file-completing-read-function "Open file in: " (remove-if (lambda (elem) (string-equal elem root)) wl-find-file-gcc-root-list))))) (wl-find-file-in-other-root (buffer-file-name) dir wl-find-file-gcc-root-list))
模仿Land of Lisp里面的程序风格,把代码分成functional和非functional两部分,其中wl-find-file-in-other-root
是functional的,实现核心功能,而接口则是非functional,使用全局变量。