2

这篇文章原本是『走近 Emacs』的内容,当时因为考虑到 Emacs 的用户未必写 C/C++ 代码,所以就将它隔离了出来。

当你用 Emacs 打开或新建一份扩展名为 .c 的文件时,Emacs 会自动开启内置的 C 模式。这个模式提供了语法高亮、自动缩进等基本功能。同时 Emacs 也允许用户深度定制符合自己使用习惯的代码编辑功能,前提是你需要对 Emacs Lisp 扩展语言有一定了解。

C/C++ 代码编辑基本配置

如果你不熟悉也不打算学习 Emacs Lisp 语言,那就只能将他人写好的配置代码扔到 $HOME/.emacs$HOME/.emacs.d/init.el 文件中。现在推荐使用后者作为 Emacs 的配置文件。

很多年前我从一个我忘记了他的网络 ID 的家伙那里抄来一段 C 代码的配置:

;;;; c mode ;;;;
(defvar xgp-cfsi-left-PAREN-old nil
  "Command used to input \"(\"")
(make-variable-buffer-local 'xgp-cfsi-left-PAREN-old)

(defun xgp-cfsi-modify-alist (alist term new)
  (let ((tl (assq term (symbol-value alist))))
    (if tl
        (setcdr tl new)
      (add-to-list alist (cons term new)))))

(defun xgp-cfsi (style)
  "Deciding whether using CFSI."
  (interactive "Style: ")
  (c-set-style style)
  (setq indent-tabs-mode
        nil
        c-hanging-semi&comma-criteria
        (quote (c-semi&comma-inside-parenlist)))

  (xgp-cfsi-modify-alist 'c-hanging-braces-alist 'class-open nil)
  (xgp-cfsi-modify-alist 'c-hanging-braces-alist 'class-close nil)
  (local-set-key " " 'self-insert-command))

(defun xgp-cfsi-erase-blanks ()
  "Erase all trivial blanks for CFSI."
  (interactive)
  (save-excursion
    (goto-char (point-min))
    (while (re-search-forward "[ \t]+$" nil t)
      (replace-match "" nil nil))))

(defun linux-c-mode()
  (define-key c-mode-map [return] 'newline-and-indent)
  (setq imenu-sort-function 'imenu--sort-by-name)
  (interactive)
  (imenu-add-menubar-index)
  (which-function-mode)
  (c-toggle-auto-state)
  (c-toggle-hungry-state)
  (setq indent-tabs-mode nil)
  (xgp-cfsi "linux"))
(add-hook 'c-mode-common-hook 'linux-c-mode)

这样配置之后,C/C++ 代码编辑功能会强大一些。例如,敲击 Backspace 键可以连续删除多行空行;在代码行尾键入 ; 会自动换行;代码缩进长度变为 8 个空白字符……这些配置,我用了很多年,到现在也不知道它具体都做了些什么。

C++ 的代码,因为我平时写的不太多,所以没作配置。不过上述的 C 模式配置的这些功能,也适合 C++ 代码的编辑。

C/C++ 代码自动提示

你现在所用的 Emacs 版本应该是 >= 24,如果不是,想办法升级吧。否则本节内容不太适合你阅读,除非你懂得如何手动安装 Emacs 扩展包。

如果用过 Visual C++.net 或者 Eclipse,想必会对它们的代码编辑器提供的代码自动提示功能念念不忘,因而抱怨 Emacs 的 C 模式未提供此功能。事实上是有的,但是要实现 C/C++ 代码的自动提示,这需要 Emacs 懂得如何去解析 C/C++ 代码,似这类繁重又专业的任务让一个文本编辑器来做,不合常理,更何况 Emacs 并非 C/C++ 程序员的专用编辑器。

Emacs 能够做到的事情必须要与文本编辑直接相关,但是它有能力借助其他工具弥补自身不足。像 C/C++ 代码分析这样的任务,交给一个专业的 C/C++ 编译器最好不过了。虽然借助我们所熟悉的 gcc 是可行的,但它不如另一款编译前端 clang 好用,因为后者在设计时就考虑到了与代码编辑器的整合。

安装 clang

我们所要做的首先是想办法安装 clang。Gentoo Linux 用户只需:

$ sudo emerge -avt clang

然后先去干别的事吧,clang 毕竟是 C++ 写的 C/C++ 编译器,是个挺大的项目,编译耗时会挺长,长的我都忘记了到底需要多久,似乎比编译 libreoffice 或者 firefox 快一些。

安装 company

Emacs 本身是无法与 clang 沟通的,但是 Emacs Lisp 可以强大到允许 Emacs 用户自行编写扩展包以实现 Emacs 与 clang 的沟通。于是就有人写出了 company 这个扩展包。

在 Emacs 24 之前的时代,要为 Emacs 安装扩展包,需要从网络上下载扩展包,然后复制到 Emacs 所能搜索到的目录,最后在 Emacs 配置文件中对扩展包进行配置。

从 Emacs 24 开始,Emacs 对扩展包进行统一管理,极大程度上简化了扩展包的搜索与安装过程。打开 Emacs,然后执行 M-x list-packages ,如果网速足够快,应该很快就能看到 Emacs 官方提供的扩展包列表。

待软件包列表出现后,执行 C-s M-r ^ +company ,回车即可让光标跳到 company 扩展包信息所在的文本行,继而敲击 i 键(表示要安装该扩展包),再敲击 x 键(表示执行安装过程),稍等片刻,Emacs 会自动从下载 company 扩展包并安装至 $HOME/.emacs.d 目录。

提示:C-s 是开启 Emacs 查找模式, M-r 是将查找模式切换为正则表达式查找模式,而 ^ +companyy 是用于匹配『位于行首且由多个空格与 company 字符串构成的字符串』的正则表达式。

如果以后要删除 company 扩展,步骤与安装步骤类似,只是将 i 键替换为 d 键(表示删除)。

配置 company

company 安装完毕后,在 Emacs 配置文件中做以下配置:

;; 代码补全
(add-hook 'c-mode-hook 'company-mode)
(add-hook 'c++-mode-hook 'company-mode)

这样便可将 company 挂接到 Emacs C 模式上。这样,每当 Emacs 打开 C/C++ 文件时company 模式便会被自动开启。

下图是 company 与clang 成功『沟通』后的结果:

company 的代码自动提示

由于 clang 默认会去 Linux 标准目录 /usr/include 中去搜索库的头文件,但是有些库的头文件是安装在非标准位置的。例如 PCL 库的头文件,默认安装在 usr/include/pcl-1.7,若要对 PCL 库函数进行自动补全,那么就需要将这个路径告诉 clang。eigen 库也存在这个问题。解决方法是在项目源码的顶层目录下创建 .dir-locals.el 文件,内容类似于:

((nil . ((company-clang-arguments . ("-I/usr/include/pcl-1.7/"
                                     "-I/usr/include/eigen3/")))))

如果谁有更好的让 clang 自动搜索库的头文件路径的方法,还请不吝赐教。


garfileo
6k 声望1.9k 粉丝

这里可能不会再更新了。


引用和评论

0 条评论