學 Vim 時希望早點知道的建議

Linux愛好者2018-08-11 10:05:22

(點擊上方公眾號,可快速關注)


英文:Petr Zemek

譯者:伯樂在線 - pine_pie 

鏈接:http://blog.jobbole.com/103343/


從 2009 年開始,我就一直把 Vim 當做我的主要(唯一)文本編輯器。在過去的這些年,我學到了很多好用的 Vim 技巧,它們令我感覺相見恨晚,因為它們極大地提高了我的文本編輯效率。在這篇博文中,我想與你們分享其中的最精華部分。


HJKL


Vim 新手通常會收到的第一條建議是“使用 h/j/k/l 鍵代替方向鍵!”在很長一段時間,我都忽略了這一條建議因為我覺得那很荒謬:我究竟為何非得那麼做?然而,有天我還是決定試一試,並且一試便一發不可收拾了。雖然我花了很多天時間才適應了這條建議,可是一旦上手,我才恍然大悟。h/j/k/l 幾個鍵直接處於本位列上,所以你的手不用(像在使用方向鍵時那樣)移動太遠的距離。這不僅節省了鍵盤操作時間,提高了效率,而且讓我的雙手得以更加放鬆。我相信這是治好我手腕疼的因素之一。另一個因素是,我在手下面墊了一塊腕墊。


如果你想學會使用 h/j/k/l 鍵代替方向鍵,那我建議你要麼關閉方向鍵要麼把它們重映射為其他更有用的指令。另一個不使用方向鍵的好處是,你將會適應更好的移動指令,如 f/F/t/T,w/W/b/B,0/^/$,或者搜索指令。使用這些指令,比起簡單地按下方向鍵或者 h/j/k/l鍵,你的輸入效率會更高。在 Vim 中,單鍵指令是一種反面模式。


相對行號


像很多用戶一樣,我也使用絕對行號,好吧,所有用戶都使用它。然而,有天我偶然發現了這篇文章,令我陷入思考:萬一相對行號更好用呢?我決定用用看。然後,就像 Ben 在這個視頻中所言,絕對行號在我的生活中就是一個謊言。Vim的正宗用法是啟用相對行號。


啟用相對行號之前,我建議把下列命令行添加到 .vimrc 文件中:


set number

set relativenumber


這兩個命令行一起,使 Vim 對當前行顯示絕對行號,而對其它行顯示相對行號。


接下來,我要說明相對行號的用處。很多 Vim 命令都有一個數字作為前綴。例如,要移動當前行以下的 10 行,可以用 10j。要移動當前行以上的 4 行,使用 4k。要對當前行及以下 2 行縮進,使用 >2j。明白了吧?有了相對行號,其它行(距離當前行)有多遠就一目瞭然了。如果你使用的是絕對行號,你要知道兩行之間相距多少行就必須做口算,把兩個行號(可能很大)相減。使用相對行號就可以減少這種數學運算。


同時,你仍然可以使用絕對行號。例如,你編譯了一個源文件,然後編譯器告知第 943 行有一個語法錯誤,這時你可以用 943G 或 :943<CR> 定位到這一行。


Vim 的一個非常好的特性是,你可以設置折行功能。很多用戶包括我會把 j/k 鍵重映射為 gj/gk,使得按下它們時,光標按虛擬行而不是按物理行移動。然而,這種重映射影響了前文提到的計數功能。為了彌補這一不足,基於這篇stackoverflow.com的博文,我們重新進行如下映射:


noremap <silent> <expr> j (v:count == 0 ? 'gj' : 'j')

noremap <silent> <expr> k (v:count == 0 ? 'gk' : 'k')


這樣之後,當遇到沒有行號的行時,gj/gk 命令會使光標按虛擬行移動,而當遇到有行號的行時,光標則按物理行移動。這與相對行號一起,堪稱絕配。


Vim and Tmux


在很長一段時間裡,我都是使用 GVim,不涉及 Vim 終端。因為它更炫,與窗口環境及集成度更高,等等。後來,我還是發現了 Tmux,它極大地改善了我的工作流程。簡言之,通過它,你可以在一個終端中打開多個獨立的會話(session),在每個會話中又可以打開多個窗口(window),而每個窗口又可以分為多個窗格(pane)。看看這個截屏感受一下吧。


Tmux 也讓我進退兩難:怎麼把它跟 GVim 配合使用呢?Tmux 是一款終端應用,而 GVim 則是一款獨立的 GUI 應用。幸運的是,通過設置,Vim 幾乎可以具備與 GVim 一樣的功能。最好用的插件是 CSApprox。它可以令 GVim 專屬的配色方案輕鬆地應用於 Vim 終端上。還有其他很多設置幫助我轉移到 Vim 終端上工作,參考我的 .vimrc 文件。


Tmux+Vim 組合的最大優勢是,它可以令你在一個終端就可以完成幾乎所有的開發工作。例如,你可以通過 ssh 遠程登錄到一個服務器並在那裡做開發,這樣你也可以在不同地方甚至不同電腦上無縫對接之前的工作。另一個好處是,服務器的運行速度通常要比筆記本或臺式電腦快。你甚至可能在一臺擁有海量核芯與內存的服務器上做開發,這取決於你公司的預算。這樣的體驗簡直會讓人流連忘返。


如果你從未用過 Tmux,那我建議你至少試它一試。它真是一個很棒的工具。萬事開頭難,我在這裡詳述了 Tmux 的配置過程,給你做個指南。仔細看看,或許你能從中學到一些技巧幫你調整並改善工作流程。例如,在該文中我介紹了一種在 Vim 與 Tmux 之間實現無縫導航的方法。


操作與行動


Vim 的一個獨特之處是它能讓你可以通過一門語言與之對話。例如,Vim 命令中有類似動詞的 d(刪除)或 y(複製),類似名詞的 b(括號)或 s(句子),以及類似形容詞的 i(內部的)或 a(全部的)。你可以把它們自由組合,因此,dib 代表刪除括號內的所有文本,yap 代表複製當前的段落。在你學會這門簡單語言之後,你不用再思考刪除一個段落需要做什麼,只需簡單地輸入 dap。很多人覺得 Vim 很難掌握,就是因為他們不習慣用這種方式來看待 Vim。


更難能可貴之處是 Vim 語言是可擴展的。事實上,用戶可以在 Vim 語法的基礎上創建自己的“動詞”和“名詞”(Vim 語法中的操作和行動/文本對象)。下面介紹一些我日常必備的好用插件。


操作


  • tcomment-vim——執行代碼註釋操作:gc。例如,為一個段落註釋,可以用 gcap(go comment  a paragraph);為當前行及以下 5 行註釋,可以用 gc5j(感謝有相對行號!)。

  • vim-sort-motion——執行排序操作:gs。例如,在 Python 中,對光標所在處的 imports 進行排序,可以用 gsip(go sort  inside paragraph)。

  • ReplaceWithRegister——執行替換操作:gr。執行替換文本操作不會覆蓋寄存器的內容。例如,要用默認的寄存器替換當前單詞,可以用 griw(go replace inner word )。gr 操作還可以與點號命令配合(.,重複上一次動作),這使它更加高效。它是我最喜歡的操作之一。

行動/文本對象


  • targets.vim——添加許多有用的文本對象。例如,daa 用於刪除一個函數調用的一個參數(deletes an argument of a function call),ci$ 用於改變美元符號之間的文本(在 LaTeX 中非常有用)。該插件的另一個特點是,即使光標未落在所欲編輯的文本對象之處,用戶也可以通過該插件使用該文本對象。例如,用 di”(delete inside quotes)可以刪除距離光標最近的雙引號內的內容。

  • vim-indent-object——對當前的縮進執行操作。例如,將當前代碼塊向左移動,可以用 <ii(left-shift inside indent)。這對 Python 來說很有用,因為它用空格標識代碼塊,而不是大括號。

  • vim-surround——對周圍環境操作。例如,cs”‘ 表示用單引號替換周圍的雙引號,而 dsb 則表示刪除周圍的括號。

當然,你也可以把在以上插件中提及的操作與行動結合起來使用。例如,在一個 Python 列表中每一項都在單獨成行,為了對列表排序,可以使用 gsii(go sort inside indent)。


有些簡單的文本對象甚至可以不借助插件來定義。例如,對一整個文件進行操作,可以把下列這行代碼加入 .vimrc:


onoremap af :<C-u>normal! ggVG<CR>


於是,要複製整個文件的內容(更準確地講,整個緩衝器),可以使用 yaf(yank a file)。


模糊查找


在 Vim 中打開一個文件,可以用 edit 或者 tabnew 命令,分別在當前緩衝器或新標籤頁中打開該文件。這種方式的一個缺點是,當你打開的是一個內嵌有很多目錄及文件的大工程時,就會非常慢。例如,要編輯文件 frontend/scripts/js/view/viewer.js,你就得敲入整個路徑。嗯,必須要有更好的方法……


幸運的是,確實有!通過使用模糊查找器,如 Command-T。現在只需要簡單地啟用查找器(輸入 ,t),敲入 fsviewer(f 與 s 是文件路徑的一部分),就可以在當前窗口或者新標籤頁中瞬間打開上述文件。一旦你知道自己工程的路徑結構或文件名,使用模糊查找器可以極大地提高文件的打開速度。


檢索


我們經常要列出所有包含給定短語或單詞(如一個函數的名稱)的文件。在我剛開始使用 Vim 時,我會轉到終端然後輸入 gvim grep –r FUNC | cut –d: -f1 從而在 GVim 中打開找到的文件。然而,為何不把這個簡單的任務交給 Vim 來做呢?


你既可以用 Vim 內置的 grep 命令,也可以用一款更高級的插件,如 vim-grepper,它能讓用戶選擇一種檢索工具(grep,git grep 或 ag)並選擇怎樣顯示結果。例如,用戶可以映射 ,/ 來在一個工程中檢索所有包含某個單詞的文件,或者用 ,∗ 在整個項目範圍內檢索包含光標所在單詞的文件。在檢索過程結束後,會彈出一個包含目標文件的窗口,Vim 用戶可以直接打開這些文件。


作為外部編輯器的 Vim


如果你在使用一款文本編輯器,最重要的是儘可能經常使用它。畢竟,當你已經瞭解 Vim 了,為何還要去學另一款編輯器呢?例如網頁上的 textarea forms?如果你在工作中處處使用 Vim,甚至還可以把它的優點發揮在之前想像不到的地方。


例如,在火狐瀏覽器中,有一個插件叫 It’s All Text!,該插件能讓用戶在 Vim 中編輯 textarea 元素。這為用戶使用自己最愛的的編輯器編輯維基網頁,寫博文,提交 bug 報告等活動提供了便利。對 Vim 用戶來說,這意味著他們可以盡情享受其語法高亮、拼寫檢查、字典補全、代碼片段以及其他功能。


又如,在雷鳥郵件客戶端中也有一個 It’s All Text! 插件。比起內置的編輯器,使用該插件可以讓你寫郵件寫得更快、更舒適。


很多終端應用也支持把 Vim 作為外部編輯器使用。例如,你可以把 Midnight Commander設置為從 Vim 打開文件。Vim 的另一個可貴之處表現在用版本控制系統,如 Git,寫提交說明的時候。你厭倦了排印錯誤嗎?那就在 Vim 中設定拼寫檢查。你想通過使用 Ctrl+n 讓出現在 diff 文件中的單詞能自動補全嗎?那就與 -verbose 參數一起提交吧。它可以把整個 diff 文件複製到 Vim 中,因此你就可以使用字典補全功能,就像函數名那樣。老闆再也不用擔心你寫提交說明了。


最後,我要提的是另一款火狐瀏覽器插件,Vimperator。它能讓用戶在瀏覽網頁的時候也可以運用 Vim 的原則,使瀏覽器用起來像 Vim 。例如,不需要動鼠標,你就可以快速地在網頁上打開連接、複製文本或者製作書籤稍後再返回。Vimperator 甚至能讓你在一個類似 .vimrc 的文件中配置火狐瀏覽器。這個是我的版本。


運行外部命令


假設你正在寫 Pyhton 代碼,並且你要在當前文件中執行單元測試。或者,假設你正在寫 Latex 文檔,為了查看結果你得進行編譯。其中一個辦法是打開一個終端,然後執行測試或進行編譯。然而,這並不是一種高效的辦法,因為它造成你工作流程的中斷。


一種較好的方式是利用 Vim 能執行外部命令的特性。例如,利用下列的自動命令,你只需要簡單的按下 F9 就可以為你的 Python 代碼保存並執行當前編輯好的單元測試:


au FileType python nnoremap <buffer> <F9> :wa<CR>:!clear; nosetests %<CR>


在 Tmux 中運行 Vim 的另一個好處就是,使在 Tmux 窗格或窗口執行外部命令成為可能。例如,你可以將當前的 Tmux 窗口分為兩個窗格,其中一個用於編輯文件,另一個用於執行測試,而不需要在它們之間切換。為了讓你體驗一下我的工作流程,下面我做個示範。我工作中使用了雙顯示器,並做了相應設置。對於一個工程,我打開兩個終端,分別在其中打開一個 Tmux 控制檯,然後令每個顯示器中分別顯示一個終端。這時,我可以在第一個 Tmux 控制檯上寫代碼,如果我想執行測試,生成文檔,或用 lint 類似的工具檢查代碼,我只需通過 Vim 發送一條命令到第二個 Tmux 控制檯,測試就會在第二個顯示器中進行。這樣,我就可以在第一個顯示器的分割窗口中寫代碼和測試文檔,在第二個顯示器中運行 git 命令、執行測試等。我還對 Fluxbox進行設置,從而可以用 Ctrl+Alt+h/l 在兩個顯示器之間切換。這是我的配置文件。此外,還有更精彩的部分哦!那就是以上介紹的工作流程甚至適用於通過 SSH 登錄到遠程服務器運行 Tmux 的情況。


配置選項與映射


Vim 是高度可擴展的。你可以根據個人喜好對它進行配置,可以為你經常使用的動作添加映射和命令。在過去的時光中,我逐漸完善了我自己的  .vimrc 文件,其中包含了很多有用的設置、映射。以下是其中的一部分,不過,我建議你們看完我的整個 .vimrc 文件。


" Quickly select the text that was just pasted. This allows you to, e.g.,

" indent it after pasting.

noremap gV `[v`]


" Stay in visual mode when indenting. You will never have to run gv after

" performing an indentation.

vnoremap < <gv

vnoremap > >gv


" Make Y yank everything from the cursor to the end of the line. This makes Y

" act more like C or D because by default, Y yanks the current line (i.e. the

" same as yy).

noremap Y y$


" Make Ctrl-e jump to the end of the current line in the insert mode. This is

" handy when you are in the middle of a line and would like to go to its end

" without switching to the normal mode.

inoremap <C-e> <C-o>$


" Allows you to easily replace the current word and all its occurrences.

nnoremap <Leader>rc :%s/<<C-r><C-w>>/

vnoremap <Leader>rc y:%s/<C-r>"/


" Allows you to easily change the current word and all occurrences to something

" else. The difference between this and the previous mapping is that the mapping

" below pre-fills the current word for you to change.

nnoremap <Leader>cc :%s/<<C-r><C-w>>/<C-r><C-w>

vnoremap <Leader>cc y:%s/<C-r>"/<C-r>"


" Replace tabs with four spaces. Make sure that there is a tab character between

" the first pair of slashes when you copy this mapping into your .vimrc!

nnoremap <Leader>rts :%s/ /    /g<CR>


" Remove ANSI color escape codes for the edited file. This is handy when

" piping colored text into Vim.

nnoremap <Leader>rac :%s/<C-v><Esc>[(d{1,2}(;d{1,2}){0,2})?[m|K]//g<CR>


參數摺疊


最後這點也很重要,我要提一下 vim-argwrap 插件。它可以讓你快速摺疊或展開函數參數(表)、列表或字典。例如,你可以用它把下列代碼


decompiler = Decompiler(api_url=args.api_url, api_key=args.api_key)


轉換為


decompiler = Decompiler(

    api_url=args.api_url,

    api_key=args.api_key

)


反之亦然,僅需要作一個簡單映射。


【今日微信公號推薦↓】

更多推薦請看值得關注的技術和設計公眾號


其中推薦了包括技術設計極客 和 IT相親相關的熱門公眾號。技術涵蓋:Python、Web前端、Java、安卓、iOS、PHP、C/C++、.NET、Linux、數據庫、運維、大數據、算法、IT職場等。點擊《值得關注的技術和設計公眾號》,發現精彩!

閱讀原文