补全示例

介绍

玩 Vim 的哲学就是追求 “基本够用”, 包括装插件、设置快捷键或自己写脚本。因为基本够用时,你才能有效地把Vim变成生产力,而不是因为“磨刀误了砍柴功”,最终丧失了对 Vim 的耐心。 Vim 的扩展可能性很多,在学会 Vim 自带的大量快捷键之前,没有必要去装一堆的插件,这篇文章就是这样的一个平衡点,恰到好处地教你使用最有用的 Vim C++ 插件。

这篇博客介绍了一种简单实用的VIM用于C++开发的配置方法,其特点是流畅的补全和在文件间便捷地跳转。

配置步骤

  1. 安装 vim
sudo apt install vim
  1. 安装 clangd-11 (官方源)
sudo apt install clang-11 clang-tools-11 clang-11-doc libclang-common-11-dev \
   libclang-11-dev libclang1-11 clang-format-11 clangd-11 clang-tidy-11 \
   libc++-11-dev libc++abi-11-dev
sudo update-alternatives --install /usr/bin/clangd clangd /usr/bin/clangd-11 100
  1. 安装 vim-plug
curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
    https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim

提示 :如果国内因DNS污染无法访问 raw.githubusercontent.com,可以通过设置 /etc/hosts 解决,在其中增加如下一行内容。

151.101.84.133  raw.githubusercontent.com
  1. 配置 vimrc

修改 ~/.vimrc 文件如下:

let mapleader = " "

call plug#begin('~/.vim/plugged')

Plug 'neoclide/coc.nvim', {'for':[ 'c', 'cpp', 'json', 'cmake', 'vim'], 'branch': 'release'}
Plug 'rhysd/vim-clang-format', {'for' : ['c', 'cpp']}
Plug 'chxuan/cpp-mode', {'for' : ['cpp']}

call plug#end()

" plugin-config vim-clang-format
let g:clang_format#auto_format=1

" plugin-config cpp-mode
nnoremap <leader>y :CopyCode<cr>
nnoremap <leader>p :PasteCode<cr>
nnoremap <leader>u :GoToFunImpl<cr>
nnoremap <silent> <leader>a :Switch<cr>

" plugin-config coc-snippets {{{
inoremap <silent><expr> <TAB>
      \ pumvisible() ? coc#_select_confirm() :
      \ coc#expandableOrJumpable() ? "\<C-r>=coc#rpc#request('doKeymap', ['snippets-expand-jump',''])\<CR>" :
      \ <SID>check_back_space() ? "\<TAB>" :
      \ coc#refresh()

function! s:check_back_space() abort
  let col = col('.') - 1
  return !col || getline('.')[col - 1]  =~# '\s'
endfunction

let g:coc_snippet_next = '<tab>'
" plugin-config coc-snippets }}}

" plugin-config coc-definition
nmap <silent> <leader>d :call CocAction('jumpDeclaration')<CR>
nmap <silent> <leader>i :call CocAction('jumpDefinition')<CR>

" options {{{
set tabstop=2
set softtabstop=2
set shiftwidth=2
set smarttab
set expandtab

set nohlsearch
set incsearch
set hidden
set nobackup
set nowritebackup
set updatetime=300
set shortmess+=c
set signcolumn=yes
set nonumber
set ttyfast
set showcmd
set cmdheight=1
set noswapfile
set nobackup
set noerrorbells
set autowrite
set ignorecase
set ruler
set cursorline
set colorcolumn=110
set title
set showmatch
set noshowmode
set mouse=v
set modifiable
set splitright
set splitbelow
set shortmess=atI
set backspace=indent,eol,start
set wildmenu
set encoding=utf-8 nobomb
set binary
set autoread
set mousehide
set spelllang=en_US
set fileformat=unix
set autoread
set autowrite
set laststatus=2
set termwinsize=10*0
set number
set background=dark
set formatoptions=c,l,1,p
set expandtab
set nowrap
" options }}}

" Uncomment the following to have Vim jump to the last position when reopening a file
if has("autocmd")
  au BufReadPost * if line("'\"") > 0 && line("'\"") <= line("$")
    \| exe "normal! g'\"" | endif
endif

if has('persistent_undo')      "check if your vim version supports it
  set undofile                 "turn on the feature
  set undodir=$HOME/.vim/undo  "directory where the undo files will be stored
endif

修改.vimrc后,请不要忘记在命令行中执行 mkdir ~/.vim/undo -p 创建一个存放历史操作记录的文件夹。

  1. 安装插件
    在 vim 默认导航模式键入:PlugInstall,vim-plug 会安装~/.vimrc中所配置的三项插件,主要用于代码自动补全和跳转。
  2. 配置补全服务器
    在 vim 默认导航模式键入:CocConfig,在打开的配置文件中粘贴如下内容:

提示: 在vim中编辑时,阁下可能需要在粘贴前 :set paste,键入i进入插入模式,按 Ctrl+Shift+V 粘贴系统剪贴板内容,Esc退出,然后:set nopaste:set paste 的作用是临时取消自动插入缩进符。

{
  "languageserver":{
    "clangd":{
      "command":"clangd",
      "filetypes":[
        "c",
        "cpp"
      ],
      "rootPatterns":[
        "compile_commands.json",
        ".git"
      ],
      "args":[
        "--compile-commands-dir=build",
        "--compile_args_from=filesystem",
        "--all-scopes-completion",
        "--background-index",
        "--clang-tidy",
        "--cross-file-rename",
        "--completion-parse=always",
        "--completion-style=detailed",
        "--function-arg-placeholders",
        "--header-insertion-decorators",
        "--query-driver=/usr/bin/**/clang-*,/home/adem/GCC-10/bin/g++*",
        "--header-insertion=never",
        "--limit-results=0",
        "-j=6",
        "--pch-storage=memory"
      ]
    }
  }
}

在后续的项目中,只要使vim所编辑的文件的各级父目录下存在compile_commands.json 文件,就可以实现整个项目中变量的跳转和补全了,并且感觉不到延时。这里的 compile_commands.json 文件可以通过许多常用的工具方便地生成,参见这里

示例: 当使用 CMake 时,在命令行中增加 -DCMAKE_EXPORT_COMPILE_COMMANDS=1 选项,或在顶层CMakeLists.txt中增加 set(CMAKE_EXPORT_COMPILE_COMMANDS ON)一行内容。

该环境下可用的部分快捷键

  • <ctrl>+n 切换下一个补全项(键入单词或函数时会自动补全,且自带实时语法检查)
  • <tab> 切换下一个补全项
  • <space>+d 跳转到(当前光标所在位置对象的)定义
  • <spacd>+i 跳转到(当前光标所在位置对象的)实现
  • <ctrl>+o 跳转到上一位置
  • <ctrl>+i 跳转到下一位置
  • <space>+a 切换头文件/cpp文件
  • <space>+y 在头文件中复制函数签名
  • <space>+p 在对应的cpp文件中粘贴函数实现的定义
  • 重新打开文件后光标会从上次退出的位置开始,并且可以保留上次编辑的历史回退记录。
  • 其它VIM中默认自带的常用快捷键在此不重复列出。

参考资料

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐