從零開始搭建你的nvim ide

雲崖君發表於2021-11-01

前言概述

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管理等相關功能還沒有新增上,後續如果有時間還會繼續進行更新。

相關文章