Emacs是强大的文本编辑器之一,尤其是进行程序设计,人们常说:“程序员可以分为三种:使用Emacs的,使用Vim的,以及其他”,可见Emacs在程序员中间的地位。不多废话,直接进入正题。本文介绍了在Ubuntu环境下使用Emacs进行C/C++进行开发的配置方法,通过两天的折腾,配置了一些基本的功能:代码提示/补齐、代码折叠、代码缩进和代码跳转等功能,后续的配置还会继续更新本文章,但仅此三项已经大大提高了开发效率。
配置方法
本文配置是基于Emacs24进行配置的,但配置原理上也支持Emacs23。配置主要用到两个Emacs扩展:CEDET和Auto-Complete。CEDET用于向Auto-Complete提供语义分析,从而向auto-complete提供代码提示支撑。配置方法如下:
-
基本概念:
Emacs在启动的时候会默认加载home目录下的.emacs配置文件,此文件是隐藏文件,如果不存在可手动建立(命令:touch .emacs),建立此文件之后可以使用gedit进行编辑(gedit .emacs)。然后配置信息都写在此文件内。
-
开启CEDET
首先需要开启CEDET,配置如下:
在CEDET1.1及以后版本中,通过设置默认语义子模式(semantic-default-submodes)来配置需要开启的模式,然后只需要(semantic-mode 1)一句话即可开启CEDET。CEDET支持的模式包括:;;set the mode enabled (setq semantic-default-submodes '(global-semanticdb-minor-mode global-semantic-idle-scheduler-mode global-semantic-idle-summary-mode global-semantic-idle-completions-mode global-semantic-decoration-mode global-semantic-highlight-func-mode global-semantic-stickyfunc-mode global-semantic-mru-bookmark-mode global-semantic-tag-folding-mode)) ;;enable cedet (semantic-mode 1)
CEDET模式列表 模式名称 模式作用 global-semanticdb-minor-mode 开启Semanticdb支持。Semanticdb用于存储已经分析出的语义结果 global-semantic-mru-bookmark-mode 开启自动书签存储,从而可以使用代码跳转 global-cedet-m3-minor-mode 激活CEDET右键菜单(还没发先有啥用) global-semantic-highlight-func-mode 高亮方法、类等的第一行 global-semantic-stickyfunc-mode 当前编辑的方法上滚到可视区域外时,将方法名显示在最顶端 global-semantic-decoration-mode 激活样式 global-semantic-idle-local-symbol-highlight-mode 高亮所有当前选中变量使用的位置 global-semantic-idle-scheduler-mode 空闲的时候对源码自动进行语义分析 global-semantic-idle-completions-mode 在空闲的时候显示可能的命名补全(CEDET自己的命名补全显示在已输入部分后面,显示为淡灰色) global-semantic-idle-summary-mode 在空闲时显示当前位置的信息 global-semantic-show-unmatched-syntax-mode 显示当前没有进行语义处理的元素 global-semantic-show-parser-state-mode 显示当前语义处理器的状态 global-semantic-highlight-edits-mode 高亮还没有进行语义处理的元素
-
配置代码提示/补齐
代码提示需要配合auto-complete进行,虽然CEDET也有代码提示功能(参见CEDET配置参考文章),但CEDET官方推荐的是使用auto-complete进行代码提示和补齐。
使用代码提示首先要开启CEDET代码补齐功能:;;开启代码补齐功能 (require 'semantic/ia) ;;添加C++头文件 (require 'semantic/bovine/gcc)
然后,将CEDET语义分析添加到ac-sources变量中,这是由于auto-complete使用ac-sources进行代码提示和补齐,配置如下:
;;添加ac-sources (defun my-c-mode-cedet-hook () (add-to-list 'ac-sources 'ac-source-gtags) (add-to-list 'ac-sources 'ac-source-semantic)) (add-hook 'c-mode-common-hook 'my-c-mode-cedet-hook)
最后,需要配置auto-complete。由于auto-complete不是Emacs标准的一部分,因此需要手动下载而配置。首先去auto-complete官网Auto Complete Mode下载最新版本的auto-complete(本文是基于1.3.1),然后解压放在~/home/.emacs.d文件夹下(.emacs.d如果不存在则手动建立),并将文件夹名称改为"auto-complete"(如果不是)。然后配置加载auto-complete如下:(add-to-list 'load-path "~/.emacs.d/auto-complete") (require 'auto-complete-config) (add-to-list 'ac-dictionary-directories "~/.emacs.d/auto-complete/dict") (ac-config-default) ;;ignore case (setq ac-ignore-case t)
最后一行配置了auto-complete代码提示忽略大小写,还有其他一些配置,例如设置提示框颜色等等,可以参考auto-complete配置参考文章。最后一行配置了忽略大小写
-
代码跳转
代码跳转时程序设计中很常用的一个功能,CEDET可以通过配置支持代码跳转功能。配置如下:
上面代码配置了使用f2进行代码跳转,然后使用shift+f2进行代码跳回(默认是使用\C-x B),另外需要注意的是使用代码跳转需要开启模式。此外如果代码无法跳回可在跳转配置前加入如下配置(参考点击打开链接):(global-set-key [f2] 'semantic-ia-fast-jump);;jump (global-set-key [S-f2];;jump back:shift+f2 (lambda () (interactive) (if (ring-empty-p (oref semantic-mru-bookmark-ring ring)) (error "Semantic Bookmark ring is currently empty")) (let* ((ring (oref semantic-mru-bookmark-ring ring)) (alist (semantic-mrub-ring-to-assoc-list ring)) (first (cdr (car alist)))) (if (semantic-equivalent-tag-p (oref first tag) (semantic-current-tag)) (setq first (cdr (car (cdr alist))))) (semantic-mrub-switch-tags first))))
(defadvice push-mark (around semantic-mru-bookmark activate) "Push a mark at LOCATION with NOMSG and ACTIVATE passed to `push-mark'. If `semantic-mru-bookmark-mode' is active, also push a tag onto the mru bookmark stack." (semantic-mrub-push semantic-mru-bookmark-ring (point) 'mark) ad-do-it)
-
代码缩进
代码缩进功能没有深入研究,就参考了GNU Emacs官方文档上的示例代码设置了一下(参见点击打开链接),代码如下:;;-------------indent setting start ;; Make a non-standard key binding. We can put this in ;; c-mode-base-map because c-mode-map, c++-mode-map, and so on, ;; inherit from it. (defun my-c-initialization-hook () (define-key c-mode-base-map "\C-m" 'c-context-line-break)) (add-hook 'c-initialization-hook 'my-c-initialization-hook) ;; offset customizations not in my-c-style ;; This will take precedence over any setting of the syntactic symbol ;; made by a style. (setq c-offsets-alist '((member-init-intro . ++))) ;; Create my personal style. (defconst my-c-style '((c-tab-always-indent . t) (c-comment-only-line-offset . 4) (c-hanging-braces-alist . ((substatement-open after) (brace-list-open))) (c-hanging-colons-alist . ((member-init-intro before) (inher-intro) (case-label after) (label after) (access-label after))) (c-cleanup-list . (scope-operator empty-defun-braces defun-close-semi)) (c-offsets-alist . ((arglist-close . c-lineup-arglist) (substatement-open . 0) (case-label . 4) (block-open . 0) (knr-argdecl-intro . -))) (c-echo-syntactic-information-p . t)) "My C Programming Style") (c-add-style "PERSONAL" my-c-style) ;; Customizations for all modes in CC Mode. (defun my-c-mode-common-hook () ;; set my personal style for the current buffer (c-set-style "PERSONAL") ;; other customizations (setq tab-width 8 ;; this will make sure spaces are used instead of tabs indent-tabs-mode nil) ;; we like auto-newline, but not hungry-delete (c-toggle-auto-newline 1)) (add-hook 'c-mode-common-hook 'my-c-mode-common-hook) ;;----------indent setting end
-
代码折叠
代码折叠功能使用了Emacs自带的hs-minor-mode,但是由于默认快捷键使用起来太不方便,所以进行了自定义为C-c ?快捷键,配置代码如下;;universal code folding (defun toggle-selective-display (column) (interactive "P") (set-selective-display (or column (unless selective-display (1+ (current-column)))))) (defun toggle-hiding (column) (interactive "P") (if hs-minor-mode (if (condition-case nil (hs-toggle-hiding) (error t)) (hs-show-all)) (toggle-selective-display column))) (load-library "hideshow") (global-set-key (kbd "C-?") 'toggle-hiding) (global-set-key (kbd "C-`") 'toggle-selective-display) (add-hook 'c-mode-common-hook 'hs-minor-mode) (add-hook 'emacs-lisp-mode-hook 'hs-minor-mode) (add-hook 'java-mode-hook 'hs-minor-mode) (add-hook 'lisp-mode-hook 'hs-minor-mode) (add-hook 'perl-mode-hook 'hs-minor-mode) (add-hook 'sh-mode-hook 'hs-minor-mode) ;;display overlay content in echo area or tooltip (defun display-code-line-counts (ov) (when (eq 'code (overlay-get ov 'hs)) (overlay-put ov 'help-echo (buffer-substring (overlay-start ov) (overlay-end ov))))) (setq hs-set-up-overlay 'display-code-line-counts)
-
其他设置
除了上述设置,还有一些其他有趣的设置,包括:
-
其他快捷键
其他快捷键设置除了代码跳转外,还可以定义其他快捷键,包括:(defun my-c-mode-cedet-key() (local-set-key "\C-cd" 'semantic-ia-show-doc);;显示方法、类等的文档 (local-set-key "\C-cs" 'semantic-ia-show-summary);;显示方法、类等的概述 (local-set-key "\C-cc" 'semantic-ia-describe-class);;列举类的方法变量等 (local-set-key "\C-ct" 'semantic-analyze-proto-impl-toggle);;在.h和.cpp文件之间进行跳转切换 (local-set-key "\C-ci" 'semantic-decoration-include-visit);;进入include中的文件 ) (add-hook 'c-mode-common-hook 'my-c-mode-cedet-key)
-
显示行号
(global-linum-mode 1)
-
Emacs24及以上版本主题设置
M-x list-faces-display
-
隐藏工具栏
(tool-bar-mode -1)
-
Yasnippe代码模板
yasnippe提供了代码模板功能,但我个人习惯了自己写书写,而且配置很麻烦,所以就没有深入弄,基本配置代码如下:
需要注意的是,yasnnipe需要自己下载安装,与auto-complete方法一致,放在对应路径下就行,本文放在了~/.emacs.d/yasnippet-0.6.1c下。具体配置方法参见yasnippet配置参考文章。(add-to-list 'load-path "~/.emacs.d/yasnippet-0.6.1c/") (require 'yasnippet) (yas/initialize) (yas/load-directory "~/.emacs.d/yasnippet-0.6.1c/snippets")
配置完成后的效果如下图:
全部配置:
;;=====================================================================
;;Emacs settings begin
;;=====================================================================
;;newline and indent
(setq c-newline-and-indent 'newline-and-indent)
;;hide tool bar
(tool-bar-mode -1)
;; display column-number-mode
(global-linum-mode 1)
;;-------------indent setting start http://www.gnu.org/software/emacs/manual/html_mono/ccmode.html#Sample-_002eemacs-File
;; Make a non-standard key binding. We can put this in
;; c-mode-base-map because c-mode-map, c++-mode-map, and so on,
;; inherit from it.
(defun my-c-initialization-hook ()
(define-key c-mode-base-map "\C-m" 'c-context-line-break))
(add-hook 'c-initialization-hook 'my-c-initialization-hook)
;; offset customizations not in my-c-style
;; This will take precedence over any setting of the syntactic symbol
;; made by a style.
(setq c-offsets-alist '((member-init-intro . ++)))
;; Create my personal style.
(defconst my-c-style
'((c-tab-always-indent . t)
(c-comment-only-line-offset . 4)
(c-hanging-braces-alist . ((substatement-open after)
(brace-list-open)))
(c-hanging-colons-alist . ((member-init-intro before)
(inher-intro)
(case-label after)
(label after)
(access-label after)))
(c-cleanup-list . (scope-operator
empty-defun-braces
defun-close-semi))
(c-offsets-alist . ((arglist-close . c-lineup-arglist)
(substatement-open . 0)
(case-label . 4)
(block-open . 0)
(knr-argdecl-intro . -)))
(c-echo-syntactic-information-p . t))
"My C Programming Style")
(c-add-style "PERSONAL" my-c-style)
;; Customizations for all modes in CC Mode.
(defun my-c-mode-common-hook ()
;; set my personal style for the current buffer
(c-set-style "PERSONAL")
;; other customizations
(setq tab-width 8
;; this will make sure spaces are used instead of tabs
indent-tabs-mode nil)
;; we like auto-newline, but not hungry-delete
(c-toggle-auto-newline 1))
(add-hook 'c-mode-common-hook 'my-c-mode-common-hook)
;;----------indent setting end
;;=====================================================================
;;emacs setting end
;;=====================================================================
;;=====================================================================
;;cedet begin
;;cedet(1.1) setting based on method descripted at
;;http://alexott.net/en/writings/emacs-devenv/EmacsCedet.html
;;=====================================================================
;;set the mode enabled
(setq semantic-default-submodes '(global-semanticdb-minor-mode
global-semantic-idle-scheduler-mode
global-semantic-idle-summary-mode
global-semantic-idle-completions-mode
global-semantic-decoration-mode
global-semantic-highlight-func-mode
global-semantic-stickyfunc-mode
global-semantic-mru-bookmark-mode
global-semantic-tag-folding-mode))
;;enable cedet
(semantic-mode 1)
;;enable advanced functionality for name completion
(require 'semantic/ia)
;;include standard C/C++ headers
(require 'semantic/bovine/gcc)
;;add ac-souces, ac-sources is used by auto-complete
(defun my-c-mode-cedet-hook ()
(add-to-list 'ac-sources 'ac-source-gtags)
(add-to-list 'ac-sources 'ac-source-semantic))
(add-hook 'c-mode-common-hook 'my-c-mode-cedet-hook)
;;solve the problem can not jump back according to http://blog.163.com/vic_kk/blog/static/494705242010726297405/#sec-3_4
(defadvice push-mark (around semantic-mru-bookmark activate)
"Push a mark at LOCATION with NOMSG and ACTIVATE passed to `push-mark'.
If `semantic-mru-bookmark-mode' is active, also push a tag onto
the mru bookmark stack."
(semantic-mrub-push semantic-mru-bookmark-ring
(point)
'mark)
ad-do-it)
;;add c-mode key set
(global-set-key [f1] 'speedbar)
(global-set-key [f2] 'semantic-ia-fast-jump);;jump
(global-set-key [S-f2];;jump back:shift+f2
(lambda ()
(interactive)
(if (ring-empty-p (oref semantic-mru-bookmark-ring ring))
(error "Semantic Bookmark ring is currently empty"))
(let* ((ring (oref semantic-mru-bookmark-ring ring))
(alist (semantic-mrub-ring-to-assoc-list ring))
(first (cdr (car alist))))
(if (semantic-equivalent-tag-p (oref first tag)
(semantic-current-tag))
(setq first (cdr (car (cdr alist)))))
(semantic-mrub-switch-tags first))))
(defun my-c-mode-cedet-key()
(local-set-key "\C-cd" 'semantic-ia-show-doc)
(local-set-key "\C-cs" 'semantic-ia-show-summary)
(local-set-key "\C-cc" 'semantic-ia-describe-class)
(local-set-key "\C-ct" 'semantic-analyze-proto-impl-toggle)
(local-set-key "\C-ci" 'semantic-decoration-include-visit)
)
(add-hook 'c-mode-common-hook 'my-c-mode-cedet-key);
;;=====================================================================
;;cedet end
;;=====================================================================
;;=====================================================================
;;auto-complete begin
;;auto-complete(1.3.1) setting based on method descripted at
;;http://cx4a.org/software/auto-complete/manual.html
;;=====================================================================
(add-to-list 'load-path "~/.emacs.d/auto-complete")
(require 'auto-complete-config)
(add-to-list 'ac-dictionary-directories "~/.emacs.d/auto-complete/dict")
(ac-config-default)
;;ignore case
(setq ac-ignore-case t)
;;=====================================================================
;;auto-complete end
;;=====================================================================
;;=====================================================================
;;yasnippet begin
;;yasnippet(0.6.1c) setting based on method descripted at
;;http://capitaomorte.github.io/yasnippet/#id3
;;=====================================================================
(add-to-list 'load-path "~/.emacs.d/yasnippet-0.6.1c/")
(require 'yasnippet)
(yas/initialize)
(yas/load-directory "~/.emacs.d/yasnippet-0.6.1c/snippets")
;;=====================================================================
;;yasnippet end
;;=====================================================================
;;=====================================================================
;;hs-minor-mode setting according to http://www.emacswiki.org/emacs/HideShow
;;=====================================================================
;;universal code folding
(defun toggle-selective-display (column)
(interactive "P")
(set-selective-display
(or column
(unless selective-display
(1+ (current-column))))))
(defun toggle-hiding (column)
(interactive "P")
(if hs-minor-mode
(if (condition-case nil
(hs-toggle-hiding)
(error t))
(hs-show-all))
(toggle-selective-display column)))
(load-library "hideshow")
(global-set-key (kbd "C-?") 'toggle-hiding)
(global-set-key (kbd "C-`") 'toggle-selective-display)
(add-hook 'c-mode-common-hook 'hs-minor-mode)
(add-hook 'emacs-lisp-mode-hook 'hs-minor-mode)
(add-hook 'java-mode-hook 'hs-minor-mode)
(add-hook 'lisp-mode-hook 'hs-minor-mode)
(add-hook 'perl-mode-hook 'hs-minor-mode)
(add-hook 'sh-mode-hook 'hs-minor-mode)
;;display overlay content in echo area or tooltip
(defun display-code-line-counts (ov)
(when (eq 'code (overlay-get ov 'hs))
(overlay-put ov 'help-echo
(buffer-substring (overlay-start ov)
(overlay-end ov)))))
(setq hs-set-up-overlay 'display-code-line-counts)
;;=====================================================================
;;hs-minor-mode end
;;=====================================================================
有用的链接