又又又又開始學 Vim 了😪

爲了能像 Gilles Castel 那樣記筆記(用 Vim + snippets 居然可以在課堂上同步記數學筆記😱),我又又又又一次撿起了 Vim 。感覺 Vim 之所以這麼難學,是因爲沒一篇教程寫對路了的😒。

我的最初想法是重現一個新手可能會遇到的問題,尋找原生的解決方案 & 更優雅的方案。不過回頭看,更加深切地感受到,這麼多年過去,Vim & Emacs 的對手(各種 IDE )換了一波又一波,它倆卻還屹立在那,不得不說其設計中有很多先進那個時代、即使在今天仍不過時的思想(當然,也必然存在很多缺陷。當我們認識了這些缺陷,並知道原生如何解決、以及如何更好地解決,使用插件🧩就更加得當)。就算從程序設計的角度,Vim 仍然值得深入學習。

Unix 上最早的文本編輯器是 ed ,而後經過幾代的改進,包括 em (editor for mortals) ,en ,最終到 ex 。再之後纔是 vi ,Vim (vi improved) 。這段有趣而沒用的歷史,我一定要告訴你。

1. 打開 & 退出

  • 用 Vim 打開某份文件:vim a.txt
  • MD,怎麼卡死了!<ctrl-w> 也退不出去🤯!
  • 哦,要按 i (insert) 進入「編輯模式🖋[1]」纔可以寫字😒;
  • MD,ctrl-s 怎麼保存不了🤯!
  • 哦,要按 <esc> 退出「編輯模式🖋」,進入到「思考模式🤔[2]」才能執行命令;
  • 保存 & 退出::wq (其實是進入了「命令行模式」);

這麼會有這麼反人性的設計😒。改下配置 vim ~/.vimrc (即,告訴 Vim 你的使用習慣)。當然,你可以改成熟知的 ctrl + s( Vim 習慣寫成 c-s ),但爲了符合 Vim 的用鍵傳統,還是用單字母吧:

" Save & quit
map Q :q<CR>
map S :w<CR>

現在你可以用 S 保存,按 Q 退出了。

但是,要是在新文件裏寫了點什麼,怎麼保存呢?:w <new_filename>

map S :write %<CR>  " % :活動緩衝區的完整文件路徑。

其實,這樣寫也不準確。改變原生鍵位最好準確指定起效的模式,要是能給出原生鍵位的替代方案就更好了。比如,幸運的是,不會和 surround.vim 的 S 命令衝突。

" Save & quit
nnoremap S :w %<CR>     " ⚠️ 幸運的是,不會和 surround.vim 的 S 命令(只在 visual mode 下起效)衝突。
nnoremap Q :q<CR>

聽人說,Vim 的強大來自「多模式」?呵呵,你也可以將「多模式」理解爲「反人性」(例如:同一鍵位在不同的模式下作用可能天差地別。詳見下表)。∴別再說什麼「「多模式」是 Vim 之髓」了😓。我認爲,Vim 的強大源於它既提供了粗粒度的操作,又提供了細粒度的操作。強大的工具其實莫不如是,比如 PS 。後面再詳細解釋。

no. 操作 思考模式🤔 可視模式🌈 編輯模式🖋
::no.:: i & a 進入「編輯模式🖋」插入 (insert / append) (或「思考模式🤔」下 <operator> 後)i<text-object>(inner / inside) & a<text-object>(arround / all)
::no.:: o 進入「編輯模式🖋」並插入新行 在高亮選區兩端來回切換
::no.:: c-r 重做 (redo) <c-r><register> 意爲插入寄存器 register 的內容

2. 怎麼對調 caps lockesc

你聽到的第一個建議,大概率是改鍵:將 <caps lock> 改爲 <esc> 。這件事在 MacOS 上原生自帶:

Windows 上也不難,下一個 PowerToys ,用裏面的 Keyboard Manager 就搞定。

最麻煩的是 Linux ,折騰了很久都沒有成功😓。

3.界面太醜怎麼辦🥴🤢🤮?

Vim 最爲人詬病的就是「記憶負擔太重」。比如:在不同的模式之間切換,完全憑腦力。再比如什麼 marks 啦、buffers 啦、tabs 啦……原廠的統統不顯示。

最簡單的改造方式是高亮顯示當前行 / 列:

set cursorline
set cursorcolumn

可以裝個叫 vim-airline 的美化插件😍,至少不同模式的顏色不同。但你得先裝個管理插件的插件 vim-plug

裝好以後在 ~/.vimrc 裏寫:

call plug#begin()
" ...
call plug#end()

現在你終於可以裝 vim-airline 了:

call plug#begin()

Plug 'vim-airline/vim-airline'
Plug 'vim-airline/vim-airline-themes'

call plug#end()

let g:airline_theme = 'simple'

airline 除了好看,一定要把 Smarter tab line 打開:

let g:airline#extensions#tabline#enabled = 1

現在,當你打開多個文件 vim *.md ,就可以用 :bprevious & :bnext 來回切換緩衝區 (buffers) 了。太蠢了是不🤢🤮?還是改個快捷鍵吧。這是從 Tim Pope 的 unimpaired.vim 那抄來的:

" 快速遍歷 Vim 列表
" ⚠️ 加 ! 後可以強制切換緩衝區。
nnoremap <silent> [b :bprevious!<CR>
nnoremap <silent> ]b :bnext!<CR>
nnoremap <silent> [B :bfirst!<CR>
nnoremap <silent> ]B :blast!<CR>

你最好再裝個 Powerline

但還是沒有解決 marks、buffers、tabs 的提示問題啊?那還得靠插件:

4. 怎麼在窗口間切換啊?

當你裝插件上癮以後,比如 NERDTreeUndo Tree,會遇到一個問題,怎麼切換到新開的窗口上呢?

原生命令是:

命令 效果
<C-w>w 在窗口間循環切換 🔁
<C-w>h 切換到左邊的窗口 ⬅️
<C-w>j 切換到下邊的窗口 ⬇️
<C-w>k 切換到上邊的窗口 ⬆️
<C-w>l 切換到下邊的窗口 ⬇️
<C-w>c 關閉活動窗口 ❌

但還是喜歡 @TheCW 的改法:

" ===
" === Window management
" ===
" Set <LEADER> as <SPACE>
let mapleader="\<space>"
" Use <space> + new arrow keys for moving the cursor around windows
map <LEADER>w <C-w>w
map <LEADER>k <C-w>k
map <LEADER>j <C-w>j
map <LEADER>h <C-w>h
map <LEADER>l <C-w>l

5. 最糾結的改鍵😵

排名 原生鍵位 想改成 改鍵原因 得失
::no.:: : ; 需要頻繁進入 Ex mode 。 ; & , 是一對操作。
::no.:: <Leader>[3] 用哪個?缺省是 \

6. 常用連招

從按鍵效率來說,當然是「單鍵」>「雙擊單鍵」>「易記的鍵組合」>……:

no. 快捷鍵 效果 初始模式 切入模式
::no.:: A (等效於 $a)在行尾添加文本。 normal mode🤔 insert mode🖋
::no.:: I (等效於 ^i)在行首添加文本。 normal mode🤔 insert mode🖋
::no.:: o (等效於 A<CR>)在當前行下方新起一行。 normal mode🤔 insert mode🖋
::no.:: O (等效於 ko)在當前行上方插入一行。 normal mode🤔 insert mode🖋
::no.:: C (等效於 c$ normal mode🤔 insert mode🖋
::no.:: s (等效於 cl)刪掉光標下的字符,然後進入插入模式。即,替換光標下的字符。 normal mode🤔 insert mode🖋
::no.:: S (等效於 ^c normal mode🤔 insert mode🖋
::no.:: dd 刪除當前行。 normal mode🤔 normal mode🤔
::no.:: >> 增加當前行縮進。 normal mode🤔 normal mode🤔
::no.:: << 減少當前行縮進。 normal mode🤔 normal mode🤔
::no.:: ea 在單詞結尾 (end) 添加文本。 normal mode🤔 insert mode🖋
::no.:: gf go to file. normal mode🤔 normal mode🤔
::no.:: xp 調換光標之後的兩個字符。 normal mode🤔 normal mode🤔
::no.:: gUU 將當前行整行轉換爲大寫。 normal mode🤔 normal mode🤔
::no.:: yyp 複製當前行,並粘貼在下方。 normal mode🤔 normal mode🤔
::no.:: daw delete a word. normal mode🤔 normal mode🤔
::no.:: vit visully select inside the tag.
::no.:: gv 重選上次的高亮選區。
::no.:: f,dt. 刪除句子的後半段。 normal mode🤔 normal mode🤔
::no.:: qaq 清空寄存器 a
::no.:: gUaw 將當前單詞轉換爲大寫。 normal mode🤔 normal mode🤔

7. 成對操作🎎

我覺得,學 Vim 完全可以比照學二外的方式——比較 & 聯繫。

no. 快捷鍵 效果 初始模式 切入模式
::no.:: a v.s. A 從後方 (append) 插入。 normal mode🤔 insert mode🖋
::no.:: i v.s. I 從前方插入 (insert) 。 normal mode🤔 insert mode🖋
::no.:: n v.s. N 下一處 (next) 。
::no.:: o v.s. O 插入新行。 normal mode🤔 insert mode🖋
::no.:: v v.s. V 進入 Visual mode 。
::no.:: f<char> / F<char> v.s. t<char> / T<char> 正向 / 反向行內查找 <char> ,區別在於包不包括 chartill 不包括)。 normal mode🤔 normal mode🤔
::no.:: ; v.s. , 繼續尋找與調轉方向搜尋前次搜尋的位置。 normal mode🤔 normal mode🤔
::no.:: /<pattern><CR> v.s. ?<pattern><CR> 文內查找。 normal mode🤔 comand mode🎛
::no.:: <C-a> v.s. <C-x> 對當前行其後最近的數字執行加 / 減操作。 normal mode🤔 normal mode🤔
::no.:: . v.s. u 重複與撤回。 normal mode🤔 normal mode🤔
::no.:: normal mode🤔下的命令 v.s. Ex 命令 ⚠️:normal mode🤔下的命令適合在本地操作,而 Ex 命令則可遠距離操作。比如: p v.s. :t (copy To) 。
::no.:: <c-]> v.s. :tag <keyword> 跳轉到 tag 到定義處。
::no.:: mm v.s. ``m` 標記位置📌 m / 跳轉到標記📌 m
::no.:: (in visual mode)o v.s. (in normal mode)% 在高亮選區兩端來回切換 v.s. 在括號(([{ v.s. }]))間跳轉 。
::no.:: <c-o> v.s. <c-i> 在跳轉列表 (:jumps) 中後退 / 前進(📢注意:低頭看一下,在 qwerty 鍵盤⌨️中,i o 是緊挨在一起的)。
重複類型 重複操作符 回退操作符
文本編輯重複 . u
行內查找重複 ; ,
全文查找重複 n N
文本替換重複 & u
宏重複 @<register> u

8. 插件🧩

no. 插件名 用途 原生解決方案
::no.:: NERDTree 文件管理 netrw,標配插件,across NETwork Read and Write files 的意思。
::no.:: coc-yank 可視複製
::no.:: vim-peekaboo 寄存器增強。(Peekaboo extends " and @ in normal mode and <CTRL-R> in insert mode so you can see the contents of the registers.)
::no.:: Undo Tree
::no.:: vim-devicons 美化插件:添加圖標
::no.:: vim-table-mode 美化插件:增強表格
::no.:: vim-signature 增強書籤📌 marks
::no.:: vim-gitgutter 在行號欄顯示修改狀態(必須置於 Git 看管之下)。 (changs list):changes & g;, g,
::no.:: vim-surround 增強 text object ,實現快速環繞編輯。請和 wildfire.vim 配合食用。
::no.:: wildfire.vim 按下 <enter> 就能智能選中最近的文本塊。請和 vim-surround 配合食用。
::no.:: vim-expand-region 快速擴大 / 縮小選中區域
::no.:: vim-commentary 註釋
::no.:: NERD Commenter 註釋
::no.:: coc.nvim 補全🤖️
::no.:: ctrlp.vim
::no.:: Tagbar tag 導航
::no.:: vim-markdown MarkDown 增強
::no.:: markdown-preview.nvim MarkDown 預覽

從 @theCW 那抄來的超有用的 MarkDown 速記技巧

動作 用途
,b 加粗
,d code
,c 代碼塊
,p 圖片🎨
,a 鏈接🔗
,f 跳轉到下一定位點 <++>
autocmd Filetype markdown inoremap ,f <Esc>/<++><CR>:nohlsearch<CR>c4l
autocmd Filetype markdown inoremap ,n ---<Enter><Enter>
autocmd Filetype markdown inoremap ,b **** <++><Esc>F*hi
autocmd Filetype markdown inoremap ,s ~~~~ <++><Esc>F~hi
autocmd Filetype markdown inoremap ,i ** <++><Esc>F*I
autocmd Filetype markdown inoremap ,d `` <++><Esc>F`i
autocmd Filetype markdown inoremap ,c ~~~<Enter><++><Enter>~~~<Enter><Enter><++><Esc>4kA
autocmd Filetype markdown inoremap ,h ====<Space><++><Esc>F=hi
autocmd Filetype markdown inoremap ,p [圖片上傳失敗...(image-cd8e3a-1663893306192)] <++><Esc>F[a
autocmd Filetype markdown inoremap ,a [](<++>) <++><Esc>F[a
autocmd Filetype markdown inoremap ,1 #<Space><Enter><++><Esc>kA
autocmd Filetype markdown inoremap ,2 ##<Space><Enter><++><Esc>kA
autocmd Filetype markdown inoremap ,3 ###<Space><Enter><++><Esc>kA
autocmd Filetype markdown inoremap ,4 ####<Space><Enter><++><Esc>kA
autocmd Filetype markdown inoremap ,l --------<Enter>

Ref📚


  1. 本應譯爲「插入模式🖋」,但我不喜歡這個翻譯。

  2. 借用 @Drew Neil 在《Practical Vim》裏的話就是:畫家在休息時不會把畫筆放在畫布上。對 Vim 而言也是這樣,normal 模式就是 Vim 的自然放鬆狀態。所以我更喜歡把 normal mode 稱之爲「思考模式🤔」。

  3. 用來自定義用戶自己的名字空間。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章