让你的Emacs像VS一样方便

来源:互联网 发布:java访问redis数据库 编辑:程序博客网 时间:2024/05/13 19:42

Emacs是强大的文本编辑器之一,尤其是进行程序设计,人们常说:“程序员可以分为三种:使用Emacs的,使用Vim的,以及其他”,可见Emacs在程序员中间的地位。不多废话,直接进入正题。本文介绍了在Ubuntu环境下使用Emacs进行C/C++进行开发的配置方法,通过两天的折腾,配置了一些基本的功能:代码提示/补齐、代码折叠、代码缩进和代码跳转等功能,后续的配置还会继续更新本文章,但仅此三项已经大大提高了开发效率。

配置方法

本文配置是基于Emacs24进行配置的,但配置原理上也支持Emacs23。配置主要用到两个Emacs扩展:CEDET和Auto-Complete。CEDET用于向Auto-Complete提供语义分析,从而向auto-complete提供代码提示支撑。配置方法如下:

  1. 基本概念:

    Emacs在启动的时候会默认加载home目录下的.emacs配置文件,此文件是隐藏文件,如果不存在可手动建立(命令:touch .emacs),建立此文件之后可以使用gedit进行编辑(gedit .emacs)。然后配置信息都写在此文件内。
  2. 开启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)
    在CEDET1.1及以后版本中,通过设置默认语义子模式(semantic-default-submodes)来配置需要开启的模式,然后只需要(semantic-mode 1)一句话即可开启CEDET。CEDET支持的模式包括: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高亮还没有进行语义处理的元素



  3. 配置代码提示/补齐

    代码提示需要配合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配置参考文章。最后一行配置了忽略大小写

  4. 代码跳转

    代码跳转时程序设计中很常用的一个功能,CEDET可以通过配置支持代码跳转功能。配置如下:
    (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))))
    上面代码配置了使用f2进行代码跳转,然后使用shift+f2进行代码跳回(默认是使用\C-x B),另外需要注意的是使用代码跳转需要开启模式。此外如果代码无法跳回可在跳转配置前加入如下配置(参考点击打开链接):
    (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 ontothe mru bookmark stack."  (semantic-mrub-push semantic-mru-bookmark-ring                      (point)                      'mark)  ad-do-it)


  5. 代码缩进

    代码缩进功能没有深入研究,就参考了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


  6. 代码折叠

    代码折叠功能使用了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)


  7. 其他设置

    除了上述设置,还有一些其他有趣的设置,包括:
  • 其他快捷键

    其他快捷键设置除了代码跳转外,还可以定义其他快捷键,包括:
    (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提供了代码模板功能,但我个人习惯了自己写书写,而且配置很麻烦,所以就没有深入弄,基本配置代码如下:
    (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")
    需要注意的是,yasnnipe需要自己下载安装,与auto-complete方法一致,放在对应路径下就行,本文放在了~/.emacs.d/yasnippet-0.6.1c下。具体配置方法参见yasnippet配置参考文章。

配置完成后的效果如下图:

配置效果图

全部配置:

;;=====================================================================;;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 ontothe 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;;=====================================================================

有用的链接

CEDET配置参考文章


auto-complete配置参考文章


yasnippet配置参考文章


代码折叠配置参考文章


EmacsWiki


配置CEDET浏览和编辑C++


GNU Emacs官方文档

原创粉丝点击