最开始(刚开始工作的时候)接触的 IDE 其实是 SourceInsight . 那时候很多 android 框架的源码要看, 要分析, 也一度想要购买正版 SI. 后来机缘巧合单位的老前辈推荐我用 emacs, 从此踏上一条不归路.
本文主要记载我的emacs配置文件, 以及配置方法. 先给一个图吧. 中间可能有一些复杂,但是按照从简单到复杂的步骤其实还好; 想要省心省力, 不折腾的同学, 可以去购买一些商业的IDE, 节省了配置的时间.
(效率上取决于对于IDE的熟悉情况, 个人以为emacs没有上限)
引子
每当别人像我展示它的 vim
的时候, 我都是不屑的.
但是渐渐的, 如果有初学者问我要不要深入emacs, 我都会建议它: 最好不要, vistual studio code, qtcreator等都是不错的选择. 因为这东西会让你投入大量的时间折腾, 而且一旦习惯了快捷键操作, 效率是很高, 不过换一种没有配置的环境, 就会感觉很不习惯的.
Emacs 就是一个坑, 一个永远挖不完坑, 会上瘾的.
闲话不多说, 马上来正文. 效率Up Up Up!
正文
根据自己的用途,一步步配置环境,下面按照顺序叙述:
- 配置基本faces和主题
- 配置按键
- 配置语言支持
- 配置hightlight
- 配置ibuffer
- 配置dropdownlist
- 配置gdb
- 配置autosave
- 配置session
- 配置showhide
- 配置tabbar
- 配置symbol-overlay (f8,f9)
- 配置cscode
- 配置autocomplete和yasippet
- 配置cedet
- 配置ecb
中途还有一些个人使用习惯,不过多解释,只贴代码
明确用途
我使用emacs, 主要是在远程shell到服务器以及linux环境下做开发的(但不是所有的内容, 什么看网页啊, 看视频啊, 写邮件啊则不是), 归纳起来如下:
- linux下的终端操作, 即shell中命令操作(所有命令)
- c/c++开发, 包括代码的编写(各种补全, 提示等), 测试用例的编写, 调试, 日志输出, doc输出
- 研究源码, 这个需求和上面有一定的区别, 研究源码的时候更加关注架构层次, 模型, 甚至详细的调用关系
- linux下的shell脚本编写, 可能包括一部分python脚本
- org-mode 文档的编写
- git 日志查看以及提交(可能会结合gitk)
(我写 Java 和 Python 应用程序统统使用IDE, JetBrain的开发环境; 一般不写QT代码, 界面无感)
配置
中途的半成品
最终配置差不多就是这个样子:
1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;From Merlin deepin15.4;;;;;;;;;;;;;;;;;;;;;;;;; |
参考gihub
代码太多了, 我直接上传了 github
补充配置
一些有用的,但是我个人又没有配置的
在配置yasnippet的时候,注意到了他的已经知道的模板
1 | yasnippet: |
备忘
这里记录一下,算是一个我自己的备忘吧.
Emacs中的按键不计其数,也可以自行设定,因为按键表示相应的lisp函数的快捷方式. 改坏了怎么办?, 把.meacs文件删除就好了.
启动参数
emacs的启动参数:1
2
3
4
5
6
7emacs -q (安静启动, 不执行.emacs文件)
emacs -u joe (使用joe用户的.emacs启动)
emacs --debug-init (调试模式启动)
emacs -nw (terminal 中启动)
emacs practice.b --insert myfile (启动practice.b文件, 并把myfile插入到打开的buffer中)
emacs --insert myfile (把myfile插入到临时的buffer中)
emacs +15 practice.b (打开文件,并定位到15行; 注意, 如果是输入的数字长于文件的总长度, 那么就会定位到文件结尾)
手册
C-h t
查看教程, 该教程看完, 用熟悉; 初次之外可以查看 info 手册:
C-h i
, 之后使用m+关键词查看, d返回, 回车是选中, 还可以使用u和l:翻页和返回上次浏览的地方)
man
使用man手册
M-x woman
M-x man
- 然后输入相关的关键字
我一般使用 M-x man
.
对于man手册的支持, emacs的woman还要去解析man文件(/usr/share/man
), 感觉比较坑爹;
基本按键
- C-x i 插入文件(在已打开的文件内插入文件)
- C-x, C-w 另存为
- C-x u 撤销(C-/)
- C-x h 全部选中 (这个后面详细说)
- C-% 查找替换(C-s以及C-r是查找)
- C-x b 选中命名的buffer
- C-x, C-b 列出所有buffer
- M-x, kill-buffer 杀死buffer, 快捷键 C-x k
- C-v 向下翻页 (C-u 8 C-v 向下翻8页)
- M-v 向上翻页
- C-k 删除一行
- C-h m 查看当前模式(terminal可能)
- C-x C-q 设置或者取消只读模式
- 格式代码(缩进)
C-x h TAB 格式化选中的代码
C-c,C-q 对整个函数进行缩进 (光标应该在函数内, 并且需要再源码mode以内)
选中区域, M-x untabify, 将 TAB 字符转换为空格
选中区域, M-x indent-region, 对齐文本块 - 注释:
M-;
在该行的末尾添加注释符号(当然选中块之后也就可以注释整个block)C-c C-c
对一块代码进行注释;
取消注释用命令uncomment-region
(其实用undo也可以) - 折叠代码(我个人设置的是
M+,
) - 标记和调整(我个人设置的是
C-c m
,C-c j
) - 括号间跳转:(括号和函数间跳转)
括号之间来回跳转的时 候按 C-M-f 和 C-M-b.C-M-a
移动到当前函数的开始(如果和系统的快捷键冲突, 那么就多加一个shift键盘)C-M-e
移动到当前函数的结尾
(注意可以把C-M-a, C-M-e合并到C-M-f和C-M-b中, 我通常采取的策略是使用%进行跳转) - 标记移动和全选:
标记整个页面c-x,c-p
(实际上这里多是整个buffer, 而不是整个frame)
标记整个缓冲区 c-x h (常用)
标记整个段落 m-h (通常没有用-而是用c-m-h)c-space
设置标记(如果冲突就多加一个shift 或者使用 c-@) 然后移动光标, 就会从标记的位置选中移动选中区域c-x c-x
快速返回移动前的光标位置(互换插入点和文本标记的位置)c-m-h
快速选中一个函数 (如何按键有冲突, 可以多加一个shift) 大小写转换(默认是被禁止)–注意是C-x开始
downcase-region (C-x C-l
) ;; 选定区域全部改为小写
upcase-region (C-x C-u
) ;; 选定区域全部改为大写
可以直接在.emacs文件中设置:1
2(put 'downcase-region 'disabled nil)
(put 'upcase-region 'disabled nil)只是转换一个单词的话, 可以用
M-u
和M-l
, 它会把从光标开始的后面一个单词变成大写或者小写.
窗口操作
frame, 缓冲区, 窗口的关系:
整个窗口在Emacs中叫做frame, 图形界面下的Emacs可以打开多个frame. 每个frame从上到下分成3部分,分别是缓冲区,状态栏和回显区(一般工具栏隐藏) 缓冲区是编辑的主区域, 但是在这里操作的还不是真正的文件, 而是文件的一个缓存(buffer)。只有执行写入操作时,才会将buffer的内容写入到文件. 缓冲区可以分成多个区域, 缓冲不同的内容. 这些区域在Emacs中成为”窗口”.
- C-x 1 只保留当前窗格
- C-x 0 关闭当前窗格
- C-x 2 切割为等宽半高的两个窗格
- C-x o 切换到另一个窗格 (窗口相关的可以参考, 参考ibuffer.el扩展)
缓冲区之下是状态栏,显示当前的一些状态信息,比如图中从左至右依次为:1
-UU-:----F1 tmp Bot L31 (Fundamental) -------
解释:
UU
: 当前的文件编码是UTF-8, 如果是GBK会显示c**
: 文件状态,**表示未保存,–表示可写,%%表示只读(C-x, C-q)tmp
: 是当前编辑的文件的名称- All: 表示当前缓冲区已经显示文件的所有内容(Bot,表示处于文件的末尾处)
- L31: 当前光标所在的行数
- fundamental: 当前的模式
模式
模式:
- 主要模式: 当前主要模式只有一种
fundamental-mode: 缺省的 Emacs 模式,拥有最少设置和绑定
text-mode:编辑文本的基本模式
c-mode:用于编辑程序源代码 (以及其他源码模式)
lisp-interaction-mode:用于编辑和编译 Lisp 代码
ptex-mode:用于编辑 TeX 文档 - 次要模式 : 可以组合到主要模式中(次要模式可以有多种), 如果输入的模式包含在当前模式中, 对于主要模式, 会清空所有的次要模式
abbrev-mode:用于生成和使用缩写
auto-fill-mode:用于自动文字回绕、填充较长的行和段落
line-number-mode:显示当前行号(默认在状态栏上显示的就是)
overwrite-mode:覆盖模式, 代替默认的插入模式
以及其他插件模式
矩阵操作
(C-x r 开头; 和寄存器, 书签有重合)
这里可以补充一个矩形操作:(矩阵操作, 其实就是列模式)
其实我并没有觉得矩形剪切和复制时多么棒的东西, 平时用到的标记剪切其实也不错.
主要就是下面几个命令:(先用C-space或者C-@设一个mark, 移动光标到另一点; 剪切的其实是对角线围成的矩形)1
2
3
4
5
6
7
8C-x r k 剪切一个矩形块
C-x r y 粘贴一个矩形块
C-x r d 删除一个矩阵块
C-x r c 清除一个矩形块(使其变成空白)
C-x r o 插入一个矩形块(打开当前的矩形区块,使用空白字符填充整个区域,并将该矩形区块的所有文本移动到右边)
C-x r t 在选定区域的所有列前插入样的字符
(没有复制啊? 我说你傻啊, 先剪切, 然后undo, 然后粘贴)
Keystrokes Command name Action
C-x r k kill-rectangle Delete a rectangle and store it.
C-x r d delete-rectangle Delete a rectangle and do not store it.
C-x r y yank-rectangle Insert the last rectangle killed
C-x r c clear-rectangle Using spaces, blank out the area marked as a rectangle and do not store it.
C-x r o open-rectangle Insert a blank rectangle in the area marked.
C-x r r r copy-rectangle-to-register Copy rectangle to register r (where r is any character) .
C-x r i r insert-register Insert rectangle from register r (where r is any character).
(none) delete-whitespace-rectangle if a rectangle includes initial whitespace, deletes it, narrowing rectangle.
C-x r t string Enter string-rectangle Change contents of marked rectangle to string (if string is narrower
or wider than rectangle, dimensions change accordingly).
(none) string-insert-rectangle Prompts for string and inserts rectangle.
不满意的话, 还可以使用 cua-mode
. (我个人不用)
除了emacs本身支持的列模式外,emacs还可以通过cua-mode支持一种可视化的列模式。在cua-mode下,按[C-return]会进入 cua rectangle模式。
在这个模式下可以通过鼠标点击确认起点,然后通过光标键来选中一个rect范围,这个rect会用另外的颜色显示出来。 直接输入字符: 在每行前(或后)都插入这个字符.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16[M-a]: 将rect中的文字左对齐
[M-b]: 用空格(tabs或者spaces)替换所有rect中的字符
[M-c]: 去掉所有行左侧的空格
[M-f]: 用单个字符替换所有rect中的字符(提示输入一个字符)
[M-i]: 对每行中第一个找到的数字进行加1操作(自动把0x开头的当作十六进制数字)
[M-k]: 剪切rect
[M-l]: 把rect中的内容全部转换为小写
[M-m]: 拷贝rect
[M-n]: 用一串自增的数字替换rect中的每一行(这个功能可以用来给每行编号) ### 非常好用的功能
[M-o]: rect的内容右移,选中的rect用空格填充
[M-r]: 用字符串替换符满足正则表达式的字符串
[M-R]: 上下反转
[M-s]: 把rect中的每一行替换为一个字符串(提示输入)
[M-t]: 把rect整个替换为一个字符串(提示输入)
[M-u]: 把rect中的内容全部转换为大写
[M-|]: 对rect执行一个shell命令
我个人一般最多用到矩阵模式.
寄存器
(这里的命令注意和矩阵相区别一下)
在多个文件中逛的时候,我们常常需要快速切换到先前访问的某个位置. 因此, 我们需要把文件及其光标位置暂时存放在某个地方. (一般我们都会根据register进行一定封装, 从而进行来回的跳转) 简单说, 这里的寄存器(register), 就是保存一些位置信息(光标位置, 文件信息等)
最基本的用法(和我定义的C-c,m以及C-c,j比起来作用弱一点儿)
将当前光标所在位置保存入一个register中:C-x r SPACE + register名
(一个字符, 比如a吧), 然后我们就可以到处瞎逛,若要回到保存的register a位置,我们可以输入: C-x r j a
当然你可以定义好多个寄存器名字(位置)1
2M-x view-register 查看某一个register
M-x list-registers 查看所有的register
在进行矩阵操作的时候, 中间有两个命令: 保存到寄存器, 并存寄存器中恢复1
2
3C-x s X copy-to-register 将选定区域保存到寄存器 X
C-x r r r copy-rectangle-to-register Copy rectangle to register r (where r is any character) .
C-x r i r insert-register Insert rectangle from register r (where r is any character).
通常来说, 我个人不会使用这么原始的方式(偶尔可能会用), 一般使用其他更加高级的标记方式,比如我自己定义的 C-.
以及 C-,
.
比如ctags, etags, gtags, 或者csope等都是比较好的选择. (我个人一般使用csope)
比如说 etags:
在代码目录中运行 etags -R
如果要向现有tags表中添加,则运行 etags -a
访问tag文件的话: M-x visit-tags-table
, 常用的快捷键如下:1
2
3M-. 访问tag
C-u M-. 访问下一个tag
M-* 返回
书签
保存缓冲区中位置的另一种工具(注意一下和矩阵操作的快捷键)
这些 Emacs 书签 的工作方式与寄存器相同,但是它们的标签可以超过一个字符长,而且它们比寄存器更为持久:如果保存了书签,那么您可以在两个不同的会话之间使用它们。它们将一直保留下来,直到您删除它们。正如它们的名称所表示的,对于保存您在缓冲区中的位置,以便您稍后可以返回到该位置(通常是在以后的 Emacs 会话期间),使用书签是非常方便的。
不过多介绍了:1
2
3
4
5C-x r m Bookmark bookmark-set 设置一个名为 Bookmark 的书签
C-x r l bookmarks-bmenu-list 列出所有已保存的书签
C-x r b Bookmark bookmark-jump 跳转至名为 Bookmark 的书签中所设置的位置(实际上是恢复书签)
未定义 bookmark-delete 删除一个书签
未定义 bookmark-save 将所有的书签保存到书签文件中(这样下次启动就可以跨越session了)
注意, 自从emacs24, 退出的时候 书签是自动保存在相关文件中的:
- In emacs 24.x, bookmark file is at ~/.emacs.d/bookmarks.
- In emacs 23.x, bookmark file is at ~/.emacs.bmk.
你也可以自己设置:1
2
3(setq bookmark-save-flag 1) ; everytime bookmark is changed, automatically save it
(setq bookmark-save-flag t) ; save bookmark when emacs quits
(setq bookmark-save-flag nil) ; never auto save.
当然你可以设置在每次启动的时候, 自动载入书签:1
2
3(require 'bookmark)
(bookmark-bmenu-list)
(switch-to-buffer "*Bookmark List*")
(我个人使用desktop插件, 所以不写该句)
当然你可以进行设置一些快捷键:1
2(global-set-key [(f9)] 'list-bookmarks)
(global-set-key [(f10)] 'bookmark-set)
在list bookmark之后(相当于打开了bookmark文件), 可以使用下列命令在列表中操作:
Type d to mark the current item for remove.
Type x to remove all D marked ones. (执行)
Type r to rename current item’s title.
Type s to save the change.
现在有了 desktop, 书签显得比较鸡肋.
cscope
下面说说我cscope的配置: (cscope和ecb功能上有一定重合)
GNU Emacs默认自带etags的支持, 但是不如cscope强大, cscope本身是一个独立软件, (建立索引之后)而且非常强大.
可以独立安装:1
2
3
4
5$ which cscope
/usr/local/bin/cscope
$ file cscope/contrib/xcscope/cscope-indexer
cscope/contrib/xcscope/cscope-indexer: POSIX shell script, ASCII text executable
在外部使用:
要使用 cscope, 先建索引, 假设所有的头文件和h都在src下面1
2find src/ -type f -iname "*.h" > cscope.files (这里创建)
find src/ -type f -iname "*.cpp" >> cscope.files (这里是>>追加)
(把所有符号都追加到一个文件可以加快建立索引文件的速度, 但是不利于之后展开文件)1
2
3
4#!/bin/sh
find . -name "*.h" -o -name "*.c" -o -name "*.cc" > cscope.files
cscope -Rbkq -i cscope.files
其他选项解释:
- -R: 在生成索引文件时, 搜索子目录树中的代码
- -b: 只生成索引文件, 不进入cscope的界面
- -q: 生成cscope.in.out和cscope.po.out文件,加快cscope的索引速度
- -k: 在生成索引文件时, 不搜索/usr/include目录
- -i: 如果保存文件列表的文件名不是cscope.files时,需要加此选项告诉cscope到哪儿去找源文件列表。可以使用“-”,表示由标准输入获得文件列表
- -I dir: 在-I选项指出的目录中查找头文件
- -u: 扫描所有文件, 重新生成交叉索引文件
- -C: 在搜索时忽略大小写
- -P path: 在以相对路径表示的文件前加上的path, 这样你不用切换到你数据库文件所在的目录也可以使用它了
使用命令 cscope -Rbkq
, 产生文件如下:1
2
3
4
5
6
7
8
9
10cscope.in.out
cscope.out //基本的符号索引
cscope.po.out
```
注意一下, k在生成索引文件时, 不搜索/usr/include目录; 此时初始化和建立索引已经完成了, 之后就可以利用命令进行查找了.
在emacs里面使用:
当然在emacs程序里, 也可以进行初始化和建立索引(如果所有的源代码以及子目录都是在同一个目录下面的).
;; C-c s a 初始化目录( 设定初始化的目录,一般是你代码的根目录)
;; C-c s I 对目录中的文件建立列表索引(生成 Cscope 的数据库)(cscope-set-initial-directory) 这一步最重要1
2
3
4
5
6一般使用 `C-c s I` 就可以了, 对应 `cscope-set-initial-directory` . 如果源代码全部处于同一个目录下面,现在就可以使用了. (个人习惯还是喜欢再外部使用cscope -bkqR)
注意:
如果源代码有多层目录,或者其他地方还有附加的源代码,则需要 `cscope-indexer` 脚本. 把那个脚本拷贝到系统 PATH 里面去(如 /usr/bin/).
$ sudo chmod u+x cscope-indexer
export PATH=$PATH:~/.emacs.d/lisp/cscope/contrib/xcscope1
2
然后在根目录, 建立索引
$ cscope-indexer -r1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
只要执行 C-c s I(cscope-index-files), 即`` 就可以生成 Cscope 的数据库, 接下来就可以使用了.
xcscope默认的快捷键都是绑定到 C-c s 的前缀上面, 更详细的使用说明请参见 xcscope.el 文件头部的注释.
我个人使用的是默认绑定: (必须要建立完索引)
* C-c s s Find symbol. 寻找符号(查找C语言符号,即查找函数名、宏、枚举值等出现的地方)
* C-c s d Find global definition. 寻找全局定义---一般用这个来查找具体的定义
* C-c s g Find global definition (alternate binding). 寻找符号, 变量的定义
* C-c s G Find global definition without prompting.
* C-c s c Find functions calling a function. 看看指定函数被哪些函数所调用
* C-c s C Find called functions (list functions called
from a function). 看看指定函数调用了哪些函数
* C-c s t Find text string. 查找字符串
* C-c s e Find egrep pattern. 正则表达式查找
* C-c s f Find a file. 寻找文件
* C-c s i Find files #including a file. 看看指定的文件被哪些文件include
下面是在搜索到的结果之间切换用的快捷键:(一般不用, 直接跳转到窗口)1
2
3
4
5
6
7C-c s b Display *cscope* buffer.
C-c s B Auto display *cscope* buffer toggle.
C-c s n Next symbol.
C-c s N Next file.
C-c s p Previous symbol.
C-c s P Previous file.
C-c s u Pop mark.
将光标停在函数名上, 按C-c s d, 回车, 即可以查询相关的定义.
xcscope.el 原来定义如下: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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46;; * Keybindings:
;;
;; All keybindings use the "C-c s" prefix, but are usable only while
;; editing a source file, or in the cscope results buffer:
;;
;; C-c s s Find symbol.
;; C-c s d Find global definition.
;; C-c s g Find global definition (alternate binding).
;; C-c s G Find global definition without prompting.
;; C-c s c Find functions calling a function.
;; C-c s C Find called functions (list functions called
;; from a function).
;; C-c s t Find text string.
;; C-c s e Find egrep pattern.
;; C-c s f Find a file.
;; C-c s i Find files #including a file.
;;
;; These pertain to navigation through the search results:
;;
;; C-c s b Display *cscope* buffer.
;; C-c s B Auto display *cscope* buffer toggle.
;; C-c s n Next symbol.
;; C-c s N Next file.
;; C-c s p Previous symbol.
;; C-c s P Previous file.
;; C-c s u Pop mark.
;;
;; These pertain to setting and unsetting the variable,
;; `cscope-initial-directory', (location searched for the cscope database
;; directory):
;;
;; C-c s a Set initial directory.
;; C-c s A Unset initial directory.
;;
;; These pertain to cscope database maintenance:
;;
;; C-c s L Create list of files to index.
;; C-c s I Create list and index.
;; C-c s E Edit list of files to index.
;; C-c s W Locate this buffer's cscope directory
;; ("W" --> "where").
;; C-c s S Locate this buffer's cscope directory.
;; (alternate binding: "S" --> "show").
;; C-c s T Locate this buffer's cscope directory.
;; (alternate binding: "T" --> "tell").
;; C-c s D Dired this buffer's directory.
如果你喜欢自定议案件的话, 提供自定义按键参考:1
2
3
4
5
6
7
8
9
10
11
12(define-key global-map [(control f3)] 'cscope-set-initial-directory)
(define-key global-map [(control f4)] 'cscope-unset-initial-directory)
(define-key global-map [(control f5)] 'cscope-find-this-symbol)
(define-key global-map [(control f6)] 'cscope-find-global-definition)
(define-key global-map [(control f7)] 'cscope-find-global-definition-no-prompting)
(define-key global-map [(control f8)] 'cscope-pop-mark)
(define-key global-map [(control f9)] 'cscope-next-symbol)
(define-key global-map [(control f10)] 'cscope-next-file)
(define-key global-map [(control f11)] 'cscope-prev-symbol)
(define-key global-map [(control f12)] 'cscope-prev-file)
(define-key global-map [(meta f9)] 'cscope-display-buffer)
(define-key global-map [(meta f10)] 'cscope-display-buffer-toggle)
搜索和替换
由于我使用了插件 symbol-overlay, 所以一般是借助f8标记和操作标记, 和 M-r
重命名, M-s
切换到isearch.
下面是可能涉及到的查找:C-%
查找替换C-s
以及 C-r
是递归查找M-x grep-find
, 已经设置快捷键为f3
find . -type f -exec grep --color -nH -e "content" {} +
下面可以详细说一下技巧, 因为查找&替换实在用的太多了:
Emacs中的搜索包括增量搜索和一般搜索。增加搜索是每次在前一次搜索的结果基础上继续搜索。在增量搜索时,如果上一次搜索之后进行了其他操作,则需要连续按两次快捷键才能召回关键词. 可以选中区块后在区块内进行搜索.
增量查找:
C - s向下查找
C - r向上查找
按下C - s后输入要搜索的词,emacs会即时显示当前光标后第一个搜索到的结果,按C - s会跳到下一个结果,按C - r会跳到上一个结果.
按Enter结束查找或按C - g取消查找回到原来的地方。
按下C - s 或 C - r后, 按M - p显示上一个搜索词, M - n显示下一个搜索词。类似C - p是上一行,C - n下一行.
按下C - s或 C - r后, 输入要查找的词的头几个字, 然后按C - w 会补全当前位置的单词.
查找替换:
按M - %启动查找替换,输入要被替换的词,回车,然后输入要替换的词,再回车。
被替换的词会高亮起来,这时,
- 输入y替换并跳到下一个
- ^ 返回上一个替换点
- 输入n忽略并跳到下一个
- 输入q结束,输入!替换剩下的全部
C - r 进入修改
(我一般重构的时候, 使用插件, M-r进行全部改名, M-s回归递归查找)
取消搜索
C-g 取消搜索,光标返回搜索前的位置
RET结束搜索,光标停留在当前位置。
Ocuur模式
有时候想列出匹配的全面模式,而不是在文档中浏览,这个可以使用occur这个函数。
例子:M - x occur RET 关键词 RET
这时emacs会新开一个窗口来列出匹配的行
(实际上再 M-s之后, 案件M-s o即可达到同样的效果)
模式
写代码的cc-mode(cc-mode 可以用来写 C/C++/Java/Obj-C)
使用cc-mode:M-x c-set-style
, 然后选择cc-mode1
2M-x customize 定制界面等
M-x customize-themes 定制主题等
文件编码
文件编码方面, 一般linux下都采用utf-8即可, 或者设置 (prefer-coding-system 'utf-8)
.
但是如你在gbk环境下, 比如你的windows7设置的是gdk, 那么此时应该设置gbk环境编码(否则读入文件时的解释编码和系统编码不一致, 肯定乱码了)1
2
3
4
5
6
7
8
9
10
11(setq file-name-coding-system 'gbk)
(set-terminal-coding-system 'gbk)
(set-keyboard-coding-system 'gbk)
(setq locale-coding-system 'gbk)
(set-selection-coding-system 'gbk)
(set-clipboard-coding-system 'ctext)
(set-clipboard-coding-system 'gbk)
(set-terminal-coding-system 'gbk)
(set-buffer-file-coding-system 'gbk)
(modify-coding-system-alist 'process "." 'gbk)
(setq default-process-coding-system '(gbk . gbk))
tabbar
关于 tabbar 的再一次调整:
要达到的效果是什么呢?
是要在一个 buffer 里面移动, 而不会切换到被的分组.
键位的设定时我特意改用了tabbar-backward-tab和tabbar-forward-tab 代替tabbar-backward和tabber-forward.
效果是使用M-left/right的时候移动不会跨组, 也就是只能在当前分组内移动, 这样好很多.
中间一段设置把标签栏左边的那些按钮都取消掉了.
原来是不分组, 最后发现还是要根据主模式分组比较好.(即下面的代码全部作废)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
30
31
32
33
34
35
36
37
38
39
40
41
42(require 'tabbar)
(tabbar-mode)
(global-set-key (kbd "<M-up>") 'tabbar-backward-group)
(global-set-key (kbd "<M-down>") 'tabbar-forward-group)
(global-set-key (kbd "<M-left>") 'tabbar-backward-tab)
(global-set-key (kbd "<M-right>") 'tabbar-forward-tab)
(setq
tabbar-scroll-left-help-function nil ;don't show help information
tabbar-scroll-right-help-function nil
tabbar-help-on-tab-function nil
tabbar-home-help-function nil
tabbar-buffer-home-button (quote (("") "")) ;don't show tabbar button
tabbar-scroll-left-button (quote (("") ""))
tabbar-scroll-right-button (quote (("") "")))
(defun my-tabbar-buffer-groups ()
"Return the list of group names the current buffer belongs to.
Return a list of one element based on major mode."
(list
(cond
((or (get-buffer-process (current-buffer))
;; Check if the major mode derives from `comint-mode' or
;; `compilation-mode'.
(tabbar-buffer-mode-derived-p
major-mode '(comint-mode compilation-mode)))
"Process"
)
((string-equal "*" (substring (buffer-name) 0 1))
"Emacs Buffer"
)
((eq major-mode 'dired-mode)
"Dired"
)
(t
"User Buffer"
))))
(setq tabbar-buffer-groups-function 'my-tabbar-buffer-groups)
gdb
一般都是激活多窗口调试模式:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22+----------------------------------------------------------------------+
| GDB Toolbar |
+-----------------------------------+----------------------------------+
| GUD buffer (I/O of GDB) | Locals buffer |
| | |
| | |
| | |
+-----------------------------------+----------------------------------+
| Source buffer | I/O buffer (of debugged program) |
| | (comint-mode) |
| | |
| | |
| | |
| | |
| | |
| | |
+-----------------------------------+----------------------------------+
| Stack buffer | Breakpoints buffer |
| RET gdb-frames-select | SPC gdb-toggle-breakpoint |
| | RET gdb-goto-breakpoint |
| | D gdb-delete-breakpoint |
+-----------------------------------+----------------------------------+
窗口说明:
- GDB Toolbar - GDB 操作Toolbar
- GUD buffer - 执行操作的buffer
- Locals buffer - 本地变量名和值的表示buffer
- Source buffer - 表示sourcecode的buffer
- IO/ buffer - 表示程序的输入输出的buffer
- Stack buffer - 运行停止的时候,调用关系的表示buffer
- Breakpoints buffer - breakpoints断点的表示buffer
- buffer崩溃的时候、通过’M-x gdb-restore-windows’返回原状态
当然你可以尝试关闭某些窗口.1
(setq gdb-use-separate-io-buffer t) ; 不需要"IO buffer"时,则设为nil
一般会把 gdb-many-windows
设置为激活状态, 实际上也可以用 gdb-restore-windows
恢复单个布局.
我个人的习惯是, 把所有的其他窗口只是作为观察窗口, 其实还是依赖主窗口, 设置相关命令, 一方面, 这个可以减少快捷键的记忆; 另外一方面, 不和单独在terminal中使用产生冲突, 其实也不错. (gud是主窗口)
快捷键命令
- 添加断点 gud-break C-x C-a C-b 或 C-x
- 删除断点 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
Autocomplete
自动补全的拆建有很多, 但是真正能够TAB键玩的溜的只有 Auotocomplete .
autocomplete在使用上, 不用刻意去按键M-/, 而是在你写代码的时候, 就可以完成提示, 并且选择的话, 一直TAB就行, 之后就可以直接在后面接着写其他的代码. (按回车可以选中所选的)
具体的快捷键:
- TAB, C-i ac-expand Completion by TAB
- RET, C-m ac-complete Completion by RET
- down, M-n ac-next Select next candidate
- up, M-p ac-previous Select previous candidate
- C-?, f1 ac-help Show buffer help
To stop completion, simply use C-g.
magit
emacs中使用git虽然很好, 但是, 无疑来说, 又会增加许多负担, 当前还是使用terminal或者gitk吧. 具体可以考虑使用 magit 插件.
speedbar
就是一个文件列表, 一般再ecb中有集成.
M-x speedbar 就可以启动它(相关于一个文件目录, 可以在多个文件中切换), 我个人设置的快捷键是 f4 .
ediff
一个相当于beyond compare的组件: M-x ediff
.
dired
emacs下一个强大的文件管理器, 大多数切换到 shell 的场景被它取代: M-x dired
.
游戏
M-x tetris
, 俄罗斯方块.
hideshow
代码折叠与展开, 这个插件有用, 不过要进行一定的调整.
1 | ;;配置代码折叠 |
我一般设置的是 M-,
用于折叠和展开.
窗口恢复
原生没有设置案件对窗口误操作的undo, 所以我设置了一下按键:1
2C-x 4 u 窗口undo
C-x 4 r 窗口redo
doxygen
这个设置起来不太麻烦, 但是我还是喜欢在shell中使用, 毕竟它可以生产图, shell操作更加方便.
cedet
给Emacs安装CEDET是最烦恼的过程之一, 由于这个插件太大了, 所以出错的几率也比较打.
CEDET包含以下几个部分:
- Semantic - Parser Infrastructure for Emacs
- EDE - File manager/ Makefile generator
- SRecode - Template manager/ code generator
- COGRE - Connected Graph Editor
emacs自带的cedet为1.0版本, 不能与ecb配合使用, 所以要下载并安装它的最新版本(LAST) cedet1.1
. 安装的时候, 请仔细阅读源码目录的 INSTALL
文件, 我直接下载的解压缩后的文件.1
$ git clone https://github.com/emacs-pkg-mirrors/cedet.git
根据它官网的步骤, 一点儿不靠谱. 请仔细阅读源码目录的 INSTALL
文件!!!
- Step 1 : Download CEDET from the Sourceforge downloads page.
- Step 2 : unpack CEDET
- Step 3 : make EMACS=emacs
- Step 4 : Configure CEDET in your .emacs file by adding code like this.
主要代码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
30
31
32
33
34
35
36
37
38
39
40-----------
;; Load CEDET.
;; See cedet/common/cedet.info for configuration details.
;; IMPORTANT: For Emacs >= 23.2, you must place this *before* any
;; CEDET component (including EIEIO) gets activated by another
;; package (Gnus, auth-source, ...).
(load-file "~/cedet-VERSION/common/cedet.el")
;; Enable EDE (Project Management) features
(global-ede-mode 1)
;; Enable EDE for a pre-existing C++ project
;; (ede-cpp-root-project "NAME" :file "~/myproject/Makefile")
;; Enabling Semantic (code-parsing, smart completion) features
;; Select one of the following:
;; * This enables the database and idle reparse engines
(semantic-load-enable-minimum-features)
;; * This enables some tools useful for coding, such as summary mode,
;; imenu support, and the semantic navigator
(semantic-load-enable-code-helpers)
;; * This enables even more coding tools such as intellisense mode,
;; decoration mode, and stickyfunc mode (plus regular code helpers)
;; (semantic-load-enable-gaudy-code-helpers)
;; * This enables the use of Exuberant ctags if you have it installed.
;; If you use C++ templates or boost, you should NOT enable it.
;; (semantic-load-enable-all-exuberent-ctags-support)
;; Or, use one of these two types of support.
;; Add support for new languages only via ctags.
;; (semantic-load-enable-primary-exuberent-ctags-support)
;; Add support for using ctags as a backup parser.
;; (semantic-load-enable-secondary-exuberent-ctags-support)
;; Enable SRecode (Template management) minor-mode.
;; (global-srecode-minor-mode 1)
编译时遇到的问题:
`makeinfo is missing on your systeme, 即makeinfo未找到命令, 此时有两种方案:
- make EMACS=emacs MAKEINFO=echo 即不编译doc
- make MAKEINFO=/usr/bin/makeinfo
安装 makeinfo
, 它包含再texinfo
包中1
2
3
4
5
6
7
8
9
10
11
12
13
14$ search apt-file
apt-file - search for files within Debian packages (command-line interface)
cabal-debian - Create a debianization for a cabal package
#利用apt-file查看某个文件属于哪个包, 再安装包
$ add apt-file
$ sudo apt-updateapt
$ apt-file search bin/makeinfo
texinfo: /usr/bin/makeinfo
$ search exinfo
texinfo - Documentation system for on-line information and printed output
$ add texinfo
$ add install-info
在 http://sourceforge.net/projects/cedet/ 下载 cedet1.1 .1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19In end of data:
semantic-tag-file.el:207:1:Warning: the function ‘ede-toplevel’ is not known
to be defined.
Eager macro-expansion failure: (invalid-function class-p)
Eager macro-expansion failure: (invalid-function class-p)
Eager macro-expansion failure: (invalid-function class-p)
Eager macro-expansion failure: (invalid-function class-p)
Eager macro-expansion failure: (invalid-function class-p)
Eager macro-expansion failure: (invalid-function class-p)
Eager macro-expansion failure: (invalid-function class-p)
Eager macro-expansion failure: (invalid-function class-p)
In toplevel form:
semantic-idle.el:42:1:Error: Invalid function: class-p
In semantic-tag-customize:
semantic-custom.el:210:22:Warning: ‘toggle-read-only’ is an obsolete
function (as of 24.3); use ‘read-only-mode’ instead.
Makefile:61: recipe for target 'semantic' failed
总之编译的时候, 就是会遇到各种各样的问题. 一定要简单安装cedet, 它真的太复杂了(我安装它也只是为了安装ecb).
ecb
这个代码浏览器, 比较实用. 配置好了普通编写代码, 跑测试用例的界面大概是这样的:
1 |
|
我一般设置如下快捷键:
- f5 启用ecb
- f6 禁用ecb
- control + f5 显示ecb窗口
- control + f6 隐藏ecb窗口
- C-c 0-4 分别是还原,以及最大化某个窗口
- M-方向键, 切换到某个窗口
- 选定某个窗口的某个展开标记(即加号减号) 方向键左代表折叠, 方向键右代表展开.
文档
学些emacs, 手册中遇到的(可能)生词:
- overlap 交叠
- likewise 相似的
- opposite 相反的
- interspersed 穿插
- parallel 并行
- repeated 重复
- paraphrase 释义
- terminal终端
- get rid of 摆脱
- contiguous 邻近的
- incremental 增量
- for reference 仅供参考
- sufficient 足够
- command 命令
- scrolling 滚动
- numeric argument 数字参数
- yank 召回,剪切
- echo area 回显区
- mode line 状态栏
- incremental search 渐进式搜索
尾巴
有些插件真坑爹…编译安装都烦, 莫名其妙的问题, 浪费了好长时间.
首先 emacs 还是很强大的, 然而不得不说, 由于平台的严谨, 以及开后和后续支持的缺乏, 对于emacs的兼容性造成了很大的调整. 如果和visual studio code相比, 其兼容性明显不好. 而且这种情况如果没有更多的人参与和带动, 不说emacs会死, 至少可以说, 能玩的起来的都是神了.
唯一的希望是, emacs的兼容性可以好起来(各种插件的稳定性慢慢变好一些).
参考资料
- 一年成为 Emacs 高手
- A Guided Tour of Emacs
- emacs按键绑定方式介绍
- emacs高亮插件推荐
- emacs项目路径设置
- woman参考
- 查找替换参考
- 查找汇总
- 书签和寄存器
(文中有一处错误:删除书签的命令是 M-x bookmark-delete而不是C-x bookmark delete) - gdb参考
- autocomplete参考
- magit参考
- hideshow
这一些列文档差不多一共有7篇, 讲的比较啰嗦, 可以自行参考一下:
- https://www.ibm.com/developerworks/cn/education/aix/emacs1/index.html
- https://www.ibm.com/developerworks/cn/education/aix/emacs2/index.html
- https://www.ibm.com/developerworks/cn/education/aix/au-emacs3/index.html
- https://www.ibm.com/developerworks/cn/education/aix/au-emacs4/index.html
- https://www.ibm.com/developerworks/cn/education/aix/au-emacs5/index.html