阅读 325

搭建基于 Vim 的 C++和 Python 开发环境[持续更新]

最近 vscode 在技术圈火了一阵子,每天都可以在掘金上看到安利文章和奇葩的插件,什么"杨超越鼓励师",还有上班摸鱼系列,"看小说插件","看股票插件",让我越发觉得 vscode 的功能越来越强大,强大到可以做任何事情,就像操作系统,而这有没有很像神之编辑器 emacs。最近台湾 emacs 圈中出了一个叛徒,最后这个维护人叛逃到 vscode 阵营并将这一消息发布到了台湾官方 emacs 推特。

编辑器之争,在语言还在蓬勃发展的今天仍在持续,Vim 和 Emacs 谁是最好的编辑器,在程序员的圈子里是一个经久不衰的话题,不论在哪个地方都能轻而易举的引起一场圣战。在公司里使用的开发语言主要是 C++ 和 python,小组同事使用的开发环境也是各种各样,有 NetBean,vscode,C++ eclipse,pycharm 以及 vim。编辑器或 IDE 始终都只是工具,工具的价值不是看它功能有多强大,有多丰富,要看它能给我们产生多少价值,所以同个工具的价值没办法放在不同的人上去比较。我的观点是如果你在开发过程中会经常使用两到三个语言,开发过程中习惯的衔接很重要,我会推荐使用 vim;但是IDE是一个经过高度封装的工具,它对开发流程,开发方式等有一定的假设,所以在很多时候特别是实际项目中,也会为我们节约了大量宝贵的时间。

每种 IDE 都有自己的配置和使用习惯,数量一多,切换来切换去学习成本也很高。除了 vim,平时我也会在 windows 下使用 sublime 看看代码,因为轻快且在 windows 下可以快速编辑剪切复制。用过 pycharm 开发过 python,用过一段时间 eclipse 进行 C++ 开发,结合 beyond compare 方便把 windows 下代码同步到远程 linux 上,然后再进行 make 编译,但最后都统一切到了 vim。

说说我选择 vim 作为主力开发环境的原因,IDE 很多,学习成本一样很高,使用 N 种语言就可能会有 N 种 IDE。IDE 有它自己的好处,它已经针对某种语言进行集成优化,用户需要配置的东西其实不会很多。但其实越高度固化的东西可能越不好用,缺少一定的灵活性。vim 插件多,支持各种语言,同时也解决了 linux 同步运行问题,著名的插件在 github 和 stackoverflow 都很活跃,一个 vim 解决所有 ide。

我使用的 vim 进行 python 和 C++ 进行后台开发,最主要的功能还是不能没有,提示补全,定义跳转,关键词搜索,语法高亮,语法检查,缩进折叠,函数展示大纲,文件模板,目录树等等,而我的 vim 现在也可以方便完成这些功能。

下面开始说说 2019,我使用的 vim 插件,主要是简单的介绍,每一个我都会简单介绍插件和使用操作,以及最重要的文档,因为里面有更详细的使用信息。

学习资源

在 github 上有一个不错的 vim 学习资源,从最简单的介绍起:

Vim 从入门到精通github.com/wsdjeg/vim-… 笨方法学 vimscriptwww.treelib.com/book-detail…

另外,很多 vim 插件我还在知乎上关注一些 Vimer,比如:

  1. 韦易笑(www.zhihu.com/people/skyw…)
  2. 赵启明(www.zhihu.com/people/zhao…)
  3. Vim专栏(zhuanlan.zhihu.com/hack-vim)

一般都会介绍如何搭建 Vim IDE 和插件。

另外,我还喜欢在 github 上通过查找 vim 相关的插件,按照 Most Star 降序浏览。

我的 .vimrc 参考:github.com/cposture/my…

插件管理

插件

vim 8 已经支持异步执行功能了,并且在大多数插件中得到了支持,异步插件管理器,比如 plug.vim,在更新插件再也不用等那么久了,不再推荐老牌的 vundle。

vim-plug 不仅支持异步更新功能,还支持针对文件类型和启动命令的延迟加载功能,让 vim 的启动速度再提高很多。

文档

  1. 安装和使用参考:blog.jobbole.com/114132/
  2. 延迟加载插件的技术:segmentfault.com/a/119000001…
  3. vim 启动速度慢分析:segmentfault.com/a/119000001…

配置

延迟加载插件

plug.vim 支持插件延迟加载,不至于不相关的插件一开始都启动;plug.vim 支持按命令(command)或文件类型(file_type)这两种配置。

" 在第一次执行 NERDTreeToggle 命令时,NERD tree 插件才开始加载
Plug 'scrooloose/nerdtree', { 'on': 'NERDTreeToggle' }
" on 支持多命令
Plug 'junegunn/vim-github-dashboard', { 'on': ['GHDashboard', 'GHActivity'] }
" 打开 clojure 类型的文件时,vim-fireplace' 才开始加载
Plug 'tpope/vim-fireplace', { 'for': 'clojure' }
" for 支持多文件类型
Plug 'kovisoft/paredit', { 'for': ['clojure', 'scheme'] }
复制代码

使用 on 延迟加载 YouCompleteMe 方法:

  1. 先把 on 命令列表置空,默认不启动
  2. 我们使用自动命令,可以让Vim自动执行指定的命令,指定的命令会在指定事件发生的时候执行;进入 insert 模式时,手动调用 call plug#load('YouCompleteMe')
  3. 删除自动命令组
# on 为空,后面手动加载
Plug '~/YouCompleteMe', {'on': []}
augroup load_ycm
    autocmd!
    "延迟加载,在 insert 模式手动加载插件
    autocmd InsertEnter * call plug#load('YouCompleteMe') | autocmd! load_ycm
augroup END
复制代码

延迟加载不是银弹,最终要看是不是有这个需求;所以我们一般在出现启动比较慢的情况下才去尝试使用延迟加载。另外,一般插件的作者都要考虑本身延迟加载功能,而不是依靠等待外部插件去实现延迟加载。

那么如何启动速度慢的情况下分析插件问题呢?

vim 启动时可以指定选项,vim --startuptime vim.log -c q,启动时把计时信息写入文件,用于分析载入 .vimrc、插件和打开首个文件的过程中时哪一步最耗时。

times in msec
 clock self+sourced self: sourced script
 clock elapsed: other lines
...
003.691 002.008 002.008: sourcing /home/luffichen/.vim/autoload/plug.vim
021.676 000.021 000.021: sourcing /usr/local/share/vim/vim81/filetype.vim
021.869 000.017 000.017: sourcing /usr/local/share/vim/vim81/filetype.vim
...
复制代码

其中第一列是时间点,第二列和第三列都是时长(区别:第二个是self+sourced,第三个是self),我们主要关注第三列,脚本本身的执行时间。

因为同一个插件会有多行数据,我们要手动把同一插件的第三列统计一个总和,这样很繁琐,所以 github 上有人写了一个插件,专门用于分析每个插件的执行耗时,并输出直线图,具体可以看看:github.com/hyiltiz/vim…

还有其他分析方法,具体可见: VIM加速:segmentfault.com/a/119000001…

简明操作

  1. :PlugInstall,安装已添加到 .vimrc 的插件
  2. :PlugStatus,查看安装进度
  3. :PlugClean,删除不在配置文件里的插件

离线安装插件

因为公司的 Linux 开发环境一般无法连接到外网,所以不能直接使用 plug 从 github 上安装插件,我的方法是:

以 auto-pairs 为例,

  1. 在可以访问外网的环境,git clone https://github.com/jiangmiao/auto-pairs
  2. 打包压缩 auto-pairs.zip
  3. 上传压缩包到服务器,并解压,rz -byeunzip auto-pairs.zip
  4. 统一拷贝到自定义的插件目录,我这里都放在目录 ~/vim-plugin 下,cp -rf auto-pairs ~/vim-plugin/
  5. 配置 .vimrc,指定插件的本地目录,Plug '~/vim-plugin/auto-pairs'
  6. 运行 vim,并执行 :PlugInstall
  7. 查看安装情况,:PlugStatus

提示补全

插件

这几个插件完美的解决了 C++ 和 python 的代码补全和提示,其他语言可以参考其他的介绍。

随着 vscode lsp 协议的推广,vim 语法补全也出现了相应的插件,比如 coc.nvim,主要是异步并且支持很多 vscode 上的语法补全插件,可以试用一下(ps:公司的系统版本比较老并且网络不通,所以一直没去折腾这插件,后面听说出现了一个打包版本,可以不用安装,后面有需求可以试用一下)。

coc.nvim 具体的介绍:zhuanlan.zhihu.com/p/39302327 coc.nvim:github.com/neoclide/co…

目前,C/C++ 的补全的话,请直接使用YouCompleteMe,没有之一;另外 YCM-Generator 主要用于解决 YouCompleteMe 配置文件生成麻烦问题。

本来最新版本的 YCM 也支持 python 的补全,只要安装一个 jedi 就可以了,但是公司开发环境系统版本不是很高,编译不了最新版本的 YCM,所以安装一个以后端 jedi 为补全客户端的插件 jedi-vim

本来还想介绍一下 SuperTab(github.com/ervandew/su…),它实现的功能简单的说就是用 tab 来调用 vim 的补全功能,这和 linux 操作习惯完全一致,并且方便而合理,但是 YCM 本身就包含了 SuperTab 的功能,所以不再多余的安装 SuperTab 插件了,以免冲突。另外 YCM 文档还说了包含其他插件的功能,具体如下:

clang_complete
AutoComplPop
Supertab
neocomplcache
复制代码

最后补充下 omnicomple,有时 YCM 和 jedi-vim 没办法在某些情况下进行补全,比如我经常遇到,我只想补全我之前写过的一个 word,这个 word 可能只是注释里的一个单词,YCM 没办法找出它;这个时候我会使用 omnicomple 命令系列。

文档

  1. jedi-vim 插件安装参考文档安装部分:xmfbit.github.io/2018/10/02/…
  2. omnicomplete,vim 万能补全,:help ins-completion
  3. YCM 操作详细参考:github.com/Valloric/Yo…
  4. YCM 配置:zhuanlan.zhihu.com/p/33046090

配置

YCM

YCM 的补全需要对文件进行语法分析,所以需要依赖 .ycm_extra_conf.py 配置文件,生成 .ycm_extra_conf.py 配置文件在 google 上有详细的介绍,我们这里使用 YCM-Generator 插件,可以对 make 编译系统生成需要的配置文件。

"=========================================
" YCM-Generator 插件配置
"=========================================
" ctrl-I 自动生成 .ycm_extra_conf.py 文件
noremap <C-I> :YcmGenerateConfig -c g++ -v -x c++ -f -b make .<CR>
复制代码

上面的配置加到 .vimrc 后,只要在项目根目录打开后执行快捷键 Ctrl - i 后就会自动在当前目录生成配置文件

  1. ctrl + I,自动生成 .ycm_extra_conf.py 文件
  2. Ctrl + Space,在任何地方触发完成建议,即使没有字符串前缀也是如此。这对于查看哪些顶级函数可供使用很有用。
  3. :YcmRestartServer,重新启动
  4. :YcmDiags:YcmDebugInfo,查询信息
  5. :YcmCompleter 命令,配合其他子选项完成功能,例如,GoToDeclaration 跳转到声明处

omnicomple

  1. Ctrl-X Ctrl-L:整行补全
  2. Ctrl-X Ctrl-N:当前文件内关键字补全
  3. Ctrl-X Ctrl-i:当前文件及其头文件内的关键字
  4. Ctrl-X Ctrl-]:tags补全
  5. Ctrl-X Ctrl-F:文件名补全
  6. Ctrl-X Ctrl-O:全能 (omni) 补全

有了 YCM 补全为什么需要 omni,YCM 没办法补全 buffer 内的字符串,这个时候就要用 Ctrl-X Ctrl-N

jedi-vim

  1. leader + d:定义跳转,包括语句和 import 模块
  2. leader + n:查看用法
  3. leader + r:重命名
  4. :Pyimport os:打开模块 os
  5. Ctrl + space:补全

说明

  1. centos 系统比较老,使用 YCM 版本不是最新的,我这里为 github.com/Valloric/Yo… 版本为 clang+llvm-3.3-amd64-Ubuntu-10.04.4.tar.gz

语法高亮

插件

vim-polyglot 是一个开箱即用型的语法高亮包,还有对齐功能,支持134 种语言;同时全部语言文件都是针对文件类型进行延迟加载的,不会影响到 vim 的启动速度。

具体的支持语言可以参考 github 上的介绍:github.com/sheerun/vim…

配置

几乎不用加载配置,只需要 vim 打开 syntax 功能。

syntax on
复制代码

缩进线

插件

indentLine 是一个显示竖直对齐线的插件 ,习惯让代码整齐,但是插件只支持空格对齐的代码,所以对于 tab 对齐的不会显示对齐线;因为不同的编辑器对 tab 的展示不太一样,有的展示 4 个空格,有的展示 8 个;我的习惯是让 vim 将输入的 tab 自动转化为 4 个空格,这样的代码在所有的编辑器的展示都是一样的。

tab 自动转化为 4 个空格:

"将输入的TAB自动展开成空格。开启后要输入TAB,需要Ctrl-V<TAB>
set expandtab
"使用每层缩进的空格数
set shiftwidth=4
"编辑时一个TAB字符占多少个空格的位置
set tabstop=4
"方便在开启了et后使用退格(backspace)键,每次退格将删除X个空格
set softtabstop=4
" 使回格键(backspace)正常处理indent(缩进位置), eol(行结束符), start(段首), 很奇怪 Vim 默认竟然不允许在这些地方使用 backspace
set backspace=indent,eol,start
"开启时,在行首按TAB将加入 shiftwidth 个空格,否则加入 tabstop 个空格
set smarttab
复制代码

indentLine 配置:

"打开缩进线
let g:indentLine_enabled = 1
let g:indentLine_char='¦'
复制代码

操作

  1. :IndentLinesToggle,打开缩进线

语法高亮+缩进线图

语法检查

插件

ale 是一款语法检查的插件,与syntastic类似,但有一个明显的优势,一个是语法检查是异步执行的,因此基本上不会出现卡顿的情况,但它只支持Vim 8.0以上的版本。

Ale 支持多种语言的各种代码分析器,就 C/C++ 而言,就支持:gcc, clang, cppcheck 以及 clang-format 等,需要另行安装并放入 PATH下面,ALE能在你修改了文本后自动调用这些 linter 来分析最新代码,然后将各种 linter 的结果进行汇总并显示再界面上。

因为 LSP 协议支持语法检查,所以 ALE 后面又支持 LSP,又顺便支持了 LSP 语法补全功能,导致 ALE 越来越庞大,后面我基本只将它作为语法检查插件来使用。

ALE 和 clang 的工具集集合起来使用应该很不错,https://github.com/w0rp/ale/blob/master/doc/ale-c.txt 在这里有很多关于 clang 的配置选项,支持 compile_commands.json,免去头文件查找问题,可惜公司的系统版本较老。

文档

  1. ale 官方文档:github.com/w0rp/ale/tr…
  2. Vim插件之ale:www.cnblogs.com/awakenedy/a…

配置

ale

ale 的配置一般都要指定语言的特定 linter 和 linter 选项;我这里只配置了 C++,C 和 python 的语法检查,C++ 和 C 使用 cppcheck,python 使用 pylint;所以这里需要额外安装 cppcheckpylint 外部程序。

g:ale_linters 用于指定 linter,同时我配置了只在修改 normal 和离开 insert 时才会进行语法检查,避免影响速度。

let g:ale_linters = {
            \ 'cpp': ['cppcheck'],
            \ 'c': ['cppcheck'],
            \ 'python': ['pylint'],
            \}
" normal 模式下文字改变运行 linter
let g:ale_lint_on_text_changed = 'normal'
" 离开 insert 模式的时候运行 linter
let g:ale_lint_on_insert_leave = 1
let g:ale_c_cppcheck_options = '--enable=all'
let g:ale_cpp_cppcheck_options = '--enable=all'
复制代码

以一小段有代码展示 cppcheck 和 ale 的语法检查结果:

int *ptr_list = NULL;
*ptr_list = 1;
复制代码

最下面的状态栏和左边栏都会提示错误:Null pointer dereference,如下:

关键词搜索

插件

FlyGrep 是从 SpaceVim(spacevim.org/cn/)中移植出来的实时代码检索工具,而且支持正则表达式,配置一个快捷键 Ctrl-F 后就和其他 IDE 的搜索没有什么区别了。

FlyGrep 只能搜索当前目录下的文件,所以如果想搜索整个项目,需要先切换到项目根目录。

文档

  1. FlyGrep 具体介绍和使用方法可以参考官方文档:github.com/wsdjeg/FlyG…

配置

FlyGrep

绑定快捷键 Ctrl-F:

"=========================================
" FlyGrep 插件配置
"=========================================
nnoremap <C-F> :FlyGrep<CR>
复制代码

操作

FlyGrep

  1. Ctrl-F,在当前目录下搜索关键词,这里我一般是在项目根目录下搜索,所以先移动收到根目录
  2. <Esc>,退出搜索
  3. <Enter>,进入选中的搜索结果
  4. <Tab>,下一个搜索结果
  5. <S-Tab>,上一个搜索结果
  6. <Home>,第一个开始结果
  7. <End>,最后一个搜索结果

vim 自带

以搜索关键词 "main" 为例:

  1. :vim /main/ % | copen:只搜索当前文件

  2. vim /main/ * | copen:只搜索当前目录

  3. vim /main/ ../** | copen:搜索上级目录下,并递归

  4. vim /main path1/** path2/** | copen:可以在多个路径中搜索

说明:

  1. % 表示当前文件
  2. copen 用于打开一个窗口,存放搜索结果,方便跳转

搜索图

源文件头文件切换

插件

C++ 项目经常需要在 header 和对应的 source 文件之前切换;CurtineIncSw 就提供了这样的功能,不过它的切换是有一定的前提的:

  1. 头文件和源文件除了后缀名和目录不一样,文件名应该是一样的;比如 foo.c 对应 foo.h
  2. 两个文件要么在同级目录,要么将要打开的文件在已打开文件的子目录

操作:

  1. leader-R:从头文件和源文件互切换

跳转

python 的跳转,我这边使用的是 jedi-vim 插件;C++ 的跳转我使用 vim + ctags 工具;标签的跳转使用 vim-matchup。

ctags 需要自己安装。

过去写几行代码又需要运行一下 ctags 来生成索引,每次生成耗费不少时间。

如今 Vim 8 下面自动异步生成 tags 的工具有很多,这里推荐:vim-gutentags,这个插件主要做两件事情:

  1. 确定文件所属的工程目录,即文件当前路径向上递归查找是否有 .git, .svn, .project 等标志性文件(可以自定义)来确定当前文档所属的工程目录。
  2. 检测同一个工程下面的文件改动,能会自动增量更新对应工程的 .tags 文件。每次改了几行不用全部重新生成,并且这个增量更新能够保证 .tags 文件的符号排序,方便 Vim 中用二分查找快速搜索符号。

配置

vim-gutentags

" gutentags 搜索工程目录的标志,碰到这些文件/目录名就停止向上一级目录递归
let g:gutentags_project_root = ['.root', '.svn', '.git', '.hg', '.project']

" 所生成的数据文件的名称
let g:gutentags_ctags_tagfile = '.tags'

" 将自动生成的 tags 文件全部放入 ~/.cache/tags 目录中,避免污染工程目录
let s:vim_tags = expand('~/.cache/tags')
let g:gutentags_cache_dir = s:vim_tags

" 配置 ctags 的参数
let g:gutentags_ctags_extra_args = ['--fields=+niazS', '--extra=+q']
let g:gutentags_ctags_extra_args += ['--c++-kinds=+px']
let g:gutentags_ctags_extra_args += ['--c-kinds=+px']
复制代码

有了上面的设置,你平时基本感觉不到 tags 文件的生成过程了,只要文件修改过,gutentags 都在后台为你默默打点是否需要更新数据文件,你根本不用管,还会帮你:setlocal tags+=...

为当前文件添加上对应的 tags 文件的路劲而不影响其他文件。得益于 Vim 8 的异步机制,你可以任意随时使用 ctags 相关功能,并且数据库都是最新的。需要注意的是,gutentags 需要靠上面定义的 project_root 里的标志,判断文件所在的工程,如果一个文件没有托管在 .git/.svn 中,gutentags 找不到工程目录的话,就不会为该野文件生成 tags,这也很合理。想要避免的话,你可以在你的野文件目录中放一个名字为 .root 的空白文件,主动告诉 gutentags 这里就是工程目录。

操作

  • 操作:
  1. ctrl+]:跳进
  2. ctrl+o:跳回
  3. %:跳转到下一个标签

文档

  1. stackoverflow.com/questions/1…
  2. vim.wikia.com/wiki/Single…
  3. blog.csdn.net/gangyanlian…
  4. releases.llvm.org/3.7.0/tools…
  5. www.skywind.me/blog/archiv…

文件模版

vim模板插件 segmentfault.com/a/119000000… Vim为特定文件载入模板 blog.csdn.net/demorngel/a…

状态栏

插件

vim-airline 是 powerline 的替代品,并且能够和 tarbar 一起工作。这两个插件装完,状态栏,大纲预览以及任务栏都齐了。

文档

  1. vim-airline 官方文档:github.com/vim-airline…
  2. tarbar 安装文档:www.wklken.me/posts/2015/…

窗口

类/方法/变量相关侧边栏

  • 操作:
  1. F9 打开
  • 插件:
  1. majutsushi/tagbar

上方 Tab 栏

  • 操作:
  1. ctrl+left,打开文件列表右边文件
  2. ctrl+right,打开文件列表左边文件
  3. ctrl+n,打开下一个 tab
  4. ctrl+p,打开上一个 tab

C/C++ 格式化

  1. F4,在 normal 模式,格式化文件代码;在 visual 模式,格式化选中的代码

折叠

插件:github.com/tmhedberg/S… 操作:zc关闭折叠并zo打开折叠

缩进

操作:<<>>,==命令来缩进当前行,可视化模式选择多行,使用=命令缩进选中的行 文档:yyq123.blogspot.com/2010/10/vim…

复制粘贴

vim 复制到 windows

  • 安装 x11:yum install libX11 libX11-devel libXtst-devel libXtst libXt-devel libXt libSM-devel libSM libXpm libXpm-devel
  • 下载 vim 8 源码,编译:
  1. ./configure --prefix=/data/luffichen/bin/vim-8.1 --with-features=huge --with-luajit --enable-luainterp=yes --enable-fail-if-missing --enable-pythoninterp=yes --with-x=yes --enable-gui=auto
  2. 查看是否支持 X11:grep X11 src/auto/config.h 如果有 #define HAVE_X11 1 #define HAVE_X11_XPM_H 1 #define HAVE_X11_SM_SMLIB_H 1 即表示依赖成功
  3. make -j4 && make install
  4. vim --version | grep clipboard 查看是否支持
  5. Run Xshell and connect to the server using the SSH protocol with X11 forwarding,具体的操作:文件-默认会话属性-隧道-X11转移,选择 X Display
  6. 配置ssh,vi /etc/ssh/sshd_config 确认有配置 X11Forwrding yes,允许SSH的X转发
  7. 安装VcXsrv X11 Server,sourceforge.net/projects/vc… 的剪切板功能貌似对中文支持不好,所以这里使用 VcXsrv)
  8. 打开 XLaunch,选择 multiple windows,和 display number 为 0,start no client,勾选 clipbord
  • 操作:
  1. visual 模式,选择要复制的内容后执行 +y,即可 安装luajit :blog.csdn.net/tao_627/art…
关注下面的标签,发现更多相似文章
评论