vimrc

這裡會紀錄我目前的 vimrc 配置,並且說明他們的功用。

前言

因為總覺得自己還有好多相關的語法沒學,所以我的 vimrc 顯得特別簡單(
發這篇文的目的大概就是提醒自己要去學一些 vim script 等等的語法,順便做個筆記,之後要是看不懂某些地方的時候可以回來看。
因為我也似懂非懂的,如果內容有誤還請告知><
這篇文預計會是持續維護的,在我的 vimrc 有什麼更動的時候都會更新這篇文(如果我還記得的話)

什麼是 vimrc?

首先要說道 vim。vim 是一個歷史悠久的文字編輯器,其好用地方在於有許多獨特的快捷鍵讓你可以不用滑鼠就作到很多工作。
而另一個知名的特色就是高度自訂性的設定檔,也就是 vimrc。
這篇只會針對 vimrc,並不會涉及 vim 的操作等等內容。

vimrc

廢話不多說,先上本體。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
set nocompatible

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

" Plug 'yuttie/comfortable-motion.vim'
" Plug 'itchyny/lightline.vim'
" Plug 'rlue/vim-barbaric'

Plug 'godlygeek/tabular'
Plug 'plasticboy/vim-markdown'
Plug 'lervag/vimtex'
Plug 'preservim/nerdtree'
Plug 'morhetz/gruvbox'
Plug 'tomasr/molokai'
Plug 'fmoralesc/molokayo'
Plug 'vim-airline/vim-airline'
Plug 'vim-airline/vim-airline-themes'
Plug 'bfrg/vim-cpp-modern'
Plug 'tribela/vim-transparent'
call plug#end()

" basic configurations
set cb^=unnamedplus,unnamed
set ts=4 " tabstop=4
set sw=4 " shiftwidth=4
set ls=2 " laststatus=2
set cul " cursorline
set ai " autoindent
set is " incsearch
filetype plugin indent on
set hls " hlsearch
set rnu " relativenumber
set showcmd
syntax enable
" colo

" additional configurations
colo molokayo
let g:airline_theme='molokai'
set mouse=n
set autochdir
set ttimeoutlen=0
" enable powerline symbols
let g:airline_powerline_fonts = 1
" do not hightlight my function
let g:cpp_function_highlight = 0
" vim markdown settings
let g:vim_markdown_math = 1

" keymaps
autocmd filetype cpp nnoremap <F9> :w <bar> !g++ -std=c++17 % -o %:r -Wall -Wextra -Wconversion -Wshadow -fsanitize=undefined -fsanitize=address <CR>
autocmd filetype cpp nnoremap <F10> :!./%:r <CR>
autocmd filetype cpp nnoremap <F11> :!./%:r < input.txt > output.txt <CR>
autocmd filetype cpp nnoremap <C-C> :s/^\(\s*\)/\1\/\/<CR> :s/^\(\s*\)\/\/\/\//\1<CR> $
inoremap { {}<Left>
inoremap {<CR> {<CR>}<Esc>O
inoremap {{ {
inoremap {} {}

" latex keymaps
autocmd filetype tex nnoremap <F9> :w <bar> :!xelatex % <CR>
autocmd filetype tex nnoremap <F10> :!okular %:r.pdf <CR>

" Set true color
let &t_8f="\<Esc>[38;2;%lu;%lu;%lum"
let &t_8b="\<Esc>[48;2;%lu;%lu;%lum"
set termguicolors

" NERDTree settings
" F5 to toggle and put the cursor back in the othe window.
nnoremap <F5> :NERDTreeToggle \| wincmd p<CR>
" Start NERDTree and put the cursor back in the other window.
autocmd VimEnter * NERDTree | wincmd p
" Exit Vim if NERDTree is the only window remaining in the only tab.
autocmd BufEnter * if tabpagenr('$') == 1 && winnr('$') == 1 && exists('b:NERDTree') && b:NERDTree.isTabTree() | quit | endif
" Close the tab if NERDTree is the only window remaining in it.
autocmd BufEnter * if winnr('$') == 1 && exists('b:NERDTree') && b:NERDTree.isTabTree() | quit | endif
let g:NERDTreeWinSize=20

" Refresh defaut code
autocmd filetype cpp command! New execute "%d|r ~/Programming/template/default.cpp|1d|41"

" encoding
set fileencodings=ucs-bom,utf-8,cp932,gb18030,gbk,gb2312,cp936
set termencoding=utf-8
set encoding=utf-8

說明

我其實是有分區的,所以就按照這樣的分區來寫。

關閉相容

set nocompatible
因為 Vim 的全名是 Vi IMproved,所以 Vim 其實會跟 Vi 的操作去相容。
不過這也導致有些 Vim 的功能會被關掉(或發生奇怪的現象)。
除非是要執行古老的 Vi script 之類的,不然通常都關掉比較好。
基本上不加這行也可以,因為 Vim 的文件有說道當偵測到 .vimrc 的存在的時候就會自動打開。
除了像是使用 -u 標籤來指定 vimrc 之類的時候就不自動打開。
為了不必要的困擾所以我還是會留著這行。
記得把這行放在 vimrc 第一行

Plugins

vim 還有一個很強大的特色就是除了 vimrc 以外你還能夠引入第三方的插件來讓整個編輯器變得更好用。
這邊其實很大部份都是抄來的,因為我很懶得自己去找有哪些插件可以用(X
如果你覺得有什麼一定要裝的插件可以分享給我ww
因為比賽通常是不會有這些插件的,所以我會盡量避免使用一些如 auto completion 等等會方便打字的,避免比賽的時候變得不會用鍵盤。
然後考慮到底下的設定可能會是在設定這些插件,跟寫程式一樣通常要先宣告有這個插件才能去設定,所以就把插件擺到前面。

vim-plug

插件可以自己亂裝,但是在插件很多的時候還是有一個 plugin manager 會比較好。
我這裡是選用 vim-plug,原因是當初查到的第一篇教學文就是用這個。

  • comfortable motion:比較舒服的滾動(? 雖然我根本沒在用他
  • lightline:很酷的狀態列,但是自從用了 airline 之後就沒用他了。
  • Tabular:排版用,不是寫程式時的縮排,在編輯一般的文字檔的時候比較好用。
  • vim markdown:highlight markdown 的語法,並且提供一些酷酷的快捷鍵與指令。
  • vimtex:hightlight latex 的語法,然後還有數不清的功能。
  • nerdtree:以樹狀形式顯示資料夾,幾乎所有 IDE 配有的功能現在在 vim 也有了!
  • gruvbox:很知名的 colorschmee,可是我還是比較喜歡 molokayo。
  • molokayo:目前在用的 colorscheme,算是 molokai 的加強版。
  • barbaric:寫程式的時候都是英文的所以沒感覺,但是在寫 blog 或者 latex 等等的時候就會發現了,vim 在從 insert mode 進到 normal mode 的時候只要按 Esc 就好,可是輸入法不會變!所以在 normal mode 會被卡輸入法導致什麼都做不了,只能先切回英文輸入法,但是在進 insert mode 時又要改成中文輸入法。這個插件就是幫你在進到 normal mode 時換成英文輸入法,但是保留輸入法設定使得進到 insert mode 時會切回原本的輸入法。寫文章神器!(但是目前好像有奇怪 bug,所以先關掉)
  • airline:超潮的狀態列,看了心情就好,寫程式有時最需要的就是良好的心情。尤其有裝 powerline 字體的話觀感又更上一層樓。
  • airline themes:airline 的補充包,裡面有很多內建的主題可以設定。
  • Vim cpp modern:給 C++ 的更多關鍵字和 STL 的東西上色,有比較多自定義功能,而且還支援到 C++20。
  • vim-transparent:因為 molokayo 有附帶背景顏色,會蓋掉 terminal 的預設背景,所以用這個把 vim 的背景顏色關掉。

Basic configurations

就是基礎設定。
通常是沒有這些東西的話我會不想要用 vim,他們是核心。
而我在比賽的時候現場打的 vimrc 大概也就只是這些和底下一些 keymap。

與系統剪貼簿同步

set cb^=unnamedplus,unnamed
在 vim 的預設中,yank、delete、paste 等操作所使用的 register 都叫 unnamed,也就是所有複製、刪除的操作都會把內容丟到那個 register,貼上也是從這個 register 的內容中拿來用。
然而這個 register 跟系統的剪貼簿是不一樣的,所以在 vim 複製的東西沒辦法貼到其他地方去,也沒辦法把其他地方複製下來的內容貼到 vim 上。
解決方法是在使用指令的時候都去指定 register,可是這樣很麻煩。
所以我們可以直接把系統的剪貼簿綁到 unnamed 這個 register,這樣就能把 vim 與系統的剪貼簿同步了。

而 unnamed 跟 unnamedplus 在 windows/macOS 是一樣的,但是在 linux 的 X11 底下會有兩個剪貼簿,所以有必要把兩個都指定起來(當然也可以不指定其中一個,更詳細的這邊就不提了)。
然而在 linux 的 wayland 底下有沒有這行好像都一樣會沒辦法同步,查網路的結果好像是無解,之前的解決方法是使用 wl-clipboard 配上自己寫 vim 的指令來做複製功能。

設置 tab 以及縮排寬度

set tabstop=4
set shiftwidth=4
寫程式的時候往往都會用 tab 去做縮排,使用這兩個可以使得 tab 鍵與系統的 shift 功能(快捷鍵:>>)的寬度都是 4 格。

狀態列表

set laststatus=2
讓右下角的狀態列表永遠開著,預設是只有在開多個 tab 的時候才會顯示出來當作分界線,但是我覺得這個的資訊量很大所以應該要隨時開著。

游標所在行

set cursorline
把游標所在的這行給標上底線,在文字量龐大的時候常常會找不到到游標在哪裡,有了這行基本上就很容易找到了。

自動縮排

filetype plugin indent on
set autoindent
vim 預設會給一些常見語言自己的縮排設定,所以透過上面那行直接讓他偵測目前檔案類型並套用特定縮排。
下面那行是單純的在建立新行的時候(Enter、O 鍵等等…)會沿用前一行的縮排。
兩者一起用似乎是上面那行的設定(如果有設定檔的話)會蓋掉下面那行,所以應該是不會出事。

強化搜尋功能

set incsearch
set hlsearch
incearch 是會在搜尋時於打字過程中就幫你跳轉畫面到當下的搜尋結果,而不用等到按下 enter 鍵再跳轉。
hlsearch 會把搜尋到的字串都標上 highlight(不懂為什麼預設會沒有 highlight,超反人性),如果搜尋完想要把 highlight 關掉就打 :noh 即可。

相對行號

set relativenumber
理論上我們會很自然的在左側顯示當前第幾行,可是 vim 有很多快捷鍵是需要去指定要作用幾行的(比如刪除等等),所以我覺得顯示相對行數會比較方便,設定之後游標那行左邊會變成從 0 開始,往上往下分別是 1 2 3…。

顯示當前指令

set showcmd
vim 的很多快捷鍵是有多個字母的,尤其是那些可以指定次數的(比如 2dd3yy 等等)。
設定了這個會在輸入快捷鍵的過程中把目前輸入的東西顯示在右下角,就可以邊打快捷鍵邊確認有沒有不小心按到什麼鍵了。

hightlight, colorscheme

syntax enable
colorscheme ???
上面就是會對每個語言的關鍵字上色,算是必備東西了吧。
下面則是可以自訂不同的 colorscheme,vim 裡面有內建了一些也可以自己裝。
因為我在下面有自己裝,所以我這邊就沒有要使用預設的 colorscheme,可是我還是佔一個行來提醒我比賽的時候要去設定 colorscheme。

additional configurations

建立在 basic configurations 之上的其他設定,主要就是沒有到太重要所以不會在比賽的時候把他打出來。

molokai

colo molokayo
優質 colorscheme。
因為我是用 plugin 去裝這個 colorscheme 的,所以記得這行必須放在 plug molokayo 的下面。

airline 主題

let g:airline_theme='molokai'
這個是從 vim-airline-theme 來的,屬於這個插件其中一個內建主題。
既然 colorscheme 都用 molokai 了,這個的乾脆就設一樣搞不好能夠讓整體變得一致。

設定滑鼠作用範圍

set mouse=n
比如滑鼠點擊左鍵的時候要不要移動游標到點擊的位置。
可以用 n(Normal), i(Insert), c(Command), v(Visual), a(All),分別對應到不同的模式。
預設是 a,但是我覺得在打字的時候手會不小心碰到觸控板,然後游標就亂跑,很煩。
所以就改成在 Normal 的時候才使用,不過其實我很少用到滑鼠來移動游標所以這行其實應該甚至可以改成 set mouse= 代表完全不要讓他作用。

自動切換所在目錄

set autochdir
當你打了類似 vim a/b.cpp 時,你會發現你的目錄其實還是在 a 的父目錄(也就是執行 vim 指令的資料夾),可以用 :pwd 指令查看(也可以使用外部的 linux 指令 :!pwd)當前所在的資料夾。
意思就是你可能做另存新檔之類的操作的時候是會在 a 外面而不是在 a 的那個資料夾的。令一個例子可能是在編譯的時候編譯器可能會把編譯出來的執行檔丟到當前的目錄,此時就有可能會程式碼跟執行檔放的位置不一樣。
這樣很麻煩,所以用了這行就能讓 vim 自動把當前目錄轉到你開的那個檔案的那邊。

關掉組合鍵的等待時間

set ttimeoutlen=0
在 barbaric 插件於我切換模式時幫我自動切換輸入法時,他會有些許延遲(觸發切換輸入法的那個操作)。
所以從 insert 切換到 normal 的時候我是有可能會被卡中文輸入法卡一小段時間的。
推測原因是在按下 ESC 時,因為 ESC 後面的組合鍵太多了,所以會有一段等待輸入後面的鍵的時間。
在 barbaric 的 README.md 中有提到這行可以把這個的等待時間關掉,也就會沒有延遲了。

一些變數

1
2
3
4
5
6
" enable powerline symbols
let g:airline_powerline_fonts = 1
" do not hightlight my function
let g:cpp_no_function_highlight = 1
" vim markdown settings
let g:vim_markdown_math = 1

這些都是插件的一些設定
第一個是因為我的字體是有支援 powerline 的,所以就可以打開 airline 的這個設定來讓整個畫面變更漂亮。
第二個是 cpp enhanced highlight 插件會把你所有的函式都給上色,這樣超怪,因為我只希望他把 STL 有的函式上色,所以可以用這個關掉。
第三個是讓 vim markdwon 插件也給數學式上色,考慮到寫的題解常常會需要數學式,所以當然是打開。

keymaps

一些自己定義的快捷鍵,除了 latex 以外大部分都會在比賽的時候也打出來。

C++

一些在檔名是 cpp 的時候才會作用的快捷鍵。
autocmd filetype cpp nnoremap <F9> :w <bar> !g++ -std=c++17 % -o %:r -Wall -Wextra -Wconversion -Wshadow -fsanitize=undefined -fsanitize=address <CR>
按下 F9 存檔並編譯,執行檔會以去掉副檔名的檔名被丟在原本的資料夾。
%:當前檔案名稱,%:r:當前檔案名稱並去掉副檔名,<bar>:一個 |,有分隔的作用,可以在一行內執行多個指令,<CR>:換行。
autocmd filetype cpp nnoremap <F10> :!./%:r <CR>
按下 F10 執行編譯後的執行檔。
autocmd filetype cpp nnoremap <C-C> :s/^\(\s*\)/\1\/\/<CR> :s/^\(\s*\)\/\/\/\//\1<CR> $
這個是從 tmw 的 vimrc 來的,用途是在按下 Ctrl+C 的時候會自動在當前這行加上或取消 // 註解,蠻好用的。

括號補全

1
2
3
4
inoremap { {}<Left>
inoremap {<CR> {<CR>}<Esc>O
inoremap {{ {
inoremap {} {}

打左括號會有右括號,打兩次左括號就不會補上右括號。
只設定 {,其他的括號一律不補全。

latex

autocmd filetype tex nnoremap <F9> :w <bar> :!xelatex % <CR>
autocmd filetype tex nnoremap <F10> :!okular %:r.pdf <CR>
F9 編譯,F10 執行,跟 C++ 同理。

設定 truecolor

truecolor 是 24-bit 的顏色,大概有一千六百萬種顏色,基本上是人眼可辨識的上限了。
以前的那些 8 種顏色、16 種顏色、256 種顏色都已經過時了。現在的主流 terminal 基本上都有支援 truecolor 了。
首先要先確定你的 terminal 有支援並開啟了 truecolor,可以透過 這邊提到的方法 去測試。
然後就直接照抄下面三行:

1
2
3
let &t_8f="\<Esc>[38;2;%lu;%lu;%lum"
let &t_8b="\<Esc>[48;2;%lu;%lu;%lum"
set termguicolors

NERDTree 設定

以下全是抄 NERDTree 的 github 的 README.md,那邊還有提到其他設定,只是我覺得不需要就沒用了。

1
2
3
4
5
6
7
8
9
" F5 to toggle and put the cursor back in the othe window.
nnoremap <F5> :NERDTreeToggle \| wincmd p<CR>
" Start NERDTree and put the cursor back in the other window.
autocmd VimEnter * NERDTree | wincmd p
" Exit Vim if NERDTree is the only window remaining in the only tab.
autocmd BufEnter * if tabpagenr('$') == 1 && winnr('$') == 1 && exists('b:NERDTree') && b:NERDTree.isTabTree() | quit | endif
" Close the tab if NERDTree is the only window remaining in it.
autocmd BufEnter * if winnr('$') == 1 && exists('b:NERDTree') && b:NERDTree.isTabTree() | quit | endif
let g:NERDTreeWinSize=20

自訂指令

就是輸入 :自訂指令,後會做的事情。注意到 vim 規定自訂指令必須是大寫字母為開頭。

自動刷新模板

autocmd filetype cpp command! New execute "%d|r ~/Programming/template/default.cpp|1d|41"
這是打比賽會用的,在輸入 :New 後會把整份 code 換成比賽用的 defaut code。

編碼

1
2
3
set fileencodings=ucs-bom,utf-8,cp932,gb18030,gbk,gb2312,cp936
set termencoding=utf-8
set encoding=utf-8

fileencodings 的順序會決定在開啟一個文件時去嘗試的編碼的順序。所以作用範圍越小的要放在越前面。
對我來說有被影響的就是之前在開日文的檔案時會出現亂碼,所以我把 ucs-bom 的編碼放到前面就解決了亂碼的問題。其餘都是按照網路上的排法排的。
termencoding 是顯示在 terminal 所用的編碼,encoding 是 vim 內部存任何字串時所用的編碼,這兩個設成 utf-8 基本上應該都不會出事。

後記

這篇文花了我超過 10 個小時orz
原本只是想要當個紀錄文用的,結果發現一堆設定我都講不出他在幹麻,所以就花一堆時間查資料。
中途又陸陸續續修改了好多地方,總覺得描述的用詞有點不太適當。
而且有些東西牽涉的知識太多了,比如 clipboard、縮排相關、ttimeoutlen、truecolor 以及編碼等等內容,希望之後自己變得更熟悉這些東西的時候可以回來補好這些部份。
如果有什麼問題或者是建議歡迎告知><
有些東西我也不敢保證我理解的就是對的,所以要是有我在耍低能亂寫的部份也希望能夠告訴我!

參考資料

In a .vimrc, is `set nocompatible` completely useless?
vim registers
What is difference between Vim’s clipboard “unnamed” and “unnamedplus” settings?
What does “filetype plugin on” really do?
Using Vim
Eliminating delays on ESC in vim and zsh
What is the meaning of a <CR> at the end of some vim mappings?
True Colour (16 million colours) support in various terminal applications and terminals
VIM学习笔记 多编码处理 (Multi-Encodings)