从vim转向Emacs _ emacser.com文章收集

在Emacs中使用gdb调试程序

http://emacser.com/emacs-gdb.htm

 

1 引言

Emacs除了具备强大的编辑功能,还能够做为调试工具gdb的前端,对程序进行调试。使用Emacs进行调试,能够将程序的编写与调试统一到Emacs中,并利用Emacs强大的功能辅助调试,是将Emacs做为IDE使用的一项必备功能。 php

本文假定读者具备基本的程序调试知识,但愿知道在Emacs下进行基本调试的对应操做。水平有限,欢迎拍砖。 html

2 准备工做:将调试信息编译在程序中

要使程序能被gdb调试,须要在编译时加入调试所需的信息。若是使用gcc/g++进行编译,须要使用参数-g,如: 前端

? View Code BASH
gcc prog.c -g -o prog

若是使用 ./confiugre && make 的编译流程,能够将使用以下方式引入-g参数: java

? View Code BASH
1
2
CFLAGS="-g" ./configuremake

注意:不要加入任何优化参数(例如-O、-O2),否则调试时会有很灵异的现象发生…… node

3 开始:开启Emacs的调试模式GUD

3.1 运行gdb

在编译好程序后,就能够开始调试了。直接运行gdb命令M-x gdb RET 在minibuffer中会出现须要执行的gdb命令。例如:gdb –annotate=3 prog 若是当前目录下有可执行文件(一般刚好是须要调试的文件),gdb会在其后自动补上可执行文件,不然须要在minibuffer中补上要调试的程序文件名。 python

继续回车,Emacs的GUD(Grand Unified Debugger)就会关联到gdb并加载要调试的程序了。 linux

3.2 gdb界面

启动gdb后,Emacs的界面会变成下面两种之一: c++

GDB单窗格模式git

GDB多窗格模式程序员

能够经过gdb-many-windows来切换这两种界面布局。

若是界面被打乱了(例如,在minibuffer中使用补全,查看帮助,从新编译程序),能够使用gdb-restore-windows来恢复界面布局。

3.3 小结

命令 功能
gdb 启动gdb进行调试
gdb-many-windows 切换单窗格/多窗格模式
gdb-restore-windows 恢复窗格布局

接下来就要开始调试程序了。

4 调试:设置断点,控制程序流程

4.1 设置、删除断点

首先将断点设置在要调试的地方。有两种方法:

第一种,在要设置断点的行左边的fringe上单击一下(就是文本左边与滚动条之间空出的那一块)。隐藏了fringe的朋友能够M-x fringe-mode显示它。

第二种,使用默认快捷键C-x C-a C-b, 或者 C-x <SPC>。它们都关联到命令gud-break。

不管使用哪一种方法,fringe上都会在设置了断点的行上显示一个红点,表示这行设了断点:

同时,在断点buffer中也会显示已有的断点信息:

断点buffer

要删除断点,一样有两种对应的方法:在fringe的断点上单击一下,或者使用快捷键C-x C-a C-d(对应命令gud-remove)。

能够在断点buffer上单击某个断点切换到断点所在位置。将光标移动到断点处回车也有一样的效果。

在断点buffer上按空格键能够切换断点的激活和禁用状态。

4.2 运行程序

设置好断点后就能够运行程序了。单击工具栏上的运行就开始运行了。也能够使用gud-go命令来运行。奇怪的是没有任何默认快捷键绑定。

当程序运行到断点时,程序会在断点处停下来,并自动打开停下的语句所在的代码文件。同时在fringe上在停下的语句处有三角形的指示器。

如今,咱们来一步步运行程序。

4.3 单步执行、运行到光标处

在调试中最经常使用的功能就是单步执行了。单步执行有两种:将函数调用做为一条语句执行(Next)和遇到函数时进入函数中进行调试(Step)。

要使用第一种方式,默认快捷键是C-x C-a C-n,对应命令为gud-next。也能够单击工具栏上的 单步运行跳过函数

第二种方式的默认快捷键是C-x C-a C-s,对应命令为gud-step。也能够单击工具栏上的 单步运行进入函数

若是想跳出当前函数,能够使用命令gud-finish,默认快捷键为C-x C-a C-f,工具栏上有 跳出函数 可用。

在Emacs中还能够运行到光标所在的行。使用命令gud-until便可,默认快捷键为C-x C-a C-u。1

也能够直接把当前语句指示器拖到任意一行,程序会运行到那一行再停下来。

4.4 继续运行程序

在程序中断后要继续运行程序,依然是使用gud-go命令或 继续运行 ,也能够使用命令gud-cont,对应快捷键为C-x C-a C-r。

4.5 小结

功能 命令 默认快捷键
添加断点 gud-break C-x C-a C-b 或 C-x <SPC>
删除断点 gud-remove C-x C-a C-d
运行/继续程序 gud-go
单步执行,无视函数 gud-next C-x C-a C-n
单步执行,进入函数 gud-step C-x C-a C-s
跳出当前函数 gud-finish C-x C-a C-f
运行到光标所在语句 gud-until C-x C-a C-u
继续运行程序 gud-cont C-x C-a C-r

5 察看变量的值

调试的过程当中免不了要查看变动的值。Emacs提供了方便地功能让咱们查看变量的值。

5.1 本地变量buffer

若是打开了gdb-many-windows,在右上角会显示Locals buffer,其中显示了当前局部变量的值。若是显示的是寄存器(Register)buffer,单击左边的Locals就能够切换到Locals buffer了。在其中能够方便地观察到各变量的值。

若是没有打开gdb-many-windows,也能够使用gdb-display-locals-buffer来显示该buffer。

5.2 察看变量值

遇到一些Locals里没有显示的变量,或者比较复杂的结构,就须要用到观察变量的功能了。

将光标停留在要观察的变量上,执行命令gud-watch,能够将变量加入观察列表中。默认的快捷键是C-x C-a C-w。也能够使用工具栏上的 查看变量

被观察的变量将在Speedbar中显示。对于复杂结构,能够单击Speedbar上的+号将其展开或收缩。在+号上按空格键也有相同的效果。2

有时候Emacs观察的变量不是你所想要的,通常是a->b这类的状况。这时能够将要观察的部分选中,再使用上述方法便可。

5.3 用工具提示显示变量值

能够用gud-tooltip-mode开启或关闭工具提示。开启后将鼠标指针停留在变量名上时将在工具提示中显示变量的值。

5.4 小结

功能 命令 默认快捷键
观察变量 gud-watch C-x C-a C-w
展开/收缩变量 <SPC>
开启/关闭工具提示 gud-tooltip-mode

6 输入输出

若是程序须要与标准输入/输出交互,那么你极可能须要用到下面要介绍的功能。

6.1 单独的IO buffer

默认来讲,程序的输入输出是在gdb buffer里显示的。这样输出信息和gdb信息混合在一块儿,阅读起来很是不便。这时候,你须要把输入输出单独显示在一个buffer里,方便查看。

使用gdb-use-separate-io-buffer,能够在程序代码buffer右侧新建一个IO buffer,程序对标准输入输出的操做都会重定向到这里。再执行一次该命令则会隐藏。

6.2 输入数据

须要输入数据的时候,只须要在IO buffer中输入数据回车便可。已经输入的数据会被加粗,以和输出信息区分开来。

6.3 重定向到文件

有时候咱们已经准备好了用于输入的数据在文件中,以免调试时烦琐的输入。这时候就须要在调试时进行输入输出重定向了。

要进行重定向,只能使用gdb自带的功能。在gdb buffer中输入 run < data.in > data.out 就能够将标准输入重定向到data.in,将标准输出重定向到data.out了。

7 按键绑定

说实话,gud自带的按键绑定实在是麻烦,使用一个功能要三次组合键才行,小姆指按Ctrl都按酸了。因此通常将经常使用的按键绑定在方便的位置,这样才能有和另的IDE同样的快感。

如下是将F五、F七、F8分别绑定到gud-go、gud-step和gud-next的代码:

? View Code LISP
1
2
3
4
(add-hook 'gdb-mode-hook '(lambda ()                             (define-key c-mode-base-map [(f5)] 'gud-go)                             (define-key c-mode-base-map [(f7)] 'gud-step)                             (define-key c-mode-base-map [(f8)] 'gud-next)))

之因此绑定到c-mode-base-map上,是由于我基本上在代码buffer中调试。若是要在gdb-buffer中使用的话,须要使用gud-mode-map。若是想在全部buffer上使用的话,能够绑定到全局按键中:

? View Code LISP
(global-set-key [(f5)] 'gud-go)

8 结尾

有了调试功能,Emacs做为一个IDE才算是完整了。本文介绍了在Emacs下使用gdb调试的基本方法,Emacs的调试功能还远不止这些,进一步学习可参阅 Emacs ManualDebuggers 一节。

因为我也是边学边写,必定有许多不足或者错误,还请各位多多指教。

Footnotes:

1 注:我在使用时只有光标所在的行在当前行以后而且位于同一函数内才行,不然会跳到很奇怪的地方,还请高手指教。

2 我在使用过程当中常常出现展开没反应,或者加入新元素后才展开,运行几步才展开的状况,求高人讲解。

分享家:Addthis中国

 

 

 

对初学者学习vim的建议

网上有很多人一方面对Vim非常好奇,另外一方面又对Vim表示出不屑一顾的鄙夷,更有甚者认为使用Vim的人只是装逼

我不知道这种意识怎么出现的,只以为这种人很傻很天真,我也不指望这种人学会Vim,假使学会,那他们可就真是用来“装逼”的了 初学者只需谨记如下几点建议:

  1. 刚开始不要纠结于配置,网上找个配置好的版本先用上再说
  2. 初学不要看Vim枯燥的文档,找几篇清晰的入门教程学会基本的几个操做就够用了
  3. 或许你会以为Vim某些地方用着不爽,那你能够试着找找改变的方法,尝试修改本身的配置文件
  4. Vim不是用来学的,学只是一个基础,最终仍是得用,最好是每天都用
  5. 不要奢望有哪一个编辑器能比Vim更强大(Emacs例外),目前来讲是不可能的,用好你的Vim就是
  6. 不要觉得用Vim就很厉害,不要将Vim用做充门面的工具,要知道,这是一种很白痴的行为
  7. 适合的就是最好的,若是你以为现有的编辑器或IDE用起来很舒服,那你不必非要来学什么Vim,感受不够舒服了再来学吧
  8. 尽可能不要转入编辑器的宗教之争,这没有任何意义,有时间还不如写点使用心得,造福后来者
  9. 本身有什么新的发现和感悟、本身的配置文件有什么高明之处,分享出来吧,Vim社区从来有崇尚分享的传统

Vim的学习曲线仍是比较陡峭的,通常来讲,一周小成一月入门半年熟练一年掌握,至少也要用上近一个月才能体会到Vim的妙处。慢慢来,无需着急,随着熟练度的愈来愈高,使用起来也会愈来愈顺手,你会发现,本身无形中已经爱上了Vim,一旦你发现本身没事干时老喜欢按jk这两个键,那么恭喜你,你已经入门

 

 

有趣或者有用的网友回复:

 

普通人的编辑利器Vim

     

  • 1.免费

    用户不再用去网上辛苦的下载D版了!

  • 2.提升输入速度

    这个相信也没有什么好争论的,纯键盘操做的速度是鼠标没法比拟的,虽然会带来必定的学习成本,可是相信仍是值得的。

  • 3.完美支持中文,并支持多种文件编码

    不少编辑器会有处理多字节编码的问题,而vim完美解决了这一点。(若是你的vim没解决,请参考linux下vim的编译以及终端乱码的最终解决方案

  • 4.文本笔记管理

    这要归功于vim的一款插件:voom,详情能够参考善用佳软的这篇博文--VOoM(原VOOF):vim实现带折叠双栏树状文本管理

    若是你是一名程序员,那就千万不要错过vim,它真的为程序员提供了太多贴心的功能。

  • 1.支持几乎全部语言类型

    不夸张的说,vim真的是将这一点作到了极致,只要是你们知道的语言,大到c++,python,小到bash,sql,vim所有都默认支持了这些语言的语法高亮,自动缩进,等等。一个编辑器搞定全部源码编写,不用为每门语言学习他的编辑器,下降学习成本,何乐而不为?

  • 2.支持各类语言的代码自动补全和智能提示

    详见:vim所支持的自动完成详解把VIM打形成一个真正的IDE(3)

  • 3.快速查找函数定义功能及显示函数列表功能

    vim+tags+taglist便可轻松实现上面的功能,功能上彻底能够替代si或者vs.详见:把VIM打形成一个真正的IDE(2)在Vim中使用ctags

  • 4.支持相似textmate的代码片断功能

    我目前使用的是snipMate,固然提供这种功能的插件可不仅这一个,你能够有更多选择~

  • 5.集成编译调试功能,快速定位编译错误

    vim提供了quickfix的功能,能够集成gcc,g++,java,c#,python,php等各类语言的错误定位功能,极大提升了代码编译调试时的错误定位。参见:VIM-一键编译单个源文件

  • 6.开源

    若是发现vim有bug,那么大能够本身去研究代码修复~

  • 7.跨平台

    在linux,windows,mac等多平台都有相应的版本,不用担忧跨平台开发的问题!

  • 8.支持插件,无限扩展本身想要的功能

    vim自己有本身的脚本语言,若是你真的不想再多学一门语言,那也不是什么大事,gvim7.3已经默认编译支持了python,ruby,lua,perl等等脚本语言,用你喜欢的脚本语言开发去吧!(我爱python!),与emacs的lisp相比,vim自身的脚本语言确实有所欠缺,可是python较之lisp也算是旗鼓至关了

    vim更像是一个超级终端,vim已经支持用python,lua,perl,ruby等多种脚本语言进行脚本编写,只要你愿意,你能够用脚本语言实现任何你想要的功能,而后经过vim展现出来。
    简单来讲,即 vim替你实现了一个通用的界面,而你只须要编写你的逻辑代码,而展示到屏幕这一层,就调用vim的接口,由vim来完成就能够了~
    这就是我所说的超级终端的定义,若是仍是不能理解,那咱们就用实例来讲明吧!


 

 

编辑上的功能基本都同样,你以为vim或者emacs没有那同样功能只是你不知道,其实是内置或者可经过某个插件来完成,我以为不一样就在于vim注重的是编辑,编辑文件时按键方面比emacs方便,而emacs注重的是功能,各类功能集成在一块儿,管理项目这些比vim方便

有一个著名的把用户看成傻瓜的软件,老是把句子的行首单词Capitalize,并且自动把他认为错了的单词改过来,每次我都要费尽心机想办法,怎么把这个功能关掉。这个软件应该是office,我也经常为这个功能头痛

 

本质上来讲,vim的哲学是浏览器+编辑器,因此浏览功能应该比emacs好些, 剩下的编辑功能,emacs靠lisp,vim靠python,都能实现那些你能想到的功能。
user experience来讲, 插件管理,窗口管理, 其实二者都有待增强。

 

我用EMACS而不用VIM由于我不喜欢ESC,不喜欢模式切换。
但我会基本的VIM,我以为VIM绝对不比EMACS差。
我以为经过组合键,不停的编辑与移动,非快非快…… 而VIM要切来切去,切来切去…… 疯

你不喜欢切换模式?不会是你的键盘Esc键没有和占用着好地盘的无用按键Capslock交换吧?改过键后,左手小指Esc切换模式使用vim,要多爽有多爽,爽到难以用语言来形容。并且不仅vim中爽,其余应用程序中,使用Esc换掉CapsLock也很爽。

 

 

@,
其实说到底仍是看我的习惯,若是习惯轻量级,专业,和击键轻松,vim比较好;
若是喜欢all in one,按组合键,emacs好。

并且emacs还能够实现vim模式,最新的叫evil,名字还颇有意思,
evil邪恶的,同时也是emas vim layer

 

 

刚刚从vim转过来,vim的输入效率确实很高,发现emacs的快捷键太复杂太麻烦,启动也要比vim慢的多。
可是vim有几个缺点:
一、插件比较挫,自己用的插件语言的表达能力就不强,有点不三不四,感受执行效率也不高,功能也比较弱,应该换成一个更通用的脚本语言,这样持续性才强。断断续续用了一年,我仍是没有找到一个能正确格式化html文件的插件。我写代码的种类比较多,vim不能知足。
二、很是陡峭的学习曲线加上不同凡响的模式转换机制,使得不少ide都不能很好的和vim integrate。eclipse和intellij都带有emacs的快捷键集,可是没有vim的(虽然有插件,可是都不太好用),由于操做方式差得太远。
vim自己比较适合快速的输入,但扩展性上确实有待提升。

 

在嵌入式平台下, 有时候须要ssh进去配置. 编辑文件的只能是vim.
因此有时候在vim编辑的时候, 不知不觉会按到crtl键

 

source in sight 的自动搜索一个函数的 caller 这个功能我认为 cscope的c-x s s, 是能够实现的。我一直这么用。

或者我还有个很笨的办法,用doxyen生成程序的文档,而后在文档内能够清晰的看到一个函数calling了哪些函数,有哪些caller,类图,集成图,协做图,还有…不少。

令:emacs里若是使用doxymacs,那么能够很是方便的生成doxyen格式的注。

cscope的确是使用tag作基础的,并且符号位置和行号相关;大量修改以后的确须要从新更新cscope.files和cscope.out。可是,若是只是微量修改,xcscope.el能够检查cscope数据库的更新状态,须要更新时会自动再次索引部分源文件,而后查找,结果仍是至关准确的。

 对,效果很不错,我就是用的xcscope.el,我写了一个大量修改后更新cscope的脚本,找的结果倒是非常精准。
ctags也很好用。

 

@negatlov, 哈,我也有这个缘由,不过我主要仍是刚用emacs就以为好用,可是就是一直用不惯vi,并且还曾经专门花时间学vi,仍是用不惯

[回复]

negatlov 回复:
四月 27th, 2010 at 1:22 下午

@ahei,

我比较讨厌VI中按ESC键。这个设计让我感受不太爽

[回复]

ahei 回复:
四月 27th, 2010 at 2:09 下午

呵呵,我也是,那么远的键,不过还好,C-c基本上99%的状况下能代替ESC,我碰到的只有C-v I的状况下不能代替

[回复]

chapter7 回复:
五月 1st, 2010 at 10:18 上午

@ahei,
VIM中 C-[ 是跟ESC等价的

[回复]

ahei 回复:
五月 1st, 2010 at 12:30 下午

呵呵,没有C-c好按

 

 

 

曾经vim对emacs最大的优点就是长期使用emacs会致使左手小拇指健康情况恶化,甚至肌肉萎缩(众所周知vim是esc到死,而emacs是ctrl到死),以致于许多用emacs的大牛如今只能单手coding。

若是按做者的方法把Esc改成c+]的话,只怕vimer也会在不久的未来面临严重的亚健康问题。

目前相对合理的作法仍是交换caps和esc的键值(for vimer)或者交换caps和ctrl的键值(for emacser),具体的交换方法网上有不少,搜索就是。

另一个折中的办法对苹果用户比较适用,设置苹果的command键为ctrl,这样的话,小拇指的压力就转移到肌肉发达的大拇指上了。如此无疑会好上许多。

我已经告别 ESC 了.如今已经习惯了ctrl+[
(其实也就适应了不到一周)
我还看到了朋友说 将 capslock 与 esc 互换.这样作也很好.
可是…
若是你在本机习惯了 capslock 与 esc 互换.换了其它机器 … 就不方便了 .

 

把emacs的ctrl映射到windows键盘的windows键就能够用大拇指按ctrl了。原本emacs设计的时候,ctrl键就是用大拇指按的。用默认ctrl位置,用手掌压,而不要用小拇指按也是省力和一种保护

有个高人专门写文章研究了ctrl的问题,考证出 emacs发明时代的键盘布局和现代键盘不一样,当时的键盘ctrl键在大拇指可及的位置。最后做者建议,ctrl键正确的使用方法是使用手掌去按

 

 

事实上 Vim 在 Insert 模式下也支持 Emacs 的不少按键,若是你只是想要一个编辑器的话,Emacs 反而很罗嗦。固然若是你须要学 Lisp 编程或者研究理想化的操做系统,Emacs 才是有必要用的。

 

vim中 ctrl+[ 能够代替esc... 我也习惯用ctrl+[

lz错了,emacs不须要用小指。改下键盘vim和emacs均可以很是舒服,而且能够同时使用。我就是这么干的,有时用vim,有时用emacs。
说下个人作法:
1.esc和capslock兑换
2.左边的control和alt兑换。
由于原来的emacs发明者用的键盘就相似这样的。
至于兑换的方法,网上有不少,能够搜下。
按键不是emacs和vim的根本区别

 

vim ESC Ctrl-[  替换为CapsLock的方法

在 ~/.Xmodmap 中加入如下几行,没有这个文件的话就建立一个:
remove Lock = Caps_Lock
keysym Escape = Caps_Lock
keysym Caps_Lock = Escape
add Lock = Caps_Lock

仅适用于 Unix.
注:若是想要 CapsLock 的功能,除了按 Escape 外,还能够先所有小写,而后 gU

图形界面下,还能够

  1. System -> Preferences -> Keyboard
  2. Select Layouts tab, then Layout Options
  3. Click on 'CapsLock key behavior'
  4. Click on 'Swap ESC and CapsLock'

http://www.cnblogs.com/sunza/archive/2011/08/20/2146935.html

 

 

 

#############################

我是如何从vim转向Emacs的

http://emacser.com/from-vi-to-emacs.htm

之前,我屡次试图从 vim 转变到 emacs 都失败了。缘由不少,主要缘由是 vim 的确一个很强大的 editor 不愧为 emacs 的主要竞争对手,vim 不少强大的功能,很难在 emacs 中找到相应的功能,那个时候尚未水木Emacs版,若是有的话,状况会好一些, 还有一个缘由就是我周围几乎没有人用 emacs ,如今也是。

emacs 的入门比较 vim 要困难不少,我指的入门不是指简单的使用,而是高效的使用。vim 的不少操做几乎不须要配置就能够完成了,可是若是离开我那些复杂的 .emacs 文件,我认为 emacs 并不比 vim好。有了个人 .emacs , emacs 绝对是最好的 platform (not only an editor) ,由于他是个人软件,一些我经常使用的功能,都是按照个人方式工做的,并且我能够随时实现我喜欢的功能,也许别人不喜欢这样的操做,可是我喜欢,我可让 emacs 让我喜欢的方式操做。几乎没有其它软件能够作到这一点。

我转变到 emacs 是一个痛苦和偶然的过程。我曾经煞有介事的“学习” emacs , 写了不少笔记,如今看来,很傻,emacs 不是学出来的,是用出来的,不少功能不是用脑子记住的,而是用手记住的,咱们不得不认可,有的时候肌肉的记忆能力,要比脑子的记忆能力强,并且快速,实用。不少体育运动员不就是用大量的训练提升肌肉对动做的记忆吗?

一次偶然的机会我发现了几个 vim 没法代替的几个功能,因而我开始真正喜欢 emacs 了。(注:笔者作此文时,vim版本为6.2)

首先是编写 TeX 文件的时候,不少数学符号能够快速的输入,能够方便的生成 dvi 文件,能够快速的输入 TeX 特有的特殊符号。

而后是 Python mode ,他是很是好的 Python 的 IDE ,能够很容易的编写 Python 程序,尤为是 Python 程序中用缩进来表示语法结构,在Emacs中很容易处理缩进。很容易把一段代码放入到Python 的解释器中执行,而后在解释器中交互的测试程序。参见 个人Python 学习笔记

一个编辑 C or C++ 的时候的一些功能,例如 auto insert 功能,hungry delete, M-SPC(M-x just-on-space) indent 功能 (TAB) ,在 emacs 中写出来的程序,是最漂亮的格式。最重要的是还能够选择本身喜欢的 c style 。 固然 vim 中也能够,可是默认的是用 tab 键格式化 ,这样的缺点就是不能保证程序在全部的编辑器中都是同样的效果,可是我之前也用 TAB 来 indent ,缘由是我不肯意输入不少 space 。并且 vim 对从新 indent 一段代码的功能也不是很好,尽管 g= 等等键也能够工做,可是不如 emacs 中的好。

vim 中的不少编辑命令要比 emacs 快的多,只要输入不多的键。

可是, 我认为中 emacs 的理念是,有不少工做,作好不要让用户记住那些快键,按照用户的习惯,猜测用户(主人)的意思,默默的作好(讨好用户)就好了。

例如,在 C 中,咱们习惯用 tab 键来 indent 程序。那么就用 tab 键来 完成 M-x indent-line 的功能。咱们常常在输入分号以后, 输入一个回车,那好,emacs 就根据上下文猜想应该回车的地方,自动回车。你想删除不少空格,那好,emacs 就会根据上下文,只留下一个空格(M-x just-on-line) 或者空行(M-x delete-blank-line) ,若是你在只有一个空行下还要 M-x delete-blank-line ,那么就把single blank line 也删掉。

还有的功能也很好用。

? View Code LISP
1
2
C-c C-c (M-x comment-region) C-u C-c C-c uncomment-region

还有自动补齐右边括号,补齐引号的功能,还有补齐大花括号的功能。 参见Emacs 中自动添加有半边括号的功能写C程序,输入左大花扩号自动补齐不少东西

还有 abbrivate 扩展的功能。

还有 fly spell 的功能。 emacs 知道主人是个粗心的人自动提示主人错了,可是 emacs 历来不把主人当傻瓜,不会自做聪明的改动,只有主人真的认可说,我错了 (按M-$)(注:我记不住具体的M-x 命令了,能够用C-h k 查一个键的bind 的函数,记作 help key bind , 也能够用 C-h w 记作 help where, 查找一个函数的快键是什么 ) ,emacs 就提示不少可选的单词,供主人选择。 我记得有一个著名的把用户看成傻瓜的软件,老是把句子的行首单词Capitalize,并且自动把他认为错了的单词改过来,每次我都要费尽心机想办法,怎么把这个功能关掉。

还有 auto fill 的功能, M-q 也总能干正确的事情。

还有 version control 的功能,emacs 几乎不用主人亲自备份文件了,他知道应该在合适的时候,备份文件。

还有 auto insert 的功能,他会自动根据环境,把当前的文件增长可执行权限,参见在保存文件的时候,会自动给脚本增长可执行权限

还能够自动增长

#!/bin/bash or #!/bin/perl #!/bin/python

参见Emacs 在建立文件的时候,自动添加 template 的内容

header.el的扩展还能够自动插入和更新 C 文件中的开头的一些信息,包括文件名称,建立日期,改动次数,纪录谁在何时为何作了修改。还有公司信息,做者信息,版权信息等等。参见轻轻松松为源 程序增长文件头信息

还有 emacs 有不少程序无缝结合 ,如 python, perl,octave(matlab), gdb, pydb 等等,emacs 是最好的 IDE 了。

总之,驯化了的 emacs 是你的忠实的奴仆,他会按照主人的方式工做,猜测主人的意图。

然而,有的时候 emacs 是奔放的野马,老是难以驾驭,要想emacs按照主人的意志工做,那么主人就有义务详细的告诉他该如何工做。

有两种办法,一种是向其余主人学习,请教,按照他的办法驯化emacs 。

另外一种办法是掌握 emacs 的高级用法,只有了解他的语言,Elisp (Emacs Lisp) ,明白了 emacs 的语言,才可以和 emacs 很好的交流,沟通, emacs 是一个很听话的孩子。

若是要融入 emacs 的文化,或者叫理念,甚至叫宗教, 那么就要 Hack 他的程序,了解他的五脏六腑,作一个 hacker。(注: hacker is NOT cracker ) 除了安装emacs-x-xx.rpm 还要安装 emacs-el.x-xx.rpm , 而后用 M-x find-function 看任何一个函数是如何实现的

浏览了一下子,你会感到什么是自由软件,什么是真正的自由。只要你愿意,你能够探索任何一个功能是怎么实现的。

使用其余的软件的时候,我老是在想办法发现软件提供给我什么功能,我怎样按照软件定义好的方式工做,我怎么去适应软件。

若是运气很差,碰到一个自觉得是的软件,我会以为被软件的做者愚弄。

若是运气再差一点,我会以为被软件的做者侮辱,由于他把我当成傻瓜。

固然,也有运气好的时候,例如 vim,他的编辑方式是最快的方式。

可是 emacs 不一样,使用 emacs 的时候,我会想我喜欢用什么样的方式完成某个功能,大多数的状况,均可以简单的用global-set-key, or local-set-key 解决掉。若是功能很复杂,就查找一下是否是有人实现过了, emacs 的社区中有不少好心人www.emacswiki.org 是一个好地方。若是没有人实现,那么就本身写一个,而后贴到网上去。

开放,自由,这就是 emacs 。

emacs 老是想办法如何适用用户的方式,固然,缺点就是,初看上去 , emacs 不是很友好, 用户须要学习如何配置emacs 。

如今我很喜欢摆弄 emacs , 我知道,只要我想获得,emacs 通常是能够作获得, 固然我想的要合理,我想买彩票中500万,emacs 确定作不到 ,并且还不能和其余你须要的功能冲突。

有一项功能我一直没有想办法办到,就是相似source in sight 的自动搜索一个函数的 caller ,自动成员变量补全,class browser 等等。这个功能很难,由于他要包含语言的语法语义分析。C++ 中的 template , typedef , #define #if , inline function, inner class (or structure, enum) , name space等等的语言特性,增长了其难度

尽管 semantic 号称能够,可是和 source in sight 还有差距。我用了几回,很差用, ECB 也是不三不四。

我认为 semantic 的目标太大了,他要容纳全部语言的语法语义模糊分析的功能,这个很难,尽管他的做者是大名鼎鼎的 eric 。

我仍是很喜欢 semantic ,由于我相信他行,因而我试图hack semantic ,实现那些功能,尽管自动补全成员变量的功能,勉强能够了,可是其余复杂的功能,仍是很难实现。semantic 太复杂了。

可是一有时间,我仍是喜欢看上 semantic 几眼。

我这篇文章是用 notepad 编辑的,因而顺便列举一些 emacs 和 notepad 相似的功能,参见相似Notepad 基本操做快速入门

 

 

用CEDET浏览和编辑C++代码(续) – 使用Emacs 23.2内置的CEDET

http://emacser.com/built-in-cedet.htm

 

1 前言

今天,emacs-23.2发布了,最大的改变就是集成进了CEDET,因此有了这个续, 介绍下build in CEDET和offical CEDET的区别,以及内置CEDET缺乏某些功能的替代方案。

PS1:虽然如今官方release版本是1.0pre7,内置的CEDET用cedet-version命令看输入也是1.0pre7,可我总感受内置的CEDET用起来比官方版本慢不少,我猜测内置的CEDET可能没升级到1.0pre7的release。

PS2:内置CEDET不支持emacs-lisp语言了,没想明白是为何。

2 semantic配置

2.1 基本配置

官方的CEDET经过semantic-load-enable-minimum-features等几个函数来启动,而内置的CEDET增长了一个单独的minor mode,即semantic-mode,能够经过(semantic-mode)命令来Enable或Disable。

(semantic-mode)是经过semantic-default-submodes这个变量来决定启用哪些minor mode,默认的semantic-default-submodes包含了下面两个minor mode:

  • global-semantic-idle-scheduler-mode
  • global-semanticdb-minor-mode

根据(semantic-mode)的文档,semantic-default-submodes里能够设置下面这些minor mode:

  • 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

能够根据本身的须要设置,好比我开启了下面4个minor mode:

? View Code LISP
1
2
3
4
5
(setq semantic-default-submodes '(global-semantic-idle-scheduler-mode
                                  global-semanticdb-minor-mode
                                  global-semantic-idle-summary-mode
                                  global-semantic-mru-bookmark-mode)) (semantic-mode 1)

另外,emacs-23.2的Tools菜单下下新增了”Source Code Parsers (Semantic)”菜单项,能够经过这个菜单项来Enable和Disable semantic-mode,和命令(semantic-mode)的功能是同样的。

此外,官方CEDET里还有其它一些minor mode,如今基本上都还能够用,好比我还打开了下面几个:

? View Code LISP
1
2
3
(global-semantic-highlight-edits-mode (if window-system 1 -1)) (global-semantic-show-unmatched-syntax-mode 1) (global-semantic-show-parser-state-mode 1)

关于system-include-dir的设置,还和之前同样:

? View Code LISP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(defconst user-include-dirs
  (list ".." "../include" "../inc" "../common" "../public"         "../.." "../../include" "../../inc" "../../common" "../../public")) (defconst win32-include-dirs
  (list "C:/MinGW/include"         "C:/MinGW/include/c++/3.4.5"         "C:/MinGW/include/c++/3.4.5/mingw32"         "C:/MinGW/include/c++/3.4.5/backward"         "C:/MinGW/lib/gcc/mingw32/3.4.5/include"         "C:/Program Files/Microsoft Visual Studio/VC98/MFC/Include")) (let ((include-dirs user-include-dirs))   (when (eq system-type 'windows-nt)     (setq include-dirs (append include-dirs win32-include-dirs)))   (mapc (lambda (dir)           (semantic-add-system-include dir 'c++-mode)           (semantic-add-system-include dir 'c-mode))         include-dirs))

2.2 代码跳转

代码跳转和官方版本同样仍是用semantic-ia-fast-jump命令,不过在emacs-23.2里直接用这个命令可能会报下面的错误:

? View Code TEXT
semantic-ia--fast-jump-helper: Symbol's function definition is void: semantic-analyze-tag-references

这多是emacs的bug,semantic-analyze-tag-references这个函数是定义在semantic/analyze/refs.el这个文件中的,而semantic/ia.el里写的是(eval-when-compile (require ’semantic/analyze/refs)),因此运行时这个feature没被load进来,咱们须要本身load一下:

? View Code LISP
(require 'semantic/analyze/refs)

另外,官方CEDET里semantic-ia-fast-jump后能够经过命令semantic-mrub-switch-tags来回到曾经跳转过的地方,不过在emacs-23.2里会提示:

Semantic Bookmark ring is currently empty

这是由于semantic-ia-fast-jump会用函数push-mark把跳过的地方放到mark ring里去,官方CEDET经过定义push-mark的advice把它也放到了semantic-mru-bookmark-ring里去,semantic-mrub-switch-tags就是从semantic-mru-bookmark-ring来找位置的,但build in的CEDET里把push-mark的advice去掉了,因此semantic-mru-bookmark-ring老是空的,个人办法是把官方CEDET里对push-mark的device拷贝到个人.emacs中来:

? View Code LISP
1
2
3
4
5
6
7
8
(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)

这样,我之前写的semantic-ia-fast-jump-back函数也能用了:

? View Code LISP
1
2
3
4
5
6
7
8
9
10
(defun semantic-ia-fast-jump-back ()   (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)))

对这个函数须要说明一下:网友fangzhzh提过能够用C-u C-space来跳回原来的mark,ahei说能够用C-x C-x来跳回,可我测试这两个按键好像跳得都有点乱,不能和semantic-ia-fast-jump的位置对应。我估计是这两个key是跳回push-mark函数mark的位置,而push-mark不光CEDET用。个人需求是只跳回semantic-ia-fast-jump曾经到过的地方,因此仍然保留了这个函数。

个人习惯仍是绑定到F12上:

? View Code LISP
1
2
3
4
5
6
7
8
(defun semantic-ia-fast-jump-or-back (&optional back)   (interactive "P")   (if back
      (semantic-ia-fast-jump-back)     (semantic-ia-fast-jump (point)))) (define-key semantic-mode-map [f12] 'semantic-ia-fast-jump-or-back) (define-key semantic-mode-map [C-f12] 'semantic-ia-fast-jump-or-back) (define-key semantic-mode-map [S-f12] 'semantic-ia-fast-jump-back)

这儿多出来个semantic-ia-fast-jump-or-back函数,是由于我有时候在putty里操做远程的emacs,putty里用不了S-f12这个key,因此我把f12绑定到semantic-ia-fast-jump-or-back上,这样我能够在putty里经过C-u f12来跳回。

之前的semantic-analyze-proto-impl-toggle命令还能用:

? View Code LISP
(define-key semantic-mode-map [M-S-f12] 'semantic-analyze-proto-impl-toggle)

2.3 代码补全

官方版本里能够用命令semantic-ia-complete-symbol-menu弹出semantic的补全菜单,不过这个命令在内置的CEDET里不存在了(多是由于emacs官方版本认为这个命令只在GUI下能用,不够通用吧)。

不过,内置的CEDET却是能够经过命令complete-symbol(默认绑定到ESC-TAB)在另外一个buffer里显示可能补全的内容,像这样:

semantic的complete-symbol

若是还但愿能使用补全菜单,能够使用其它插件,好比auto-complete或company-mode:company-mode-0.5已经能够支持emacs内置的CEDET了;auto-complete-1.2对内置CEDET的支持还有些问题,关于如何配置auto-complete-1.2让它支持内置的CEDET,我准备另外写文章介绍。

3 EDE配置

ede和官方版本没有区别,仍然用(global-ede-mode t)启用就好了;不过emacs-23.3的Tools菜单下新增了”Project support (EDE)”菜单项,能够完成global-ede-mode同样的功能。

4 其它

4.1 可视化书签

官方CEDET里的visual-studio-bookmarks在内置的CEDET里没有了,因此我如今使用bm了。

4.2 pulse

pulse的功能在内置CEDET里还存在,不过官方CEDET里能够用pulse-toggle-integration-advice函数来切换pulse,在内置CEDET里这个函数消失了,如今的办法是设置pulse-command-advice-flag变量来切换:

? View Code LISP
(setq pulse-command-advice-flag (if window-system 1 nil))

另外,官方版本里对下面这些函数设置了pulse的device:

  • goto-line
  • exchange-point-and-mark
  • find-tag
  • tags-search
  • tags-loop-continue
  • pop-tag-mark
  • imenu-default-goto-function

内置版本里这些device都没了,因此我直接把官方版本里的advice拷贝过来了:

? View Code LISP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
(defadvice goto-line (after pulse-advice activate)   "Cause the line that is `goto'd to pulse when the cursor gets there."   (when (and pulse-command-advice-flag (interactive-p))     (pulse-momentary-highlight-one-line (point)))) (defadvice exchange-point-and-mark (after pulse-advice activate)   "Cause the line that is `goto'd to pulse when the cursor gets there."   (when (and pulse-command-advice-flag (interactive-p)              (> (abs (- (point) (mark))) 400))     (pulse-momentary-highlight-one-line (point)))) (defadvice find-tag (after pulse-advice activate)   "After going to a tag, pulse the line the cursor lands on."   (when (and pulse-command-advice-flag (interactive-p))     (pulse-momentary-highlight-one-line (point)))) (defadvice tags-search (after pulse-advice activate)   "After going to a hit, pulse the line the cursor lands on."   (when (and pulse-command-advice-flag (interactive-p))     (pulse-momentary-highlight-one-line (point)))) (defadvice tags-loop-continue (after pulse-advice activate)   "After going to a hit, pulse the line the cursor lands on."   (when (and pulse-command-advice-flag (interactive-p))     (pulse-momentary-highlight-one-line (point)))) (defadvice pop-tag-mark (after pulse-advice activate)   "After going to a hit, pulse the line the cursor lands on."   (when (and pulse-command-advice-flag (interactive-p))     (pulse-momentary-highlight-one-line (point)))) (defadvice imenu-default-goto-function (after pulse-advice activate)   "After going to a tag, pulse the line the cursor lands on."   (when pulse-command-advice-flag
    (pulse-momentary-highlight-one-line (point))))

另外,我还喜欢对下面这些函数定义pulse:

? View Code LISP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
(defadvice cua-exchange-point-and-mark (after pulse-advice activate)   "Cause the line that is `goto'd to pulse when the cursor gets there."   (when (and pulse-command-advice-flag (interactive-p)              (> (abs (- (point) (mark))) 400))     (pulse-momentary-highlight-one-line (point)))) (defadvice switch-to-buffer (after pulse-advice activate)   "After switch-to-buffer, pulse the line the cursor lands on."   (when (and pulse-command-advice-flag (interactive-p))     (pulse-momentary-highlight-one-line (point)))) (defadvice previous-buffer (after pulse-advice activate)   "After previous-buffer, pulse the line the cursor lands on."   (when (and pulse-command-advice-flag (interactive-p))     (pulse-momentary-highlight-one-line (point)))) (defadvice next-buffer (after pulse-advice activate)   "After next-buffer, pulse the line the cursor lands on."   (when (and pulse-command-advice-flag (interactive-p))     (pulse-momentary-highlight-one-line (point)))) (defadvice ido-switch-buffer (after pulse-advice activate)   "After ido-switch-buffer, pulse the line the cursor lands on."   (when (and pulse-command-advice-flag (interactive-p))     (pulse-momentary-highlight-one-line (point)))) (defadvice beginning-of-buffer (after pulse-advice activate)   "After beginning-of-buffer, pulse the line the cursor lands on."   (when (and pulse-command-advice-flag (interactive-p))     (pulse-momentary-highlight-one-line (point))))

4.3 h/cpp切换

官方CEDET里的eassist.el没有了,因此eassist-switch-h-cpp也没了,如今我用sourcepair代替,sourcepair比eassist-switch-h-cpp更好用。

4.4 代码折叠

semantic-tag-folding.el没有了,可我没找到其它更好的替代方案,因此我把官方CEDET里的semantic-tag-folding.el拷过来了,只须要把文件中(require ’semantic-decorate-mode)替换成(require ’semantic/decorate/mode)就能像之前同样用了。

之前的senator-fold-tag功能还能够使用。

最后插播个广告,我关于内置CEDET的配置(最后那部分):http://github.com/meteor1113/dotemacs/blob/master/init-basic.el

 

 

 

在Emacs下用C/C++编程

http://emacser.com/emacs-cpp-dev.htm

 

1 参考文献

按照惯例,我写的文章在最开始处放参考文献。

  • hhuu @ newsmth 的《Emacs的平常生活》
  • emacs 的文档
  • emacs 相关插件的文档

2

用emacs写程序也有5个年头了,深切地体会到Emacs的强大。程序员有三种,一种是用vi的,一种是用emacs的,还有一种是其余。或许有些夸张,但也颇能体现出emacs在程序员中的地位。

emacs最大的问题在于入门门槛较高。它看起来和多数人想象中的IDE相差甚远,不少人看到emacs的第一眼就以为它是个记事本(仍是个很是难用的记事本),稍微好些的每每以为emacs也就是个ultraEditor而已,真是暴殄天物了。

我是个懒人,不喜欢记太多的快捷键,相信不少人和我同样。因此从我后面的叙述能够看出来,除了经常使用的命令都是快捷键外,其余命令多数都是用M-x执行或者用鼠标点菜单。这仅仅是我的风格问题,先说明一下。

个人基本编程环境是:

  • Debian GNU/Linux sid 操做系统
  • Gnome 2.10.0 桌面环境
  • GUN Emacs 23.0.0.1 for debian
  • 使用 Gnu tool chains(gcc,make,gdb等等)

后面的叙述都基于上述环境。另外,本文主要针对C/C++程序开发,对其余语言有些也适用,从难度上说,本文主要针对入门者。

本文确定会有不少错误,请指正, 谢谢。

3 基本流程

写C++程序基本上是这么几个步骤:

  1. 编辑代码
  2. 编写Makefile
  3. 编译代码,修改编译错误
  4. 调试代码,修改逻辑错误

固然,每每还须要阅读别人的代码。

根据上述步骤,本文主要针对如下几个方面:

  • 配置Emacs,创建便利的代码编辑环境和Makefile编写环境。
  • 在Emacs中编译代码,并修改编译错误。
  • 在Emacs中配合GDB调试程序。
  • 利用cscope和ecb在emacs中阅读代码

4 基本环境设置

4.1 编辑环境配置

要写C++程序,固然要用到cc-mode插件。CC-Mode本来是支持C语言的,但如今也能支持不少语言,好比 C++,Java,Objective-C,CORBA,AWK,Pike等等。CC-Mode是gnu-emacs的标准插件。若是您要求不高,那么默认的配置或许就能知足。CC-Mode的各类行为均可以自由地定制,您能够参考这里的文档:CC-Mode参考文档

这里是个人.emacs文件中关于CC-Mode配置的部分,仅供参考:

1
2
3
4
5
;;;; CC-mode配置 http://cc-mode.sourceforge.net/ (require 'cc-mode) (c-set-offset 'inline-open 0) (c-set-offset 'friend '-) (c-set-offset 'substatement-open 0)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
;;;;个人C/C++语言编辑策略  (defun my-c-mode-common-hook()   (setq tab-width 4 indent-tabs-mode nil)   ;;; hungry-delete and auto-newline   (c-toggle-auto-hungry-state 1)   ;;按键定义   (define-key c-mode-base-map [(control \`)] 'hs-toggle-hiding)   (define-key c-mode-base-map [(return)] 'newline-and-indent)   (define-key c-mode-base-map [(f7)] 'compile)   (define-key c-mode-base-map [(meta \`)] 'c-indent-command)   ;; (define-key c-mode-base-map [(tab)] 'hippie-expand)   (define-key c-mode-base-map [(tab)] 'my-indent-or-complete)   (define-key c-mode-base-map [(meta ?/)] 'semantic-ia-complete-symbol-menu)

注意一下,上面最后两行是代码自动补齐的快捷键。后面我会提到代码自动补齐。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
;;预处理设置 (setq c-macro-shrink-window-flag t) (setq c-macro-preprocessor "cpp") (setq c-macro-cppflags " ") (setq c-macro-prompt-flag t) (setq hs-minor-mode t) (setq abbrev-mode t) ) (add-hook 'c-mode-common-hook 'my-c-mode-common-hook)  ;;;;个人C++语言编辑策略 (defun my-c++-mode-hook() (setq tab-width 4 indent-tabs-mode nil) (c-set-style "stroustrup") ;; (define-key c++-mode-map [f3] 'replace-regexp) )

4.2 自动补齐

自动补齐一般用的都是hippie-expand,我也用了很长时间。不过有时候会以为这个自动补齐“傻”了一点,常会补齐出一些绝不相干的东西,由于hippie-expand是根据你敲过的词和kill-ring等进行判断的,并不对程序语法进行分析。

因此你还须要安装一个代码分析工具,而后把它加进hippie-expand的扩展策略里去。咱们能够用semantic。实际上,hippie-expand+semantic是我所发现的最好的选择了,若是您有更好的,请您也告诉我一声:)

Semantic是CEDET 中的一个工具,CEDET是Collection of Emacs Development Environment Tools的缩写,它包含了好几个工具,都挺不错的。惋惜我只会用其中两个。

您能够在.emacs中对Semantic进行配置,下面是个人.emacs相关的配置,仅供参考:

导入cedet:

(load-file "~/lib/emacs-lisp/cedet-1.0pre3/common/cedet.el")

配置Semantic的检索范围:

1
2
3
(setq semanticdb-project-roots (list (expand-file-name "/")))

自定义自动补齐命令,这部分是抄hhuu的,若是在单词中间就补齐,不然就是tab。

1
2
3
4
5
6
7
8
(defun my-indent-or-complete ()   (interactive)   (if (looking-at "\\>")       (hippie-expand nil)     (indent-for-tab-command))   )  (global-set-key [(control tab)] 'my-indent-or-complete)

hippie的自动补齐策略,优先调用了senator的分析结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
(autoload 'senator-try-expand-semantic "senator")  (setq hippie-expand-try-functions-list       '(         senator-try-expand-semantic
        try-expand-dabbrev
        try-expand-dabbrev-visible
        try-expand-dabbrev-all-buffers
        try-expand-dabbrev-from-kill
        try-expand-list         try-expand-list-all-buffers
        try-expand-line
        try-expand-line-all-buffers
        try-complete-file-name-partially
        try-complete-file-name         try-expand-whole-kill
        )       )

注意一下我前面CC-Mode配置中有这么两行:

1
2
(define-key c-mode-base-map [(tab)] 'my-indent-or-complete) (define-key c-mode-base-map [(meta ?/)] 'semantic-ia-complete-symbol-menu)

这样,咱们在CC-Mode中就能够调用自定义的hippie补全了,快捷键是Tab。

另外,我还把快捷键“Alt + / ”绑定到了semantic-ia-complete-symbol-menu命令上,这是semantic的命令,它会根据分析结果弹出补齐的菜单,效果如图显示:

自动补齐效果图

CEDET中还有一个不错的工具是speedbar,你能够用它在多个文件中快速切换。在个人.emacs配置文件里,我把speedbar关联到了F5上:

(global-set-key [(f5)] 'speedbar)

这样用F5就能够调出speedbar,效果以下:

speedbar

不过说实话,我本身不多用到speedbar,我一般都是用dired配合bookmark使用:)

5 编译和调试程序

按上面的配置,写完程序和Makefile文件后,在Emacs源代码窗口中按F7就能够进行编译。由于在my-c-mode-common-hook()函数里,有这么一行:

(define-key c-mode-base-map [(f7)] 'compile)

默认状况下,emacs的compile命令是调用make -k,我把它改为了make。你也能够把它改为其余的,好比gcc之类的。改下面的“make”就好了。

'(compile-command "make")

Emacs会划分一个窗格显示编译的消息,在编译结束后,emacs会自动将编译器的输出和程序关联起来,告诉你第几行的程序有问题。直接在出错的行号上按Enter,就能够跳转到相应文件的相应行。其实我一般都是用鼠标中键去点出错行号:)

搞定了编译错误后,接着要和逻辑错误斗争了。其实对简单的程序来讲,把中间结果打印到终端是最简单好用的调试办法:)不过稍微复杂点的程序就会晕菜了,这时咱们就须要拿gdb跟踪程序流程了。

你用下面的命令就能够启动gdb了。

M-x gdb

一般我喜欢进入gdb-many-windows模式,这样就会把一个Frame划分为5个窗格,同时显示:gdb命令窗口,当前局部变量,程序文本,调用栈和断点。

gdb的命令就不在这里说了,它的文档几乎处处都是。emacs把gdb的命令和快捷键作了绑定,对于经常使用的命令,仍是输入快捷键比较方便。好比,C-c C-n是Next line,C-c C-s是step in,其实用的最多的快捷键也就是这两个。

下面是个人gdb效果图:

GDB

6 阅读代码

在emacs下读代码一般有三种工具,最简单的是etags,最复杂的是ecb(emacs code browser),位于中间的是cscope。

etags和ctags同样,只不过前者是用于emacs的,后者是用于vi的。我我的以为etags功能稍稍显得不够用一点,固然,也多是我用的很差:) 欢迎大牛指导。

使用tags以前要先对源代码分析创建tags文件,在代码所在目录中运行:etags -R 便可。

我经常使用的就这几个命令和快捷键:

M-x visit-tags-table <RET> FILE <RET>   选择tags文件
M-. [TAG] <RET>                         访问标签
M-*                                     返回
C-u M-.                                 寻找标签的下一个定义

ecb听说功能强大,可是太复杂了,我懒得折腾它。谁搞定了教教我吧:) 下面是一张ecb的效果图。

cscope是我感受比较合适的一个工具。它实际上是一个独立的软件,彻底能够脱离vi和emacs使用。可是结合emacs的强大功能,cscope就显得更加方便了。GNU Emacs默认自带cscope的支持。在使用以前,cscope也须要对代码进行索引。在emacs中能够这样作:

C-c s a             设定初始化的目录,通常是你代码的根目录
C-s s I             对目录中的相关文件创建列表并进行索引

建完索引以后,你就能够用cscope在代码里游荡了。经常使用的一些命令以下:

C-c s s             序找符号
C-c s g             寻找全局的定义
C-c s c             看看指定函数被哪些函数所调用
C-c s C             看看指定函数调用了哪些函数
C-c s e             寻找正则表达式
C-c s f             寻找文件
C-c s i             看看指定的文件被哪些文件include

上面这些快捷键其实我本身也经常记不全,不要紧,抬头看看上面的菜单栏,有一栏就是Cscope,这些命令里头都有:)

贴一个cscope的效果图吧:

cscope

写完了。但愿这篇文章对您能有一些用处。有问题或建议能够和 联系。

 

 

用CEDET浏览和编辑C++代码

http://emacser.com/cedet.htm

 

1 前言

网上关于如何用emacs+cedet作C++ IDE的文章已经不少了,但是大都只列出了配置文件和效果,没有讲清楚具体的配置过程;一篇讲得比较具体的文章(http://alexott.net/en/writings/emacs-devenv/EmacsCedet.html ,这篇文章是被cedet官方推荐的)仍是英文的。刚接触cedet的用户常常照抄了别人的配置却发现不能补全,并且配置文件是别人的想改还没法下手。本文中我尽可能详细解释各个语句的做用,但愿能给初次接触的人提供点帮助。

cedet于2010年2月26日发布了1.0pre7,强烈建议之前用过cedet以为速度慢而放弃的同窗试试1.0pre7,这个版本速度比之前有很大很大提升。

2 简介

cedet是一堆彻底用elisp实现的emacs工具的集合,主要有:

2.1 EDE

用来管理项目,它能够把emacs模拟得像一个IDE那样,把一堆文件做为一个project来管理。

2.2 Semantic

Semantic应该是cedet里用得最多的组件了,代码间跳转和自动补全这两大功能都是经过semantic来实现的

2.3 SRecode

SRecode是一个模板系统,经过一些预约义的模板,能够很快地插入一段代码。我的以为这个功能跟msf-abbrev和yasnippet的功能有些相似。

2.4 Cogre

全称叫”Connected Graph Editor”,主要和图形相关,好比能够用它来为C++类生成UML图。

2.5 Speedbar

Speedbar能够单首创建一个frame,用于显示目录树,函数列表等等。这个组件已经包含在emacs官方发布包中。

2.6 EIEIO

EIEIO是一个底层库,它为elisp加入了OO支持。cedet的其它组件都依赖于EIEIO。

3 安装

安装就很少说了,这儿详细说明了如何下载安装。

要注意的是经过cvs下载必需要编译后才能用,而官方发布后的包能够直接解压不编译也是能用。

安装完后首先固然要load它(确保安装的路径已经在load-path中了):

(require 'cedet)

4 semantic配置

先介绍一下最经常使用的semantic。

4.1 功能介绍

通常装插件的思路,都是先load而后enable某个minor mode。cedet基本上也遵循这个规则,不过有点区别是semantic定义了不少个mode,要是挨个去enable,用户可能就要骂娘了,因此cedet的做者Eric定义了几个方便使用的函数,这些函数会自动帮你enable某些minor mode,大概有这么几个:

1
2
3
4
5
(semantic-load-enable-minimum-features) (semantic-load-enable-code-helpers) (semantic-load-enable-guady-code-helpers) (semantic-load-enable-excessive-code-helpers) (semantic-load-enable-semantic-debugging-helpers)

简单介绍一下各个函数的功能:

4.1.1 semantic-load-enable-minimum-features

这个函数开启了最基本的三个特性:

  • semantic-idle-scheduler-mode

    enable这个mode让cedet在emacs空闲的时候自动分析buffer内容,好比正在编辑的buffer内容改变后。这个mode通常应该是须要enable的,若是没有enable这个mode,那只有手工触发才会让cedet从新分析。

  • semanticdb-minor-mode

    semanticdb是semantic用来保存分析后的内容的,因此也是应该enable的。

  • semanticdb-load-ebrowse-caches

    这个feature我不是很肯定,大概的意思好像是semantic能够利用ebrowse的结果。这个feature大概就是把ebrowse生成的文件load给semantic使用。(要是谁了解这个feature具体意义请告诉我下)

4.1.2 semantic-load-enable-code-helpers

这个函数除enable semantic-load-enable-minimum-features外,还包括:

  • imenu

    这个feature可让imenu显示semantic分析出的类,函数等tags。如图:

    imenu显示semantic分析出的类

  • semantic-idle-summary-mode

    打开这个mode以后,光标停留在一个类/函数等tag上时,会在minibuffer显示出这个函数原型,如图:

    用ssemantic在minibuffer显示函数原型

  • senator-minor-mode

    senator开启以后,会在emacs上增长一个senator的菜单,能够经过菜单在当前文件的各个tag之间先后移动,跳转;还能够在里面方便地打开/关闭某个feature;还有另一些实用的功能,看看菜单大概就能明白:

    senator菜单

  • semantic-mru-bookmark-mode

    cedet有tag跳转的功能,可是常常跳转完后还须要跳回刚才的位置,这时候就须要mru-bookmark-mode了。打开这个mode以后,每次跳转semantic都会把位置看成书签同样记录下来,之后能够经过M-x semantic-mrub-switch-tags(绑定到按键C-x B上)来选择跳回之前的任意一个位置。

4.1.3 semantic-load-enable-gaudy-code-helpers

这个函数除enable semantic-load-enable-code-helpers以外,还包括:

  • semantic-stickyfunc-mode

    这个mode会根据光标位置把当前函数名显示在buffer顶上,如图:

    在head-line上显示函数名

    这个mode我以为用处不大,由于基本上能够用which-func-mode代替。并且我习惯打开tabbar-mode,这个mode会覆盖tabbar-mode,因此我是不打开它的。

  • semantic-decoration-mode

    打开这个mode后,semantic会在类/函数等tag上方加一条蓝色的线,源文件很大的时候用它能够提示出哪些是类和函数的头。如图:

    semantic标记函数头

  • semantic-idle-completions-mode

    这个mode打开后,光标在某处停留一段时间后,semantic会自动提示此处能够补全的内容。好比下面这段代码:

    semantic自动补全当前光标内容

    若是把光标停留在”this->”的后面,稍隔一会会提示:

    semantic自动补全当前光标内容

    若是提示的函数不是须要的,按TAB键能够在各个可能的函数之间循环,按回车就能够肯定了。

4.1.4 semantic-load-enable-excessive-code-helpers

这个函数除enable semantic-load-enable-gaudy-code-helpers以外,还包括:

  • semantic-highlight-func-mode

    打开这个mode的话,semantic会用灰的底色把光标所在函数名高亮显示,以下图中,函数Delete被高亮了,而LexicalCast没被高亮:

    semantic高亮当前函数

  • semantic-idle-tag-highlight-mode

    用过XCode或eclipse的人应该会喜欢高亮光标处变量的功能:就是在函数内部,光标停留在一个变量上,整个函数内部用这个变量的地方都高亮了。在emacs里只要打开semantic-idle-tag-highlight-mode,光标在变量处停留一会,就会把相同的变量全都高亮,好比下图中的变量mAddr:

    semantic智能高亮当前符号

    semantic的这个tag-highlight虽然智能,但是我感受它显示得太慢了,因此我是用另外一个插件highlight-symbol来高亮的,这儿有它的介绍。

  • semantic-decoration-on-*-members

    把private和protected的函数用颜色标识出来,如图:

    semantic用颜色区分方法的访问权限

  • which-func-mode

    这个其实就是emacs自带的which-function-mode,把光标当前所在的函数名显示在mode-line上。

4.1.5 semantic-load-enable-semantic-debugging-helpers

这个函数会enable几个和调试semantic相关的特性:

  • semantic-highlight-edits-mode

    打开这个mode后,emacs会把最近修改过的内容高亮出来,以下图中begin就是刚输入的,因此用灰底色高亮了:

    semantic高亮最近修改

    隔一段时间后高亮会自动取消,不会一直高亮着让整个buffer看起来混乱。

    其实emacs自带也有高亮修改内容的mode:highlight-changes-mode,它会用红色的字体高亮全部修改的内容,可是不会自动取消,因此修改多了整个buffer就会乱七八糟糕。用semantic这个就好多了。

  • semantic-show-unmatched-syntax-mode

    这个mode会把semantic解析不了的内容用红色下划线标识出来,好比下面这个文件是从emacs源代码中来的:

    semantic用红色下划线标记不匹配的语法

  • semantic-show-parser-state-mode

    打开这个mode,semantic会在modeline上显示出当前解析状态,这是关闭mode的样子:

    这是打开mode的样子:

    能看出modeline上文件名前的横线多了一条,其实倒数第二条就是用来显示当前semantic解析状态的:未解析时显示为”!”,正在解析时显示”@”,解析完后显示”-”,若是buffer修改后未从新解析显示为”^”。

    semantic会在空闲时自动解析,另外能够打开senator-minor-mode,按[C-c , ,]或者在senator菜单中选[Force Tag Refresh]强制它立刻解析。

4.2 基本配置

了解了上面这些feature,就能够根据须要配置了,为了使用semantic,至少须要开启semantic-load-enable-minimum-features定义的三个基础feature,其他的feature就能够根据本身的须要开启了。好比个人配置是:

1
2
3
4
5
;; (semantic-load-enable-minimum-features) (semantic-load-enable-code-helpers) ;; (semantic-load-enable-guady-code-helpers) ;; (semantic-load-enable-excessive-code-helpers) (semantic-load-enable-semantic-debugging-helpers)

由于imenu,idle-summary-mode,senator-mode,mru-bookmark-mode都是我须要的。特别是senator,有时候我会碰到semantic等好久也不自动解析文件的问题,这时候就须要在senator菜单里[Force Tag Refresh]一下了,而且senator还能够经过菜单方便地打开和关闭某些mode,用起来仍是很方便的。

(semantic-load-enable-guady-code-helpers)和(semantic-load-enable-excessive-code-helpers)定义的那些feature,对我来讲用处不大,并且我感受打开的话还会让emacs反应变慢,因此我就不启用了。

(semantic-load-enable-semantic-debugging-helpers)的几个feature我都比较喜欢,因此我也启用了。

有了这些基本配置,在emacs打开C和C++文件的时候,semantic就会自动解析文件。不过有个问题,一个cpp文件中确定会include不少头文件,要想解析这个cpp的内容,头文件的信息是必要的;可是头文件可能和cpp放在一块儿,也可能放在系统某个目录下,semantic怎么才能找到这个头文件一块儿解析呢?

semantic是这样处理的:一、若是当前目录中能找到,就直接在当前文件中读取头文件。二、若是当前目录下没有,就上系统INCLUDE目录中去找(在Linux下,咱们通常使用gcc编译器,semantic会自动调用gcc,取得gcc的INCLUDE目录,好比/usr/include,/usr/local/include等,可是Windows下就不行了)。

BTW:不少文档中提到须要load semantic-gcc,不过我没有load它,在Linux下semantic仍然能自动把gcc的INCLUDE目录加进来。

semantic这种找法确定会形成大量的头文件找不到的(找不到头文件还怎么解析啊),有两个问题须要解决:一、不少工程中都会把头文件和实现文件分开放置,好比头文件放在include(或者inc,public,common等)目录中,实现文件放在src目录中,这些目录semantic是不能本身找的;二、在Windows下怎么能让semantic去找编译器的INCLUDE目录。

既然semantic不能自动查找找,那就只能咱们告诉semantic了,办法是调用semantic-add-system-include函数,这个函数会根据mode把路径加入到semantic-dependency-system-include-path里去。下面是个人配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
;; (setq semanticdb-project-roots (list (expand-file-name "/"))) (defconst cedet-user-include-dirs
  (list ".." "../include" "../inc" "../common" "../public"         "../.." "../../include" "../../inc" "../../common" "../../public")) (defconst cedet-win32-include-dirs
  (list "C:/MinGW/include"         "C:/MinGW/include/c++/3.4.5"         "C:/MinGW/include/c++/3.4.5/mingw32"         "C:/MinGW/include/c++/3.4.5/backward"         "C:/MinGW/lib/gcc/mingw32/3.4.5/include"         "C:/Program Files/Microsoft Visual Studio/VC98/MFC/Include")) (require 'semantic-c nil 'noerror) (let ((include-dirs cedet-user-include-dirs))   (when (eq system-type 'windows-nt)     (setq include-dirs (append include-dirs cedet-win32-include-dirs)))   (mapc (lambda (dir)           (semantic-add-system-include dir 'c++-mode)           (semantic-add-system-include dir 'c-mode))         include-dirs))

由于我在Windows下可能用MinGW和VC6,因此我把它们的include目录都加进来了,要是你用别的编译器,就改为本身的目录好了。

另外,我找了一些通常项目中常常用到的头文件目录名(include,inc,common,public),把它们也加进来了,这样对于通常的项目来讲基本上都能解析正确(好比咱们在项目中见到头文件放在include目录实现文件放在src目录的方式,对src目录下一个cpp文件,经过“../include”这个路径就能找到对应的头文件)。若是你的项目中还用了其它一些目录名,也能够配置在这儿。

上面配置中那一行(require ’semantic-c nil ‘noerror)是必须的,由于semantic的大部分功能是autoload的,若是不在这儿load semantic-c,那打开一个c文件时会自动load semantic-c,它会把semantic-dependency-system-include-path重设为/usr/include,结果就形成前面自定义的include路径丢失了。

顺便说一下semanticdb-project-roots的配置,不少地方都说要把它配置成”/”,可是我在Linux/Mac/Windows都试验过,不配这一行并没什么影响。

解析文件是semantic基本高级功能的基础,正确地解析了文件咱们才能实现:代码跳转和代码补全。

4.3 代码跳转

有了前面的配置,semantic自动就解析c/c++文件,解析完后跳转就容易了:光标放在函数上,执行M-x semantic-ia-fast-jump,立刻就跳转到函数的定义上了。若是跳不过去,那就检查一下前面配置的INCLUDE路径,是否是当前文件include的全部头文件都能在INCLUDE中找到。若是检查了不少遍都很差用,那就换个项目或者别的文件试试,确实存在semantic对某些文件支持不太好的状况,好比boost。

semantic-ia-fast-jump这个功能如此经常使用,我就把它绑定到f12上去了。

(global-set-key [f12] 'semantic-ia-fast-jump)

另外,前面咱们说过跳转过去了咱们还须要跳回来,在打开mru-bookmark-mode的状况下,按[C-x B],emacs会提示你跳回到哪一个地方,通常默认的就是上一次semantic-ia-fast-jump的位置,因此回车就能够回去了。

不过看代码时候我常常须要跳转后立刻就跳回来,要按[C-x B] [RET]这么多键实在有点麻烦,因此我写了个函数不提示直接就跳回上次的位置,并把它绑定到shift+f12上了:

1
2
3
4
5
6
7
8
9
10
11
12
(global-set-key [S-f12]                 (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))))

除了semantic-ia-fast-jump能够跳转以外,其实semantic中还有两个函数也有相似的功能:

  • semantic-complete-jump-local
  • semantic-complete-jump

看名字很容易看出来,前一个只能在当前buffer内跳转,后一个能够跳转到其它文件。不过这两个命令都须要用户手工输入要跳转的Tag名,不能像semantic-ia-fast-jump那样自动识别当前光标处单词,因此浏览代码时仍是semantic-ia-fast-jump舒服。

cedet还有个功能在函数和声明和实现间跳转,通常的,函数声明放在h文件中,函数的实现放在cpp文件中,光标在函数体的时候经过M-x semantic-analyze-proto-impl-toggle能够跳到函数声明去,在声明处再执行的话就会再跳回函数体,我把它绑定到M-S-F12上了:

(define-key c-mode-base-map [M-S-f12] 'semantic-analyze-proto-impl-toggle)

不是这个功能不是十分准确,通常在cpp中函数实现处想跳到函数声明处正常,可是从声明处跳到实现处的话cedet不必定能找到cpp文件的位置。

4.4 代码补全

semantic中有4个用来代码补全的命令:

  • senator-complete-symbol
  • senator-completion-menu-popup
  • semantic-ia-complete-symbol
  • semantic-ia-complete-symbol-menu

senator-complete-symbol和semantic-ia-complete-symbol这两个函数是新开一个buffer提示可能的补全内容;而senator-completion-menu-popup和semantic-ia-complete-symbol-menu会弹出一个补全菜单。

至于功能,以senator开头的两个函数是调用senator补全,另外两个是调用semantic-ia补全。至于senator和semantic-ia的区别,http://alexott.net/en/writings/emacs-devenv/EmacsCedet.html#sec9是这样解释的:

“semantic-ia调用semantic-analyze-possible-completions函数来取得可能的补全内容,它能为用户提供精确的补全列表;而senator用了一个更简单的的函数来获取补全内容,因此有可能会提供错误的结果。”

也就是说semantic-ia的补全更智能一些。

至于semantic-ia这两个补全选哪同样就看各人喜爱了,我喜欢用semantic-ia-complete-symbol-menu,由于看起来更直观一些,像这样:

semantic的补全菜单

我喜欢把它绑定到[Alt+n]上:

(define-key c-mode-base-map (kbd "M-n") 'semantic-ia-complete-symbol-menu)

不过semantic-ia-complete-symbol-menu只能用于GUI下,要是在终端下,就只能用semantic-ia-complete-symbol了。(终端下想要semantic-ia-complete-symbol同样的结果能够用别的插件,好比auto-complete或者company-mode)

若是启用了semantic-idle-completions-mode,不用按键只须要光标在.或者->后面停一会semantic就会自动开始补全了。

若是你用cedet不能补全,检查一下semantic是否是已经启用了,个人emacs上常常出现第一次打开c++-mode时semantic没自动启用的状况。看semantic是否正常有个直观的方法就是senator,若是启用了senator-minor-mode,打开c++文件时emacs会出现Senator菜单,若是没有Senator菜单你能够关掉再从新打开试试,要是仍然不出现菜单那就得检查配置是否是有问题。

若是确认semantic启用了仍然不能补全,就须要检查INCLUDE路径的配置,经过C-h v semantic-dependency-system-include-path RET检查INCLUDE路径,确保当前cpp中直接或间接include的头文件都能在INCLUDE路径中找到。

5 EDE配置

EDE是用来管理project的工具,用下面的代码启用它:

(global-ede-mode t)

EDE会在emacs中加一个叫作“Project”的菜单:

EDE的Project菜单

经过菜单能够建立project,往project里添加/移除文件;还能够编译project,不过好像只能经过已有的Makefile编译。

另外EDE还能够经过Speedbar显示整个project的目录树(见右边的Speedbar):

用Speedbar显示project的目录树

EDE能够支持四种类型的project:

  • Automake
  • 手工写的Makefile
  • C++ Root project
  • Simple project

而且EDE能解析Autoconf/Automake,若是打开一个文件时在当前或者上级目录中能找到Makefile.am文件,EDE会自动解析文件(认为这是一个Automake的project),识别出Makefile.am中定义的target和编译需用到的文件;打开目录树的话EDE能由Makefile.am中涉及到的文件生成目录树(上图的目录树就是EDE经过Makefile.am自动生成的)。

为了让semantic找到C/C++的头文件,前面是经过调用semantic-add-system-include把系统中可能出现的INCLUDE目录都告诉semantic的来实现的。其实semantic还能够经过EDE识别project中特定的INCLUDE目录,方法是在.emacs文件中定义C++ Root project,好比:

1
2
3
4
5
6
7
8
9
10
11
(setq libutil-project
      (ede-cpp-root-project "libutil"                             :file "~/projects/libutil/configure.in"                             :system-include-path '("/home/meteor1113/projects/include"                                                    "/home/meteor1113/projects/common"                                                    "/home/meteor1113/projects/libutil/pub"))) (setq test-project
      (ede-cpp-root-project "test"                             :file "~/test/Makefile"                             :system-include-path '("/test/include"                                                    "/usr/include/boost-1.42")))

上面定义了两个project,而且设定了各个project各自的INCLUDE目录。

不过这种方式有两个缺点:

  • 不能支持常见的Makefile/Makefile.am型project。
  • 我不肯意为每一个project都定义这样一个project,对于天天都要本身写代码的项目生成个C++ Root project还能够接受,有时候只是临时阅读一下其它项目,要是还要为它写个EDE的project配置就太麻烦了。

因此这个功能我也一直没用过,有问题的请参考官方文档。我以为把全部可能的目录都加进system-include里更方便。

6 其它

6.1 可视化书签

emacs有自带的书签功能(c-x r m, c-x r b, c-x r l),不过对于用了多年VC6的我来讲仍是更习惯让一个书签能高亮显示出来。cedet里就带了一个可视化的书签,经过下面的语句能够启用它:

(enable-visual-studio-bookmarks)

以后就能够经过下面几个按键操做书签了:

  • F2 在当前行设置或取消书签
  • C-F2 查找下一个书签
  • S-F2 查找上一个书签
  • C-S-F2 清空当前文件的全部书签

看这个效果:

cedet的可视化标签

有点遗憾的是这个书签功能只能在当前buffer的书签间跳转。

6.2 pluse

使用semantic-ia-fast-jump跳转时,cedet有个很酷的效果:在跳转到的行上实现一个淡入淡出的效果。具体的分析和使用看这儿

6.3 h/cpp切换

cedet的contrib目录下有一些实用的小功能,好比eassist.el就提供了一个在C++的头文件和实现文件间跳转的小功能

要使用这个功能首先要load它:

(require 'eassist nil 'noerror)

以后就能够经过命令M-x eassist-switch-h-cpp来切换了,我喜欢把它绑定到M-F12上:

(define-key c-mode-base-map [M-f12] 'eassist-switch-h-cpp)

这个功能是依赖semantic的,也就是说经过cpp找头文件时它也会上配置好的INCLUDE路径中去查找,不过若是经过头文件找cpp文件,好像只能找和头文件所在的同一目录了。

eassist-switch-h-cpp有个BUG:它是经过文件扩展名来匹配的(经过eassist-header-switches可配置),默认它能识别h/hpp/cpp/c/C/H/cc这几个扩展名的文件;可是C++的扩展名还可能会有别的,好比c++,cxx等,对一个扩展名为cxx的文件调用eassist-switch-h-cpp的话,它会建立一个新buffer显示错误信息。因此我把eassist-header-switches配置为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(setq eassist-header-switches
      '(("h" . ("cpp" "cxx" "c++" "CC" "cc" "C" "c" "mm" "m"))         ("hh" . ("cc" "CC" "cpp" "cxx" "c++" "C"))         ("hpp" . ("cpp" "cxx" "c++" "cc" "CC" "C"))         ("hxx" . ("cxx" "cpp" "c++" "cc" "CC" "C"))         ("h++" . ("c++" "cpp" "cxx" "cc" "CC" "C"))         ("H" . ("C" "CC" "cc" "cpp" "cxx" "c++" "mm" "m"))         ("HH" . ("CC" "cc" "C" "cpp" "cxx" "c++"))         ("cpp" . ("hpp" "hxx" "h++" "HH" "hh" "H" "h"))         ("cxx" . ("hxx" "hpp" "h++" "HH" "hh" "H" "h"))         ("c++" . ("h++" "hpp" "hxx" "HH" "hh" "H" "h"))         ("CC" . ("HH" "hh" "hpp" "hxx" "h++" "H" "h"))         ("cc" . ("hh" "HH" "hpp" "hxx" "h++" "H" "h"))         ("C" . ("hpp" "hxx" "h++" "HH" "hh" "H" "h"))         ("c" . ("h"))         ("m" . ("h"))         ("mm" . ("h"))))

基本上全部C/C++的扩展名都包含了,同时ObjectiveC也能够用了。

6.4 代码折叠

6.4.1 semantic-tag-folding

从我开始用emacs开始就听大虾们说hs-minor-mode能够实现代码折叠,因此个人.emacs里一直把hs-minor-mode打开的,但是用了5年以后我发现仍是不习惯它的按键,另外也不是很喜欢它显示的样子,5年来Hide/Show这个菜单对我来讲基本上是个摆设。

我期待像eclipse那样能够经过鼠标在直接点击就能够打开和折叠代码,这个功能在cedet也实现了(惋惜这么长时间一直没发现它),就是semantic-tag-folding.el(也在cedet的contrib目录下)。

1
2
(require 'semantic-tag-folding nil 'noerror) (global-semantic-tag-folding-mode 1)

看这个图:

cedet的代码折叠

只要用鼠标点击左侧的小三角图标就能够打开或折叠代码了。箭头向下的空心三角表示这段代码能够被折叠,箭头向右的实心三角表示这段代码被打折过了。

为了方便键盘操做,我把按键绑定到了[C-c , -]和[C-c , +]上(绑定这么复杂的
按键主要是为了和senator兼容,后面会讲到senator实现代码折叠):

1
2
(define-key semantic-tag-folding-mode-map (kbd "C-c , -") 'semantic-tag-folding-fold-block) (define-key semantic-tag-folding-mode-map (kbd "C-c , +") 'semantic-tag-folding-show-block)

同时它还提供了两个函数能够同时打开和折叠整个buffer的全部代码,分别是
semantic-tag-folding-fold-all和semantic-tag-folding-show-all,我把它们
绑定到了[C-_]和[C-+]上:

1
2
(define-key semantic-tag-folding-mode-map (kbd "C-_") 'semantic-tag-folding-fold-all) (define-key semantic-tag-folding-mode-map (kbd "C-+") 'semantic-tag-folding-show-all))

打开semantic-tag-folding-mode后,用gdb调试时不能点左侧的fringe切换断点了,因此我把C-?定义为semantic-tag-folding-mode的切换键,在gdb调试时临时把semantic-tag-folding关掉:

(global-set-key (kbd "C-?") 'global-semantic-tag-folding-mode)

不过,semantic-tag-folding在终端下会有一点点小问题:终端下semantic-tag-folding在函数前面加了个“+”或“-”号,看下面这个图:

终端下的semantic-tag-folding

虽然功能不受影响(除了不能用鼠标操做外,快捷键和GUI下是同样的),不过代码不能对齐了仍是令我有些不爽,因此终端下我是禁用semantic-tag-folding的,最终个人配置以下:

1
2
3
4
5
6
7
(when (and window-system (require 'semantic-tag-folding nil 'noerror))   (global-semantic-tag-folding-mode 1)   (global-set-key (kbd "C-?") 'global-semantic-tag-folding-mode)   (define-key semantic-tag-folding-mode-map (kbd "C-c , -") 'semantic-tag-folding-fold-block)   (define-key semantic-tag-folding-mode-map (kbd "C-c , +") 'semantic-tag-folding-show-block)   (define-key semantic-tag-folding-mode-map (kbd "C-_") 'semantic-tag-folding-fold-all)   (define-key semantic-tag-folding-mode-map (kbd "C-+") 'semantic-tag-folding-show-all))

须要注意的是,semantic-tag-folding依赖于语法解析,也就是说必须等semantic解析完文件以后才能使用。若是找开文件在fringe处找不到空心三角,能够[Force Tag Refresh]下,或者检查下semantic是否配置正确。

6.4.2 senator-fold-tag

终端下不用semantic-tag-folding了,最好能有替代方案吧:首先能够用回hs-minor-mode,此外cedet的senator也提供了一种代码折叠方案。

只要启用了senator-minor-mode(emacs中会出现Senator菜单),就能够经过M-x senator-fold-tag和M-x senator-unfold-tag来折叠和打开代码了,GUI和终端下均可以使用。

默认地,senator-fold-tag绑定到[C-c , -],senator-unfold-tag绑定到[C-c , +]上(因此前面我把semantic折叠的快捷键也绑定到这两个键上,这样GUI和终端下快捷键就一致了)。不过senator里好像没有对应的fold-all和show-all方法。

7 Todo

以上只是cedet里我用到的一些功能,其实cedet还有不少优秀的功能,好比经过模板自动生成代码(SRecode);经过代码画UML图以及经过UML图生成代码(Cogre)等;另外semantic除了能够本身解析代码外还能够借助ctags,global,ebrowse来解析。更多的功能须要进一步发掘。

最后,欢迎参观个人cedet配置: http://github.com/meteor1113/dotemacs/blob/master/init-site.el

 

 

 

 

Emacs配置文件 - DEA

http://emacser.com/dea.htm

相关文章
相关标签/搜索