所需即所获:IDE = _plugins_ + vim

本文详细介绍了如何将VIM配置成一个功能强大的IDE,包括:1) 使用vimscript实现全屏快捷键;2) 添加辅助信息,如光标位置、行号和高亮;3) 选择YaHei Consolas Hybrid字体改善视觉效果;4) 通过插件Powerline美化状态栏;5) 使用IndentGuides增强缩进可视化;6) 设置代码折叠和导航功能;7) 实现代码收藏(书签功能);8) 安装easymotion插件实现快速移动;9) 更新.vimrc配置文件,实现文件类型侦测、实时搜索、语法高亮等功能;10) 使用ctags进行代码导航;11) 通过pathogen管理插件,优化编辑器设置,如禁用光标闪烁、滚动条等;12) 定制代码补全、折叠、切换、搜索、替换等快捷键。通过这些定制,VIM成为一个高度个性化的IDE。
摘要由CSDN通过智能技术生成
新版迁移:https://github.com/yangyangwithgnu/use_vim_as_ide

http://yangyangwithgnu.github.io/







0 vim 必知会
    0.1 .vimrc 文件
    0.2 .vim/ 目录
1 源码安装编辑器 vim
2 插件管理
3 界面美化
    3.1 主题风格
    3.2 营造专注氛围
    3.3 添加辅助信息
    3.4 其他
4 代码分析
    4.1 语法高亮
    4.2 代码缩进
    4.3 代码折叠
    4.4 接口与实现快速切换
    4.5 代码收藏
    4.6 代码导航
    4.7 标签列表
5 代码开发
    5.1 快速开关注释
    5.2 模板补全
    5.3 快速输入结对符
    5.4 智能补全
        基于标签的智能补全
        基于语义的智能补全
    5.5 由接口快速生成实现框架
    5.6 库信息参考
6 工程管理
    6.1 工程文件浏览
    6.2 多文档编辑
    6.3 环境恢复
7 工具链集成
    7.1 编译器/构建工具集成
        代码编译
        系统构建
        一键编译
    7.2 静态分析器集成
8 其他辅助
    8.1 内容查找
    8.2 内容替换
    8.3 快速移动
9 尾声


开始前,我假设你:0)具备基本的 vim 操作能力,清楚如何打开/编辑/保存文档、命令与插入模式间切换;1)希望将 vim 打造成 C/C++ 语言的 IDE,而非其他语言。
关于 vim 的优点,你在网上能查到 128+ 项,对我而言,只有两项:0)所想即所得,让手输入的速度跟上大脑思考的速度,1)所需即所获,只有你想不到的功能、没有实现不了的插件。希望获得前者的能力,你需要两本教程深入学习,《Practical Vim: Edit Text at the Speed of Thought》和《vim user manual》;要想拥有后者的能力,通读本文 -。-#。对于 vim 的喜爱,献上湿哥哥以表景仰之情:
vi 之大道如我心之禅,
  vi 之漫路即为禅修,  
  vi 之命令禅印于心,  
 未得此道者视之怪诞,
 与之为伴者洞其真谛,
 长修此道者巨变人生。
作: reddy@lion.austin.com
译:yangyang.gnu@gmail.com
言归正传,说说 vim 用于代码编写提供了哪些直接和间接功能支撑。vim 用户手册中,50% 的例子都是在讲 vim 如何高效编写代码,由此可见,vim 是一款面向于程序员的编辑器,即使某些功能 vim 无法直接完成,借助其丰富的插件资源,必定可以达成目标,这就是所需即所获。
我是个目标驱动的信奉者,本文内容,我会先给出优秀 C/C++ IDE 应具备哪些功能,再去探索如何通过 vim 的操作或插件来达到目标。最终至少要像这个样子:
(图形环境下IDE总揽)
(纯字符模式下IDE总揽)

0 vim 必知会
在正式开始前先介绍几个 vim 的必知会,这不是关于如何使用而是如何配置 vim 的要点,这对理解后续相关配置非常有帮助。

0.1 .vimrc 文件
.vimrc 是控制 vim 行为的配置文件,位于 ~/.vimrc,不论 vim 窗口外观、显示字体,还是操作方式、快捷键、插件属性均可通过编辑该配置文件将 vim 调教成最适合你的编辑器。
很多人之所以觉得 vim 难用,是因为 vim 缺少默认设置,甚至安装完后你连配置文件自身都找不到,不进行任何配置的 vim 的确难看、难用。不论用于代码还是普通文本编辑,有必要将如下基本配置加入 .vimrc 中:
    前缀键。vim 插件帮助文档中经常出现 <leader>,即,前缀键。vim 中很多快捷键,再加上各类插件的快捷键,在单层空间中难免引起冲突,为缓解该问题,引入了前缀键 <leader>,这样,键 r 可以配置成r、<leader>r、<leader><leader>r 等等多个快捷键。前缀键是 vim 使用率较高的一个键(最高的当属 Esc),选一个最方便输入的键作为前缀键,将有助于提高编辑效率。找个无须眼睛查找、无须移动手指的键 —— 分号键,挺方便的,就在你右手小指处:
" 定义快捷键的前缀,即<Leader>
let mapleader=";"
既然前缀键是为快捷键服务的,那随便说下快捷键设定原则:不同快捷键尽量不要有同序的相同字符。比如,<leader>e 执行操作 0 和 <leader>eb 执行操作 1,在你键入 <leader>e 后,vim 不会立即执行操作 0,而是继续等待用户键入 b,即便你只想键入 <leader>e,vim 也不得不花时间等待输入以确认是哪个快捷键,显然,这让 <leader>e 响应速度变慢。<leader>ea 和 <leader>eb 就没问题。
    文件类型侦测。允许基于不同语言加载不同插件(如,C++ 的语法高亮插件与 python 的不同):
" 开启文件类型侦测
filetype on
" 根据侦测到的不同类型加载对应的插件
filetype plugin on
    快捷键。把 vim(非插件)常用操作设定成快捷键,提升效率:
" 定义快捷键到行首和行尾
nmap lb 0
nmap le $
" 设置快捷键将选中文本块复制至系统剪贴板
vnoremap <Leader>y "+y
" 设置快捷键将系统剪贴板内容粘贴至 vim
nmap <Leader>p "+p
" 定义快捷键关闭当前分割窗口
nmap <Leader>q :q<CR>
" 定义快捷键保存当前窗口内容
nmap <Leader>w :w<CR>
" 定义快捷键保存所有窗口内容并退出 vim
nmap <Leader>WQ :wa<CR>:q<CR>
" 不做任何保存,直接退出 vim
nmap <Leader>Q :qa!<CR>
" 依次遍历子窗口
nnoremap nw <C-W><C-W>
" 跳转至右方的窗口
nnoremap <Leader>lw <C-W>l
" 跳转至方的窗口
nnoremap <Leader>hw <C-W>h
" 跳转至上方的子窗口
nnoremap <Leader>kw <C-W>k
" 跳转至下方的子窗口
nnoremap <Leader>jw <C-W>j
" 定义快捷键在结对符之间跳转,助记pair
nmap <Leader>pa %
    其他。搜索、vim 命令补全等设置:
" 开启实时搜索功能
set incsearch
" 搜索时大小写不敏感
set ignorecase
" 关闭兼容模式
set nocompatible
" vim 自身命令行模式智能补全
set wildmenu
以上的四类配置不仅影响 vim,而且影响插件是否能正常运行。很多插件不仅要在 .vimrc 中添加各自特有的配置信息,还要增加 vim 自身的配置信息,在后文的各类插件介绍中,我只介绍对应插件特有配置信息,当你发现按文中介绍操作后插件未生效,很可能是 vim 自身配置信息未添加,所以一定要把上述配置拷贝至到你的 .vimrc 中,再对照本文介绍一步步操作。.vimrc 完整配置信息参见附录,每个配置项都有对应注释。另外,由于有些插件还未来得及安装,在你实验前面的插件是否生效时,vim 可能有报错信息提示,先别理会,安装完所有插件后自然对了。

0.2 .vim/ 目录
.vim/ 目录是存在所有插件的地方。vim 有一套自己的脚本语言 vimscript,通过这种脚本语言可以实现与vim交互,达到功能扩展的目的。一组 vimscript 就是一个vim插件,vim的很多功能都由各式插件实现。此外,vim 还支持 perl、python、lua、ruby 等主流脚本语言编写的插件,前提是 vim 源码编译时增加 ---enable-perlinterp、--enable-pythoninterp、--enable-luainterp、--enable-rubyinterp 等选项。vim.org 和 github.com 有丰富的插件资源,任何你想得到的功能,如果vim无法直接支持,那一般都有对应的插件为你服务,有需求时可以去逛逛。
vim 插件目前分为 *.vim 和 *.vba 两类,前者是传统格式的插件,实际上就是一个文本文件,通常 someplugin.vim(插件脚本)与 someplugin.txt(插件帮助文件)并存在一个打包文件中,解包后将 someplugin.vim 拷贝到 ~/.vim/plugin/ 目录,someplugin.txt 拷贝到 ~/.vim/doc/ 目录即可完成安装,重启 vim 后刚安装的插件就已经生效,但帮助文件需执行 :helptags ~/.vim/doc/ 才能生效,可通过 :h someplugin 查看插件帮助信息。传统格式插件需要解包和两次拷贝才能完成安装,相对较繁琐,所以后来又出现了 *.vba 格式插件,安装便捷,只需在 shell 中依次执行如下命令即可:
vim someplugin.vba
:so %
:q
不论是直接拷贝插件文件到目录,还是通过 *.vba 安装,都不便于插件卸载、升级,后来又出现了管理插件的插件 pathogen,后文介绍。
后面就正式开始了喽,文中前后内容顺序敏感,请依次查阅。

1 源码安装编辑器 vim
发行套件的软件源中预编译的 vim 要么不是最新版本,要么功能有阉割,有必要升级成全功能的最新版,当然,源码安装必须滴。
卸载老版、下载新版(ftp://ftp.vim.org/pub/vim/unix/vim-7.4.tar.bz2),解压至 ~/downloads/vim74/:
cd ~/downloads/vim74/
./configure --with-features=huge --enable-rubyinterp --enable-pythoninterp --with-python-config-dir=/usr/lib/python2.7/config/ --enable-perlinterp --enable-gui=gtk2 --enable-cscope --prefix=/usr --enable-luainterp
make VIMRUNTIMEDIR=/usr/share/vim/vim74 && make install
其中,--enable-rubyinterp、--enable-pythoninterp、--enable-perlinterp、--enable-luainterp 等分别表示支持 ruby、pthon、perl、lua 编写的插件,--enable-gui=gtk2 表示生成 gvim,--enable-cscope 支持 cscope,--with-python-config-dir=/usr/lib/python2.7/config/ 指定 python 路径,这几个特性非常重要,影响后面各类插件的使用。如果安装过程中出现缺失依赖库及其头文件,按提示自行安装后重新编译。

2 插件管理
既然本文主旨在于讲解如何通过插件将 vim 打造成中意的 C/C++ IDE,那么高效管理插件是首要解决的问题。
vim 自身希望通过在 .vim/ 目录中预定义子目录管理所有插件(比如,子目录 doc/ 存放插件帮助文档、plugin/ 存放通用插件脚本),vim 的各插件打包文档中通常也包含上述两个(甚至更多)子目录,用户将插件打包文档中的对应子目录拷贝至 .vim/ 目录即可完成插件的安装。一般情况下这种方式没问题,但我等重口味插件用户,.vim/ 将变得混乱不堪,至少存在如下几个问题:
    0)插件名字冲突。所有插件的帮助文档都在 doc/ 子目录、插件脚本都在 plugin/ 子目录,同个名字空间下必然引发名字冲突;
    1)插件卸载麻烦。你需要先知道 doc/ 和 plugin/ 子目录下哪些文件是属于该插件的,再逐一删除,容易多删/漏删。
我希望 .vim/ 下的每个子目录是对应一个插件,这样需要升级、卸载插件时,直接找到对应插件目录变更即可。pathogen 为此而生,它突破了 vim 只能识别 .vim/doc/、.vim/plugin/ 等等路径的限制,你可以在按插件名创建独立目录,然后将插件打包档提取至各自插件目录中。通常来说,你需要先创建 ~/.vim/bundle/ 目录,bundle/ 就是以后存放各插件目录的父目录。
安装:先清空 .vim/ 下的所有文件(备份?);创建目录 ~/.vim/bundle/pathogen/autoload/;下载 pathogen.vim(http://www.vim.org/scripts/script.php?script_id=2332)至 ~/.vim/bundle/pathogen/autoload/。
设置:接下来在 .vimrc 增加相关配置信息:
# 将 pathogen 自身也置于独立目录中,需指定其路径
runtime bundle/pathogen/autoload/pathogen.vim
# 运行 pathogen
execute pathogen#infect()
    使用:比如要安装新插件 plugin_name,先在 ~/.vim/bundle/ 下创建目录  plugin_name/,然后到 vim 官网下载 plugin_name 压缩包并解压至 ~/.vim/bundle/plugin_name/ 即可,注意不要重复包含多次 plugin_name/ 目录,如,~/.vim/bundle/plugin_name/plugin_name/。要卸载插件,直接删除 plugin_name/ 插件目录即可。另外,通过 pathogen 管理插件后,相较以前有几点变化:
    0)切勿通过发行套件自带的软件管理工具安装任何插件,不然 .vim/ 又要混乱了;    1)pathogen 无法安装配色主题风格,只能将主题插件手工放置于 ~/.vim/colors/;
    2)安装 *.vba 类型插件:
:e plugin_name.vba
:!mkdir -p ~/.vim/bundle/plugin_name
:UseVimball ~/.vim/bundle/plugin_name
    3)生成帮助文档:
:Helptags
非特殊情况,后文介绍到的插件不再累述如何安装。
另外,说说插件的下载源。相同插件在 vim.org 和 github.com 上都能找到,有些插件在 vim.org 上是最新版,有些又在 github.com 上更新,比如,indexer 插件,在 vim.org(http://www.vim.org/scripts/script.php?script_id=3221)上的版本是 4.15,而在 github.com 上的却是 1.2(https://github.com/shemerey/vim-indexer),所以我建议先去作者个人网站上找,没有再在 vim.org 和 github.com 上比较哪个的最新。甚至,同在 github.com 上都有很多重名插件,自己得稍微花时间确认下,本文中出现的插件,我都会附上最新版下载地址。

3 界面美化
玉不琢不成器,vim 不配不算美。刚安装好的 vim 朴素得吓人,这是与我同时代的软件么?
(默认 vim 界面)
就我的审美观而言,至少有几个问题:语法高亮太单薄、主题风格太简陋、窗口元素太冗余、辅助信息太欠缺。

3.1 主题风格
    一套好的配色方案绝对会影响你的编码效率,vim 内置了 10 多种配色方案供你选择,GUI 下,可以通过菜单(Edit -> Color Scheme)试用不同方案,字符模式下,需要你手工调整配置信息,再重启 vim 查看效果(csExplorer 插件,可在字符模式下不用重启即可查看效果)。不满意,可以去http://vimcolorschemetest.googlecode.com/svn/html/index-c.html慢慢选。我自认为“阅美无数”,目前最夯三甲得算素雅 solarized(https://github.com/altercation/vim-colors-solarized)、多彩 molokai(https://github.com/tomasr/molokai)、复古 phd(http://www.vim.org/scripts/script.php?script_id=3139)。前面说过,pathogen 无法安装主题插件,请将主题插件(仅 *.vim 文件而非插件目录,即,solarized.vim、molokai.vim、phd.vim)拷贝至 ~/.vim/colors/,然后在 .vimrc 中设定选用其作为主题:
" 配色方案
set background=dark
colorscheme solarized
"colorscheme molokai
"colorscheme phd
其中,不同主题都有暗/亮色系之分,这样三种主题六种风格,久不久换一换,给你不一样的心情:
(solarized 主题风格)

3.2 营造专注氛围
    如今的 UX 设计讲究的是内容至上,从 GNOME3 的变化就能看出。编辑器界面展示的应全是代码,不应该有工具条、菜单、滚动条浪费空间的元素,另外,编程是种精神高度集中的脑力劳动,不应出现闪烁光标、花哨鼠标这些分散注意力的东东。配置如下:
" 禁止光标闪烁
set gcr=a:block-blinkon0
" 禁止显示滚动条
set guioptions-=l
set guioptions-=L
set guioptions-=r
set guioptions-=R
" 禁止显示菜单和工具条
set guioptions-=m
set guioptions-=T
    重启 vim 后效果如下:
(去除冗余窗口元素)
    还容易分神?好吧,我们把 vim 弄成全屏模式。vim 自身无法实现全屏,必须借助第三方工具 wmctrl,一个控制窗口 XYZ 坐标、窗口尺寸的命令行工具。先自行安装 wmctrl,再在 .vimrc 中增加如下信息:
" 将外部命令 wmctrl 控制窗口最大化的命令行参数封装成一个 vim 的函数
fun! ToggleFullscreen()
    call system("wmctrl -ir " . v:windowid . " -b toggle,fullscreen")
endf
" 全屏开/关快捷键
map <silent> <F11> :call ToggleFullscreen()<CR>
" 启动 vim 时自动全屏
autocmd VimEnter * call ToggleFullscreen()

上面是一段简单的 vimscript 脚本,外部命令 wmctrl 及其命令行参数控制将指定窗口 windowid(即,vim)全屏,绑定快捷键 F11实现全屏/窗口模式切换(LINUX 下各 GUI 软件约定使用 F11 全屏,最好遵守约定),最后配置启动时自动全屏。



3.3添加辅助信息

去除了冗余元素让vim界面清爽多了,为那些实用辅助信息腾出了空间。光标当前位置、显示行号、高亮当前行/列等等都很有用:

"总是显示状态栏
setlaststatus=2

"显示光标当前位置
setruler

"开启行号显示
setnumber

"高亮显示当前行/
setcursorline
set cursorcolumn

"高亮显示搜索结果
sethlsearch

效果如下:

(添加辅助信息)



3.4其他美化

默认字体不好看,挑个自己喜欢的,前提是你得先安装好该字体。中文字体,我喜欢饱满方正的(微软雅黑),英文字体喜欢圆润的(Consolas),vim无法同时使用两种字体,怎么办?有人制作发布了一款中文字体用微软雅黑、英文字体用Consolas的混合字体——yaheiconsolas hybrid字体,号称最适合中国程序员使用的字体,效果非常不错(本文全文采用该字体)。在.vimrc中设置下:

"设置gvim显示字体
setguifont=YaHei\ Consolas\ Hybrid\ 11.5

其中,由于字体名存在空格,需要用转义符“\”进行转义;最后的11.5用于指定字体大小。

代码折行也不太美观,禁止掉:

"禁止折行
setnowrap

前面介绍的主题风格对状态栏不起作用,需要借助插件Powerlinehttps://github.com/Lokaltog/vim-powerline)美化状态栏,在.vimrc中设定状态栏主题风格:

"设置状态栏主题风格
letg:Powerline_colorscheme='solarized256'

效果如下:

(界面美化最终效果)

图中,中英文混合字体看着是不是很舒服哈;增强后的状态栏,不仅界面漂亮多了,而且多了好些辅助信息(所在函数名、文件编码格式、文件类型)。



4代码分析

阅读优秀开源项目源码是提高能力的重要手段,营造舒适、便利的阅读环境至关重要。



4.1语法高亮

代码只有一种颜色的编辑器,就好像红绿灯只有一种颜色的路口,全然无指引。现在已是千禧年后的十年了,早已告别上世纪六、七十年代黑底白字的时代,即使在字符模式下编程(感谢伟大的fbterm),我也需要语法高亮。所幸vim自身支持语法高亮,只需显式打开即可

"开启语法高亮功能
syntaxenable

"允许用指定语法高亮配色方案替换默认方案
syntaxon

效果如下:

(语法高亮)

上图中STL容器模板类unordered_multimap并未高亮,对滴,vimC++语法高亮支持不够好(特别是STLC++11新增元素),必须借由插件stl.vim进行增强,下载(http://www.vim.org/scripts/script.php?script_id=4293)后拷贝至~/.vim/bundle/STL-Syntax/after/syntax/cpp/,重启即可。效果如下:

增强C++11STL的语法高亮



4.2代码缩进

C/C++中的代码执行流由复合语句控制,如if(){}判断复合语句、for(){}循环符号语句等等,这势必出现大量缩进。缩进虽然不影响语法正确性,但对提升代码清晰度有不可替代的功效。

vim中有两类缩进表示法,一类是用1个制表符('\t'),一类是用多个空格('')。两者并无本质区别,只是源码文件存储的字符不同而已,但,缩进可视化插件对两类缩进显示方式不同,前者只能显示为粗块,后者可显示为细条,就我的审美观而言,选后者。增加如下配置信息:

"自适应不同语言的智能缩进
filetypeindent on

"将制表符扩展为空格
setexpandtab

"设置编辑时制表符占用空格数
settabstop=4

"设置格式化时制表符占用空格数
setshiftwidth=4

"vim把连续数量的空格视为一个制表符
setsofttabstop=4

其中,注意下expandtabtabstopshiftwidthsofttabstopretab

  • expandtab,把制表符转换为多个空格,具体空格数量参考tabstopshiftwidth变量;

  • tabstopshiftwidth是有区别的。tabstop指定我们在插入模式下输入一个制表符占据的空格数量,LINUX内核编码规范建议是8,看个人需要;shiftwidth指定在进行缩进格式化源码时制表符占据的空格数。所谓缩进格式化,指的是通过vim命令由vim自动对源码进行缩进处理,比如其他人的代码不满足你的缩进要求,你就可以对其进行缩进格式化。缩进格式化,需要先选中指定行,要么键入=vim对该行进行智能缩进格式化,要么按需键入多次<>手工缩进格式化;

  • softtabstop,如何处理连续多个空格。因为expandtab已经把制表符转换为空格,当你要删除制表符时你得连续删除多个空格,该就是告诉vim把连续数量的空格视为一个制表符,即,只删一个字符即可。通常应将这tabstopshiftwidthsofttabstop个变量设置为相同值;

另外,你总会阅读其他人的代码吧,他们对制表符定义规则与你不同,这时你可以手工执行vimretab命令,让vim按上述规则重新处理制表符与空格关系。

很多编码规范建议缩进(代码嵌套类似)最多不能超过4层,但难免有更多层的情况,缩进一多,我那个晕啊:

(多层缩进)

我希望有种可视化的方式能将相同缩进的代码关联起来,IndentGuideshttps://github.com/nathanaelkane/vim-indent-guides)来了。安装好该插件后,增加如下配置信息:

"vim自启动
letg:indent_guides_enable_on_vim_startup=1

"从第二层开始可视化显示缩进
letg:indent_guides_start_level=2

"色块宽度
letg:indent_guides_guide_size=1

"快捷键i/关缩进可视化
:nmap<silent> <Leader>i <Plug>IndentGuidesToggle

重启vim效果如下:

(不连续的缩进可视化)

(*__*)?断节?IndentGuides通过识别制表符来绘制缩进连接线,断节处是空行,没有制表符,自然绘制不出来,算是个小bug,但瑕不掩瑜,有个小技巧可以解决:换行-空格-退格:

(完美可视化缩进)



4.3代码折叠

有时为了去除干扰,集中精力在某部分代码片段上,我会把不关注部分代码折叠起来。vim自身支持多种折叠:手动建立折叠(manual)、基于缩进进行折叠(indent)、基于语法进行折叠(syntax)、未更改文本构成折叠(diff)等等,其中,indentsyntax比较适合编程,按需选用。增加如下配置信息:
" 基于缩进或语法进行代码折叠
"set foldmethod=indent
set foldmethod=syntax
" 启动 vim 时关闭折叠代码
set nofoldenable
    操作:za,打开或关闭当前折叠;zM,关闭所有折叠;zR,打开所有折叠。效果如下:
(代码折叠)

4.4 接口与实现快速切换
    我习惯把类的接口和实现分在不同文件中,肯定会出现编辑接口-编辑实现的循环,分别先打开接口文件(*.h)和实现文件(*.cpp),再手动切换是一种方式,但效率不高。我希望,假如我在接口文件中,vim 自动帮我找到对应的实现文件,当前键入快捷键,要么把当前窗口切换为对应实现文件,要么增加子窗口显示对应实现文件

a.vimhttps://github.com/vim-scripts/a.vim)来了。安装后增加配置信息:

"*.cpp*.h间切换
nmap<Leader>ch :A<CR>
"
子窗口中显示*.cpp*.h
nmap<Leader>sch :AS<CR>

这样,兼容;ch就能在实现文件和接口文件间切换,兼容;sch子窗口中将显示实现文件/接口文件。

a.vim实现原理很简单,基于文件名进行关联,比如,a.vim能识别my_class.hmy_class.cpp,而无法识别my_class.hyour_class.cpp。所以,你在命名文件时得注意下。



4.5代码收藏

源码分析过程中,常常需要在不同代码间来回跳转,我需要“收藏”分散在不同处的代码行,以便需要查看时能快速跳转过去,这时,vim的书签(mark)功能派上大用途了。

vim书签的使用很简单,在你需要收藏的代码行键入mm,这样就收藏好了,你试试,没反应?不会吧,难道你LINUX内核编译参数有问题,或者,vim的编译参数没给全,让我想想,别急,喔,对了,你是指看不到书签?对对对,书签本来就看不到吖。这可不行,小二,来个让书签可视化的插件,亲,来了,visualmarkhttps://github.com/vim-scripts/Visual-Mark),记得好评。

visual mark使用快捷键mm创建/删除书签,F2正向遍历书签,Shift+ F2 逆向遍历,不太方便,得改;另外,书签颜色不好看,得调。看

看帮助如何配置,昏,没帮助,得,直接改它的源码吧。找到~/.vim/bundle/Visual-Mark/plugin/visualmark.vim,将

map<unique> <F2> <Plug>Vm_goto_next_sign
map<unique> <s-F2> <Plug>Vm_goto_prev_sign

替换成

map<unique>mn <Plug>Vm_goto_next_sign
map<unique> mp <Plug>Vm_goto_prev_sign

这样,mn正向遍历书签、mp逆向遍历;再将

if&bg == "dark"
highlight SignColor ctermfg=whitectermbg=blue guifg=white guibg=RoyalBlue3
else
highlightSignColor ctermbg=white ctermfg=blue guibg=grey guifg=RoyalBlue3
endif

替换成

if&bg == "dark"
highlight SignColor ctermfg=whitectermbg=blue guifg=#FD971F guibg=#1D1D1D
else
highlightSignColor ctermbg=white ctermfg=blue guifg=LightGreenguibg=DarkRed
endif

你可以根据自己喜好提取喜欢颜色的RGB(推荐,提色工具gpick,色卡http://www.colorschemer.com/schemes/),按上例设置即可。提醒下,RGB的前缀是#而非0X,别惯性思维.*_*.

效果如下:
(可视化书签)
    另外,我虽然选用了 visual mark,但不代表它完美了,对我而言,存在两个硬伤:一是,创建的书签无法保存,下次打开该文件后又得重新窗口;一是,无法在不同文件的书签间跳转。前者可借由 vim 的 session 和 viminfo 特性解决,详见后文“环境恢复”节,后者暂无解决思路,只能先切换文件再跳转书签。

4.6 代码导航
    假设你正在分析某个开源项目源码,在 main.cpp 中遇到调用函数 func(),想要查看它如何实现,一种方式:在 main.cpp 中查找 -> 若没有在工程内查找 -> 找到后打开对应文件 -> 文件内查找其所在行 -> 移动光标到该行 -> 分析完后切换会先前文件,不仅效率太低更要命的是影响我的思维连续性。我需要另外高效的方式,就像真正函数调用一样:光标选中调用处的 func() -> 键入某个快捷键自动转换到 func() 实现处 -> 键入某个键又回到 func() 调用处,这就是所谓的代码导航。
    先了解下什么是标签(tag)。这可厉害了,标签可谓是现代 IDE 的基石之一,没有它,类/函数/对象列表、代码补全、代码导航、函数原型提示等等功能是不可能实现的。代码中的类、结构、类成员、函数、对象、宏这些元素就是标签,每个标签有它自己的名字、定义、类型、所在文件中的行位置、所在文件的路径等等属性。
    编译环节之一就是提取标签,但由于编译器并未把生成的标签输出至文本,后来出现了专门用于生成标签的工具 Exuberant Ctags (http://ctags.sourceforge.net/,有墙,后简称 ctags)。ctags,最初只支持生成 C/C++ 语言的标签,目前已支持 41 种语言,具体列表运行如下命令获取:
ctags --list-languages
    学习知识最好方式就是动手实践。我们以 main.cpp、my_class.h、my_class.cpp 三个文件为例:
    第一步,准备代码文件。创建演示目录
/data/workplace/example/
、库子目录/data/workplace/example/lib/,创建如下内容的main.cpp

#include<iostring>
#include <string>
#include"lib/my_class.h"

usingnamespace std;

intg_num = 128;

//重载函数
staticvoid
printMsg (char ch)
{
std::cout << ch <<std::endl;
}

int
main (void)
{
//
局部对象
conststring name = "yangyang.gnu";

//
MyClass one;

//成员函数
one.printMsg();

//使用局部对象
cout<< g_num << name << endl;

return (EXIT_SUCCESS);
}

创建如下内容的my_class.h

#pragmaonce

classMyClass
{
public:
void printMsg(void);

private:
;
};

创建如下内容的my_class.cpp

#include"my_class.h"

//重载函数
staticvoid
printMsg (int i)
{
std::cout << i <<std::endl;
}

void
MyClass::printMsg (void)
{
std::cout << "I'MMyClass!" << std::endl;
}

第二步,生成标签文件。现在运行ctags生成标签文件:

cd/data/workplace/example/
ctags -R--c++-kinds=+p+l+x+c+d+e+f+g+m+n+s+t+u+v --fields=+liaS --extra=+q--language-force=c++

命令行参数较

多,主要关注--c++-kindsctags默认并不会提取所有标签,运行

ctags--list-kinds=c++

可看到ctags支持生成标签类型的全量列表:

c classes
d macro definitions
e enumerators (values insidean enumeration)
f function definitions
g enumeration names
l local variables [off]
m class, struct, and unionmembers
n namespaces
p function prototypes [off]
s structure names
t typedefs
u union names
v variabledefinitions
x external and forward variable declarations[off]

其中,标为off的局部对象、函数声明、外部对象等类型默认不会生成标签,所以我显式加上所有类型。运行完后,example/下多了个文件tags,内容大致如下:

!_TAG_FILE_FORMAT 2 /extendedformat; --format=1 will not append ;" to lines/
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
!_TAG_PROGRAM_AUTHOR DarrenHiebert /dhiebert@users.sourceforge.net/
!_TAG_PROGRAM_NAME Exuberant Ctags //
!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
!_TAG_PROGRAM_VERSION 5.8 //
MyClass lib/my_class.h /^classMyClass $/;" c
MyClass::printMsg lib/my_class.cpp /^MyClass::printMsg (void)$/;" f class:MyClass signature:(void)
MyClass::printMsg lib/my_class.h /^ voidprintMsg(void);$/;" p class:MyClass access:public signature:(void)
endl lib/my_class.cpp /^ std::cout << "I'M MyClass!"<< std::endl;$/;" m class:std file:
endl lib/my_class.cpp /^ std::cout << i <<std::endl;$/;" m class:std file:
endl main.cpp /^ cout <<g_num << name << endl;$/;" l
endl main.cpp /^ std::cout << ch <<std::endl;$/;" m class:std file:
g_num main.cpp /^int g_num= 128;$/;" v
main main.cpp /^main (void)$/;" f signature:(void)
name main.cpp /^ const string name ="yangyang.gnu";$/;" l
one main.cpp /^ MyClass one;$/;" l
printMsg lib/my_class.cpp /^MyClass::printMsg (void)$/;" f class:MyClass signature:(void)
printMsg lib/my_class.cpp /^printMsg (int i)$/;" f file: signature:(int i)
printMsg lib/my_class.h /^ voidprintMsg(void);$/;" p class:MyClass access:public signature:(void)
printMsg main.cpp /^ one.printMsg();$/;" p file: signature:()
printMsg main.cpp /^printMsg (char ch)$/;" f file: signature:(char ch)
std::endl lib/my_class.cpp /^ std::cout << "I'MMyClass!" << std::endl;$/;" m class:std file:
std::endl lib/my_class.cpp /^ std::cout << i <<std::endl;$/;" m class:std file:
std::endl main.cpp /^ std::cout << ch <<std::endl;$/;" m class:std file:

其中,!开头的几行是ctags生成的软件信息忽略之,下面的就是我们需要的标签,每个标签项至少有如下字段(命令行参数不同标签项的字段数不同):标签名、标签所在的文件名(也是文件路径)、标签项所在行的内容、标签类型(如,l表示局部对象),另外,如果是函数,则有函数签名字段,如果是成员函数,则有访问性字段等等。

第三步,引入标签文件。就是让vim知晓标签文件的路径。在/data/workp

lace/example/目录下用vim打开main.cpp,在vim中执行如下目录引入标签文件tags

:settags+=/data/workplace/example/tags

既然vim有个专门的命令来引入标签,说明vim能识别标签。虽然标签文件中并无行号,但已经有标签所在文件,以及标签所在行的完整内容,vim只需切换至对应文件,再在文件内作内容查找即可找到对应行。换言之,只要有对应的标签文件,vim就能根据标签跳转至标签定义处。

这时,你可以体验下初级的代码导航功能。把光标移到main.cppone.printMsg()那行的printMsg上,键入快捷键g]vim将罗列出名为printMsg的所有标签候选列表,按需选择键入编号即可导航进入。如下图:

(待选标签)

目前为止,离我预期还有差距。

第一,选择候选列表影响思维连续性。首先得明白为何会出现待选列表。前面说过,vim做的事情很简单,就是把光标所在单词放到标签文件中查找,如果只有一个,当前你可以直接导航过去,大部分时候会找到多项匹配标签,比如,函数声明、函数定义、函数调用、函数重载等等都会导致同个函数名出现在多个标签中,vim

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值