从零开始搭建你的nvim ide

时间:2024-04-16 09:16:11

前言概述

vim由于其丰富的扩展性、出色的跨平台性、高效率的操作性深受一大批粉丝的追捧,甚至就连vim和emacs之间孰优孰劣的话题都能被引起一场编辑器之间的圣战,足以见vim是多么的优秀。

vim的灵魂在于高定制性,高可玩性,一个原生的vim没有任何插件加持的情况下还是非常难以上手的,但是我们可以通过一些插件的点缀让它变得熠熠生辉,甚至可以配置出一个只属于自己的IDE。

  • 在观看本章节前,你应该熟悉vim的基本操作
  • 此外,还应当对vim的插件化管理vim-plug有所了解
  • 可参照之前的文章

vimcdoc 中文文档

vimcdoc提供了vim的中文文档,安装该插件后在命令模式中输入:help即可获取vim中文文档。

我们只需要把下面这一行放~/.config/nvim/init.vim文件中的call begin和call end之间即可:

Plug \'yianwillis/vimcdoc\'

然后使用vim-plug进行下载,在vim命令模式中输入:PlugInstall,后续的插件安装我们将省略这一步骤:

:PlugInstall

效果如下:

image-20211030185215252

indentLine 可视缩进

indentLine提供一个可视化的缩进服务(仅支持空格缩进):

" 可视化缩进
Plug \'Yggdroot/indentLine\'

效果如下:

image-20211029224602725

vim-monokai 主题配色

vim-monokai是我最喜欢的一款代码主题,之前在vscode上我也一直使用monokai主题:

" monokai主题
Plug \'crusoexia/vim-monokai\'

然后需要再加上下面一行配置:

" 开启语法高亮
syntax on
" 主题选用monokai
colorscheme monokai

效果如下:

image-20211029224522232

vim-airline 状态标签

vim-airline为vim提供了一个非常好看的状态栏以及标签栏:

" 加载vim-airline
Plug \'vim-airline/vim-airline\'    
" 使用的主题
Plug \'vim-airline/vim-airline-themes\'

还需要做一些样式与按键上的调整:

" 关于标签栏的样式
" -- 启用标签栏
let g:airline#extensions#tabline#enabled = 1
" -- 设置标签栏分隔符
let g:airline#extensions#tabline#left_sep = \' \'
let g:airline#extensions#tabline#left_alt_sep = \'|\'
" -- 设置标签栏格式
let g:airline#extensions#tabline#formatter = \'default\'
" -- 设置标签栏样式
let g:airline_theme = \'desertink\'
"-- 快捷键e切换到前一个标签
nmap e <Plug>AirlineSelectPrevTab
"-- 快捷键E切换到后一个标签
nmap E <Plug>AirlineSelectNextTab

效果如下:

image-20211029234050314

nerdtree 资源管理

nerdtree为vim提供了一个文件资源管理器,我们可以通过h、j、k、l来进行文件的选择:

" nerdtree支持
Plug \'preservim/nerdtree\'
" 显示nredtree中文件和目录的Git状态标志
Plug \'Xuyuanp/nerdtree-git-plugin\'
" 支持nredtree中文件和目录的图标
Plug \'ryanoasis/vim-devicons\'
" 支持高亮显示nredtree中的图标
Plug \'tiagofumo/vim-nerdtree-syntax-highlight\'

默认的nerdtree是没有任何文件图标的,若想添加图标,请访问nerd-fonts下载字体图标。

需要按照不同的操作系统进行阅读自述文件,下面以MAC平台为例。

我们可以直接找到Droid Sans Mono Nerd这个字体,然后选择下载Droid Sans Mono Nerd Font Complete.otf,下载完成后双击即可安装字体。

安装字体完成后需要将Terminal的字体调整为Droid Sans Mono Nerd,下面是ITerm的设置:

image-20211030175758674

接下来我们对nerdtree做一些基本的设置:

" nerdtree配置
" -- 为打开或关闭nerdtree设置一个快捷键
nnoremap 1 :NERDTreeToggle<CR>
" -- 自动开启nerdtree
autocmd vimenter * NERDTree 
" -- 设定nerdtree的窗口大小
let g:NERDTreeWinSize = 25
" -- 打开nerdtree时自动显示bookmarks
let NERDTreeShowBookmarks=1
" -- 打开nvim时若没有任何文件,则自动打开nerdtree
autocmd vimenter * if !argc()|NERDTree|endif
" -- 当nerdtree为唯一视窗时,自动关闭
autocmd bufenter * if (winnr("$") == 1 && exists("b:NERDTree") && b:NERDTree.isTabTree()) | q | endif
" -- 每次打开一个新的标签,都默认打开nerdtree
autocmd BufWinEnter * if getcmdwintype() == \'\' | silent NERDTreeMirror | endif
" -- 设置树的图标,以区分已打开或未打开
let g:NERDTreeDirArrowExpandable = \'▸\'
let g:NERDTreeDirArrowCollapsible = \'▾\'
" -- 是否显示行号
let g:NERDTreeShowLineNumbers=0
" -- 是否显示隐藏文件
let g:NERDTreeHidden=0
" -- 让nerdtree更漂亮
let NERDTreeMinimalUI = 1
let NERDTreeDirArrows = 1
" -- 过滤不显示的文件
let NERDTreeIgnore=[\'\.pyc\',\'\~$\',\'\.swp\']
" -- nerdtree的git文件状设置
let g:NERDTreeGitStatusIndicatorMapCustom = {
                \ \'Modified\'  :\'✹\',
                \ \'Staged\'    :\'✚\',
                \ \'Untracked\' :\'✭\',
                \ \'Renamed\'   :\'➜\',
                \ \'Unmerged\'  :\'═\',
                \ \'Deleted\'   :\'✖\',
                \ \'Dirty\'     :\'✗\',
                \ \'Ignored\'   :\'☒\',
                \ \'Clean\'     :\'✔︎\',
                \ \'Unknown\'   :\'?\',
                \ }
" -- 为不同的文件进行不同的高亮上色
let s:brown = "905532"
let s:aqua =  "3AFFDB"
let s:blue = "689FB6"
let s:darkBlue = "44788E"
let s:purple = "834F79"
let s:lightPurple = "834F79"
let s:red = "AE403F"
let s:beige = "F5C06F"
let s:yellow = "F09F17"
let s:orange = "D4843E"
let s:darkOrange = "F16529"
let s:pink = "CB6F6F"
let s:salmon = "EE6E73"
let s:green = "8FAA54"
let s:lightGreen = "31B53E"
let s:white = "FFFFFF"
let s:rspec_red = \'FE405F\'
let s:git_orange = \'F54D27\'

let g:NERDTreeExtensionHighlightColor = {} " this line is needed to avoid error
let g:NERDTreeExtensionHighlightColor[\'css\'] = s:blue " sets the color of css files to blue

let g:NERDTreeExactMatchHighlightColor = {} " this line is needed to avoid error
let g:NERDTreeExactMatchHighlightColor[\'.gitignore\'] = s:git_orange " sets the color for .gitignore files

let g:NERDTreePatternMatchHighlightColor = {} " this line is needed to avoid error
let g:NERDTreePatternMatchHighlightColor[\'.*_spec\.rb$\'] = s:rspec_red " sets the color for files ending with _spec.rb

let g:WebDevIconsDefaultFolderSymbolColor = s:beige " sets the color for folders that did not match any rule
let g:WebDevIconsDefaultFileSymbolColor = s:blue " sets the color for files that did not match any rule

下面是nerdtree的一些操作方式:

?:获取帮助文档
h、j、k、l:移动方式
t:以tab形式打开文件,并将光标移动至打开的文件中
T:以tab形式打开文件,不将光标移动至打开的文件中
o:以buffer形式打开文件,并将光标移动至打开的文件中
O:以tab形式打开文件,不将光标移动至打开的文件中
e:以文件管理的方式打开选中的目录
q:关闭nerdtree
r:刷新nerdtree
m:增删改查子项目

效果如下:

image-20211030184047731

caw.vim 自动注释

关于注释插件的选择,推荐caw.vim

尽管网上有很多人都在推荐nerdcommenter这款注释插件,但我断言caw.vim比nerdcommenter更加优秀。

nredcommenter是根据文件类型来进行注释的,也就是说它无法做到单文件多语言的注释风格切换。

而caw.vim则是根据当前光标所在区域内容来自动切换语言注释风格,这依赖于context_filetype插件。

举一个简单的例子,在编写vim时我们会出现<template>、<script>、以及<style>等标签,这种情况下nredcommenter的注释总是//,而使用caw.vim,你在不同的标签区域内能就获得不同的注释方式,这是我选择它最关键的一点:

" 根据内容自动获取文件类型
Plug \'Shougo/context_filetype.vim\'
" 自动进行注释
Plug \'tyru/caw.vim\'

它的使用方式也非常简单,gcc即是注释、取消注释的快捷键。

由于我平常喜欢使用ctrl+/进行注释,所以这里修改一下它的映射:

" caw.vim注释快捷键修改
"  -- ctrl+/设置为打开、关闭注释
" 注意!Unix操作系统中的ctrl+/会被认为是ctrl+_,所以下面有这样一条if判断
if has(\'win32\')
    nmap <C-/> gcc
    vmap <C-/> gcc
else
    nmap <C-_> gcc
    vmap <C-_> gcc
endif

auto-pairs 括号补全

默认的vim中当你输入诸如{}、()、""、\'\'等成对字符时,它是不会帮你进行补全的,因此我们需要使用auto-pairs来进行自动补全。

" 自动填充成对出现的符号
Plug \'jiangmiao/auto-pairs\'

rainbow 括号高亮

默认的vim中当你选择上诸如{}、()等成对字符时,它是不会进行高亮显示另一半字符的,因此我们需要使用rainbow来进行高亮显示。

" 自动高亮成对出现的符号
Plug \'luochen1990/rainbow\'

此外还需要做一些额外的配置项:

 rainbow设置
" -- 开启rainbow
let g:rainbow_active = 0
" -- 解决与nerdtree/vim-devicons冲突的问题
let g:rainbow_conf = {
	\	\'separately\': {
	\		\'nerdtree\': 0,
	\	}
	\}
" -- rainbow匹配成对符号的颜色设置
let g:rainbow_conf = {
\   \'guifgs\': [\'darkorange3\', \'seagreen3\', \'royalblue3\', \'firebrick\'],
\   \'ctermfgs\': [\'lightyellow\', \'lightcyan\',\'lightblue\', \'lightmagenta\'],
\   \'operators\': \'_,_\',
\   \'parentheses\': [\'start=/(/ end=/)/ fold\', \'start=/\[/ end=/\]/ fold\', \'start=/{/ end=/}/ fold\'],
\   \'separately\': {
\       \'*\': {},
\       \'tex\': {
\           \'parentheses\': [\'start=/(/ end=/)/\', \'start=/\[/ end=/\]/\'],
\       },
\       \'lisp\': {
\           \'guifgs\': [\'darkorange3\', \'seagreen3\', \'royalblue3\', \'firebrick\'],
\       },
\       \'vim\': {
\           \'parentheses\': [\'start=/(/ end=/)/\', \'start=/\[/ end=/\]/\', \'start=/{/ end=/}/ fold\', \'start=/(/ end=/)/ containedin=vimFuncBody\', \'start=/\[/ end=/\]/ containedin=vimFuncBody\', \'start=/{/ end=/}/ fold containedin=vimFuncBody\'],
\       },
\       \'html\': {
\           \'parentheses\': [\'start=/\v\<((area|base|br|col|embed|hr|img|input|keygen|link|menuitem|meta|param|source|track|wbr)[ >])@!\z([-_:a-zA-Z0-9]+)(\s+[-_:a-zA-Z0-9]+(\=("[^"]*"|\'."\'".\'[^\'."\'".\']*\'."\'".\'|[^ \'."\'".\'"><=`]*))?)*\>/ end=#</\z1># fold\'],
\       },
\       \'css\': 0,
\   }
\}

vim-easymotion 快速跳转

vim-easymotion为vim提供了快速查找并跳转到某个字符的功能。

" 快速跳转
Plug \'easymotion/vim-easymotion\'

你只需要按下:

# 全局定位某个字符
<leader><leader>s<char>

即可完成搜索。当搜索完成后它会对搜索的字符进行高亮,此时只需按下高亮后的快捷键即可跳转到该字符上。

我们可以将它定义成快捷键ctrl+f:

" easymotion设置
" --将全局搜索修改成ctrl+f
nmap <C-f> <Plug>(easymotion-s)

其他的操作,可自行进行映射:

# 定位移动j、k、h、l
<leader><leader>j

# 跳转到前一个词上
<leader><leader>b

# 跳转到后一个词上
<leader><leader>w

# 重复上一动作
<leader><leader>.

vim-surround 包裹修改

vim-surround插件非常的方便,如果你想修改、或者删除单引号和双引号,它带给你的体验将是无与伦比的。

Plug \'tpope/vim-surround\'

以下是它的语法:

ds<existing>
cs<existing><desired>

示例如下:

# 删除以下的[]
[1, 2, 3] -> ds[

# 将以下的[]修改为()
[1, 2, 3] -> cs[(

tagbar 大纲预览

tagbar为vim提供了当前文件下的类、函数预览功能。它依赖于ctags,所以我们需要先下载ctags。

$ wget http://prdownloads.sourceforge.net/ctags/ctags-5.8.tar.gz
$ tar -xvf ctags-5.8.tar.gz
$ cd ctags-5.8
$ ./configure --prefix=/usr/local/application
$ make -j
$ make install # 安装到完成后会在指定路径下创建一个bin目录
$ rm -rf ctags-5.8
$ rm -rf ctags-5.8.tar.gz

然后把安装路径添加到环境变量中,我目前使用的是bash,所以直接添加到/etc/profile里即可:

PATH=/usr/local/application/bin:$PATH

source /etc/profile

在终端输入ctags,如出现以下字样则按照成功:

ctags: No files specified. Try "ctags --help".

接下来我们就要安装tagbar了:

Plug \'majutsushi/tagbar\'

下面再设置一下按键和tagbar的宽度就搞定了:

let g:tagbar_width=30
nnoremap 3 <F4> :TagbarToggle<CR>

效果图示:

image-20211031164906359

SimpyFold 代码折叠

SimpyFold是一款非常好用的代码折叠工具,使用它能够让我们编辑代码时逻辑结果更加清楚。

" 代码折叠
Plug \'tmhedberg/simpylfold\' 

然后添加一些额外的配置:

" 自动按照缩进进行代码折叠
set foldmethod=indent

" 启用预览被折叠的代码
let g:SimpylFold_docstring_preview = 1

使用这个插件非常简单,你只需要遵循vim自带的代码折叠机制即可:

  • zf:创建折叠
  • zo:打开折叠
  • zc:关闭折叠
  • zR:打开所有
  • zM:关闭所有
  • zj:移动到下一个折叠
  • zk:移动到上一个折叠

coc.nvim 智能补全

coc.nvim是只有nvim才能使用的智能补全插件平台。

了解它之前我们我们必须了解它的模式,它本身仅是一个平台,类似于vim-plug,我们可以在coc.nvim中安装很多我们需要的其他coc插件。

首先,coc.nvim必须基于Node.Js,所以请确保你的机器上安装了Node.js,如果没有安装或者你根本不知道Node.Js是啥,可以直接运行下面这段代码:

$ curl -sL install-node.now.sh/lts | bash

然后我们就需要使用vim-plug装上coc.nvim平台了:

" coc智能代码补全平台
Plug \'neoclide/coc.nvim\', {\'branch\': \'release\'}

安装完成之后,还需要使用npm安装一些2个东西:

$ npm install -g neovim yarn

此外,coc平台插件还需要依赖Python,所以我们需要在Python中安装neovim:

$ pip3 install neovim
$ pip2 install neovim

最后一步,必须让vim关联上Python,所以在init.vim配置文件中你需要设置:

" coc配置pythonx
if has(\'python3\')
  set pyx=3
elseif has(\'python2\')
  set pyx=2
endif

现在让我们打开vim,并在命令模式下执行:checkhealth命令,检查是否安装成功:

:checkhealth

主要查看health#nvim#check下面的这3个选项是否是ok,一般情况下只要按照上述步骤做了就没什么问题:

image-20211031220925894

下面添加一些coc的配置项:

" 允许未保存文件时跳转文件
set hidden
" 增加响应
set updatetime=100
" 让弹窗栏更加简洁
set shortmess+=c
" 让我们的tab作为切换扩展的按键
inoremap <silent><expr> <TAB>
      \ pumvisible() ? "\<C-n>" :
      \ <SID>check_back_space() ? "\<TAB>" :
      \ coc#refresh()
inoremap <expr><S-TAB> pumvisible() ? "\<C-p>" : "\<C-h>"

function! s:check_back_space() abort
  let col = col(\'.\') - 1
  return !col || getline(\'.\')[col - 1]  =~# \'\s\'
endfunction
" 按下ctrl+space键跳出或关闭自动补全
if has(\'nvim\')
  inoremap <silent><expr> <c-space> coc#refresh()
else
  inoremap <silent><expr> <c-@> coc#refresh()
endif
" 当使用enter键作为补全选择时,它将不会自动切换到下一行
inoremap <silent><expr> <cr> pumvisible() ? coc#_select_confirm()
                              \: "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"
" 使用[g或者]g来查找上一个或者下一个代码报错
nmap <silent> [g <Plug>(coc-diagnostic-prev)
nmap <silent> ]g <Plug>(coc-diagnostic-next)
" 使用gd来跳转到函数定义处、gy获取类型定义,
nmap <silent> gd <Plug>(coc-definition)
nmap <silent> gy <Plug>(coc-type-definition)
nmap <silent> gi <Plug>(coc-implementation)
nmap <silent> gr <Plug>(coc-references)
" 通过gh来显示文档
nnoremap gh :call <SID>show_documentation()<CR>
function! s:show_documentation()
  if (index([\'vim\',\'help\'], &filetype) >= 0)
    execute \'h \'.expand(\'<cword>\')
  elseif (coc#rpc#ready())
    call CocActionAsync(\'doHover\')
  else
    execute \'!\' . &keywordprg . " " . expand(\'<cword>\')
  endif
endfunction
" 高亮相同的词汇
autocmd CursorHold * silent call CocActionAsync(\'highlight\')

" 符号重命名
nmap <leader>rn <Plug>(coc-rename)

" 格式化插件
xmap <leader>f  <Plug>(coc-format-selected)
nmap <leader>f  <Plug>(coc-format-selected)
augroup mygroup
  autocmd!
  " Setup formatexpr specified filetype(s).
  autocmd FileType typescript,json setl formatexpr=CocAction(\'formatSelected\')
  " Update signature help on jump placeholder.
  autocmd User CocJumpPlaceholder call CocActionAsync(\'showSignatureHelp\')
augroup end

我们说过coc.nvim类似于vim-plug,所以他也有一套自己的命令:

  • CocInstall:安装一个coc插件
  • CocList:获取所有已安装的coc插件
  • CocConfig:创建一份Coc配置文件
  • CocCommand:运行一个coc插件命令

先安装一个coc-marketplace,通过它你可以发现很多coc插件:

:CocInstall coc-marketplace

下载完成后,输入以下命令即可选取你需要的coc插件:

:CocList marketplace

其实通过CocInstall来下载coc插件并不是一个比较好的选择,因为一旦切换了开发环境,那么所有的coc插件都需要重新下载一次。

因此我推荐将coc插件的下载存放在init.vim文件中:

" coc下载插件
let g:coc_global_extensions = [
\  \'coc-marketplace\',
\  \'coc-json\',
\  \'coc-vimlsp\'
\   ]

下次当你打开vim时,它会自动对没有安装的coc插件进行下载。

通过CocList extensions来查看已经安装了哪些插件,其中*号是已启用,+号是未启用,它是自动根据文件类型来进行选择的。

按下tab键它会提示给你一些管理coc插件的选项:

Choose action:
[t]oggle, (c)onfiguration, (o)pen, (d)isable, (e)nable, (l)ock, (h)elp, (r)eload
, (f)ix, (u)ninstall:

下面是我安装的插件,其中*代表已加载的,+号代表未加载的。

image-20211101195926318

image-20211101200026296

其他的功能

现在一款IDE已经初具雏形,但是对于debug调试、git管理等相关功能还没有添加上,后续如果有时间还会继续进行更新。