LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1362|回复: 1

增强 Emacs 的 hippie-expand

[复制链接]
发表于 2005-12-9 15:18:38 | 显示全部楼层 |阅读模式
Vim 的 C-p 和 C-n 命令非常好用,因为它可以自动补全一些内容。在写 C 代码时,vim 会自动打开头文件,补全函数名。例如,在输入下面的代码时:

  1. #include <stdio.h>

  2. int main(void)
  3. {
  4.         int c;

  5.         while ((c = get
复制代码


光标此时位于 get 之后。按下 C-p 并多按几次,vim 就会自动补上 getchar。这个功能很方便。

Emacs 中提供了 hippie-expand 来完成类似的功能。我试了一下,效果并没有 vim 里那样好,因为 Emacs 并不会像 vim 那样自动打开程序中包含的头文件。但是,一旦打开了头文件,Emacs 就可以工作得一样好,甚至更好(在我的试验中,Emacs 会根据上下文只给出特定的备选答案,如函数名,而 vim 则会给出与上下文不相关的备选答案)。所以只要在打开 C/C++ 文件时自动打开它们包含的头文件就可以了。搜索了一下,这个功能似乎不是 Emacs 自带的,我也没有在网上找到,所以自己写了一个,虽然不完善,但凑合着可用了。

把下面的代码加到 ~/.emacs 中:

  1. (defgroup xgp-c-header-files nil
  2.   "Group for reading C/C++ header files."
  3.   :group 'c)

  4. (defcustom xgp-c-system-include-paths
  5.   '("/usr/include"
  6.         "/usr/local/include")
  7.   "List of directories where C/C++ header files are found."
  8.   :type '(repeat string)
  9.   :group 'xgp-c-header-files)

  10. (defun xgp-c-define-local-variables ()
  11.   "Make variable XGP-C-USER-INCLUDE-PATHS directory of file in the current buffer."
  12.   (make-local-variable 'xgp-c-user-include-paths)
  13.   (setq xgp-c-user-include-paths (list (file-name-directory (buffer-file-name)))))

  14. (defun xgp-c-load-header-files-in-current-buffer ()
  15.   "Try load C/C++ header files included by file in the current buffer.

  16. First search in the directory relative to the directory of the file
  17. in the current buffer, then user defined directories, then system
  18. wide directory."
  19.   (interactive)
  20.   (save-excursion
  21.         (goto-char (point-min))
  22.         (let (b e f af)
  23.           (while (and (setq b (re-search-forward "#include[ \t]+" nil t))
  24.                                   (setq e (re-search-forward "\n" nil t)))
  25.                 (setq f (buffer-substring-no-properties (1+ b) (- e 2)))
  26.                 (if (eq (char-before (1- e)) ?>)
  27.                         (dotimes (n (length xgp-c-system-include-paths))
  28.                           (setq af (concat (nth n xgp-c-system-include-paths) "/" f))
  29.                           (if (file-exists-p af)
  30.                                   (find-file-noselect af t)))
  31.                   (dotimes (n (length xgp-c-user-include-paths))
  32.                         (setq af (concat (nth n xgp-c-user-include-paths) "/" f))
  33.                         (if (file-exists-p af)
  34.                                 (find-file-noselect af t)))))
  35.           )))
复制代码


然后把这两个函数加到 c-mode-common-hook 中:

  1. (defun my-c-mode-common-hook ()
  2.   (xgp-c-define-local-variables)
  3.   (xgp-c-load-header-files-in-current-buffer))

  4. (add-hook 'c-mode-common-hook
  5.           (function (lambda ()
  6.                       (my-c-mode-common-hook))))
复制代码


并将 M-/ 绑定为 hippie-expand:

  1. (global-set-key (kbd "M-/") 'hippie-expand)
复制代码


就可以了。用 Emacs 打开一个 C/C++ 文件,Emacs 就会自动打开它包含的头文件。回到开头的代码,Emacs 也可以自动补全了。需要注意的几点:

1. 如果加入了新的头文件(即写了新的 #include 的行),就要重新执行 xgp-c-load-header-files-in-current-buffer 命令。

2. 头文件分两种类型:用 <> 包围的和用 "" 包围的。第一种要在系统的目录里找,第二种要在当前目录里找。这些目录的值是用变量保存的。第一种的默认值是 /usr/include 和 /usr/local/include。如果要自定义它,可以使用 M-x customize-variable RET xgp-c-system-include-paths RET 来配置。第二种的值是打开的 C/C++ 文件所在的目录。

也许别人已经写过更完善的程序来解决这个问题了,如果有这样的解决方案,请告诉我。
发表于 2005-12-9 22:49:59 | 显示全部楼层
Post by herberteuler
Vim 的 C-p 和 C-n 命令非常好用,因为它可以自动补全一些内容。在写 C 代码时,vim 会自动打开头文件,补全函数名。例如,在输入下面的代码时:

  1. #include <stdio.h>

  2. int main(void)
  3. {
  4.         int c;

  5.         while ((c = get
复制代码


光标此时位于 get 之后。按下 C-p 并多按几次,vim 就会自动补上 getchar。这个功能很方便。

Emacs 中提供了 hippie-expand 来完成类似的功能。我试了一下,效果并没有 vim 里那样好,因为 Emacs 并不会像 vim 那样自动打开程序中包含的头文件。但是,一旦打开了头文件,Emacs 就可以工作得一样好,甚至更好(在我的试验中,Emacs 会根据上下文只给出特定的备选答案,如函数名,而 vim 则会给出与上下文不相关的备选答案)。所以只要在打开 C/C++ 文件时自动打开它们包含的头文件就可以了。搜索了一下,这个功能似乎不是 Emacs 自带的,我也没有在网上找到,所以自己写了一个,虽然不完善,但凑合着可用了。

把下面的代码加到 ~/.emacs 中:

  1. (defgroup xgp-c-header-files nil
  2.   "Group for reading C/C++ header files."
  3.   :group 'c)

  4. (defcustom xgp-c-system-include-paths
  5.   '("/usr/include"
  6.         "/usr/local/include")
  7.   "List of directories where C/C++ header files are found."
  8.   :type '(repeat string)
  9.   :group 'xgp-c-header-files)

  10. (defun xgp-c-define-local-variables ()
  11.   "Make variable XGP-C-USER-INCLUDE-PATHS directory of file in the current buffer."
  12.   (make-local-variable 'xgp-c-user-include-paths)
  13.   (setq xgp-c-user-include-paths (list (file-name-directory (buffer-file-name)))))

  14. (defun xgp-c-load-header-files-in-current-buffer ()
  15.   "Try load C/C++ header files included by file in the current buffer.

  16. First search in the directory relative to the directory of the file
  17. in the current buffer, then user defined directories, then system
  18. wide directory."
  19.   (interactive)
  20.   (save-excursion
  21.         (goto-char (point-min))
  22.         (let (b e f af)
  23.           (while (and (setq b (re-search-forward "#include[ \t]+" nil t))
  24.                                   (setq e (re-search-forward "\n" nil t)))
  25.                 (setq f (buffer-substring-no-properties (1+ b) (- e 2)))
  26.                 (if (eq (char-before (1- e)) ?>)
  27.                         (dotimes (n (length xgp-c-system-include-paths))
  28.                           (setq af (concat (nth n xgp-c-system-include-paths) "/" f))
  29.                           (if (file-exists-p af)
  30.                                   (find-file-noselect af t)))
  31.                   (dotimes (n (length xgp-c-user-include-paths))
  32.                         (setq af (concat (nth n xgp-c-user-include-paths) "/" f))
  33.                         (if (file-exists-p af)
  34.                                 (find-file-noselect af t)))))
  35.           )))
复制代码


然后把这两个函数加到 c-mode-common-hook 中:

  1. (defun my-c-mode-common-hook ()
  2.   (xgp-c-define-local-variables)
  3.   (xgp-c-load-header-files-in-current-buffer))

  4. (add-hook 'c-mode-common-hook
  5.           (function (lambda ()
  6.                       (my-c-mode-common-hook))))
复制代码


并将 M-/ 绑定为 hippie-expand:

  1. (global-set-key (kbd "M-/") 'hippie-expand)
复制代码


就可以了。用 Emacs 打开一个 C/C++ 文件,Emacs 就会自动打开它包含的头文件。回到开头的代码,Emacs 也可以自动补全了。需要注意的几点:

1. 如果加入了新的头文件(即写了新的 #include 的行),就要重新执行 xgp-c-load-header-files-in-current-buffer 命令。

2. 头文件分两种类型:用 <> 包围的和用 "" 包围的。第一种要在系统的目录里找,第二种要在当前目录里找。这些目录的值是用变量保存的。第一种的默认值是 /usr/include 和 /usr/local/include。如果要自定义它,可以使用 M-x customize-variable RET xgp-c-system-include-paths RET 来配置。第二种的值是打开的 C/C++ 文件所在的目录。

也许别人已经写过更完善的程序来解决这个问题了,如果有这样的解决方案,请告诉我。

[color="Magenta"]非常好,加精呀!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表