Ubuntu16.04下vim8配置

Ubuntu16.04下vim8配置


1. 准备工作

# 卸载老旧发霉的exuberant-ctags
sudo apt-get --purge remove exuberant-ctags
# 卸载旧版vim及其相关组件
sudo apt-get --purge remove vim*
# 自动卸载无用依赖软件
sudo apt-get --purge autoremove
# 清理无用软件包
sudo apt-get autoclean
# 更新软件源
sudo apt-get update
# 安装checkinstall
sudo apt-get install checkinstall
# 安装pyton库
sudo apt-get -f install python-dev
sudo apt-get -f install python3-dev
# 安装界面相关库
sudo apt-get install libncurses5-dev
# 安装编译工具集
sudo apt-get install cmake build-essential
# 安装自动配置工具
sudo apt-get install autoconf pkg-config
# 安装cscope和global
sudo apt-get install cscope
sudo apt-get install global
# 安装powerline字体
sudo apt-get install fonts-powerline

说明:

  • exuberant-ctags 已经8年没更新,抛弃它,使用基于它之上的universal-ctags替代。
  • 由于YCM插件需要python支持,所以要卸载apt方式安装的vim,自行使用源码编译安装的最新vim。
  • make install安装软件会在/usr/local/下的各个子目录分别生成软件相关文件,这会导致如果想卸载软件很麻烦,需要从一个个目录中找出要卸载的软件相关的所有文件,然后一一删除。当然也可以在configure的时候为软件指定好单独的安装目录(例如:/opt/xxx , /usr/local/xxx 等等),这个做法的好处是卸载软件只需要删除指定的那个目录就行了,但是这样做安装完后shell找不到软件在哪里,还需要修改环境变量PATH增加新安装的软件路径才能正常使用,如果安装的软件太多,那么PATH就会特别长而且很乱,所以这种方式也不太好。checkinstall是一个源码安装工具,它收集安装信息,并且生成deb软件包,这使得所安装的软件可以用dpkg 来管理,dpkg -l xxx查询,dpkg -P xxx卸载干净。
  • python 库是必需的,很多插件需要python。
  • ncurses 是独立于终端基于文本的用户界面库,很多软件需要调用它提供的api(比如:make menuconfig)。
  • build-essential 是编译工具集,编译源码基本少不了它。
  • cmake 是一个基于软件源码自动生成Makefile的工具。
  • autoconf 是一个自动配置源码的工具,编译universal-ctags时需要。
  • cscope 配合vim实现代码查找跳转软件,这个不用说了,用vim的应该都知道。
  • global(gnu-global内部包含gtags、global、gtags-cscope)功能和cscope差不多,可以生成gtags数据库,比cscope强的地方在于数据库增量更新非常快,比ctags强的地方在于不仅能查找定义还能查找引用。
  • fonts-powerline 基于终端的字体,vim状态栏插件ariline需要它(不然箭头图标等显示不正确)。

2. 安装vim8

vim8新增了异步处理任务的特性,这使很多插件任务运行时vim还可以正常编辑,不会卡顿。由于gutentags插件需要vim8.0以上的版本才能工作,还有vim7更新GTAGS和cscope数据库时也会导致vim卡住不动,及其影响编辑体验,所以有必要安装最新的vim8。

ubuntu16.04的官方软件源目前没有vim8的deb,ubuntu18.04虽然支持apt直接安装vim8.0,但是默认安装不支持python,所以建议使用源码安装。

安装步骤:

# 从github克隆最新vim源码
git clone https://github.com/vim/vim.git
# 进入源码目录
cd vim
# 配置生成Makefile
./configure --with-features=huge \
            --enable-pythoninterp=yes \
            --with-python-config-dir=/usr/lib/python2.7/config-x86_64-linux-gnu/ \
            --enable-python3interp=yes \
            --with-python3-config-dir=/usr/lib/python3.5/config-3.5m-x86_64-linux-gnu/ \
            --enable-rubyinterp=yes \
            --enable-luainterp=yes \
            --enable-perlinterp=yes \
            --enable-tclinterp=yes \
            --enable-multibyte \
            --enable-cscope \
            --enable-gui=gtk2
# 编译
make -j8
# 安装(输入软件说明一路回车)
sudo checkinstall
# 完成后删除源码
cd ..
sudo rm -rf vim
# 使用dpkg查看
dpkg -l vim
# 设置vim为默认编辑器(vi和editor默认调用vim)
sudo update-alternatives --install /usr/bin/editor editor /usr/local/bin/vim 50
sudo update-alternatives --set editor /usr/local/bin/vim
sudo update-alternatives --install /usr/bin/vi vi /usr/local/bin/vim 50
sudo update-alternatives --set vi /usr/local/bin/vim

vim

3. 安装universal-ctags

# 从github克隆最新universal-ctags源码
git clone https://github.com/universal-ctags/ctags.git
# 进入源码目录
cd ctags
# 运行自动配置脚本
./autogen.sh
# 配置生成Makefile
./configure
# 编译
make -j8
# 安装(输入软件说明一路回车)
# checkinstall的时候版本号不能为空(可以填0.0.0)
sudo checkinstall
# 完成后删除源码
cd ..
sudo rm -rf ctags
# 使用dpkg查看
dpkg -l ctags

ctags

4. 安装gnu-global

# 下载gnu-global源码
wget http://tamacom.com/global/global-6.6.2.tar.gz
# 解压
tar xvf global-6.6.2.tar.gz
# 进入源码目录
cd global-6.6.2
# 配置生成Makefile
./configure
# 编译
make -j8
# 安装(输入软件说明一路回车)
sudo checkinstall
# 完成后删除源码
cd ..
sudo rm -rf global-6.6.2*
# 使用dpkg查看
dpkg -l global

global

5. 安装fonts-powerline

安装

# 从github克隆最新powerline/fonts源码
git clone https://github.com/powerline/fonts.git --depth=1
# 进入源码目录
cd fonts
# 执行安装脚本
./install.sh
# 完成后删除源码
cd ..
rm -rf fonts

设置终端字体

  • ubuntu终端标题栏选择 Edit >> ProfilePreference >> General >> Custom font
  • 选择原来的字体替换成带Powerline的同名字体 :
    powerline

6. 安装vim-plug插件管理器

vim-plug是一个类似于Vundle的vim插件管理器,比Vundle更强大的地方在于支持全异步并发安装更新加载插件,还有支持插件按指定条件加载和延迟加载。

# 备份原来的vim配置
tar czvf vimbak.tar.gz ~/.vim ~/.vimrc
# 删除vim配置文件
rm -rf ~/.vim*
# 下载安装vim-plug插件
curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
    https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim

关于vim-plug怎么使用这里由于篇幅原因不细说,请参考一下链接:
https://vim.ink/vim-plug.html
https://www.jianshu.com/p/f4fb7877829f

7. 添加vimrc配置

需要的插件

  • vim中文帮助手册:yianwillis/vimcdoc
  • C++语法高亮增强:octol/vim-cpp-enhanced-highlight
  • 最近打开的文件维护插件:vim-scripts/mru.vim
  • 状态栏插件:
    vim-airline/vim-airline
    vim-airline/vim-airline-themes
  • Taglist插件:vim-scripts/taglist.vim
  • 树形目录插件:scrooloose/nerdtree
  • 通用函数插件:vim-scripts/genutils
  • 查找文件插件(依赖于genutils):vim-scripts/lookupfile
  • 自动更新tags插件:ludovicchabant/vim-gutentags
  • 自动加载切换gtags数据库:skywind3000/gutentags_plus
  • 预览 quickfix 窗口 ctrl-w z 关闭:skywind3000/vim-preview
  • 代码补齐插件:
    MarcWeber/vim-addon-mw-utils
    tomtom/tlib_vim
    garbas/vim-snipmate
  • 代码补齐模板:honza/vim-snippets
  • 自动补全插件YCM:Valloric/YouCompleteMe
  • 异步静态代码检查:w0rp/ale
  • 主题配色:
    morhetz/gruvbox
    mhinz/vim-janah
    nanotech/jellybeans.vim
    tomasr/molokai
    jpo/vim-railscasts-theme
    tpope/vim-vividchalk
    joshdick/onedark.vim

我的vimrc

" =============================================================================
" vim-plug插件管理
" =============================================================================
call plug#begin('~/.vim/plug')

" vim中文帮助手册
Plug 'yianwillis/vimcdoc'
" C++语法高亮增强
Plug 'octol/vim-cpp-enhanced-highlight'
" 最近打开的文件维护插件
Plug 'vim-scripts/mru.vim'
" 状态栏插件
Plug 'vim-airline/vim-airline'
Plug 'vim-airline/vim-airline-themes'

" Taglist插件
Plug 'vim-scripts/taglist.vim', { 'on': 'TlistToggle' }
" 树形目录插件
Plug 'scrooloose/nerdtree', { 'on':  'NERDTreeToggle' }

" 通用函数插件
Plug 'vim-scripts/genutils'
" 查找文件插件(依赖于genutils)
Plug 'vim-scripts/lookupfile'

" 自动更新tags插件
Plug 'ludovicchabant/vim-gutentags'
" 自动加载切换gtags数据库
Plug 'skywind3000/gutentags_plus', { 'on': 'GscopeKill' }
" 预览 quickfix 窗口 ctrl-w z 关闭
Plug 'skywind3000/vim-preview', { 'on': 'GscopeKill' }

" 代码补齐插件
Plug 'MarcWeber/vim-addon-mw-utils'
Plug 'tomtom/tlib_vim'
Plug 'garbas/vim-snipmate'
" 代码补齐模板
Plug 'honza/vim-snippets'

" 自动补全插件YCM
Plug 'Valloric/YouCompleteMe', { 'do': './install.py --clang-completer',
            \ 'for': ['s', 'S', 'c', 'h', 'C', 'cpp', 'cc', 'cxx', 'py', 'go', 'java', 'js', 'php', 'sh'] }

" 异步静态代码检查
Plug 'w0rp/ale', { 'for': ['s', 'S', 'c', 'h', 'C', 'cpp', 'cc', 'cxx', 'py', 'go', 'java', 'js', 'php', 'sh'] }

" 主题配色
Plug 'morhetz/gruvbox'
Plug 'mhinz/vim-janah'
Plug 'nanotech/jellybeans.vim'
Plug 'tomasr/molokai'
Plug 'jpo/vim-railscasts-theme'
Plug 'tpope/vim-vividchalk'
Plug 'joshdick/onedark.vim'

call plug#end() 

" =============================================================================
" 编码相关
" =============================================================================
set termencoding=utf-8  " 设置终端显示编码
set encoding=utf-8      " 设置vim内部编码
" 菜单显示编码
set langmenu=zh_CN.UTF-8
" 设置可识别文件编码列表
set fileencodings=utf-8,gb2312,gbk,gb18030,cp936,utf-16,big5,latin1   

" =============================================================================
" 基本配置
" =============================================================================
" 开启文件类型检查,根据不同的文件类型加载不同的插件采用不同的缩进
filetype plugin indent on
syntax on               " 打开语法高亮
set t_Co=256            " 启用256色
set nocompatible        " 不与vi兼容(采用vim自己的操作命令) 
set background=dark     " 设置背景色
set cursorline          " 高亮光标所在行
" 高亮行颜色
highlight CursorLine cterm=Bold ctermbg=Black ctermfg=NONE guibg=Black guifg=NONE
"设置主题配色
"colorscheme gruvbox
"colorscheme janah
"colorscheme jellybeans
colorscheme molokai
"colorscheme railscasts
"colorscheme vividchalk
"colorscheme onedark
"colorscheme desert
"colorscheme torte
"colorscheme ron
set number              " 显示行号
set laststatus=2        " 是否显示状态栏(0,1,2)
set ruler               " 在状态栏显示当前光标坐标
set showmode            " 底行显示当前处于哪种模式
set showcmd             " 命令模式下,在底行显示键入的指令
set mouse=v             " 鼠标模式(n,v,i,c,h,a,r,A)
set scrolloff=7         " 垂直滚动时光标距离顶部/底部的行数
set sidescrolloff=7     " 水平滚动时光标距离边缘的字符数
set showmatch           " 光标遇到括号时自动高亮对应的另一个括号
set nobackup            " 不创建备份文件
set noerrorbells        " 出错时不要发出声音
"set visualbell          " 出错时发出视觉提示(通常时屏幕闪烁)
set history=1024        " 记录历史操作的数量
set autoread            " 打开文件监视,如果在编辑中的文件被外部修改则提示
set autowrite           " 跳转时自动保存
" 文件换行符检测列表
set fileformats=unix,dos,mac
set foldenable          " 默认折叠
set foldmethod=marker   " 折叠方式
set guioptions-=T       " gvim不包含工具栏
set guioptions-=m       " gvim不使用菜单栏
set guioptions-=r       " gvim不显示右边滚动条
set guioptions-=l       " gvim不显示左边滚动条
set helpheight=10       " 帮助窗口的最小高度
set helplang=cn,en      " 帮助手册语言
set hidden              " 允许在有未保存的修改时切换缓冲区
set nowrap              " 不自动折行
set helplang=cn         " 中文帮助优先
"自动向上递归查找tags文件
set tags=./tags;

" =============================================================================
" 编辑相关
" =============================================================================
set tabstop=4           " 制表符宽度(Tab空格数)
set softtabstop=4       " 软制表符宽度(按Tab键和Backspace键时光标跳转的空格数)
set shiftwidth=4        " 缩进宽度(空格数)
set expandtab           " 制表符替换为空格
set autoindent          " 自动缩进
set cindent             " 特别针对C语言的自动缩进
set cinoptions=:0       " 自动缩进方案
set smartindent         " 插入新行时自动缩进
" 启用退格键删除功能
set backspace=indent,eol,start
set whichwrap=h,l       "使用指定的左右移动光标键可以移到前一行和后一行
" 自动补全模式
set complete=.,w,b,u,t,i,d
" 自动补全选项
set completeopt=longest,menuone
set pumheight=10        " 自动补全菜单显示的最多项目数
" 文件和目录名补全忽略的文件
set wildignore=*.bak,*.o,*.e,*~
set wildmenu            " 命令模式下,按Tab键补全命令
" 命令补全模式
set wildmode=longest:list,full
set hlsearch            " 查找时高亮显示匹配结果
set incsearch           " 查找输入时,每输入一个字符,自动跳转到第一个匹配结果
set ignorecase          " 查找时忽略大小写
set smartcase           " 针对只有首字母时大写的查找词不忽略大小写

" =============================================================================
" 自动命令
" =============================================================================
" 打开文件光标自动跳转到上次关闭时的位置
autocmd BufReadPost *
    \ if line("'\"") > 0 && line("'\"") <= line("$") |
    \     exe "normal g'\"" |
    \ endif

" =============================================================================
" 快捷键
" =============================================================================
" Leader键设置
let mapleader=' '

" 使用分号进入命令模式
nnoremap ; :
vnoremap ; :

" 窗口切换快捷键
nnoremap <C-h> <C-w>h
nnoremap <C-j> <C-w>j
nnoremap <C-k> <C-w>k
nnoremap <C-l> <C-w>l
inoremap <C-h> <Esc><C-w>h
inoremap <C-j> <Esc><C-w>j
inoremap <C-k> <Esc><C-w>k
inoremap <C-l> <Esc><C-w>l

" 窗口大小调整
nnoremap + :resize +1<cr>
nnoremap _ :resize -1<cr>
nnoremap > :vertical resize +1<cr>
nnoremap < :vertical resize -1<cr>
 
" shell命令调用函数
function! RunShell(Msg, Shell)
	echo a:Msg . '...'
	call system(a:Shell)
	echon 'done'
endfunction

" vimgrep查找字符串
nmap <F6> :vimgrep /<C-R>=expand("<cword>")<cr>/ **/*.c **/*.h<cr><C-o>:cw<cr>
" 生成GTAGS数据库文件快捷键F8
nmap <F8> :call RunShell("Generate GTAGS.*", 'find . -name "*.[chsS]" -o -name "*.cpp" -o -name "*.cc" -o -name "*.C", -o -name "*.cxx"> gtags.files && gtags')<cr>
" 生成tags文件快捷键F9 
nmap <F9> :call RunShell("Generate tags", "ctags -R --c-kinds=+lpxzL --c++-kinds=+lpxzLANU --fields=+niazS --extras=+q --output-format=e-ctags")<cr>
" 生成cscope数据库文件快捷键F10 
nmap <F10> :call RunShell("Generate cscope.*", 'find `pwd` -name "*.[chsS]" -o -name "*.cpp" -o -name "*.cc" -o -name "*.C", -o -name "*.cxx"> cscope.files && cscope -bkq')<cr>

" =============================================================================
" 插件配置
" =============================================================================
" lookupfile.vim
" -----------------------------------------------------------------------------
" 生存filename.tags快捷键F7
nmap <F7> :call RunShell("Generate filename.tags", "genftag")<cr>
" 映射LookupFile快捷键
nmap <Leader>lt :LUTags<cr>
" 映射LUBufs快捷键
nmap <Leader>lb :LUBufs<cr>
" 映射LUWalk快捷键
nmap <Leader>lw :LUWalk<cr>  
" 最少输入2个字符才开始查找
let g:LookupFile_MinPatLength=2
" 不保存上次查找的字符串
let g:LookupFile_PreserveLastPattern=0
" 保存查找历史
let g:LookupFile_PreservePatternHistory=1
" 回车打开第一个匹配项目
let g:LookupFile_AlwaysAcceptFirst=1
" 不允许创建不存在的文件
let g:LookupFile_AllowNewFiles=0
" 关闭对搜索结果的字母排序
let g:LookupFile_SortMethod=""
" 向上递归查找tags文件
let g:filename_tags=findfile("filename.tags", ".;")
" 设置tags文件
if filereadable(g:filename_tags)
    let g:LookupFile_TagExpr='"'.g:filename_tags.'"'
endif
" 查找忽略大小写
function! LookupFile_IgnoreCaseFunc(pattern)
    let _tags = &tags
    try
        let &tags = eval(g:LookupFile_TagExpr)
        let newpattern = '\c' . a:pattern
        let tags = taglist(newpattern)
    catch
        echohl ErrorMsg | echo "Exception: " . v:exception | echohl NONE
        return ""
    finally
        let &tags = _tags
    endtry

    " Show the matches for what is typed so far.
    let files = map(tags, 'v:val["filename"]')
    return files
endfunction
let g:LookupFile_LookupFunc = 'LookupFile_IgnoreCaseFunc'

" mru.vim
" -----------------------------------------------------------------------------
" 打开mru快捷键F4
nmap  <F4> :MRU<cr>

" man.vim
" -----------------------------------------------------------------------------
" 启动man插件
source $VIMRUNTIME/ftplugin/man.vim
" man 光标定位的函数
nmap <Leader>mm :Man <C-R>=expand("<cword>")<cr><cr>
" man 2 光标定位的函数
nmap <Leader>m2 :Man 2 <C-R>=expand("<cword>")<cr><cr>
" man 3 光标定位的函数
nmap <Leader>m3 :Man 3 <C-R>=expand("<cword>")<cr><cr>

" taglist.vim
" -----------------------------------------------------------------------------
" 设置打开关闭快捷键F2
nmap  <F2> :TlistToggle<cr>
" 自动更新tags列表
let g:Tlist_Auto_Update=1
" 始终解析文件中的tag,不管taglist窗口有没有打开
let g:Tlist_Process_File_Always=1
" 当taglist窗口是最后一个窗口时退出vim
let g:Tlist_Exit_OnlyWindow=1
" 只显示一个文件的tags
let g:Tlist_Show_One_File=1
" 窗口宽度
let g:Tlist_WinWidth=30
" 只显示当前文件的tags
let g:Tlist_Enable_Fold_Column=0
" 高亮显示当前tag
let g:Tlist_Auto_Highlight_Tag=1
" 设置窗口显示在右侧
"let g:Tlist_Use_Right_Window=1
" 打开时光标定位于taglist窗口
let g:Tlist_GainFocus_On_ToggleOpen=1

" NERDTree.vim
" -----------------------------------------------------------------------------
" 设置打开关闭快捷键F3 
nmap  <F3> :NERDTreeToggle<cr>
" 窗口美化
let NERDChristmasTree=1
" 自动调整光标到窗口中心
let NERDTreeAutoCenter=1
" 指定鼠标模式(1.双击打开;2.单目录双文件;3.单击打开)
let NERDTreeMouseMode=2
" 默认显示文件
let NERDTreeShowFiles=1
" 默认显示隐藏文件
let NERDTreeShowHidden=1
" 窗口位置('left' or 'right')
let g:NERDTreeWinPos="right"
" 窗口宽度
let g:NERDTreeWinSize=30
" 显示行号
let g:NERDTreeShowLineNumbers=1
" 打开文件后关闭NERDTree窗口
let g:NERDTreeQuitOnOpen=1
" 高亮显示当前行目录或文件
let NERDTreeHightCursorline=1

" cscope配置
" -----------------------------------------------------------------------------
" 更新cscope数据库函数
function! UpdateCsdb(path)
    if (a:path != '') 
        execute "cd " . a:path
    endif
    call job_start("cscope -bkq")
    if (a:path != '') 
        execute "cd -"
    endif
    execute "silent cs reset"
endfunction

" 更新GTAGS数据库函数
function! UpdateGtags(f)
    let g:dir = fnamemodify(a:f, ':p:h')
    execute "cd " . g:dir
    call job_start("global -u")
	execute "cd -"
endfunction

if executable('cscope')
    " 获取GTAGS目录
    let s:gtfile = system('global -pq')
	" 向上递归寻找cscope.files
    let g:csfile = findfile("cscope.out", ".;")

	" 如果存在cscope.out则获取目录
    if filereadable(g:csfile)
        " 设置cscope模式标志
        let g:csflag = 0
        " 获取cscope.out目录
        let s:pathlen = strridx(g:csfile, "cscope.out")
		let g:cspath = strpart(g:csfile, 0, s:pathlen)
	" 如果存在cscope.out则获取目录
    elseif s:gtfile != ""
        " 设置cscope模式标志
        let g:csflag = 1
        " 获取GTAGS目录
		let g:gtpath = strpart(s:gtfile, 0, strlen(s:gtfile) - 1)
    " 使用gutentags_plus
    else
        " 设置cscope模式标志
        let g:csflag = 2
	endif

    " cscope程序位置
	if !exists("g:cspath") && executable('gtags-cscope')
        " 设置cscope映射的程序
        set csprg=/usr/local/bin/gtags-cscope
        if g:csflag == 1
            " 加载GTAGS
            execute 'silent cs add ' . g:gtpath . '/GTAGS'
            " 保存文件后自动更新GTAGS
            autocmd BufWritePost * call UpdateGtags(expand('<afile>'))
        else
            execute 'silent GscopeKill'
        endif
    else
        " 设置cscope映射的程序
        set csprg=/usr/bin/cscope
        " 自动命令查找结果不使用quickfix窗口
        " autocmd BufReadPost * set cscopequickfix=""
        " 保存文件后自动更新GTAGS
        autocmd BufWritePost * call UpdateCsdb(g:cspath)
        " 加载cscope.out
    	set nocsverb
		execute 'cs add ' . g:csfile
    endif

    " 显示添加数据库结果
    set csverb
    " 使用cstag命令代替tag命令 
    set cst
    " 优先搜索tags,失败再搜索cscope.out
    set csto=0
    " 显示文件路径全名 
    set cspc=0
endif

" cscope当前窗口直接跳转快捷键
nnoremap <Leader>fs :cs find s <C-R>=expand("<cword>")<cr><cr>
nnoremap <Leader>fg :cs find g <C-R>=expand("<cword>")<cr><cr>
nnoremap <Leader>fd :cs find d <C-R>=expand("<cword>")<cr><cr>
nnoremap <Leader>fc :cs find c <C-R>=expand("<cword>")<cr><cr>
nnoremap <Leader>ft :cs find t <C-R>=expand("<cword>")<cr><cr>
nnoremap <Leader>fe :cs find e <C-R>=expand("<cword>")<cr><cr>
nnoremap <Leader>ff :cs find f <C-R>=expand("<cfile>")<cr><cr>
nnoremap <Leader>fi :cs find i <C-R>=expand("<cfile>")<cr><cr>
nnoremap <Leader>fa :cs find a <C-R>=expand("<cword>")<cr><cr>

" cscope跳转同时新建水平分割窗口快捷键
nnoremap <Leader>ss :scs find s <C-R>=expand("<cword>")<cr><cr>
nnoremap <Leader>sg :scs find g <C-R>=expand("<cword>")<cr><cr>
nnoremap <Leader>sd :scs find d <C-R>=expand("<cword>")<cr><cr>
nnoremap <Leader>sc :scs find c <C-R>=expand("<cword>")<cr><cr>
nnoremap <Leader>st :scs find t <C-R>=expand("<cword>")<cr><cr>
nnoremap <Leader>se :scs find e <C-R>=expand("<cword>")<cr><cr>
nnoremap <Leader>sf :scs find f <C-R>=expand("<cfile>")<cr><cr>
nnoremap <Leader>si :scs find i <C-R>=expand("<cfile>")<cr><cr>
nnoremap <Leader>sa :scs find a <C-R>=expand("<cword>")<cr><cr>

" cscope跳转同时新建垂直分割窗口快捷键
nnoremap <Leader>vs :vert scs find s <C-R>=expand("<cword>")<cr><cr>
nnoremap <Leader>vg :vert scs find g <C-R>=expand("<cword>")<cr><cr>
nnoremap <Leader>vd :vert scs find d <C-R>=expand("<cword>")<cr><cr>
nnoremap <Leader>vc :vert scs find c <C-R>=expand("<cword>")<cr><cr>
nnoremap <Leader>vt :vert scs find t <C-R>=expand("<cword>")<cr><cr>
nnoremap <Leader>ve :vert scs find e <C-R>=expand("<cword>")<cr><cr>
nnoremap <Leader>vf :vert scs find f <C-R>=expand("<cfile>")<cr><cr>
nnoremap <Leader>vi :vert scs find i <C-R>=expand("<cfile>")<cr><cr>
nnoremap <Leader>va :vert scs find a <C-R>=expand("<cword>")<cr><cr>

" gutentags.vim && gutentags_plus.vim
" -----------------------------------------------------------------------------
" 搜索工程目录的标志,碰到这些文件/目录名就停止向上一级目录递归 "
let g:gutentags_project_root = ['.root', '.svn', '.git', '.project', 'workspace', 'cscope.out', 'GTAGS', 'tags', 'filename.tags']
" 所生成的数据文件的名称 "
let g:gutentags_ctags_tagfile = '.tags'
" tags模式设置
let g:gutentags_modules = []
if executable('ctags')
	let g:gutentags_modules += ['ctags']
endif
if g:csflag == 2 && executable('gtags-cscope')
	let g:gutentags_modules += ['gtags_cscope']
    " 光标定位于quickfix窗口
    let g:gutentags_plus_switch = 1
endif
" 将自动生成的 tags 文件全部放入 ~/.cache/tags 目录中,避免污染工程目录 "
let s:vim_tags = expand('~/.cache/tags')
let g:gutentags_cache_dir = s:vim_tags
" 检测 ~/.cache/tags 不存在就新建 "
if !isdirectory(s:vim_tags)
   silent! call mkdir(s:vim_tags, 'p')
endif
" 配置ctags的参数 "
let g:gutentags_ctags_extra_args = ['--fields=+niazS', '--extras=+q']
let g:gutentags_ctags_extra_args += ['--c++-kinds=+lpxzLANU']
let g:gutentags_ctags_extra_args += ['--c-kinds=+lpxzL']
" 如果使用universal ctags需要增加下面一行
let g:gutentags_ctags_extra_args += ['--output-format=e-ctags']
" 禁用 gutentags 自动加载 gtags 数据库的行为
" 避免多个项目数据库相互干扰
" 使用plus插件解决问题
let g:gutentags_auto_add_gtags_cscope = 0

" vim-preview.vim
if g:csflag == 2 && executable('gtags-cscope')
    " p预览 大P关闭
    autocmd FileType qf nnoremap <silent><buffer> p :PreviewQuickfix<cr>
    autocmd FileType qf nnoremap <silent><buffer> P :PreviewClose<cr>
    noremap <Leader>u :PreviewScroll -1<cr> " 往上滚动预览窗口
    noremap <Leader>d :PreviewScroll +1<cr> "  往下滚动预览窗口
endif

" YouCompleteMe.vim
" -----------------------------------------------------------------------------
" 补全配置脚本 
let g:ycm_global_ycm_extra_conf='~/.vim/.ycm_extra_conf.py'

" 弹出列表时选择第1项的快捷键(默认为<TAB>和<Down>)
let g:ycm_key_list_select_completion = ['<C-n>', '<Down>']
" 弹出列表时选择前1项的快捷键(默认为<S-TAB>和<UP>)
let g:ycm_key_list_previous_completion = ['<C-p>', '<Up>']
" 主动补全, 默认为<C-Space>
let g:ycm_key_invoke_completion = '<C-x>'
" 停止显示补全列表(防止列表影响视野),可以按<C-Space>重新弹出
let g:ycm_key_list_stop_completion = ['<C-y>']

" 停止提示是否载入本地ycm_extra_conf文件
let g:ycm_confirm_extra_conf = 0
" 语法关键字补全
let g:ycm_seed_identifiers_with_syntax = 1
" 开启YCM 基于标签引擎
let g:ycm_collect_identifiers_from_tags_files = 1
" 从第2个键入字符就开始罗列匹配项
let g:ycm_min_num_of_chars_for_completion = 2
" 开启输入注释时补全
let g:ycm_complete_in_comments = 1
" 开启输入字符串时补全
let g:ycm_complete_in_strings = 1
" 开启注释和字符串中收集补全
let g:ycm_collect_identifiers_from_comments_and_strings = 1
" 关闭函数预览
let g:ycm_add_preview_to_completeopt = 0
" 关闭代码诊断
let g:ycm_show_diagnostics_ui = 0
" 设置标识符补全最小字符数
let g:ycm_min_num_identifier_candidate_chars = 2
" 设置以下语言自动弹出语义补全(默认需要输入'.->::'或者按主动补全组合键)
let g:ycm_semantic_triggers =  {
			\ 'c,cpp,python,java,go,erlang,perl': ['re!\w{2}'],
			\ 'cs,lua,javascript': ['re!\w{2}'],
			\ }
" 白名单(以外的文件类型不分析补全)
let g:ycm_filetype_whitelist = { 
			\ "s":1,
			\ "S":1,
			\ "c":1,
			\ "C":1,
			\ "cc":1,
			\ "cxx":1,
			\ "cpp":1,
			\ "py":1,
			\ "go":1,
			\ "java":1, 
			\ "objc":1,
			\ "sh":1,
			\ "zsh":1,
			\ "zimbu":1,
			\ }

" ALE.vim
" -----------------------------------------------------------------------------
"普通模式下警告跳转快捷键
nmap <silent> <Leader>p <Plug>(ale_previous_wrap)
nmap <silent> <Leader>n <Plug>(ale_next_wrap)
"<Leader>x触发/关闭语法检查
nmap <Leader>x :ALEToggle<CR>
"<Leader>y查看错误或警告的详细信息
nmap <Leader>y :ALEDetail<CR>
"始终开启标志列
"let g:ale_sign_column_always = 1
" 错误警告消息格式
let g:ale_echo_msg_error_str = 'E'
let g:ale_echo_msg_warning_str = 'W'
let g:ale_echo_msg_format = '[%linter%] %s [%severity%]'
" 文件打开时不进行检查
"let g:ale_lint_on_enter = 0
" 文件修改时不进行检查
let g:ale_lint_on_text_changed = 'never'
" 文件保存时进行检查(默认)
"let g:ale_lint_on_save = 1
" 指定对应语言的检查工具
"let g:ale_linters = {
"            \   'c++': ['clang'],
"            \   'c': ['clang'],
"            \   'python': ['pylint'],
"            \   'go': ['gofmt', 'golint'],
"            \}
" 关闭补全功能
let g:ale_completion_enabled = 0
" 使能airline状态栏扩展
let g:airline#extensions#ale#enabled = 1
" 禁用高亮显示
"let g:ale_set_highlights = 0
" 自定义error和warning标志
"let g:ale_sign_error = '✗'
"let g:ale_sign_warning = '⚡'

" airline.vim
" -----------------------------------------------------------------------------
" 设置主题
let g:airline_theme='bubblegum'
" 这个是安装字体后必须设置此项"
let g:airline_powerline_fonts = 1
" 开启标签栏
let g:airline#extensions#tabline#enabled = 1
" 显示缓冲区编号
let g:airline#extensions#tabline#buffer_nr_show = 1
" tabline中当前buffer两端的分隔字符
"let g:airline#extensions#tabline#left_sep = ' '
" tabline中未激活buffer两端的分隔字符
"let g:airline#extensions#tabline#left_alt_sep = '|'
" 缓冲区切换快捷键
nnoremap <Leader>. :bn<cr>
nnoremap <Leader>, :bp<cr>
" 关闭状态显示空白符号计数"
let g:airline#extensions#whitespace#enabled = 0
" 状态栏显示设置
if !exists('g:airline_symbols')
    let g:airline_symbols = {}
endif
" powerline symbols
let g:airline_left_sep = ''
let g:airline_left_alt_sep = ''
let g:airline_right_sep = ''
let g:airline_right_alt_sep = ''
let g:airline_symbols.branch = ''
let g:airline_symbols.readonly = ''
let g:airline_symbols.linenr = '☰'
let g:airline_symbols.maxlinenr = ''

说明:

  • 拷贝上文vimrc写入新建的~/.vimrc,然后打开vim,输入命令 :PlugInstall 即可自动安装插件。
  • 由于YCM插件有接近400M大小,下载很慢所以建议先注释掉Plug ‘Valloric/YouCompleteMe’,等安装完其余插件后再取消注释单独安装YCM。
  • YCM下载需要等待一段时间,下载完成可进入~/.vim/plug/YouCompleteMe下执行:git submodule update --init --recursive检查完整性
  • 使用 :PlugInstall 安装YCM,会自动下载自动执行./inshall.py --clang-completer编译,编译过程中会自动下载libclang7.0,不需要系统手动安装libclang,不过下载可能失败,如果自动编译不成功,需要进入:~/.vim/plug/YouCompleteMe目录下手动执行:./inshall.py --clang-completer进行编译。
  • 最后8行符号需要powerline字体才能显示,可以参考.vim/plug/vim-airline/doc/airline.txt第300行左右的配置。
  • 安装完成后效果:
    在这里插入图片描述

8. 使用

以下只介绍上文vimrc配置的功能如何使用,vim本身自带的功能和操作不讨论,有需要的同学请自行google。

快捷键

  • F2: 启动左侧Taglist窗口
  • F3: 打开右侧NerdTree窗口
  • F4: 打开mru窗口显示最近打开过的文件,选择文件回车打开
  • F5: 窗口上方打开LookupFile搜索窗口,输入文件名或者目录名查找文件,Ctrl-N、Ctrl-P选择,回车打开
  • F6: 打开vimgrep,输入任意字符进行搜索(相当于shell的grep命令)
  • F7: 在当前目录下生成filename.tags文件,LookupFile使用该文件进行查找,生成过程中vim不允许操作
  • F8: 在当前目录下生成GTAGS数据库相关文件,gtags-cscope使用该数据库进行代码查找和跳转
  • F9: 在当前目录下生成tags文件,供ctags使用
  • F10: 在当前目录下生成cscope数据库相关文件,cscope基于cscope.out进行代码搜索和跳转
  • ; : 进入底行命令模式
  • Ctrl - h: 从当前窗口切换到左侧窗口
  • Ctrl - l: 从当前窗口切换到右侧窗口
  • Ctrl - k: 从当前窗口切换到上侧窗口
  • Ctrl - j: 从当前窗口切换到下侧窗口
  • Ctrl - x: 主动补全
  • Ctrl - y: 关闭补全列表
  • Ctrl - n: 补全列表向下选择
  • Ctrl - p: 补全列表向上选择
  • Shift - =: “+” 增加当前窗口高度
  • Shift - -: “_” 减小当前窗口高度
  • Shift - ,: “<” 减小当前窗口宽度
  • Shift - .: “>” 增加当前窗口宽度
  • 空格 lt: 打开LookupFile按tags搜索文件
  • 空格 lb: 打开LookupFile按vim缓冲区搜索文件
  • 空格 lw: 打开LookupFile按目录搜索文件
  • 空格 mm: man查找当前光标所在函数
  • 空格 m2: man 2查找当前光标所在函数(系统调用)
  • 空格 m3: man 3查找当前光标所在函数(库函数)
  • 空格 fs: 查找并跳转到当前光标所在标识符出现的地方
  • 空格 fg: 查找并跳转到当前光标所在标识符的定义处
  • 空格 fd: 查找并跳转到被当前光标所在函数调用的函数
  • 空格 fc: 查找并跳转到调用当前光标所在函数的地方
  • 空格 ft: 查找并跳转到当前光标所在的字符串
  • 空格 fe: egrep模式查找并跳转到当前光标所在的字符串
  • 空格 ff: 查找并跳转到当前光标所在的文件名
  • 空格 fi: 查找并跳转到当前文件所包含的文件
  • 空格 fa: 查找并跳转到当前光标所在的标识符被赋值的地方
  • 空格 ss: 查找并水平分割窗口跳转到当前光标所在标识符出现的地方
  • 空格 sg: 查找并水平分割窗口跳转到当前光标所在标识符的定义处
  • 空格 sd: 查找并水平分割窗口跳转到被当前光标所在函数调用的函数
  • 空格 sc: 查找并水平分割窗口跳转到调用当前光标所在函数的地方
  • 空格 st: 查找并水平分割窗口跳转到当前光标所在的字符串
  • 空格 se: egrep模式查找并水平分割窗口跳转到当前光标所在的字符串
  • 空格 sf: 查找并水平分割窗口跳转到当前光标所在的文件名
  • 空格 si: 查找并水平分割窗口跳转到当前文件所包含的文件
  • 空格 sa: 查找并水平分割窗口跳转到当前光标所在的标识符被赋值的地方
  • 空格 vs: 查找并垂直分割窗口跳转到当前光标所在标识符出现的地方
  • 空格 vg: 查找并垂直分割窗口跳转到当前光标所在标识符的定义处
  • 空格 vd: 查找并垂直分割窗口跳转到被当前光标所在函数调用的函数
  • 空格 vc: 查找并垂直分割窗口跳转到调用当前光标所在函数的地方
  • 空格 vt: 查找并垂直分割窗口跳转到当前光标所在的字符串
  • 空格 ve: egrep模式查找并垂直分割窗口跳转到当前光标所在的字符串
  • 空格 vf: 查找并垂直分割窗口跳转到当前光标所在的文件名
  • 空格 vi: 查找并垂直分割窗口跳转到当前文件所包含的文件
  • 空格 va: 查找并垂直分割窗口跳转到当前光标所在的标识符被赋值的地方
  • p: 在gutentags_plus插件启动gtags-cscope跳转快捷键换出qucikfix窗口是显示光标所在行的预览窗口
  • P: 在gutentags_plus插件启动gtags-cscope跳转快捷键换出qucikfix窗口是关闭光标所在行的预览窗口
  • 空格 u: quickfix窗口预览窗口向上滚动
  • 空格 d: quickfix窗口预览窗口向下滚动
  • 空格 x: 打开/关闭语法检查
  • 空格 y: 显示语法错误或警告详细信息
  • 空格 p: 跳转到上一处错误或警告
  • 空格 n: 跳转到下一处错误或警告
  • 空格 .: 切换到下一个缓冲区(标签栏下一个)
  • 空格 ,: 切换到下一个缓冲区(标签栏上一个)

genftag脚本

由于Lookupfile插件默认基于ctags产生的索引进行查找文件,ctags本身除了文件信息还有大量的代码标识符等其他信息,这会使得Lookupfile查找速度很慢,所以一般都是专门为Lookupfile建立一个只有文件索引的tags文件。为了方便使用,把建立Lookupfile专用tags文件写成一个shell脚本放到~/.local/bin目录下,命名为genftag,这样只需要在项目根目录下执行:./genftag 命令就可以生成filename.tags供Lookupfile使用了。

#!/bin/sh                                                                                                                                                                              
# generate filename tags for lookupfile plugin
(echo "!_TAG_FILE_SORTED        2       /2=foldcase/";
(find . -not -name '*.o' -not -wholename '*.svn*' -not -wholename '*.git*' -not -regex '.*\.\(png\|gif\)' -type f -printf "%f\t%p\t1\n" | \
sort -f)) > filename.tags

在~/.local/bin目录下新建名为genftag的文件,然后把上面的脚本内容拷贝进去,保存,然后运行:source ~/.profile 或者退出当前用户重新登录系统,就可以在任意目录下使用genftag命令了。

ctags的使用

在项目根目录执行:ctags -R即可生成tags文件,使用vim打开项目目录下的任何文件都会自动向上递归寻找tags文件然后加载。可以在vim里输入 :set tags 查看当前加载的tags文件路径。

  • ctags在vim的操作:
    ctags -R :在当前目录递归遍历所有子目录生成的tags文件
    Ctrl - ] :跳转到标识符定义处
    Ctrl - T:跳转返回
    vim -t tag:在tags目录下直接用vim打开tag变量或函数定义的地方
    :ts :列出所有tag列表
    :tn :跳转到下一个tag处
    :tp :跳转到上一个tag处

由于默认ctags -R命令会把所有文件都包好进来,有很多是不需要的非代码文件,这不但会导致tags文件过大,而且还会影响生成tags的速度,同时影响查找跳转的效率,因为多了很多无关信息。所以建议使用如下命令生成tags文件:

ctags -R --c-kinds=+lpxzL --c++-kinds=+lpxzLANU --fields=+niazS --extras=+q --output-format=e-ctags

因为我们使用了universal-ctags,所以要加上 --output-format=e-ctags ,该选项表示生成兼容exuberant-ctags格式的tags文件。

gutentags插件

  • 上一节手动生成tags的方式有一个巨大的不足,就是当你修改了某个文件内容,tags文件是不会自动更新的,必须返回tags目录下手动更新tags,并且tags不支持增量更新,所以相当于重新生成一遍,速度很慢。
  • 为了解决这个问题,就引进了gutentags插件,它支持修改保存文件的时候异步自动更新tags,该插件必需在vim8以上版本才能正常运行。
  • gutentags会从当前打开文件的目录向上递归查找项目根目录,找到了就会在~/.cache/tags下生成对应项目的tags文件,并且当使用vim打开项目下的文件时自动加载对应的tags,并且当修改保存文件时自动更新tags,而且是异步完成更新,也就是更新过程中还可以正常使用vim,不会卡住不动。
  • gutentags查找项目根目录的依据是寻找特殊文件,找到就认为该目录是项目根目录,这些特殊文件可以自定义,参考上文vimrc配置里面的gutentags插件配置部分,以下是我的vimrc使用的特殊文件列表:
    .root、.svn、.git、.project、workspace、cscope.out、GTAGS、tags、filename.tags
  • 所以如果想让gutentags自动创建自动加载自动更新tags,就需要在工程目录下存在以上特殊文件,没有的话直接touch一个.root空文件就可以了

cscope和gtags-cscope

这两个家伙功能基本一致,使用方法也一样,参考上面快捷键。关于cscope和gtags的介绍请自行google,本文不做详细介绍。cscope使用方法可以在vim命令下输入 :cscope help 获得,配置项详情可以通过 :help cscope 查看,上文的vimrc已经配置好了中文vim帮助手册,查看任何配置项详细介绍只需要在vim命令行输入 :help xxx 即可。
上文vimrc实现了自动检测cscope和gtags数据库,并且自动加载,由于这两者使用的快捷键一样(空格 f、空格 s、空格v 三组快捷键),所以只能二选一,参考我的vimrc配置中关于cscope部分的详细内容,规则如下:

  • 使用vim打开文件自动向上递归查找cscope.out数据库文件
  • 如果找到,则设置cscopegprg = /usr/bin/cscope,自动加载cscope.out,不再加载GTAGS
  • 如果没找到cscope.out,则设置cscopegprg = /usr/local/bin/gtags-cscope,并且从当前文件目录自动向上递归查找GTAGS数据库文件
  • 如果找到,自动加载GTAGS
  • 如果没找到GTAGS,则启动gutentags_plus插件,该插件自动加载在~/.cache/tags/“工程目录名”/ 下面的GTAGS数据库,如果没有该工程目录,则gutentags插件会依据生成tags的同样规则(参考上一节)自动生成当前工程的GTAGS数据库文件
  • 如果gutentags没有找到特殊文件,从而没法确定项目根目录,则认为该文件不属于工程文件,不加载GTAGS
    通过上述规则,vim可以自动判断并加装cscope和gtags,而且是优先是用cscope。

另外还有一点,如果启用了gutentags_plus插件,查找跳转快捷键不再是原来自定义的三组快捷键了(空格 f、空格 s、空格v 三组快捷键),因为gutentags_plus插件本身定义了自己的快捷键,并且使用quickfix窗口来显示查找结果,而且可以按p预览,P关闭预览。启用了gutentags_plus插件的快捷键如下:

  • 空格 cs: 查找当前光标所在标识符出现的地方
  • 空格 cg: 查找当前光标所在标识符的定义处
  • 空格 cd: 查找被当前光标所在函数调用的函数
  • 空格 cc: 查找调用当前光标所在函数的地方
  • 空格 ct: 查找当前光标所在的字符串
  • 空格 ce: egrep模式当前光标所在的字符串
  • 空格 cf: 查找当前光标所在的文件名
  • 空格 ci: 查找当前文件所包含的文件
  • 空格 ca: 查找当前光标所在的标识符被赋值的地方

默认不直接跳转,而是打开quickfix窗口显示查找结果,可以选择某个结果按回车跳转,也可以按p预览。

最后

以上只大概介绍了本文的vim配置的部分功能,实际使用中的一些细节无法详细描述,比如还有状态栏主题更换,ALE静态代码检查等等,需要自己亲自体验之后修改vimrc对应部分的配置来实现个性化。本文提供的vimrc基本上每部分都有注释说明,各个配置详细说明还可以通过vim中文帮助 :help xxx 来查看。大家可根据自己需要自行修改。

关于tags、cscope.*、GTAGS、filename.tags等文件的生成和删除,个人建议在~/.bashrc下映射几个常用命令:

# 建立tags文件
alias genctag='ctags -R --c-kinds=+lpxzL --c++-kinds=+lpxzLANU --fields=+niazS --extras=+q --output-format=e-ctags'
# 建立cscope数据库
alias gencsdb='find . -name "*.[ch]" -o -name "*.cpp" -o -name "*.cc" -o -name "*.C", -o -name "*.cxx"> cscope.files && cscope -bkq'
# 建立GTAGS数据库
alias gengtag='find . -name "*.[ch]" -o -name "*.cpp" -o -name "*.cc" -o -name "*.C", -o -name "*.cxx"> gtags.files && gtags'
# 删除tags文件
alias clnctag='rm -rf tags'
# 删除filename.tags文件
alias clnftag='rm -rf filename.tags'
# 删除GTAGS数据库相关文件
alias clngtag='rm -rf GTAGS GRTAGS GPATH gtags.files'
# 删除cscope数据库相关文件
alias clncsdb='rm -rf cscope.*' 

设置好之后运行:source ~/.bashrc 或者退出终端重新登录即可在任意目录下使用以上命令了。

vim还有无数本文没介绍的各种功能插件,有需要的同学请自行添加配置。

猜你喜欢

转载自blog.csdn.net/oaix101125/article/details/85019942
今日推荐