美文网首页大数据 爬虫Python AI SqlPython小哥哥
搭建基于 Vim 的 C++和 Python 开发环境!

搭建基于 Vim 的 C++和 Python 开发环境!

作者: 14e61d025165 | 来源:发表于2019-05-16 16:33 被阅读1次

    最近 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 的启动速度再提高很多。

    image

    文档

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

    配置

    延迟加载插件

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

    <pre class="prettyprint hljs vim">" 在第一次执行 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'] }
    复制代码</pre>

    使用 on 延迟加载 YouCompleteMe 方法:

    1. 先把 on 命令列表置空,默认不启动
    2. 我们使用自动命令,可以让Vim自动执行指定的命令,指定的命令会在指定事件发生的时候执行;进入 insert 模式时,手动调用 call plug#load('YouCompleteMe')
    3. 删除自动命令组

    <pre class="prettyprint hljs vim"># on 为空,后面手动加载
    Plug '~/YouCompleteMe', {'on': []}
    augroup load_ycm
    autocmd!
    "延迟加载,在 insert 模式手动加载插件
    autocmd InsertEnter * call plug#load('YouCompleteMe') | autocmd! load_ycm
    augroup END
    复制代码</pre>

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

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

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

    <pre class="prettyprint hljs groovy">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
    ...
    复制代码</pre>

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

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

    image

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

    简明操作

    <pre class="hljs clojure">:PlugInstall
    :PlugStatus
    :PlugClean
    </pre>

    离线安装插件

    因为公司的 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 文档还说了包含其他插件的功能,具体如下:

    <pre class="prettyprint hljs nginx">clang_complete
    AutoComplPop
    Supertab
    neocomplcache
    复制代码</pre>

    最后补充下 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 编译系统生成需要的配置文件。

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

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

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

    omnicomple

    <pre class="prettyprint hljs">Ctrl-X Ctrl-L
    Ctrl-X Ctrl-N
    Ctrl-X Ctrl-i
    Ctrl-X Ctrl-]
    Ctrl-X Ctrl-F
    Ctrl-X Ctrl-O
    </pre>

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

    jedi-vim

    <pre class="hljs lua">leader + d
    leader + n
    leader + r
    :Pyimport os
    Ctrl + space
    </pre>

    说明

    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 功能。

    <pre class="hljs nginx">syntax on
    复制代码</pre>

    缩进线

    插件

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

    tab 自动转化为 4 个空格:

    <pre class="prettyprint hljs vim">"将输入的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
    复制代码</pre>

    indentLine 配置:

    <pre class="prettyprint hljs vim">"打开缩进线
    let g:indentLine_enabled = 1
    let g:indentLine_char='¦'
    复制代码</pre>

    操作

    1. :IndentLinesToggle ,打开缩进线

    语法高亮+缩进线图

    image

    语法检查

    插件

    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 时才会进行语法检查,避免影响速度。

    <pre class="prettyprint hljs vim">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'
    复制代码</pre>

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

    <pre class="hljs vbscript">int *ptr_list = NULL;
    *ptr_list = 1;
    复制代码</pre>

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

    image

    关键词搜索

    插件

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

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

    文档

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

    配置

    FlyGrep

    绑定快捷键 Ctrl-F:

    <pre class="prettyprint hljs vim">"=========================================
    " FlyGrep 插件配置
    "=========================================
    nnoremap <C-F> :FlyGrep<CR>
    复制代码</pre>

    操作

    FlyGrep

    <pre class="prettyprint hljs xml">Ctrl-F
    <Esc>
    <Enter>
    <Tab>
    <S-Tab>
    <Home>
    <End>
    </pre>

    vim 自带

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

    <pre class="prettyprint hljs vim">:vim /main/ % | copen
    vim /main/ * | copen
    vim /main/ ../** | copen
    vim /main path1/** path2/** | copen
    </pre>

    说明:

    <pre class="hljs vim">%
    copen
    </pre>

    搜索图

    image

    源文件头文件切换

    插件

    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

    <pre class="prettyprint hljs vim">" 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']
    复制代码</pre>

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

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

    操作

    • 操作:

    <pre class="hljs erlang">ctrl+]
    ctrl+o
    %
    </pre>

    文档

    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/…
    image

    窗口

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

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

    上方 Tab 栏

    • 操作:

    <pre class="hljs vbscript">ctrl+left
    ctrl+right
    ctrl+n
    ctrl+p
    </pre>

    C/C++ 格式化

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

    折叠

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

    缩进

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

    复制粘贴

    vim 复制到 windows

    <pre class="prettyprint hljs nginx">yum install libX11 libX11-devel libXtst-devel libXtst libXt-devel libXt libSM-devel libSM libXpm libXpm-devel
    </pre>

    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…

    相关文章

      网友评论

        本文标题:搭建基于 Vim 的 C++和 Python 开发环境!

        本文链接:https://www.haomeiwen.com/subject/ocniaqtx.html