<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Vim 從入門到精通【轉(zhuǎn)載】

      Vim 從入門到精通

      聲明:該文章轉(zhuǎn)載自github - wsdjeg的項(xiàng)目(見如下鏈接),此處僅供查閱方便:https://github.com/wsdjeg/vim-galore-zh_cn#vim-%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E7%B2%BE%E9%80%9A

      簡介

      什么是 Vim?

      Vim 是一個歷史悠久的文本編輯器,可以追溯到
      qed
      Bram Moolenaar
      1991 年發(fā)布初始版本。

      Linux、Mac 用戶,可以使用包管理器安裝 Vim,對于 Windows 用戶,可以從
      我的網(wǎng)盤 下載。
      該版本可輕易添加 python 、python3lua 等支持,只需要安裝 python、lua
      即可。

      項(xiàng)目在 Github 上開發(fā),項(xiàng)目討論請訂閱
      vim_dev 郵件列表。

      通過閱讀 Why, oh WHY, do those #?@! nutheads use vi?
      來對 Vim 進(jìn)行大致的了解。

      Vim 哲學(xué)

      Vim 采用模式編輯的理念,即它提供了多種模式,按鍵在不同的模式下作用不同。
      你可以在普通模式 下瀏覽文件,在插入模式下插入文本,
      可視模式下選擇行,在命令模式下執(zhí)行命令等等。起初這聽起來可能很復(fù)雜,
      但是這有一個很大的優(yōu)點(diǎn):不需要通過同時按住多個鍵來完成操作,
      大多數(shù)時候你只需要依次按下這些按鍵即可。越常用的操作,所需要的按鍵數(shù)量越少。

      和模式編輯緊密相連的概念是 操作符動作。操作符 指的是開始某個行為,
      例如:修改、刪除或者選擇文本,之后你要用一個 動作 來指定需要操作的文本區(qū)域。
      比如,要改變括號內(nèi)的文本,需要執(zhí)行 ci( (讀做 change inner parentheses);
      刪除整個段落的內(nèi)容,需要執(zhí)行 dap (讀做:delete around paragraph)。

      如果你能看見 Vim 老司機(jī)操作,你會發(fā)現(xiàn)他們使用 Vim 腳本語言就如同鋼琴師彈鋼琴一樣。
      復(fù)雜的操作只需要幾個按鍵就能完成。他們甚至不用刻意去想,因?yàn)檫@已經(jīng)成為肌肉記憶了。
      這減少認(rèn)識負(fù)荷并幫助人們專注于實(shí)際任務(wù)。

      入門

      Vim 自帶一個交互式的教程,內(nèi)含你需要了解的最基礎(chǔ)的信息,你可以通過終端運(yùn)行以下命令打開教程:

      $ vimtutor
      

      不要因?yàn)檫@個看上去很無聊而跳過,按照此教程多練習(xí)。你以前用的 IDE 或者其他編輯器很少是有“模式”概念的,因此一開始你會很難適應(yīng)模式切換。但是你 Vim 使用的越多,肌肉記憶 將越容易形成。

      Vim 基于一個 vi 克隆,叫做 Stevie,支持兩種運(yùn)行模式:"compatible" 和 "nocompatible"。在兼容模式下運(yùn)行 Vim 意味著使用 vi 的默認(rèn)設(shè)置,而不是 Vim 的默認(rèn)設(shè)置。除非你新建一個用戶的 vimrc 或者使用 vim -N 命令啟動 Vim,否則就是在兼容模式下運(yùn)行 Vim!請大家不要在兼容模式下運(yùn)行 Vim。

      下一步

      1. 創(chuàng)建你自己的 vimrc。
      2. 在第一周準(zhǔn)備備忘錄。
      3. 通讀基礎(chǔ)章節(jié)了解 Vim 還有哪些功能。
      4. 按需學(xué)習(xí)!Vim 是學(xué)不完的。如果你遇到了問題,先上網(wǎng)尋找解決方案,你的問題可能已經(jīng)被解決了。Vim 擁有大量的參考文檔,知道如何利用這些參考文檔很有必要:獲取離線幫助。
      5. 瀏覽附加資源

      最后一個建議:使用插件之前,請先掌握 Vim 的基本操作。很多插件都只是對 Vim 自帶功能的封裝。

      返回主目錄 ??

      精簡的 vimrc

      Vim 啟動是會按照一定的優(yōu)先順序來搜索配置文件,這個順序,可以通過 :version 命令查看。下面分 Windows 系統(tǒng),
      和 *niux 系統(tǒng)分別來說明 Vim 是如何載入配置文件的。

      Windows 系統(tǒng)

         system vimrc file: "$VIM\vimrc"
           user vimrc file: "$HOME\_vimrc"
       2nd user vimrc file: "$HOME\vimfiles\vimrc"
       3rd user vimrc file: "$VIM\_vimrc"
            user exrc file: "$HOME\_exrc"
        2nd user exrc file: "$VIM\_exrc"
        system gvimrc file: "$VIM\gvimrc"
          user gvimrc file: "$HOME\_gvimrc"
      2nd user gvimrc file: "$HOME\vimfiles\gvimrc"
      3rd user gvimrc file: "$VIM\_gvimrc"
             defaults file: "$VIMRUNTIME\defaults.vim"
          system menu file: "$VIMRUNTIME\menu.vim"
      

      我們只看上面這一段,Vim 會優(yōu)先讀取 user vimrc file: $HOME\_vimrc, 當(dāng)這一文件不存在是,
      Vim 再去尋找 2nd user vimrc file: $HOME\vimfiles\vimrc; 倘若這個文件還是不存在,那么 Vim
      會去繼續(xù)尋找 3rd user vimrc file: $VIM\_vimrc。 了解以上順序后,就不會再因?yàn)?Vim
      總是不讀取配置文件而感到煩惱了。

      Linux 或者 Mac OS

      同 Windows 系統(tǒng)類似,也可以使用 :version 命令查看 vim 載入配置的優(yōu)先順序。

           系統(tǒng) vimrc 文件: "/etc/vimrc"
           用戶 vimrc 文件: "$HOME/.vimrc"
       第二用戶 vimrc 文件: "~/.vim/vimrc"
            用戶 exrc 文件: "$HOME/.exrc"
             defaults file: "$VIMRUNTIME/defaults.vim"
               $VIM 預(yù)設(shè)值: "/etc"
        $VIMRUNTIME 預(yù)設(shè)值: "/usr/share/vim/vim81"
      

      建議:大多數(shù)插件作者都維護(hù)不止一個插件并且將他們的 vimrc 放在 Github 上展示(通常放在叫做 "vim-config" 或者 "dotfiles" 的倉庫中),所以當(dāng)你發(fā)現(xiàn)你喜歡的插件時,去插件維護(hù)者的 Github 主頁看看有沒有這樣的倉庫。

      返回主目錄 ??

      我正在使用什么樣的 Vim

      使用 :version 命令將向你展示當(dāng)前正在運(yùn)行的 Vim 的所有相關(guān)信息,包括它是如何編譯的。

      第一行告訴你這個二進(jìn)制文件的編譯時間和版本號,比如:7.4。接下來的一行呈現(xiàn) Included patches: 1-1051,這是補(bǔ)丁版本包。因此你 Vim 確切的版本號是 7.4.1051。

      另一行顯示著一些像 Tiny version without GUI 或者 Huge version with GUI 的信息。很顯然這些信息告訴你當(dāng)前的 Vim 是否支持 GUI,例如:從終端中運(yùn)行 gvim 或者從終端模擬器中的 Vim 內(nèi)運(yùn)行 :gui 命令。另一個重要的信息是 TinyHuge。Vim 的特性集區(qū)分被叫做 tiny,smallnormalbig and huge,所有的都實(shí)現(xiàn)不同的功能子集。

      :version 主要的輸出內(nèi)容是特性列表。+clipboard 意味這剪貼板功能被編譯支持了,-clipboard 意味著剪貼板特性沒有被編譯支持。

      一些功能特性需要編譯支持才能正常工作。例如:為了讓 :prof 工作,你需要使用 huge 模式編譯的 Vim,因?yàn)槟欠N模式啟用了 +profile 特性。

      如果你的輸出情況并不是那樣,并且你是從包管理器安裝 Vim 的,確保你安裝了 vim-xvim-x11vim-gtk,vim-gnome 這些包或者相似的,因?yàn)檫@些包通常都是 huge 模式編譯的。

      你也可以運(yùn)行下面這段代碼來測試 Vim 版本以及功能支持:

      " Do something if running at least Vim 7.4.42 with +profile enabled.
      if (v:version > 704 || v:version == 704 && has('patch42')) && has('profile')
        " do stuff
      endif
      

      相關(guān)幫助:

      :h :version
      :h feature-list
      :h +feature-list
      :h has-patch
      

      返回主目錄 ??

      備忘錄

      為了避免版權(quán)問題,我只貼出鏈接:

      或者在 Vim 中快速打開備忘錄:vim-cheat40

      返回主目錄 ??

      基礎(chǔ)

      緩沖區(qū),窗口,標(biāo)簽

      Vim 是一個文本編輯器。每次文本都是作為緩沖區(qū)的一部分顯示的。每一份文件都是在他們自己獨(dú)有的緩沖區(qū)打開的,插件顯示的內(nèi)容也在它們自己的緩沖區(qū)中。

      緩沖區(qū)有很多屬性,比如這個緩沖區(qū)的內(nèi)容是否可以修改,或者這個緩沖區(qū)是否和文件相關(guān)聯(lián),是否需要同步保存到磁盤上。

      窗口 是緩沖區(qū)上一層的視窗。如果你想同時查看幾個文件或者查看同一文件的不同位置,那樣你會需要窗口。

      請別把他們叫做 分屏 。你可以把一個窗口分割成兩個,但是這并沒有讓這兩個窗口完全 分離 。

      窗口可以水平或者豎直分割并且現(xiàn)有窗口的高度和寬度都是可以被調(diào)節(jié)設(shè)置的,因此,如果你需要多種窗口布局,請考慮使用標(biāo)簽。

      標(biāo)簽頁 (標(biāo)簽)是窗口的集合。因此當(dāng)你想使用多種窗口布局時候請使用標(biāo)簽。

      簡單的說,如果你啟動 Vim 的時候沒有附帶任何參數(shù),你會得到一個包含著一個呈現(xiàn)一個緩沖區(qū)的窗口的標(biāo)簽。

      順帶提一下,緩沖區(qū)列表是全局可見的,你可以在任何標(biāo)簽中訪問任何一個緩沖區(qū)。

      返回主目錄 ??

      已激活、已載入、已列出、已命名的緩沖區(qū)

      用類似 vim file1 的命令啟動 Vim 。這個文件的內(nèi)容將會被加載到緩沖區(qū)中,你現(xiàn)在有一個已載入的緩沖區(qū)。如果你在 Vim 中保存這個文件,緩沖區(qū)內(nèi)容將會被同步到磁盤上(寫回文件中)。

      由于這個緩沖區(qū)也在一個窗口上顯示,所以他也是一個已激活的緩沖區(qū)。如果你現(xiàn)在通過 :e file2 命令加載另一個文件,file1 將會變成一個隱藏的緩沖區(qū),并且 file2 變成已激活緩沖區(qū)。

      使用 :ls 我們能夠列出所有可以列出的緩沖區(qū)。插件緩沖區(qū)和幫助緩沖區(qū)通常被標(biāo)記為不可以列出的緩沖區(qū),因?yàn)槟遣⒉皇悄憬?jīng)常需要在編輯器中編輯的常規(guī)文件。通過 :ls! 命令可以顯示被放入緩沖區(qū)列表的和未被放入列表的緩沖區(qū)。

      未命名的緩沖區(qū)是一種沒有關(guān)聯(lián)特定文件的緩沖區(qū),這種緩沖區(qū)經(jīng)常被插件使用。比如 :enew 將會創(chuàng)建一個無名臨時緩沖區(qū)。添加一些文本然后使用 :w /tmp/foo 將他寫入到磁盤,這樣這個緩沖區(qū)就會變成一個已命名的緩沖區(qū)。

      返回主目錄 ??

      參數(shù)列表

      全局緩沖區(qū)列表是 Vim 的特性。在這之前的 vi 中,僅僅只有參數(shù)列表,參數(shù)列表在 Vim 中依舊可以使用。

      每一個通過 shell 命令傳遞給 Vim 的文件名都被記錄在一個參數(shù)列表中??梢杂卸鄠€參數(shù)列表:默認(rèn)情況下所有參數(shù)都被放在全局參數(shù)列表下,但是你可以使用 :arglocal 命令去創(chuàng)建一個新的本地窗口的參數(shù)列表。

      使用 :args 命令可以列出當(dāng)前參數(shù)。使用 :next,:previous:first,:last 命令可以在切換在參數(shù)列表中的文件。通過使用 :argadd,:argdelete 或者 :args 等命令加上一個文件列表可以改變參數(shù)列表。

      偏愛緩沖區(qū)列表還是參數(shù)列表完全是個人選擇,我的印象中大多數(shù)人都是使用緩沖區(qū)列表的。

      然而參數(shù)列表在有些情況下被大量使用:批處理
      使用 :argdo! 一個簡單的重構(gòu)例子:

      :args **/*.[ch]
      :argdo %s/foo/bar/ge | update
      

      這條命令將替換掉當(dāng)前目錄下以及當(dāng)前目錄的子目錄中所有的 C 源文件和頭文件中的“foo”,并用“bar”代替。

      相關(guān)幫助::h argument-list

      返回主目錄 ??

      按鍵映射

      使用 :map 命令家族你可以定義屬于你自己的快捷鍵。該家族的每一個命令都限定在特定的模式下。從技術(shù)上來說 Vim 自帶高達(dá) 12 中模式,其中 6 種可以被映射。另外一些命令作用于多種模式:

      遞歸 非遞歸 模式
      :map :noremap normal, visual, operator-pending
      :nmap :nnoremap normal
      :xmap :xnoremap visual
      :cmap :cnoremap command-line
      :omap :onoremap operator-pending
      :imap :inoremap insert

      例如:這個自定義的快捷鍵只在普通模式下工作。

      :nmap <space> :echo "foo"<cr>
      

      使用 :nunmap <space> 可以取消這個映射。

      對于更少數(shù),不常見的模式(或者他們的組合),查看 :h map-modes。

      到現(xiàn)在為止還好,對新手而言有一個問題會困擾他們::nmap遞歸執(zhí)行的!結(jié)果是,右邊執(zhí)行可能的映射。

      你自定義了一個簡單的映射去輸出“Foo”:

      :nmap b :echo "Foo"<cr>
      

      但是如果你想要映射 b (回退一個單詞)的默認(rèn)功能到一個鍵上呢?

      :nmap a b
      

      如果你敲擊a,我們期望著光標(biāo)回退到上一個單詞,但是實(shí)際情況是“Foo”被輸出到命令行里!因?yàn)樵谟疫叄?code>b 已經(jīng)被映射到別的行為上了,換句話說就是 :echo "Foo"<cr>

      解決此問題的正確方法是使用一種 非遞歸 的映射代替:

      :nnoremap a b
      

      經(jīng)驗(yàn)法則:除遞歸映射是必須的,否則總是使用非遞歸映射。

      通過不給一個右值來檢查你的映射。比如:nmap 顯示所以普通模式下的映射,:nmap <leader> 顯示所有以 <leader> 鍵開頭的普通模式下的映射。

      如果你想禁止用標(biāo)準(zhǔn)映射,把他們映射到特殊字符 <nop> 上,例如::noremap <left> <nop>

      相關(guān)幫助:

      :h key-notation
      :h mapping
      :h 05.3
      

      返回主目錄 ??

      映射前置鍵

      映射前置鍵(Leader 鍵)本身就是一個按鍵映射,默認(rèn)為 \。我們可以通過在 map 中調(diào)用 <leader> 來為把它添加到其他按鍵映射中。

      nnoremap <leader>h :helpgrep<space>
      

      這樣,我們只需要先按 \ 然后按 h 就可以激活這個映射 :helpgrep<space>。如果你想通過先按 空格 鍵來觸發(fā),只需要這樣做:

      let g:mapleader = ' '
      nnoremap <leader>h :helpgrep<space>
      

      此處建議使用 g:mapleader,因?yàn)樵?Vim 腳本中,函數(shù)外的變量缺省的作用域是全局變量,但是在函數(shù)內(nèi)缺省作用域是局部變量,而設(shè)置快捷鍵前綴需要修改全局變量 g:mapleader 的值。

      另外,還有一個叫 <localleader> 的,可以把它理解為局部環(huán)境中的 <leader>,默認(rèn)值依然為 \。當(dāng)我們需要只對某一個條件下(比如,特定文件類型的插件)的緩沖區(qū)設(shè)置特別的 <leader> 鍵,那么我們就可以通過修改當(dāng)前環(huán)境下的 <localleader> 來實(shí)現(xiàn)。

      注意:如果你打算設(shè)置 Leader 鍵,請確保在設(shè)置按鍵映射之前,先設(shè)置好 Leader 鍵。如果你先設(shè)置了含有 Leader 鍵的映射,然后又修改了 Leader 鍵,那么之前映射內(nèi)的 Leader 鍵是不會因此而改變的。你可以通過執(zhí)行 :nmap <leader> 來查看普通模式中已綁定給 Leader 鍵的所有映射。

      請參閱 :h mapleader:h maploacalleader 來獲取更多幫助。

      返回主目錄 ??

      寄存器

      寄存器就是存儲文本的地方。我們常用的「復(fù)制」操作就是把文本存儲到寄存器,「 粘貼」 操作就是把文本從寄存器中讀出來。順便,在 Vim 中復(fù)制的快捷鍵是 y,粘貼的快捷鍵是 p

      Vim 為我們提供了如下的寄存器:

      類型 標(biāo)識 讀寫者 是否為只讀 包含的字符來源
      Unnamed " vim 最近一次的復(fù)制或刪除操作 (d, c, s, x, y)
      Numbered 09 vim 寄存器 0: 最近一次復(fù)制。寄存器 1: 最近一次刪除。寄存器 2: 倒數(shù)第二次刪除,以此類推。對于寄存器 19,他們其實(shí)是只讀的最多包含 9 個元素的隊(duì)列。這里的隊(duì)列即為數(shù)據(jù)類型 queue
      Small delete - vim 最近一次行內(nèi)刪除
      Named az, AZ 用戶 如果你通過復(fù)制操作存儲文本至寄存器 a,那么 a 中的文本就會被完全覆蓋。如果你存儲至 A,那么會將文本添加給寄存器 a,不會覆蓋之前已有的文本
      Read-only :.% vim :: 最近一次使用的命令,.: 最近一次添加的文本,%: 當(dāng)前的文件名
      Alternate buffer # vim 大部分情況下,這個寄存器是當(dāng)前窗口中,上一次訪問的緩沖區(qū)。請參閱 :h alternate-file 來獲取更多幫助
      Expression = 用戶 復(fù)制 VimL 代碼時,這個寄存器用于存儲代碼片段的執(zhí)行結(jié)果。比如,在插入模式下復(fù)制 <c-r>=5+5<cr>,那么這個寄存器就會存入 10
      Selection +* vim *+剪貼板 寄存器
      Drop ~ vim 最后一次拖拽添加至 Vim 的文本(需要 "+dnd" 支持,暫時只支持 GTK GUI。請參閱 :help dnd:help quote~
      Black hole _ vim 一般稱為黑洞寄存器。對于當(dāng)前操作,如果你不希望在其他寄存器中保留文本,那就在命令前加上 _。比如,"_dd 命令不會將文本放到寄存器 "1、+*
      Last search pattern / vim 最近一次通過 /、?:global 等命令調(diào)用的匹配條件

      只要不是只讀的寄存器,用戶都有權(quán)限修改它的內(nèi)容,比如:

      :let @/ = 'register'
      

      這樣,我們按 n 的時候就會跳轉(zhuǎn)到單詞"register" 出現(xiàn)的地方。

      有些時候,你的操作可能已經(jīng)修改了寄存器,而你沒有察覺到。請參閱 :h registers 獲取更多幫助。

      上面提到過,復(fù)制的命令是 y,粘貼的命令是 p 或者 P。但請注意,Vim 會區(qū)分「字符選取」與「行選取」。請參閱 :h linewise 獲取更多幫助。

      行選取
      命令 yyY 都是復(fù)制當(dāng)前行。這時移動光標(biāo)至其他位置,按下 p 就可以在光標(biāo)下方粘貼復(fù)制的行,按下 P 就可以在光標(biāo)上方粘貼至復(fù)制的行。

      字符選取
      命令 0yw 可以復(fù)制第一個單詞。這時移動光標(biāo)至其他位置,按下 p 就可以在當(dāng)前行、光標(biāo)后的位置粘貼單詞,按下 P 就可以在當(dāng)前行、光標(biāo)前的位置粘貼單詞。

      將文本存到指定的寄存器中
      命令 "aY 可以將當(dāng)前行復(fù)制,并存儲到寄存器 a 中。這時移動光標(biāo)至其他位置,通過命令 "AY 就可以把這一行的內(nèi)容擴(kuò)展到寄存器 a 中,而之前存儲的內(nèi)容也不會丟失。

      為了便于理解和記憶,建議大家現(xiàn)在就試一試上面提到的這些操作。操作過程中,你可以隨時通過 :reg 來查看寄存器的變化。

      有趣的是
      在 Vim 中,y 是復(fù)制命令,源于單詞 "yanking"。而在 Emacs 中,"yanking" 代表的是粘貼(或者說,重新插入剛才刪掉的內(nèi)容),而并不是復(fù)制。

      返回主目錄 ??

      范圍

      范圍 (Ranges) 其實(shí)很好理解,但很多 Vim 用戶的理解不到位。

      • 很多命令都可以加一個數(shù)字,用于指明操作范圍
      • 范圍可以是一個行號,用于指定某一行
      • 范圍也可以是一對通過 ,; 分割的行號
      • 大部分命令,默認(rèn)只作用于當(dāng)前行
      • 只有 :write:global 是默認(rèn)作用于所有行的

      范圍的使用是十分直觀的。以下為一些例子(其中,:d:delete 的縮寫):

      命令 操作的行
      :d 當(dāng)前行
      :.d 當(dāng)前行
      :1d 第一行
      :$d 最后一行
      :1,$d 所有行
      :%d 所有行(這是 `1,
      ------------------- -----------------------------------------------------------------
      :d 當(dāng)前行
      :.d 當(dāng)前行
      :1d 第一行
      的語法糖)
      :.,5d 當(dāng)前行至第 5 行
      :,5d 同樣是當(dāng)前行至第 5 行
      :,+3d 當(dāng)前行及接下來的 3 行
      :1,+3d 第一行至當(dāng)前行再加 3 行
      :,-3d 當(dāng)前行及向上的 3 行(Vim 會彈出提示信息,因?yàn)檫@是一個保留的范圍)
      :3,'xdelete 第三行至標(biāo)注 為 x 的那一行
      :/^foo/,$delete 當(dāng)前行以下,以字符 "foo" 開頭的那一行至結(jié)尾
      :/^foo/+1,$delete 當(dāng)前行以下,以字符 "foo" 開頭的那一行的下一行至結(jié)尾

      需要注意的是,; 也可以用于表示范圍。區(qū)別在于,a,bb 是以當(dāng)前行作為參考的。而 a;bb 是以 a 行作為參考的。舉個例子,現(xiàn)在你的光標(biāo)在第 5 行。這時 :1,+1d 會刪除第 1 行至第 6 行,而 :1;+1d 會刪除第 1 行和第 2 行。

      如果你想設(shè)置多個尋找條件,只需要在條件前加上 /,比如:

      :/foo//bar//quux/d
      

      這就會刪除當(dāng)前行之后的某一行。定位方式是,先在當(dāng)前行之后尋找第一個包含 "foo" 字符的那一行,然后在找到的這一行之后尋找第一個包含 "bar" 字符的那一行,然后再在找到的這一行之后尋找第一個包含 "quux" 的那一行。刪除的就是最后找到的這一行。

      有時,Vim 會在命令前自動添加范圍。舉個例子,如果你先通過 V 命令進(jìn)入行選取模式,選中一些行后按下 : 進(jìn)入命令模式,這時候你會發(fā)現(xiàn) Vim 自動添加了 '<,'> 范圍。這表示,接下來的命令會使用之前選取的行號作為范圍。但如果后續(xù)命令不支持范圍,Vim 就會報錯。為了避免這樣的情況發(fā)生,有些人會設(shè)置這樣的按鍵映射::vnoremap foo :<c-u>command,組合鍵 Ctrl + u 可以清除當(dāng)前命令行中的內(nèi)容。

      另一個例子是在普通模式中按下 !!,命令行中會出現(xiàn) :.!。如果這時你如果輸入一個外部命令,那么當(dāng)前行的內(nèi)容就會被這個外部命令的輸出替換。你也可以通過命令 :?^$?+1,/^$/-1!ls 把當(dāng)前段落的內(nèi)容替換成外部命令 ls 的輸出,原理是向前和向后各搜索一個空白行,刪除這兩個空白行之間的內(nèi)容,并將外部命令 ls 的輸出放到這兩個空白行之間。

      請參閱以下兩個命令來獲取更多幫助:

      :h cmdline-ranges
      :h 10.3
      

      返回主目錄 ??

      標(biāo)注

      你可以使用標(biāo)注功能來標(biāo)記一個位置,也就是記錄文件某行的某個位置。

      標(biāo)注 設(shè)置者 使用
      a-z 用戶 僅對當(dāng)前的一個文件生效,也就意味著只可以在當(dāng)前文件中跳轉(zhuǎn)
      A-Z 用戶 全局標(biāo)注,可以作用于不同文件。大寫標(biāo)注也稱為「文件標(biāo)注」。跳轉(zhuǎn)時有可能會切換到另一個緩沖區(qū)
      0-9 viminfo 0 代表 viminfo 最后一次被寫入的位置。實(shí)際使用中,就代表 Vim 進(jìn)程最后一次結(jié)束的位置。1 代表 Vim 進(jìn)程倒數(shù)第二次結(jié)束的位置,以此類推

      如果想跳轉(zhuǎn)到指定的標(biāo)注,你可以先按下 ' / g' 或者 ` / g` 然后按下標(biāo)注名。

      如果你想定義當(dāng)前文件中的標(biāo)注,可以先按下 m 再按下標(biāo)注名。比如,按下 mm 就可以把當(dāng)前位置標(biāo)注為 m。在這之后,如果你的光標(biāo)切換到了文件的其他位置,只需要通過 'm 或者 `m即可回到剛才標(biāo)注的行。區(qū)別在于,'m會跳轉(zhuǎn)回被標(biāo)記行的第一個非空字符,而`m會跳轉(zhuǎn)回被標(biāo)記行的被標(biāo)記列。根據(jù) viminfo 的設(shè)置,你可以在退出 Vim 的時候保留小寫字符標(biāo)注。請參閱:h viminfo-' 來獲取更多幫助。

      如果你想定義全局的標(biāo)注,可以先按下 m 再按下大寫英文字符。比如,按下 mM 就可以把當(dāng)前文件的當(dāng)前位置標(biāo)注為 M。在這之后,就算你切換到其他的緩沖區(qū),依然可以通過 'M`M 跳轉(zhuǎn)回來。

      關(guān)于跳轉(zhuǎn),還有以下的方式:

      按鍵 跳轉(zhuǎn)至
      '[`[ 上一次修改或復(fù)制的第一行或第一個字符
      ']`] 上一次修改或復(fù)制的最后一行或最后一個字符
      '<`< 上一次在可視模式下選取的第一行或第一個字符
      '>`> 上一次在可視模式下選取的最后一行或最后一個字符
      ''`' 上一次跳轉(zhuǎn)之前的光標(biāo)位置
      '"`" 上一次關(guān)閉當(dāng)前緩沖區(qū)時的光標(biāo)位置
      '^`^ 上一次插入字符后的光標(biāo)位置
      '.`. 上一次修改文本后的光標(biāo)位置
      '(`( 當(dāng)前句子的開頭
      ')`) 當(dāng)前句子的結(jié)尾
      '{`{ 當(dāng)前段落的開頭
      '}`} 當(dāng)前段落的結(jié)尾

      標(biāo)注也可以搭配 范圍 一起使用。前面提到過,如果你在可視模式下選取一些文本,然后按下 :,這時候你會發(fā)現(xiàn)命令行已經(jīng)被填充了 :'<,'>。對照上面的表格,現(xiàn)在你應(yīng)該明白了,這段代表的就是可視模式下選取的范圍。

      請使用 :marks 命令來顯示所有的標(biāo)注,參閱 :h mark-motions 來獲取關(guān)于標(biāo)注的更多幫助。

      返回主目錄 ??

      補(bǔ)全

      Vim 在插入模式中為我們提供了多種補(bǔ)全方案。如果有多個補(bǔ)全結(jié)果,Vim 會彈出一個菜單供你選擇。

      常見的補(bǔ)全有標(biāo)簽、項(xiàng)目中引入的模塊或庫中的方法名、文件名、字典及當(dāng)前緩沖區(qū)的字段。

      針對不同的補(bǔ)全方案,Vim 為我們提供了不同的按鍵映射。這些映射都是在插入模式中通過 Ctrl + x 來觸發(fā):

      映射 類型 幫助文檔
      <c-x><c-l> 整行 :h i^x^l
      <c-x><c-n> 當(dāng)前緩沖區(qū)中的關(guān)鍵字 :h i^x^n
      <c-x><c-k> 字典(請參閱 :h 'dictionary')中的關(guān)鍵字 :h i^x^k
      <c-x><c-t> 同義詞字典(請參閱 :h 'thesaurus')中的關(guān)鍵字 :h i^x^t
      <c-x><c-i> 當(dāng)前文件以及包含的文件中的關(guān)鍵字 :h i^x^i
      <c-x><c-]> 標(biāo)簽 :h i^x^]
      <c-x><c-f> 文件名 :h i^x^f
      <c-x><c-d> 定義或宏定義 :h i^x^d
      <c-x><c-v> Vim 命令 :h i^x^v
      <c-x><c-u> 用戶自定義補(bǔ)全(通過 'completefunc' 定義) :h i^x^u
      <c-x><c-o> Omni Completion(通過 'omnifunc' 定義) :h i^x^o
      <c-x>s 拼寫建議 :h i^Xs

      盡管用戶自定義補(bǔ)全與 Omni Completion 是不同的,但他們做的事情基本一致。共同點(diǎn)在于,他們都是一個監(jiān)聽當(dāng)前光標(biāo)位置的函數(shù),返回值為一系列的補(bǔ)全建議。用戶自定義補(bǔ)全是由用戶定義的,基于用戶的個人用途,因此你可以根據(jù)自己的喜好和需求隨意定制。而 Omni Completion 是針對文件類型的補(bǔ)全,比如在 C 語言中補(bǔ)全一個結(jié)構(gòu)體(struct)的成員(members),或者補(bǔ)全一個類的方法,因而它通常都是由文件類型插件設(shè)置和調(diào)用的。

      如果你設(shè)置了 'complete' 選項(xiàng),那么你就可以在一次操作中采用多種補(bǔ)全方案。這個選項(xiàng)默認(rèn)包含了多種可能性,因此請按照自己的需求來配置。你可以通過 <c-n> 來調(diào)用下一個補(bǔ)全建議,或通過 <c-p> 來調(diào)用上一個補(bǔ)全建議。當(dāng)然,這兩個映射同樣可以直接調(diào)用補(bǔ)全函數(shù)。請參閱 :h i^n:h 'complete' 來獲得更多幫助。

      如果你想配置彈出菜單的行為,請一定要看一看 :h 'completeopt' 這篇幫助文檔。默認(rèn)的配置已經(jīng)不錯了,但我個人(原作者)更傾向于把 "noselect" 加上。

      請參閱以下文檔獲取更多幫助:

      :h ins-completion
      :h popupmenu-keys
      :h new-omni-completion
      

      返回主目錄 ??

      動作,操作符,文本對象

      動作也就是指移動光標(biāo)的操作,你肯定很熟悉 hj、kl,以及 wb。但其實(shí),/ 也是一個動作。他們都可以搭配數(shù)字使用,比如 2?the<cr> 可以將光標(biāo)移動到倒數(shù)第二個 "the" 出現(xiàn)的位置。

      以下會列出一些常用的動作。你也可以通過 :h navigation 來獲取更多的幫助。

      操作符是對某個區(qū)域文本執(zhí)行的操作。比如,d、~gU> 都是操作符。這些操作符既可以在普通模式下使用,也可以在可視模式下使用。在普通模式中,順序是先按操作符,再按動作指令,比如 >j。在可視模式中,選中區(qū)域后直接按操作符就可以,比如 Vjd。

      與動作一樣,操作符也可以搭配數(shù)字使用,比如 2gUw 可以將當(dāng)前單詞以及下一個單詞轉(zhuǎn)成大寫。由于動作和操作符都可以搭配數(shù)字使用,因此 2gU2w 與執(zhí)行兩次 gU2w 效果是相同的。

      請參閱 :h operator 來查看所有的操作符。你也可以通過 :set tildeop 命令把 ~ 也變成一個操作符

      值得注意的是,動作是單向的,而文本對象是雙向的。文本對象不僅作用于符號(比如括號、中括號和大括號等)標(biāo)記的范圍內(nèi),也作用于整個單詞、整個句子等其他情況。

      文本對象不能用于普通模式中移動光標(biāo)的操作,因?yàn)楣鈽?biāo)還沒有智能到可以向兩個方向同時跳轉(zhuǎn)。但這個功能可以在可視模式中實(shí)現(xiàn),因?yàn)樵趯ο蟮囊欢诉x中的情況下,光標(biāo)只需要跳轉(zhuǎn)到另一端就可以了。

      文本對象操作一般用 ia 加上對象標(biāo)識符操作,其中 i 表示在對象內(nèi)(英文 inner)操作,a 表示對整個對象(英文 around)操作,這時開頭和結(jié)尾的空格都會被考慮進(jìn)來。舉個例子,diw 可以刪除當(dāng)前單詞,ci( 可以改變括號中的內(nèi)容。

      文本對象同樣可以與數(shù)字搭配使用。比如,像 ((( ))) 這樣的文本,假如光標(biāo)位于最內(nèi)層的括號上或最內(nèi)層的括號內(nèi),那么 d2a( 將會刪除從最內(nèi)層開始的兩對括號,以及他們之間的所有內(nèi)容。其實(shí),d2a( 這個操作等同于 2da(。在 Vim 的命令中,如果有兩處都可以接收數(shù)字作為參數(shù),那么最終結(jié)果就等同于兩個數(shù)字相乘。在這里,da( 都是可以接收參數(shù)的,一個參數(shù)是 1,另一個是 2,我們可以把它們相乘然后放到最前面。

      請參閱 :h text-objects 來獲取更多關(guān)于文本對象的幫助。

      返回主目錄 ??

      自動命令

      在特定的情況下,Vim 會傳出事件。如果你想針對這些事件執(zhí)行回調(diào)方法,那么就需要用到自動命令這個功能。

      如果沒有了自動命令,那你基本上是用不了 Vim 的。自動命令一直都在執(zhí)行,只是很多時候你沒有注意到。不信的話,可以執(zhí)行命令 :au ,不要被結(jié)果嚇到,這些是當(dāng)前有效的所有自動命令。

      請使用 :h {event} 來查看 Vim 中所有事件的列表,你也可以參考 :h autocmd-events-abc 來獲取關(guān)于事件的更多幫助。

      一個很常用的例子,就是針對文件類型執(zhí)行某些設(shè)置:

      autocmd FileType ruby setlocal shiftwidth=2 softtabstop=2 comments-=:#
      

      但是緩沖區(qū)是如何知道當(dāng)前的文件中包含 Ruby 代碼呢?這其實(shí)是另一個自動命令檢測的到的,然后把文件類型設(shè)置成為 Ruby,這樣就觸發(fā)了上面的 FileType 事件。

      在配置 vimrc 的時候,一般第一行加進(jìn)去的就是 filetype on。這就意味著,Vim 啟動時會讀取 filetype.vim 文件,然后根據(jù)文件類型來觸發(fā)相應(yīng)的自動命令。

      如果你勇于嘗試,可以查看下 :e $VIMRUNTIME/filetype.vim,然后在輸出中搜索 "Ruby"。這樣,你就會發(fā)現(xiàn)其實(shí) Vim 只是通過文件擴(kuò)展名 .rb 判斷某個文件是不是 Ruby 的。

      注意:對于相同事件,如果有多個自動命令,那么自動命令會按照定義時的順序執(zhí)行。通過 :au 就可以查看它們的執(zhí)行順序。

      au BufNewFile,BufRead *.rb,*.rbw setf ruby
      

      BufNewFileBufRead 事件是被寫在 Vim 源文件中的。因此,每當(dāng)你通過 :e 或者類似的命令打開文件,這兩個事件都會觸發(fā)。然后,就是讀取 filetype.vim 文件來判斷打開的文件類型。

      簡單來說,事件和自動命令在 Vim 中的應(yīng)用十分廣泛。而且,Vim 為我們留出了一些易用的接口,方便用戶配置適合自己的事件驅(qū)動回調(diào)。

      請參閱 :h autocommand 來獲取更多幫助

      返回主目錄 ??

      變更歷史,跳轉(zhuǎn)歷史

      在 Vim 中,用戶最近 100 次的文字改動都會被保存在變更歷史中。如果在同一行有多個小改動,那么 Vim 會把它們合并成一個。盡管內(nèi)容改動會合并,但作用的位置還是會只記錄下最后一次改動的位置。

      在你移動光標(biāo)或跳轉(zhuǎn)的時候,每一次的移動或跳轉(zhuǎn)前的位置會被記錄到跳轉(zhuǎn)歷史中。類似地,跳轉(zhuǎn)歷史也可以最多保存 100 條記錄。對于每個窗口,跳轉(zhuǎn)記錄是獨(dú)立的。但當(dāng)你分離窗口時(比如使用 :split 命令),跳轉(zhuǎn)歷史會被復(fù)制過去。

      Vim 中的跳轉(zhuǎn)命令,包括 '、`、G、/、?、n、N%、()、[[、]]、{}、:s、:tagL、M、H 以及開始編輯一個新文件的命令。

      列表 顯示所有條目 跳轉(zhuǎn)到上一個位置 跳轉(zhuǎn)到下一個位置
      跳轉(zhuǎn)歷史 :jumps [count]<c-o> [count]<c-i>
      變更歷史 :changes [count]g; [count]g,

      如果你執(zhí)行第二列的命令顯示所有條目,這時 Vim 會用 > 標(biāo)記來為你指示當(dāng)前位置。通常這個標(biāo)記位于 1 的下方,也就代表最后一次的位置。

      如果你希望關(guān)閉 Vim 之后還保留這些條目,請參閱 :h viminfo-' 來獲取更多幫助。

      注意:上面提到過,最后一次跳轉(zhuǎn)前的位置也會記錄在標(biāo)注中,也可以通過連按 ``'' 跳轉(zhuǎn)到那個位置

      請參閱以下兩個命令來獲取更多幫助:

      :h changelist
      :h jumplist
      

      返回主目錄 ??

      內(nèi)容變更歷史記錄

      Vim 會記錄文本改變之前的狀態(tài)。因此,你可以使用「撤銷」操作 u 來取消更改,也可以通過「重做」操作 Ctrl + r 來恢復(fù)更改。

      值得注意的是,Vim 采用 tree 數(shù)據(jù)結(jié)構(gòu)來存儲內(nèi)容變更的歷史記錄,而不是采用 queue。你的每次改動都會成為存儲為樹的節(jié)點(diǎn)。而且,除了第一次改動(根節(jié)點(diǎn)),之后的每次改動都可以找到一個對應(yīng)的父節(jié)點(diǎn)。每一個節(jié)點(diǎn)都會記錄改動的內(nèi)容和時間。其中,「分支」代表從任一節(jié)點(diǎn)到根節(jié)點(diǎn)的路徑。當(dāng)你進(jìn)行了撤銷操作,然后又輸入了新的內(nèi)容,這時候就相當(dāng)于創(chuàng)建了分支。這個原理和 git 中的 branch(分支)十分類似。

      考慮以下這一系列按鍵操作:

      ifoo<esc>
      obar<esc>
      obaz<esc>
      u
      oquux<exc>
      

      那么現(xiàn)在,Vim 中會顯示三行文本,分別是 "foo"、"bar" 和 "quux"。這時候,存儲的樹形結(jié)構(gòu)如下:

           foo(1)
             /
          bar(2)
         /      \
      baz(3)   quux(4)
      

      這個樹形結(jié)構(gòu)共包含四次改動,括號中的數(shù)字就代表時間順序。

      現(xiàn)在,我們有兩種方式遍歷這個樹結(jié)構(gòu)。一種叫「按分支遍歷」,一種叫「按時間遍歷」。

      撤銷 u 與重做 Ctrl + r 操作是按分支遍歷。對于上面的例子,現(xiàn)在我們有三行字符。這時候按 u 會回退到 "bar" 節(jié)點(diǎn),如果再按一次 u 則會回退到 "foo" 節(jié)點(diǎn)。這時,如果我們按下 Ctrl + r 就會前進(jìn)至 "bar" 節(jié)點(diǎn),再按一次就回前進(jìn)至 "quux" 節(jié)點(diǎn)。在這種方式下,我們無法訪問到兄弟節(jié)點(diǎn)(即 "baz" 節(jié)點(diǎn))。

      與之對應(yīng)的是按時間遍歷,對應(yīng)的按鍵是 g-g+。對于上面的例子,按下 g- 會首先回退到 "baz" 節(jié)點(diǎn)。再次按下 g- 會回退到 "bar" 節(jié)點(diǎn)。

      命令/按鍵 執(zhí)行效果
      [count]u:undo [count] 回退到 [count] 次改動之前
      [count]<c-r>:redo [count] 重做 [count] 次改動
      U 回退至最新的改動
      [count]g-:earlier [count]? 根據(jù)時間回退到 [count] 次改動之前。"?" 為 "s"、"m"、"h"、"d" 或 "f"之一。例如,:earlier 2d 會回退到兩天之前。:earlier 1f 則會回退到最近一次文件保存時的內(nèi)容
      [count]g+:later [count]? 類似 g-,但方向相反

      內(nèi)容變更記錄會儲存在內(nèi)存中,當(dāng) Vim 退出時就會清空。如果需要持久化存儲內(nèi)容變更記錄,請參閱備份文件,交換文件,撤銷文件以及 viminfo 文件的處理章節(jié)的內(nèi)容。

      如果你覺得這一部分的內(nèi)容難以理解,請參閱 undotree,這是一個可視化管理內(nèi)容變更歷史記錄的插件。類似的還有 vim-mundo。

      請參閱以下鏈接獲取更多幫助:

      :h undo.txt
      :h usr_32
      

      返回主目錄 ??

      全局位置信息表,局部位置信息表

      在某一個動作返回一系列「位置」的時候,我們可以利用「全局位置信息表」和「局部位置信息表」來存儲這些位置信息,方便以后跳轉(zhuǎn)回對應(yīng)的位置。每一個存儲的位置包括文件名、行號和列號。

      比如,編譯代碼是出現(xiàn)錯誤,這時候我們就可以把錯誤的位置直接顯示在全局位置信息表,或者通過外部抓取工具使位置顯示在局部位置信息表中。

      盡管我們也可以把這些信息顯示到一個空格緩沖區(qū)中,但用這兩個信息表顯示的好處在于接口調(diào)用很方便,而且也便于瀏覽輸出。

      Vim 中,全局位置信息表只能有一個,但每一個窗口都可以有自己的局部位置信息表。這兩個信息表的外觀看上去很類似,但在操作上會稍有不同。

      以下為兩者的操作比較:

      動作 全局位置信息表 局部位置信息表
      打開窗口 :copen :lopen
      關(guān)閉窗口 :cclose :lclose
      下一個條目 :cnext :lnext
      上一個條目 :cprevious :lprevious
      第一個條目 :cfirst :lfirst
      最后一個條目 :clast :llast

      請參閱 :h :cc 以及底下的內(nèi)容,來獲取更多命令的幫助。

      應(yīng)用實(shí)例
      如果我們想用 grep 遞歸地在當(dāng)前文件夾中尋找某個關(guān)鍵詞,然后把輸出結(jié)果放到全局位置信息表中,只需要這樣:

      :let &grepprg = 'grep -Rn $* .'
      :grep! foo
      <grep output - hit enter>
      :copen
      

      執(zhí)行了上面的代碼,你就能看到所有包含字符串 "foo" 的文件名以及匹配到的相關(guān)字段都會顯示在全局位置信息表中。

      返回主目錄 ??

      你可以在 Vim 中錄制一系列按鍵,并把他們存儲到寄存器中。對于一些需要臨時使用多次的一系列操作,把它們作為宏保存起來會顯著地提升效率。對于一些復(fù)雜的操作,建議使用 Vim 腳本來實(shí)現(xiàn)。

      • 首先,按下 q,然后按下你想要保存的寄存器,任何小寫字母都可以。比如我們來把它保存到 q 這個寄存器中。按下 qq,你會發(fā)現(xiàn)命令行里已經(jīng)顯示了 "recording @q"。
      • 如果你已經(jīng)錄制完成,那么只需要再按一次 q 就可以結(jié)束錄制。
      • 如果你想調(diào)用剛才錄制的宏,只需要 [count]@q
      • 如果你想調(diào)用上一次使用的宏,只需要 [count]@@

      實(shí)例 1

      一個插入字符串 "abc" 后換行的宏,重復(fù)調(diào)用十次:

      qq
      iabc<cr><esc>
      q
      10@q
      

      (對于上面這個功能,你同樣可以通過如下的按鍵: oabc 然后 ESC 然后 10. 來實(shí)現(xiàn))。

      實(shí)例 2

      一個在每行前都加上行號的宏。從第一行開始,行號為 1,后面依次遞增。我們可以通過 Ctrl + a 來實(shí)現(xiàn)遞增的行號,在定義宏的時候,它會顯示成 ^A。

      qq
      0yf jP0^A
      q
      1000 @q
      

      這里能實(shí)現(xiàn)功能,是因?yàn)槲覀兗俣宋募疃嘀挥?1000 行。但更好的方式是使用「遞歸」宏,它會一直執(zhí)行,知道不能執(zhí)行為止:

      qq
      0yf jP0^A@q
      q
      @q
      

      (對于上面這個插入行號的功能,如果你不愿意使用宏,同樣可以通過這段按鍵操作來實(shí)現(xiàn)::%s/^/\=line('.') . '. ')。

      這里向大家展示了如何不用宏來達(dá)到相應(yīng)的效果,但要注意,這些不用宏的實(shí)現(xiàn)方式只適用于這些簡單的示例。對于一些比較復(fù)雜的自動化操作,你確實(shí)應(yīng)該考慮使用宏。

      請參閱以下文檔獲取更多幫助:

      :h recording
      :h 'lazyredraw'
      

      返回主目錄 ??

      顏色主題

      顏色主題可以把你的 Vim 變得更漂亮。Vim 是由多個組件構(gòu)成的,我們可以給每一個組件都設(shè)置不同的文字顏色、背景顏色以及文字加粗等等。比如,我們可以通過這個命令來設(shè)置背景顏色:

      :highlight Normal ctermbg=1 guibg=red
      

      執(zhí)行后你會發(fā)現(xiàn),現(xiàn)在背景顏色變成紅色了。請參閱 :h :highlight 來獲取更多幫助。

      其實(shí),顏色主題就是一系列的 :highlight 命令的集合。

      事實(shí)上,大部分顏色主題都包含兩套配置。一套適用于例如 xterm 和 iTerm 這樣的終端環(huán)境(使用前綴 cterm),另一套適用于例如 gvim 和 MacVim 的圖形界面環(huán)境(使用前綴 gui)。對于上面的例子,ctermbg 就是針對終端環(huán)境的,而 guibg 就是針對圖形界面環(huán)境的。

      如果你下載了一個顏色主題,并且在終端環(huán)境中打開了 Vim,然后發(fā)現(xiàn)顯示的顏色與主題截圖中差別很大,那很可能是配置文件只設(shè)置了圖形界面環(huán)境的顏色。反之同理,如果你使用的是圖形界面環(huán)境,發(fā)現(xiàn)顯示顏色有問題,那就很可能是配置文件只設(shè)置了終端環(huán)境的顏色。

      第二種情況(圖形界面環(huán)境的顯示問題)其實(shí)不難解決。如果你使用的是 Neovim 或者 Vim 7.4.1830 的后續(xù)版本,可以通過打開真彩色設(shè)置來解決顯示問題。這就可以讓終端環(huán)境的 Vim 使用 GUI 的顏色定義,但首先,你要確認(rèn)一下你的終端環(huán)境和環(huán)境內(nèi)的組件(比如 tmux)是否都支持真彩色??梢钥匆幌?a target="_blank" rel="noopener nofollow">這篇文檔,描述的十分詳細(xì)。

      請參閱以下文檔或鏈接來獲取更多幫助:

      返回主目錄 ??

      折疊

      每一部分文字(或者代碼)都會有特定的結(jié)構(gòu)。對于存在結(jié)構(gòu)的文字和代碼,也就意味著它們可以按照一定的邏輯分割成不同區(qū)域。Vim 中的折疊功能,就是按照特定的邏輯把文字和代碼折疊成一行,并顯示一些簡短的描述。折疊功能涉及到很多操作,而且折疊功能可以嵌套使用。

      在 Vim 中,有以下 6 中折疊類型:

      折疊方式 概述
      diff 在「比較窗口」中折疊未改變的文本
      expr 使用 'foldexpr' 來創(chuàng)建新的折疊邏輯
      indent 基于縮進(jìn)折疊
      manual 使用 zfzF:fold 來自定義折疊
      marker 根據(jù)特定的文本標(biāo)記折疊(通常用于代碼注釋)
      syntax 根據(jù)語法折疊,比如折疊 if 代碼塊

      注意:折疊功能可能會顯著地影響性能。如果你在使用折疊功能的時候出現(xiàn)了打字卡頓之類的問題,請考慮使用 FastFold 插件。這個插件可以讓 Vim 按需更新折疊內(nèi)容,而不是一直調(diào)用。

      請參閱以下文檔獲取更多幫助:

      :h usr_28
      :h folds
      

      會話

      如果你保存了當(dāng)前的「視圖」(請參閱 :h :mkview),那么當(dāng)前窗口、配置和按鍵映射都會被保存下來(請參閱 :h :loadview)。

      「會話」就是存儲所有窗口的相關(guān)設(shè)置,以及全局設(shè)置。簡單來說,就是給當(dāng)前的 Vim 運(yùn)行實(shí)例拍個照,然后把相關(guān)信息存儲到會話文件中。存儲之后的改動就不會在會話文件中顯示,你只需要在改動后更新一下會話文件就可以了。

      你可以把當(dāng)前工作的「項(xiàng)目」存儲起來,然后可以在不同的「項(xiàng)目」之間切換。

      現(xiàn)在就來試試吧。打開幾個窗口和標(biāo)簽,然后執(zhí)行 :mksession Foo.vim。如果你沒有指定文件名,那就會默認(rèn)保存為 Session.vim。這個文件會保存在當(dāng)前的目錄下,你可以通過 :pwd 來顯示當(dāng)前路徑。重啟 Vim 之后,你只需要執(zhí)行 :source Foo.vim,就可以恢復(fù)剛才的會話了。所有的緩沖區(qū)、窗口布局、按鍵映射以及工作路徑都會恢復(fù)到保存時的狀態(tài)。

      其實(shí) Vim 的會話文件就只是 Vim 命令的集合。你可以通過命令 :vs Foo.vim 來看看會話文件中究竟有什么。

      你可以決定 Vim 會話中究竟要保存哪些配置,只需要設(shè)置一下 'sessionoptions' 就可以了。

      為了方便開發(fā),Vim 把最后一次調(diào)用或?qū)懭氲臅捹x值給了一個內(nèi)部變量 v:this_session

      請參閱以下文檔來獲取更多幫助:

      :h Session
      :h 'sessionoptions'
      :h v:this_session
      

      局部化

      以上提到的很多概念,都有一個局部化(非全局)的版本:

      全局 局部 作用域 幫助文檔
      :set :setlocal 緩沖區(qū)或窗口 :h local-options
      :map :map <buffer> 緩沖區(qū) :h :map-local
      :autocmd :autocmd * <buffer> 緩沖區(qū) :h autocmd-buflocal
      :cd :lcd 窗口 :h :lcd
      :<leader> :<localleader> 緩沖區(qū) :h maploacalleader

      變量也有不同的作用域,詳細(xì)內(nèi)容請參考 Vim scripting 的文檔。

      用法

      獲取離線幫助

      Vim 自帶了一套很完善的幫助文檔,它們是一個個有固定排版格式的文本文件,通過標(biāo)簽可以訪問這些文件的特定位置。

      在開始之前先讀一下這個章節(jié)::help :help。執(zhí)行這個命令以后會在新窗口打開 $VIMRUNTIME/doc/helphelp.txt 文件并跳轉(zhuǎn)到這個文件中 :help 標(biāo)簽的位置。

      一些關(guān)于幫助主題的簡單規(guī)則:

      • 用單引號把文本包起來表示選項(xiàng),如::h 'textwidth'
      • 以小括號結(jié)尾表示 VimL 函數(shù),如::h reverse()
      • 以英文冒號開頭表示命令,如::h :echo

      使用快捷鍵 <c-d> (這是 ctrl+d)來列出所有包含你當(dāng)前輸入的內(nèi)容的幫助主題。如::h tab<c-d> 會列出所有包含 tab 主題,從 softtabstopsetting-guitablabel (譯者注:根據(jù)安裝的插件不同列出的選項(xiàng)也會不同)。

      你想查看所有的 VimL 方法嗎?很簡單,只要輸入::h ()<c-d> 就可以了。你想查看所有與窗口相關(guān)的函數(shù)嗎?輸入 :h win*()<c-d>

      相信你很快就能掌握這些技巧,但是在剛開始的時候,你可能對于該通過什么進(jìn)行查找一點(diǎn)線索都沒有。這時你可以想象一些與要查找的內(nèi)容相關(guān)的關(guān)鍵字,再讓 :helpgrep 來幫忙。

      :helpgrep backwards
      

      上面的命令會在所有的幫助文件中搜索“backwards”,然后跳轉(zhuǎn)到第一個匹配的位置。所有的匹配位置都會被添加到全局位置信息表,用 :cp / :cn 可以在匹配位置之間進(jìn)行切換。或者用 :copen 命令來打開全局位置信息表,將光標(biāo)定位到你想要的位置,再按 回車就可以跳轉(zhuǎn)到該匹配項(xiàng)。詳細(xì)說明請參考 :h quickfix。

      獲取離線幫助(補(bǔ)充)

      這個列表最初發(fā)表在 vim_dev,由 @chrisbra 編輯的,他是 Vim 開發(fā)人員中最活躍的一個。

      經(jīng)過一些微小的改動后,重新發(fā)布到了這里。


      如果你知道你想要找什么,使用幫助系統(tǒng)的搜索會更簡單一些,因?yàn)樗阉鞒龅闹黝}都帶有固定的格式。

      而且?guī)椭到y(tǒng)中的主題包含了你當(dāng)前使用的 Vim 版本的所特有特性,而網(wǎng)上那些已經(jīng)過時或者是早期發(fā)布的話題是不會包含這些的。

      因此學(xué)習(xí)使用幫助系統(tǒng)以及它所用的語言是很有必要的。這里是一些例子(不一定全,我有可能忘了一些什么)。

      (譯者注:下面列表中提及的都是如何指定搜索主題以便快速準(zhǔn)確的找到你想要的幫助)

      1. 選項(xiàng)要用單引號引起來。用 :h 'list' 來查看列表選項(xiàng)幫助。只有你明確的知道你要找這么一個選項(xiàng)的時候才可以這么做,不然的話你可以用 :h options.txt 來打開所有選項(xiàng)的幫助頁面,再用正則表達(dá)式進(jìn)行搜索,如:/width。某些選項(xiàng)有它們自己的命名空間,如::h cpo-a,:h cpo-A, :h cpo-b 等等。

      2. 普通模式的命令不能用冒號作為前綴。使用 :h gt 來轉(zhuǎn)到“gt”命令的幫助頁面。

      3. 正則表達(dá)式以“/”開頭,所以 :h /\+ 會帶你到正則表達(dá)式中量詞“+”的幫助頁面。

      4. 組合鍵經(jīng)常以一個字母開頭表示它們可以在哪些模式中使用。如::h i_CTRL-X 會帶你到插入模式下的 CTRL-X 命令的用法幫助頁面,這是一個自動完成類的組合鍵。需要注意的是某些鍵是有固定寫法的,如 Control 鍵寫成 CTRL。還有,查找普通模式下的組合鍵幫助時,可以省略開頭的字母“n”,如::h CTRL-A。而 :h c_CTRL-A(譯者注:原文為 :h c_CRTL-R,感覺改為 A 更符合上下文語境)會解釋 CTRL-A 在命令模式下輸入命令時的作用;:h v_CTRL-A 說的是在可見模式下把光標(biāo)所在處的數(shù)字加 1;:h g_CTRL-A 則說的是 g 命令(你需要先按 "g" 的命令)。這里的 "g" 代表一個普通的命令,這個命令總是與其它的按鍵組合使用才生效,與 "z" 開始的命令相似。

      5. 寄存器是以 "quote" 開頭的。如::h quote: (譯者注:原文為:h quote,感覺作者想以":"來舉例)來查看關(guān)于":"寄存器的說明。

      6. 關(guān)于 Vim 腳本(VimL)的幫助都在 :h eval.txt 里。而某些方面的語言可以使用 :h expr-X 獲取幫助,其中的 'X' 是一個特定的字符,如::h expr-! 會跳轉(zhuǎn)到描述 VimL 中'!'(非)的章節(jié)。另外一個重要提示,可以使用 :h function-list 來查看所有函數(shù)的簡要描述,列表中包括函數(shù)名和一句話描述。

      7. 關(guān)于映射都可以在 :h map.txt 中找到。通過 :h mapmode-i 來查找 :imap 命令的相關(guān)信息;通過 :h map-topic 來查找專門針對映射的幫助(譯者注:topic 為一個占位符,正如上面的字符 'X' 一樣,在實(shí)際使用中需要替換成相應(yīng)的單詞)(如::h :map-local 查詢本地 buffer 的映射,:h map-bar 查詢?nèi)绾卧谟成渲刑幚?|')。

      8. 命令定義用 "command-" 開頭,如用 :h command-bar 來查看自定義命令中'!'的作用。

      9. 窗口管理類的命令是以 "CTRL-W" 開頭的,所以你可以用 :h CTRL-W_* 來查找相應(yīng)的幫助(譯者注:'*'同樣為占位符)(如::h CTRL-W_p 查看切換到之前訪問的窗口命令的解釋)。如果你想找窗口處理的命令,還可以通過訪問 :h windows.txt 并逐行向下瀏覽,所有窗口管理的命令都在這里了。

      10. 執(zhí)行類的命令以":"開頭,即::h :s 講的是 "??" 命令。

      11. 在輸入某個話題時按 CTRL-D,讓 Vim 列出所有的近似項(xiàng)輔助你輸入。

      12. :helpgrep 在所有的幫助頁面(通常還包括了已安裝的插件的幫助頁面)中進(jìn)行搜索。參考 :h :helpgrep 來了解如何使用。當(dāng)你搜索了一個話題之后,所有的匹配結(jié)果都被保存到了全局位置信息表(或局部位置信息表)當(dāng)中,可以通過 :copen:lopen 打開。在打開的窗口中可能通過 / 對搜索結(jié)果進(jìn)行進(jìn)一步的過濾。

      13. :h helphelp 里介紹了如何使用幫助系統(tǒng)。

      14. 用戶手冊。它采用了一種對初學(xué)者更加友好的方式來展示幫助話題。用 :h usr_toc.txt 打開目錄(你可能已經(jīng)猜到這個命令的用處了)。瀏覽用戶手冊能幫助你找出某些你想了解的話題,如你可以在第 24 章看到關(guān)于“復(fù)合字符”以及“輸入特殊字符”的講解(用 :h usr_24.txt 可以快速打開相關(guān)章節(jié))。

      15. 高亮分組的幫助以 hl- 開頭。如::h hl-WarningMsg 說的是警告信息分組的高亮。

      16. 語法高亮以:syc- 開頭,如::h :syn-conceal 講的是 :syn 命令的對于隱藏字符是如何顯示的。

      17. 快速修復(fù)命令以 :c 開頭,而位置列表命令以 :l 開頭。

      18. :h BufWinLeave 講的是 BufWinLeave 自動命令。還有,:h autocommand-events (譯者注:原文是 :h autocommands-events,但是沒有該幫助)講的是所有可用的事件。

      19. 啟動參數(shù)都以“-”開頭,如::h -f 會告訴你 Vim 中 “-f” 參數(shù)的作用。

      20. 額外的特性都以“+”開頭,如::h +conceal 講的是關(guān)于隱藏字符的支持。

      21. 錯誤代碼可以在幫助系統(tǒng)中直接查到。:h E297 會帶你到關(guān)于這一錯誤的詳細(xì)解釋。但是有時并沒有轉(zhuǎn)到錯誤描述,而是列出了經(jīng)常導(dǎo)出這一錯誤的 Vim 命令,如 :h E128 (譯者注:原文為:h hE128,但是并沒有該幫助)會直接跳轉(zhuǎn)到 :function 命令。

      22. 關(guān)于包含的語法文件的文檔的幫助話題格式是 :h ft-*-syntax。如::h ft-c-syntax 說的就是 C 語言語法文件以及它所提供的選項(xiàng)。有的語法文件還會帶有自動完成(:h ft-php-omni)或文件類型插件(:h ft-tex-plugin)相關(guān)的章節(jié)可以查看。

      另外在每個幫助頁的頂端通常會包含一個用戶文檔鏈接(更多的從從用戶的角度出發(fā)來主角命令的功能和用法,不涉及那么多細(xì)節(jié))。如::h pattern.txt 里包含了 :h 03.9:h usr_27 兩個章節(jié)的鏈接。

      獲取在線幫助

      如果你遇到了無法解決的問題,或者需要指引的話,可以參考 Vim 使用郵件列表。 IRC 也是一個很不錯的資源。 Freenode 上的 #vim 頻道很龐大,并且里面有許多樂于助人的人。

      如果你想給 Vim 提交 Bug 的話,可以使用 vim_dev 郵件列表。

      執(zhí)行自動命令

      你可以觸發(fā)任何事件,如::doautocmd BufRead

      用戶自定義事件

      對于插件而言,創(chuàng)建你自己的自定義事件有時非常有用。

      function! Chibby()
          " A lot of stuff is happening here.
          " And at last..
          doautocmd User ChibbyExit
      endfunction
      

      現(xiàn)在你插件的用戶可以在 Chibby 執(zhí)行完成之后做任何他想做的事情:

      autocmd User ChibbyExit call ChibbyCleanup()
      

      順便提一句,如果在使用 :autocmd:doautocmd 時沒有捕捉異常,那么會輸出 "No matching autocommands" 信息。這也是為什么許多插件用 silent doautocmd ... 的原因。但是這也會有不足,那就是你不能再在 :autocmd 中使用 echo "foo" 了,取而代之的是你要使用 unsilent echo "foo" 來輸出。

      這就是為什么要在觸發(fā)事件之前先判斷事件是否存在的原因,

      if exists('#User#ChibbyExit')
        doautocmd User ChibbyExit
      endif
      

      幫助文檔::h User

      事件嵌套

      默認(rèn)情況下,自動命令不能嵌套!如果某個自動命令執(zhí)行了一個命令,這個命令再依次觸發(fā)其它的事件,這是不可能的。

      例如你想在每次啟動 Vim 的時候自動打開你的 vimrc 文件:

      autocmd VimEnter * edit $MYVIMRC
      

      當(dāng)你啟動 Vim 的時候,它會幫你打開你的 vimrc 文件,但是你很快會注意到這個文件沒有任何的高亮,盡管平時它是正常可以高亮的。

      問題在于你的非嵌套自動命令 :edit 不會觸發(fā)“BufRead”事件,所以并不會把文件類型設(shè)置成“vim”,進(jìn)而 $VIMRUNTIME/syntax/vim.vim 永遠(yuǎn)不會被引入。詳細(xì)信息請參考::au BufRead *.vim。要想完成上面所說的需求,使用下面這個命令:

      autocmd VimEnter * nested edit $MYVIMRC
      

      幫助文檔::h autocmd-nested

      剪切板

      如果你想在沒有 GUI 支持的 Unix 系統(tǒng)中使用 Vim 的 'clipboard' 選項(xiàng),則需要 +clipboard 以及可選的 +xterm_clipboard 兩個特性支持。

      幫助文檔:

      :h 'clipboard'
      :h gui-clipboard
      :h gui-selections
      

      另外請參考:持續(xù)粘貼(為什么我每次都要設(shè)置 'paste' 模式

      剪貼板的使用(Windows, OSX)

      Windows 自帶了剪貼板,OSX 則帶了一個粘貼板

      在這兩個系統(tǒng)中都可以用大家習(xí)慣用的 ctrl+c / cmd+c 復(fù)制選擇的文本,然后在另外一個應(yīng)用中用 ctrl+v / cmd+v 進(jìn)行粘貼。

      需要注意的是復(fù)制的文本已經(jīng)被發(fā)送到了剪貼板,所以你在粘貼復(fù)制的內(nèi)容之前關(guān)閉這個應(yīng)用是沒有任何問題的。

      每次復(fù)制的時候,都會向剪貼板寄存器 * 中寫入數(shù)據(jù)。 而在 Vim 中分別使用 "*y"*p 來進(jìn)行復(fù)制(yank) 和 粘貼(paste)。

      如果你不想每次操作都要指定 * 寄存器,可以在你的 vimrc 中添加如下配置:

      set clipboard=unnamed
      

      通常情況下復(fù)制/刪除/放入操作會往 " 寄存器中寫入數(shù)據(jù),而加上了上面的配置之后 * 寄存器也會被寫入同樣數(shù)據(jù),因此簡單的使用 yp 就可以復(fù)制粘貼了。

      我再說一遍:使用上面的選項(xiàng)意味著每一次的復(fù)制/粘貼,即使在同一個 Vim 窗口里,都會修改剪貼板的內(nèi)容。你自己決定上面的選項(xiàng)是否適合。

      如果你覺得輸入 y 還是太麻煩的話,可以使用下面的設(shè)置把在可視模式下選擇的內(nèi)容發(fā)送到剪貼板:

      set clipboard=unnamed,autoselect
      set guioptions+=a
      

      幫助文檔:

      :h clipboard-unnamed
      :h autoselect
      :h 'go_a'
      

      剪貼板的使用(Linux, BSD, ...)

      如果你的系統(tǒng)使用了 X 圖形界面,事情會變得有一點(diǎn)不同。X 圖形界面實(shí)現(xiàn)了 X 窗口系統(tǒng)協(xié)議, 這個協(xié)議在 1987 年發(fā)布的主版本 11,因此 X 也通常被稱為 X11。

      在 X10 版本中,剪貼緩沖區(qū)被用來實(shí)現(xiàn)像 clipboard 一樣由 X 來復(fù)制文本,并且可以被所有的程序訪問?,F(xiàn)在這個機(jī)制在 X 中還存在,但是已經(jīng)過時了,很多程序都不再使用這一機(jī)制。

      近年來數(shù)據(jù)在程序之間是通過選擇進(jìn)行傳遞的。一共有三種選擇,經(jīng)常用到的有兩種:PRIMARY 和 CLIPBOARD。

      選擇的工作工模大致是這樣的:

      Program A:<ctrl+c>
      Program A:聲稱對 CLIPBOARD 的所有權(quán)
      Program B:<ctrl+v>
      Program B:發(fā)現(xiàn)CLIPBOARD的所有權(quán)被Program A持有
      Program B:從Program A請求數(shù)據(jù)
      Program A:響應(yīng)這個請求并發(fā)送數(shù)據(jù)給Program B
      Program B:從Program A接收數(shù)據(jù)并插入到窗口中
      
      選擇 何時使用 如何粘貼 如何在 Vim 中訪問
      PRIMARY 選擇文本 鼠標(biāo)中鍵, shift+insert * 寄存器
      CLIPBOARD 選擇文本并按 ctrl+c ctrl+v +寄存器

      注意:X 服務(wù)器并不會保存選擇(不僅僅是 CLIPBOARD 選擇)!因此在關(guān)閉了相應(yīng)的程序后,你用 ctrl+c 復(fù)制的內(nèi)容將丟失。

      使用 "*p 來貼粘 PRIMARY 選擇中的內(nèi)容,或者使用 "+y1G 來將整個文件的內(nèi)容復(fù)制到 CLIPBOARD 選擇。

      如果你需要經(jīng)常訪問這兩個寄存器,可以考慮使用如下配置:

      set clipboard^=unnamed          " * 寄存器
      " 或者
      set clipboard^=unnamedplus      " + 寄存器
      

      ^= 用來將設(shè)置的值加到默認(rèn)值之前,詳見::h :set^=

      這會使得所有復(fù)制/刪除/放入操作使用 *+ 寄存器代替默認(rèn)的未命令寄存器 "。之后你就可以直接使用 yp 訪問你的 X 選擇了。

      幫助文檔:

      :h clipboard-unnamed
      :h clipboard-unnamedplus
      

      打開文件時恢復(fù)光標(biāo)位置

      如果沒有這個設(shè)置,每次打開文件時光標(biāo)都將定位在第一行。而加入了這個設(shè)置以后,你就可以恢復(fù)到上次關(guān)閉文件時光標(biāo)所在的位置了。

      將下面的配置添加到你的 vimrc 文件:

      autocmd BufReadPost *
          \ if line("'\"") > 1 && line("'\"") <= line("$") |
          \   exe "normal! g`\"" |
          \ endif
      

      這是通過判斷之前的光標(biāo)位置是否存在(文件可能被其它程序修改而導(dǎo)致所記錄的位置已經(jīng)不存在了),如果存在的話就執(zhí)行 g`" (轉(zhuǎn)到你離開時的光標(biāo)位置但是不更改跳轉(zhuǎn)列表)。

      這需要使用 viminfo 文件::h viminfo-。

      臨時文件

      根據(jù)選項(xiàng)的不同, Vim 最多會創(chuàng)建 4 種工作文件。

      備份文件

      你可以讓 Vim 在將修改寫入到文件之前先備份原文件。默認(rèn)情況下, Vim 會保存一個備份文件但是當(dāng)修改成功寫入后會立即刪除它(:set writebackup)。如果你想一直保留這個備份文件的話,可以使用 :set backup。而如果你想禁用備份功能的話,可以使用 :set nobackup nowritebackup

      咱們來看一下上次我在 vimrc 中改了什么:

      $ diff ~/.vim/vimrc ~/.vim/files/backup/vimrc-vimbackup
      390d389
      < command! -bar -nargs=* -complete=help H helpgrep <args>
      

      幫助文檔::h backup

      交換文件

      假設(shè)你有一個非常棒的科幻小說的構(gòu)思。在按照故事情節(jié)已經(jīng)寫了好幾個小時幾十萬字的時候..忽然停電了!而那時你才想起來你上次保存 ~/來自外太空的邪惡入侵者.txt 是在.. 好吧,你從來沒有保存過。

      但是并非沒有希望了!在編輯某個文件的時候, Vim 會創(chuàng)建一個交換文件,里面保存的是對當(dāng)前文件所有未保存的修改。自己試一下,打開任意的文件,并使用 :swapname 獲得當(dāng)前的交換文件的保存路徑。你也可以將 :set noswapfile 加入到 vimrc 中來禁用交換文件。

      默認(rèn)情況下,交換文件會自動保存在被編輯文件所在的目錄下,文件名以 .file.swp 后綴結(jié)尾,每當(dāng)你修改了超過 200 個字符或是在之前 4 秒內(nèi)沒有任何動作時更新它的內(nèi)容,在你不再編輯這個文件的時候會被刪除。你可以自己修改這些數(shù)字,詳見::h 'updatecount':h 'updatetime'。

      而在斷電時,交換文件并不會被刪除。當(dāng)你再次打開 vim ~/來自外太空的邪惡入侵者.txt 時, Vim 會提示你恢復(fù)這個文件。

      幫助文檔::h swap-file:h usr_11

      撤銷文件

      內(nèi)容變更歷史記錄是保存在內(nèi)存中的,并且會在 Vim 退出時清空。如果你想讓它持久化到磁盤中,可以設(shè)置 :set undofile。這會把文件 ~/foo.c 的撤銷文件保存在 ~/foo.c.un~。

      幫助文檔::h 'undofile':h undo-persistence

      viminfo 文件

      備份文件、交換文件和撤銷文件都是與文本狀態(tài)相關(guān)的,而 viminfo 文件是用來保存在 Vim 退出時可能會丟失的其它的信息的。包括歷史記錄(命令歷史、搜索歷史、輸入歷史)、寄存器內(nèi)容、標(biāo)注、緩沖區(qū)列表、全局變量等等。

      默認(rèn)情況下,viminfo 被保存在 ~/.viminfo。

      幫助文檔::h viminfo:h 'viminfo'

      臨時文件管理設(shè)置示例

      如果你跟我一樣,也喜歡把這些文件放到一個位置(如:~/.vim/files)的話,可以使用下面的配置:

      " 如果文件夾不存在,則新建文件夾
      if !isdirectory($HOME.'/.vim/files') && exists('*mkdir')
        call mkdir($HOME.'/.vim/files')
      endif
      
      " 備份文件
      set backup
      set backupdir   =$HOME/.vim/files/backup/
      set backupext   =-vimbackup
      set backupskip  =
      " 交換文件
      set directory   =$HOME/.vim/files/swap//
      set updatecount =100
      " 撤銷文件
      set undofile
      set undodir     =$HOME/.vim/files/undo/
      " viminfo 文件
      set viminfo     ='100,n$HOME/.vim/files/info/viminfo
      

      注意:如果你在一個多用戶系統(tǒng)中編輯某個文件時, Vim 提示你交換文件已經(jīng)存在的話,可能是因?yàn)橛衅渌挠脩舸藭r正在編輯這個文件。而如果將交換文件放到自己的 home 目錄的話,這個功能就失效了。因此服務(wù)器非常不建議將這些文件修改到 HOME 目錄,避免多人同時編輯一個文件,卻沒有任何警告。

      編輯遠(yuǎn)程文件

      Vim 自帶的 netrw 插件支持對遠(yuǎn)程文件的編輯。實(shí)際上它將遠(yuǎn)程的文件通過 scp 復(fù)制到本地的臨時文件中,再用那個文件打開一個緩沖區(qū),然后在保存時把文件再復(fù)制回遠(yuǎn)程位置。

      下面的命令在你本地的 VIM 配置與 SSH 遠(yuǎn)程服務(wù)器上管理員想讓你使用的配置有沖突時尤其有用:

      :e scp://bram@awesome.site.com/.vimrc
      

      如果你已經(jīng)設(shè)置了 ~/.ssh/config,SSH 會自動讀取這里的配置:

      Host awesome
          HostName awesome.site.com
          Port 1234
          User bram
      

      如果你的 ~/.ssh/config 中有以上的內(nèi)容,那么下面的命令就可以正常執(zhí)行了:

      :e scp://awesome/.vimrc
      

      可以用同樣的方法編輯 ~/.netrc, 詳見::h netrc-netrc。

      確保你已經(jīng)看過了 :h netrw-ssh-hack:h g:netrw_ssh_cmd。

      另外一種編輯遠(yuǎn)程文件的方法是使用 sshfs,它會用 FUSE 來掛載遠(yuǎn)程的文件系統(tǒng)到你本地的系統(tǒng)當(dāng)中。

      插件管理

      Pathogen是第一個比較流行的插件管理工具。實(shí)際上它只是修改了 runtimepath:h 'rtp') 來引入所有放到該目錄下的文件。你需要自己克隆插件的代碼倉庫到那個目錄。

      真正的插件管理工具會在 Vim 中提供幫助你安裝或更新插件的命令。以下是一些常用的插件管理工具:

      多行編輯

      這是一種可以同時輸入多行連續(xù)文本的技術(shù)。參考這個示例

      <c-v> 切換到可視塊模式。然后向下選中幾行,按 IA (譯者注:大寫字母,即 shift+i 或 shift+a)然后開始輸入你想要輸入的文本。

      在剛開始的時候可能會有些迷惑,因?yàn)槲谋局怀霈F(xiàn)在了當(dāng)前編輯的行,只有在當(dāng)前的插入動作結(jié)束后,之前選中的其它行才會出現(xiàn)插入的文本。

      舉一個簡單的例子:<c-v>3jItext<esc>

      如果你要編輯的行長度不同,但是你想在他們后面追加相同的內(nèi)容的話,可以試一下這個:<c-v>3j$Atext<esc>。

      有時你可能需要把光標(biāo)放到當(dāng)前行末尾之后,默認(rèn)情況下你是不可能做到的,但是可能通過設(shè)置 virtualedit 選項(xiàng)達(dá)到目的:

      set virtualedit=all
      

      設(shè)置之后 $10l90| 都會生效,即使超過了行尾的長度。

      詳見 :h blockwise-examples。在開始的時候可能會覺得有些復(fù)雜,但是它很快就會成為你的第二天性的。

      如果你想探索更有趣的事情,可以看看多光標(biāo)

      使用外部程序和過濾器

      免責(zé)聲明:Vim 是單線程的,因此在 Vim 中以前端進(jìn)程執(zhí)行其它的程序時會阻止其它的一切。當(dāng)然你可以使用 Vim 程序接口,如 Lua,并且使用它的多線程支持,但是在那期間, Vim 的處理還是被阻止了。Neovim 添加了任務(wù) API 解決了此問題。

      (據(jù)說 Bram 正在考慮在 Vim 中也添加任務(wù)控制。如果你使用了較新版本的的 Vim ,可以看一下 :helpgrep startjob。)

      使用 :! 啟動一個新任務(wù)。如果你想列出當(dāng)前工作目錄下的所有文件,可以使用 :!ls。 用 | 來將結(jié)果通過管道重定向,如::!ls -l | sort | tail -n5

      沒有使用范圍時(譯者注:范圍就是 :! 之間的內(nèi)容,. 表示當(dāng)前行,+4 表示向下偏移 4 行,$ 表示最末行等,多行時用 , 將它們分開,如 .,$ 表示從當(dāng)前行到末行),:! 會顯示在一個可滾動的窗口中(譯者注:在 GVim 和在終端里運(yùn)行的結(jié)果稍有不同)。相反的,如果指定了范圍,這些行會被過濾。這意味著它們會通過管道被重定向到過濾程序的 stdin,在處理后再通過過濾程序的 stdout 輸出,用輸出結(jié)果替換范圍內(nèi)的文本。例如:為接下來的 5 行文本添加行號,可以使用:

      :.,+4!nl -ba -w1 -s' '
      

      由于手動添加范圍很麻煩, Vim 提供了一些輔助方法以方便的添加范圍。如果需要經(jīng)常帶著范圍的話,你可以在可見模式中先選擇,然后再按 : (譯者注:選中后再按 ! 更方便)。還可以使用 ! 來取用一個 motion 的范圍,如 !ipsort (譯者注:原文為 !ip!sort ,但經(jīng)過實(shí)驗(yàn)發(fā)現(xiàn)該命令執(zhí)行報錯,可能是因?yàn)?Vim 版本的原因造成的,新版本使用 ip 選擇當(dāng)前段落后自動在命令后添加了 ! ,按照作者的寫法來看,可能之前的版本沒有自動添加 ! )可以將當(dāng)前段落的所有行按字母表順序進(jìn)行排序。

      一個使用過濾器比較好的案例是Go 語言。它的縮進(jìn)語法非常個性,甚至還專門提供了一個名為 gofmt 的過濾器來對 Go 語言的源文件進(jìn)行正確的縮進(jìn)。Go 語言的插件通常會提供一個名為 :Fmt 的函數(shù),這個函數(shù)就是執(zhí)行了 :%!gofmt 來對整個文件進(jìn)行縮進(jìn)。

      人們常用 :r !prog 將 prog 程序的插入放到當(dāng)前行的下面,這對于腳本來說是很不錯的選擇,但是在使用的過程中我發(fā)現(xiàn) !!ls 更加方便,它會用輸出結(jié)果替換當(dāng)前行的內(nèi)容。(譯者注:前面命令中的 prog 只是個占位符,在實(shí)際使用中需要替換成其它的程序,如 :r !ls,這就與后面的 !!ls 相對應(yīng)了,兩者唯一的不同是第一個命令不會覆蓋當(dāng)前行內(nèi)容,但是第二個命令會)

      幫助文檔:

      :h filter
      :h :read!
      

      Cscope

      Cscope 的功能比 ctags 要完善,但是只支持 C(通過設(shè)置 cscope.files 后同樣支持 C++以及 Java)。

      鑒于 Tag 文件只是知道某個符號是在哪里定義的,cscope 的數(shù)據(jù)庫里的數(shù)據(jù)信息就多的多了:

      • 符號是在哪里定義的?
      • 符號是在哪里被使用的?
      • 這個全局符號定義了什么?
      • 這個變量是在哪里被賦值的?
      • 這個函數(shù)在源文件的哪個位置?
      • 哪些函數(shù)調(diào)用了這個函數(shù)?
      • 這個函數(shù)調(diào)用了哪些函數(shù)?
      • "out of space"消息是從哪來的?
      • 在目錄結(jié)構(gòu)中當(dāng)前的源文件在哪個位置?
      • 哪些文件引用了這個頭文件?

      1. 構(gòu)建數(shù)據(jù)庫

      在你項(xiàng)目的根目錄執(zhí)行下面的命令:

      $ cscope -bqR
      

      這條命令會在當(dāng)前目錄下創(chuàng)建三個文件:cscope{,.in,.po}.out 。把它們想象成你的數(shù)據(jù)庫。

      不幸的時 cscope 默認(rèn)只分析 *.[c|h|y|l] 文件。如果你想在 Java 項(xiàng)目中使用 cscope ,需要這樣做:

      $ find . -name "*.java" > cscope.files
      $ cscope -bq
      

      2. 添加數(shù)據(jù)庫

      打開你新創(chuàng)建的數(shù)據(jù)庫連接:

      :cs add cscope.out
      

      檢查連接已經(jīng)創(chuàng)建成功:

      :cs show
      

      (當(dāng)然你可以添加多個連接。)

      3. 查詢數(shù)據(jù)庫

      :cs find <kind> <query>
      

      如::cs find d foo 會列出 foo(...) 調(diào)用的所有函數(shù)。

      Kind 說明
      s symbol:查找使用該符號的引用
      g global:查找該全局符號的定義
      c calls:查找調(diào)用當(dāng)前方法的位置
      t text:查找出現(xiàn)該文本的位置
      e egrep:使用 egrep 搜索當(dāng)前單詞
      f file:打開文件名
      i includes:查詢引入了當(dāng)前文件的文件
      d depends:查找當(dāng)前方法調(diào)用的方法

      推薦一些比較方便的映射,如:

      nnoremap <buffer> <leader>cs :cscope find s  <c-r>=expand('<cword>')<cr><cr>
      nnoremap <buffer> <leader>cg :cscope find g  <c-r>=expand('<cword>')<cr><cr>
      nnoremap <buffer> <leader>cc :cscope find c  <c-r>=expand('<cword>')<cr><cr>
      nnoremap <buffer> <leader>ct :cscope find t  <c-r>=expand('<cword>')<cr><cr>
      nnoremap <buffer> <leader>ce :cscope find e  <c-r>=expand('<cword>')<cr><cr>
      nnoremap <buffer> <leader>cf :cscope find f  <c-r>=expand('<cfile>')<cr><cr>
      nnoremap <buffer> <leader>ci :cscope find i ^<c-r>=expand('<cfile>')<cr>$<cr>
      nnoremap <buffer> <leader>cd :cscope find d  <c-r>=expand('<cword>')<cr><cr>
      

      所以 :tag (或 <c-]>)跳轉(zhuǎn)到標(biāo)簽定義的文件,而 :cstag 可以達(dá)到同樣的目的,同時還會打開 cscope 的數(shù)據(jù)庫連接。'cscopetag' 選項(xiàng)使得 :tag 命令自動的像 :cstag 一樣工作。這在你已經(jīng)使用了基于標(biāo)簽的映射時會非常方便。

      幫助文檔::h cscope

      MatchIt

      由于 Vim 是用 C 語言編寫的,因此許多功能都假設(shè)使用類似 C 語言的語法。默認(rèn)情況下,如果你的光標(biāo)在 {#endif , 就可以使用 % 跳轉(zhuǎn)到與之匹配的 }#ifdef。

      Vim 自帶了一個名為 matchit.vim 的插件,但是默認(rèn)沒有啟用。啟用后可以用 % 在 HTML 相匹配的標(biāo)簽或 VimL 的 if/else/endif 塊之間進(jìn)行跳轉(zhuǎn),它還帶來了一些新的命令。

      在 Vim 8 中安裝

      " vimrc
      packadd! matchit
      

      在 Vim 7 或者更早的版本中安裝

      "vimrc
      runtime macros/matchit.vim
      

      由于 matchit 的文檔很全面,我建議安裝以后執(zhí)行一次下面的命令:

      :!mkdir -p ~/.vim/doc
      :!cp $VIMRUNTIME/macros/matchit.vim ~/.vim/doc
      :helptags ~/.vim/doc
      

      簡短的介紹

      至此這個插件已經(jīng)可以使用了。 參考 :h matchit-intro 來獲得支持的命令以及 :h matchit-languages 來獲得支持的語言。

      你可以很方便的定義自己的匹配對,如:

      autocmd FileType python let b:match_words = '\<if\>:\<elif\>:\<else\>'
      

      之后你就可以在任何的 Python 文件中使用 % (向前)或 g% (向后)在這三個片斷之間跳轉(zhuǎn)了。

      幫助文檔:

      :h matchit-install
      :h matchit
      :h b:match_words
      

      技巧

      跳至選擇的區(qū)域另一端

      在使用 v 或者 V 選擇某段文字后,可以用 o 或者 O 按鍵跳至選擇區(qū)域的開頭或者結(jié)尾。

      :h v_o
      :h v_O
      

      聰明地使用 n 和 N

      nN 的實(shí)際跳轉(zhuǎn)方向取決于使用 / 還是 ? 來執(zhí)行搜索,其中 / 是向后搜索,? 是向前搜索。一開始我(原作者)覺得這里很難理解。

      如果你希望 n 始終為向后搜索,N 始終為向前搜索,那么只需要這樣設(shè)置:

      nnoremap <expr> n  'Nn'[v:searchforward]
      nnoremap <expr> N  'nN'[v:searchforward]
      

      聰明地使用命令行歷史

      我(原作者)習(xí)慣用 Ctrl + pCtrl + n 來跳轉(zhuǎn)到上一個/下一個條目。其實(shí)這個操作也可以用在命令行中,快速調(diào)出之前執(zhí)行過的命令。

      不僅如此,你會發(fā)現(xiàn) 其實(shí)更智能。如果命令行中已經(jīng)存在了一些文字,我們可以通過按方向鍵來匹配已經(jīng)存在的內(nèi)容。比如,命令行中現(xiàn)在是 :echo,這時候我們按 ,就會幫我們補(bǔ)全成 :echo "Vim rocks!"(前提是,之前輸入過這段命令)。

      當(dāng)然,Vim 用戶都不愿意去按方向鍵,事實(shí)上我們也不需要去按,只需要設(shè)置這樣的映射:

      cnoremap <c-n> <down>
      cnoremap <c-p> <up>
      

      這個功能,我(原作者)每天都要用很多次。

      智能 Ctrl-l

      Ctrl + l 的默認(rèn)功能是清空并「重新繪制」當(dāng)前的屏幕,就和 :redraw! 的功能一樣。下面的這個映射就是執(zhí)行重新繪制,并且取消通過 /? 匹配字符的高亮,而且還可以修復(fù)代碼高亮問題(有時候,由于多個代碼高亮的腳本重疊,或者規(guī)則過于復(fù)雜,Vim 的代碼高亮顯示會出現(xiàn)問題)。不僅如此,還可以刷新「比較模式」(請參閱 :help diff-mode)的代碼高亮:

      nnoremap <leader>l :nohlsearch<cr>:diffupdate<cr>:syntax sync fromstart<cr><c-l>
      

      禁用錯誤報警聲音和圖標(biāo)

      set noerrorbells
      set novisualbell
      set t_vb=
      

      請參閱 Vim Wiki: Disable beeping。

      快速移動當(dāng)前行

      有時,我(原作者)想要快速把當(dāng)前行上移或下移一行,只需要這樣設(shè)置映射:

      nnoremap [e  :<c-u>execute 'move -1-'. v:count1<cr>
      nnoremap ]e  :<c-u>execute 'move +'. v:count1<cr>
      

      這個映射,同樣可以搭配數(shù)字使用,比如連續(xù)按下 2 ] e 就可以把當(dāng)前行向下移動兩行。

      快速添加空行

      nnoremap [<space>  :<c-u>put! =repeat(nr2char(10), v:count1)<cr>'[
      nnoremap ]<space>  :<c-u>put =repeat(nr2char(10), v:count1)<cr>
      

      設(shè)置之后,連續(xù)按下 5 [ 空格 在當(dāng)前行上方插入 5 個空行。

      運(yùn)行時檢測

      需要的特性:+profile

      Vim 提供了一個內(nèi)置的運(yùn)行時檢查功能,能夠找出運(yùn)行慢的代碼。

      :profile 命令后面跟著子命令來確定要查看什么。

      如果你想查看所有的:

      :profile start /tmp/profile.log
      :profile file *
      :profile func *
      <do something in Vim>
      <quit Vim>
      

      Vim 不斷地在內(nèi)存中檢查信息,只在退出的時候輸出出來。(Neovim 已經(jīng)解決了這個問題用 :profile dump 命令)

      看一下 /tmp/profile.log 文件,檢查時運(yùn)行的所有代碼都會被顯示出來,包括每一行代碼運(yùn)行的頻率和時間。

      大多數(shù)代碼都是用戶不熟悉的插件代碼,如果你是在解決一個確切的問題,
      直接跳到這個日志文件的末尾,那里有 FUNCTIONS SORTED ON TOTAL TIMEFUNCTIONS SORTED ON SELF TIME 兩個部分,如果某個 function 運(yùn)行時間過長一眼就可以看到。

      查看啟動時間

      感覺 Vim 啟動的慢?到了研究幾個數(shù)字的時候了:

      vim --startuptime /tmp/startup.log +q && vim /tmp/startup.log
      

      第一欄是最重要的因?yàn)樗@示了絕對運(yùn)行時間,如果在前后兩行之間時間差有很大的跳躍,那么是第二個文件太大或者含有需要檢查的錯誤的 VimL 代碼。

      NUL 符用新行表示

      文件中的 NUL 符 (\0),在內(nèi)存中被以新行(\n)保存,在緩存空間中顯示為 ^@。

      更多信息請參看 man 7 ascii:h NL-used-for-Nul 。

      快速編輯自定義宏

      這個功能真的很實(shí)用!下面的映射,就是在一個新的命令行窗口中讀取某一個寄存器(默認(rèn)為 *)。當(dāng)你設(shè)置完成后,只需要按下 回車 即可讓它生效。

      在錄制宏的時候,我經(jīng)常用這個來更改拼寫錯誤。

      nnoremap <leader>m  :<c-u><c-r><c-r>='let @'. v:register .' = '. string(getreg(v:register))<cr><c-f><left>
      

      只需要連續(xù)按下 leader m 或者 " leader m 就可以調(diào)用了。

      請注意,這里之所以要寫成 <c-r><c-r> 是為了確保 <c-r> 執(zhí)行了。請參閱 :h c_^R^R

      快速跳轉(zhuǎn)到源(頭)文件

      這個技巧可以用在多種文件類型中。當(dāng)你從源文件或者頭文件中切換到其他文件的時候,這個技巧可以設(shè)置「文件標(biāo)記」(請參閱 :h marks),然后你就可以通過連續(xù)按下 ' C 或者 ' H 快速跳轉(zhuǎn)回去(請參閱 :h 'A)。

      autocmd BufLeave *.{c,cpp} mark C
      autocmd BufLeave *.h       mark H
      

      注意:由于這個標(biāo)記是設(shè)置在 viminfo 文件中,因此請先確認(rèn) :set viminfo? 中包含了 :h viminfo-'。

      在 GUI 中快速改變字體大小

      印象中,我(原作者)記得一下代碼是來自 tpope's 的配置文件:

      command! Bigger  :let &guifont = substitute(&guifont, '\d\+$', '\=submatch(0)+1', '')
      command! Smaller :let &guifont = substitute(&guifont, '\d\+$', '\=submatch(0)-1', '')
      

      根據(jù)模式改變光標(biāo)類型

      我(原作者)習(xí)慣在普通模式下用塊狀光標(biāo),在插入模式下用條狀光標(biāo)(形狀類似英文 "I" 的樣子),然后在替換模式中使用下劃線形狀的光標(biāo)。

      if empty($TMUX)
        let &t_SI = "\<Esc>]50;CursorShape=1\x7"
        let &t_EI = "\<Esc>]50;CursorShape=0\x7"
        let &t_SR = "\<Esc>]50;CursorShape=2\x7"
      else
        let &t_SI = "\<Esc>Ptmux;\<Esc>\<Esc>]50;CursorShape=1\x7\<Esc>\\"
        let &t_EI = "\<Esc>Ptmux;\<Esc>\<Esc>]50;CursorShape=0\x7\<Esc>\\"
        let &t_SR = "\<Esc>Ptmux;\<Esc>\<Esc>]50;CursorShape=2\x7\<Esc>\\"
      endif
      

      原理很簡單,就是讓 Vim 在進(jìn)入和離開插入模式的時候,輸出一些序列,請參考 escape sequence。Vim 與終端之間的中間層,比如 tmux 會處理并執(zhí)行上面的代碼。

      但上面這個還是有一個缺點(diǎn)的。終端環(huán)境的內(nèi)部原理不盡相同,對于序列的處理方式也稍有不同。因此,上面的代碼可能無法在你的環(huán)境中運(yùn)行。甚至,你的運(yùn)行環(huán)境也有可能不支持其他光標(biāo)形狀,請參閱你的 Vim 運(yùn)行環(huán)境的文檔。

      好消息是,上面這個代碼,可以在 iTerm2 中完美運(yùn)行。

      防止水平滑動的時候失去選擇

      如果你選中了一行或多行,那么你可以用 <> 來調(diào)整他們的縮進(jìn)。但在調(diào)整之后就不會保持選中狀態(tài)了。

      你可以連續(xù)按下 g v 來重新選中他們,請參考 :h gv。因此,你可以這樣來配置映射:

      xnoremap <  <gv
      xnoremap >  >gv
      

      設(shè)置好之后,在可視模式中使用 >>>>> 就不會再出現(xiàn)上面提到的問題了。

      選擇當(dāng)前行至結(jié)尾,排除換行符

      在 Vim 里,我們可以同過 v$ 選擇當(dāng)前行至結(jié)尾,但此時會把最后一個換行符也選中,通常需要按額外的 h 來取消最后選中最后一個換行符號。
      Vim 提供了一個 g_ 快捷鍵,可以移動光標(biāo)至最后一個非空字符。因此,為達(dá)到次效果,可以使用 vg_。當(dāng)然,如果覺得按三個鍵比較麻煩,
      可以添加一個映射:

      nnoremap L g_
      

      這樣就可以通過 vL 達(dá)到一樣的效果了。

      重新載入保存文件

      通過自動命令,你可以在保存文件的同時觸發(fā)一些其他功能。比如,如果這個文件是一個配置文件,那么就重新載入;或者你還可以對這個文件進(jìn)行代碼風(fēng)格檢查。

      autocmd BufWritePost $MYVIMRC source $MYVIMRC
      autocmd BufWritePost ~/.Xdefaults call system('xrdb ~/.Xdefaults')
      

      更加智能的當(dāng)前行高亮

      我(原作者)很喜歡「當(dāng)前行高亮」(請參閱 :h cursorline)這個功能,但我只想讓這個效果出現(xiàn)在當(dāng)前窗口,而且在插入模式中關(guān)閉這個效果:

      autocmd InsertLeave,WinEnter * set cursorline
      autocmd InsertEnter,WinLeave * set nocursorline
      

      更快的關(guān)鍵字補(bǔ)全

      關(guān)鍵字補(bǔ)全(<c-n><c-p>)功能的工作方式是,無論 'complete' 設(shè)置中有什么,它都會嘗試著去補(bǔ)全。這樣,一些我們用不到的標(biāo)簽也會出現(xiàn)在補(bǔ)全列表中。而且,它會掃描很多文件,有時候運(yùn)行起來非常慢。如果你不需要這些,那么完全可以像這樣把它們禁用掉:

      set complete-=i   " disable scanning included files
      set complete-=t   " disable searching tags
      

      改變顏色主題的默認(rèn)外觀

      如果你想讓狀態(tài)欄在顏色主題更改后依然保持灰色,那么只需要這樣設(shè)置:

      autocmd ColorScheme * highlight StatusLine ctermbg=darkgray cterm=NONE guibg=darkgray gui=NONE
      

      同理,如果你想讓某一個顏色主題(比如 "lucius")的狀態(tài)欄為灰色(請使用 :echo color_name 來查看當(dāng)前可用的所有顏色主題):

      autocmd ColorScheme lucius highlight StatusLine ctermbg=darkgray cterm=NONE guibg=darkgray gui=NONE
      

      命令

      下面的命令都比較有用,最好了解一下。用 :h :<command name> 來了解更多關(guān)于它們的信息,如::h :global

      :global 和 :vglobal - 在所有匹配行執(zhí)行命令

      在所有符合條件的行上執(zhí)行某個命令。如: :global /regexp/ print 會在所有包含 "regexp" 的行上執(zhí)行 print 命令(譯者注:regexp 有正則表達(dá)式的意思,該命令同樣支持正則表達(dá)式,在所有符合正則表達(dá)式的行上執(zhí)行指定的命令)。

      趣聞:你們可能都知道老牌的 grep 命令,一個由 Ken Thompson 編寫的過濾程序。它是干什么用的呢?它會輸出所有匹配指定正則表達(dá)式的行!現(xiàn)在猜一下 :global /regexp/ print 的簡寫形式是什么?沒錯!就是 :g/re/p 。 Ken Thompsom 在編寫 grep 程序的時候是受了 vi :global 的啟發(fā)。(譯者注: https://robots.thoughtbot.com/how-grep-got-its-name)

      既然它的名字是 :global,理應(yīng)僅作用在所有行上,但是它也是可以帶范圍限制的。假設(shè)你想使用 :delete 命令刪除從當(dāng)前行到下一個空行(由正則表達(dá)式 ^$ 匹配)范圍內(nèi)所有包含 "foo" 的行:

      :,/^$/g/foo/d
      

      如果要在所有 匹配的行上執(zhí)行命令的話,可以使用 :global! 或是它的別名 :vglobal ( V 代表的是 inVerse )。

      :normal 和 :execute - 腳本夢之隊(duì)

      這兩個命令經(jīng)常在 Vim 的腳本里使用。

      借助于 :normal 可以在命令行里進(jìn)行普通模式的映射。如::normal! 4j 會令光標(biāo)下移 4 行(由于加了"!",所以不會使用自定義的映射 "j")。

      需要注意的是 :normal 同樣可以使用范圍數(shù)(譯者注:參考 :h range:h :normal-range 了解更多),故 :%norm! Iabc 會在所有行前加上 "abc"。

      借助于 :execute 可以將命令和表達(dá)式混合在一起使用。假設(shè)你正在編輯一個 C 語言的文件,想切換到它的頭文件:

      :execute 'edit' fnamemodify(expand('%'), ':r') . '.h'
      

      (譯者注:頭文件為與與源文件同名但是擴(kuò)展名為 .h 的文件。上面的命令中 expand 獲得當(dāng)前文件的名稱,fnamemodify 獲取不帶擴(kuò)展名的文件名,再連上 '.h' 就是頭文件的文件名了,最后在使用 edit 命令打開這個頭文件。)

      這兩個命令經(jīng)常一起使用。假設(shè)你想讓光標(biāo)下移 n 行:

      :let n = 4
      :execute 'normal!' n . 'j'
      

      重定向消息

      許多命令都會輸出消息,:redir 用來重定向這些消息。它可以將消息輸出到文件、寄存器或是某個變量中。

      " 將消息重定向到變量 `neatvar` 中
      :redir => neatvar
      " 打印所有寄存器的內(nèi)容
      :reg
      " 結(jié)束重定向
      :redir END
      " 輸出變量
      :echo neatvar
      " 惡搞一下,我們把它輸出到當(dāng)前緩沖區(qū)
      :put =neatvar
      

      再 Vim 8 中,可以更簡單的方式即位:

      :put =execute('reg')
      

      (譯者注:原文最后一條命令是 :put =nicevar 但是實(shí)際會報變量未定義的錯誤)
      (實(shí)測 neovim/vim8 下沒問題)

      幫助文檔::h :redir

      調(diào)試

      常規(guī)建議

      如果你遇到了奇怪的行為,嘗試用這個命令重現(xiàn)它:

      vim -u NONE -N
      

      這樣會在不引用 vimrc(默認(rèn)設(shè)置)的情況下重啟 vim,并且在 nocompatible 模式下(使用 vim 默認(rèn)設(shè)置而不是 vi 的)。(搜索 :h --noplugin 命令了解更多啟動加載方式)

      如果仍舊能夠出現(xiàn)該錯誤,那么這極有可能是 vim 本身的 bug,請給 vim_dev 發(fā)送郵件反饋錯誤,多數(shù)情況下問題不會立刻解決,你還需要進(jìn)一步研究

      許多插件經(jīng)常會提供新的(默認(rèn)的/自動的)操作。如果在保存的時候發(fā)生了,那么請用 :verb au BufWritePost 命令檢查潛在的問題

      如果你在使用一個插件管理工具,將插件行注釋調(diào),再進(jìn)行調(diào)試。

      問題還沒有解決?如果不是插件的問題,那么肯定是你的自定義的設(shè)置的問題,可能是你的 options 或 autocmd 等等。

      到了一行行代碼檢查的時候了,不斷地排除縮小檢查范圍知道你找出錯誤,根據(jù)二分法的原理你不會花費(fèi)太多時間的。

      在實(shí)踐過程中,可能就是這樣,把 :finish 放在你的 vimrc 文件中間,Vim 會跳過它之后的設(shè)置。如果問題還在,那么問題就出在:finish之前的設(shè)置中,再把:finish放到前一部分設(shè)置的中間位置。否則問題就出現(xiàn)在它后面的半部分設(shè)置,那么就把:finish放到后半部分的中間位置。不斷的重復(fù)即可找到。

      調(diào)整日志等級

      Vim 現(xiàn)在正在使用的另一個比較有用的方法是增加 debug 信息輸出詳細(xì)等級?,F(xiàn)在 Vim 支持 9 個等級,可以用:h 'verbose'命令查看。

      :e /tmp/foo
      :set verbose=2
      :w
      :set verbose=0
      

      這可以顯示出所有引用的文件、沒有變化的文件或者各種各樣的作用于保存的插件。

      如果你只是想用簡單的命令來提高等級,也是用 :verbose ,放在其他命令之前,通過計(jì)數(shù)來指明等級,默認(rèn)是 1.

      :verb set verbose
      "  verbose=1
      :10verb set verbose
      "  verbose=10
      

      通常用等級 1 來顯示上次從哪里設(shè)置的選項(xiàng)

      :verb set ai?
      "      Last set from ~/.vim/vimrc
      

      一般等級越高輸出信息月詳細(xì)。但是不要害怕,亦可以把輸出導(dǎo)入到文件中:

      :set verbosefile=/tmp/foo | 15verbose echo "foo" | vsplit /tmp/foo
      

      你可以一開始的時候就打開 verbosity,用 -V 選項(xiàng),它默認(rèn)設(shè)置調(diào)試等級為 10。 例如:vim -V5

      查看啟動日志

      查看運(yùn)行時日志

      Vim 腳本調(diào)試

      如果你以前使用過命令行調(diào)試器的話,對于:debug命令你很快就會感到熟悉。

      只需要在任何其他命令之前加上:debug就會讓你進(jìn)入調(diào)試模式。也就是,被調(diào)試的 Vim 腳本會在第一行停止運(yùn)行,同時該行會被顯示出來。

      想了解可用的 6 個調(diào)試命令,可以查閱:h >cont和閱讀下面內(nèi)容。需要指出的是,類似 gdb 和其他相似調(diào)試器,調(diào)試命令可以使用它們的簡短形式:c、 q、ns、 if。

      除了上面的之外,你還可以自由地使用任何 Vim 的命令。比如,:echo myvar,該命令會在當(dāng)前的腳本代碼位置和上下文上被執(zhí)行。

      只需要簡單使用:debug 1,你就獲得了REPL調(diào)試特性。

      當(dāng)然,調(diào)試模式下是可以定義斷點(diǎn)的,不然的話每一行都去單步調(diào)試就會十分痛苦。(斷點(diǎn)之所以被叫做斷點(diǎn),是因?yàn)檫\(yùn)行到它們的時候,運(yùn)行就會停止下來。因此,你可以利用斷點(diǎn)跳過自己不感興趣的代碼區(qū)域)。請查閱:h :breakadd、 :h :breakdel:h :breaklist獲取更多細(xì)節(jié)。

      假設(shè)你需要知道你每次在保存一個文件的時候有哪些代碼在運(yùn)行:

      :au BufWritePost
      " signify  BufWritePost
      "     *         call sy#start()
      :breakadd func *start
      :w
      " Breakpoint in "sy#start" line 1
      " Entering Debug mode.  Type "cont" to continue.
      " function sy#start
      " line 1: if g:signify_locked
      >s
      " function sy#start
      " line 3: endif
      >
      " function sy#start
      " line 5: let sy_path = resolve(expand('%:p'))
      >q
      :breakdel *
      

      正如你所見,使用<cr>命令會重復(fù)之前的調(diào)試命令,也就是在該例子中的s命令。

      :debug命令可以和verbose選項(xiàng)一起使用。

      語法文件調(diào)試

      語法文件由于包含錯誤的或者復(fù)制的正則表達(dá)式,常常會使得 Vim 的運(yùn)行較慢。如果 Vim 在編譯的時候包含了+profile feature特性,就可以給用戶提供一個超級好用的:syntime命令。

      :syntime on
      " 多次敲擊<c-l>來重繪窗口,這樣的話就會使得相應(yīng)的語法規(guī)則被重新應(yīng)用一次
      :syntime off
      :syntime report
      

      輸出結(jié)果包含了很多的度量維度。比如,你可以通過結(jié)果知道哪些正則表達(dá)式耗時太久需要被優(yōu)化;哪些正則表達(dá)式一直在別使用但重來沒有一次成功匹配。

      請查閱:h :syntime。

      雜項(xiàng)

      附加資源

      資源名稱 簡介
      七個高效的文本編輯習(xí)慣 作者:Bram Moolenaar(即 Vim 的作者)
      七個高效的文本編輯習(xí)慣 2.0(PDF 版) 同上
      IBM DeveloperWorks: 使用腳本編寫 Vim 編輯器 Vim 腳本編寫五輯
      《漫漫 Vim 路》 使用魔抓定制 Vim 插件
      《 Vim 實(shí)踐 (第 2 版)》 輕取 Vim 最佳書籍
      Vimcasts.org Vim 錄屏演示
      為什么是個腳本都用 vi? 常見誤區(qū)釋疑
      你不愛 vi,所以你不懂 Vim 簡明,扼要,準(zhǔn)確的干貨

      Vim 配置集合

      目前,網(wǎng)上有很多流行 Vim 配置集合,對于 Vim 配置集合,個人認(rèn)為有利有弊。
      對于維護(hù)的比較好的配置,比如 SpaceVim 還是值得嘗試的,可以節(jié)省很多自行配置的時間。
      當(dāng)然,網(wǎng)上還有很多其他很流行的配置,比如:

      常見問題

      編輯小文件時很慢

      有兩個因素對性能影響非常大:

      1. 過于復(fù)雜的 正則表達(dá)式 。尤其是 Ruby 的語法文件,以前會造成性能下降。(見調(diào)試語法文件

      2. 屏幕重繪 。有一些功能會強(qiáng)制重繪所有行。

      典型肇事者 原因 解決方案
      :set cursorline 會導(dǎo)致所有行重繪 :set nocursorline
      :set cursorcolumn 會導(dǎo)致所有行重繪 :set nocursorcolumn
      :set relativenumber 會導(dǎo)致所有行重繪 :set norelativenumber
      :set foldmethod=syntax 如果語法文件已經(jīng)很慢了,這只會變得更慢 :set foldmethod=manual:set foldmethod=marker 或者使用快速折疊插件
      :set synmaxcol=3000 由于內(nèi)部表示法,Vim 處理比較長的行時會有問題。讓它高亮到 3000 列…… :set synmaxcol=200
      matchparen.vim Vim 默認(rèn)加載的插件,用正則表達(dá)式查找配對的括號 禁用插件::h matchparen

      注意:只有在你真正遇到性能問題的時候才需要做上面的調(diào)整。在大多數(shù)情況下使用上面提到的選項(xiàng)是完全沒有問題的。

      編輯大文件的時候很慢

      Vim 處理大文件最大的問題就是它會一次性讀取整個文件。這么做是由于緩沖區(qū)的內(nèi)部機(jī)理導(dǎo)致的(在 vim_dev 中討論)。

      如果只是想查看的話,tail hugefile | vim - 是一個不錯的選擇。

      如果你能接受沒有語法高亮,并且禁用所有插件和設(shè)置的話,使用:

      $ vim -u NONE -N
      

      這將會使得跳轉(zhuǎn)變快很多,尤其是省去了基于很耗費(fèi)資源的正則表達(dá)式的語法高亮。你還可以告訴 Vim 不要使用交換文件和 viminfo 文件,以避免由于寫這些文件而造成的延時:

      $ vim -n -u NONE -i NONE -N
      

      簡而言之,盡量避免使用 Vim 寫過大的文件。

      持續(xù)粘貼(為什么我每次都要設(shè)置 'paste' 模式)

      持續(xù)粘貼模式讓終端模擬器可以區(qū)分輸入內(nèi)容與粘貼內(nèi)容。

      你有沒有遇到過往 Vim 里粘貼代碼之后被搞的一團(tuán)糟?

      這在你使用 cmd+vshirt-insert、middle-click 等進(jìn)行粘貼的時候才會發(fā)生。
      因?yàn)槟菢拥脑捘阒皇窍蚪K端模擬器扔了一大堆的文本。
      Vim 并不知道你剛剛是粘貼的文本,它以為你在飛速的輸入。
      于是它想縮進(jìn)這些行但是失敗了。

      這明顯不是個問題,如果你用 Vim 的寄存器粘貼,如:"+p ,這時 Vim 就知道了你在粘貼,就不會導(dǎo)致格式錯亂了。

      使用 :set paste 就可以解決這個問題正常進(jìn)行粘貼。見 :h 'paste':h 'pastetoggle' 獲取更多信息。

      如果你受夠了每次都要設(shè)置 'paste' 的話,看看這個能幫你自動設(shè)置的插件:bracketed-paste。

      點(diǎn)此查看該作者對于這個插件的更多描述。

      Neovim 嘗試把這些變得更順暢,如果終端支持的話,它會自動開啟持續(xù)粘貼模式,無須再手動進(jìn)行切換。

      在終端中按 ESC 后有延時

      如果你經(jīng)常使用命令行,那么肯定要接觸 終端模擬器 ,如 xterm、gnome-terminal、iTerm2 等等(與實(shí)際的終端不同)。

      終端模擬器與他們的祖輩一樣,使用 轉(zhuǎn)義序列 (也叫 控制序列 )來控制光標(biāo)移動、改變文本顏色等。轉(zhuǎn)義序列就是以轉(zhuǎn)義字符開頭的 ASCII 字符串(用脫字符表示法表示成 ^[ )。當(dāng)遇到這樣的字符串后,終端模擬器會從終端信息數(shù)據(jù)庫中查找對應(yīng)的動作。

      為了使用問題更加清晰,我會先來解釋一下什么是映射超時。在映射存在歧義的時候就會產(chǎn)生映射超時:

      :nnoremap ,a :echo 'foo'<cr>
      :nnoremap ,ab :echo 'bar'<cr>
      

      上面的例子中兩個映射都能正常工作,但是當(dāng)輸入 ,a 之后,Vim 會延時 1 秒,因?yàn)樗_認(rèn)用戶是否還要輸入那個 b

      轉(zhuǎn)義序列會產(chǎn)生同樣的問題:

      • <esc> 作為返回普通模式或取消某個動作的按鍵而被大量使用
      • 光標(biāo)鍵使用轉(zhuǎn)義序列進(jìn)行的編碼
      • Vim 期望 Alt (也叫作 Mate Key )會發(fā)送一個正確的 8-bit 編碼的高位,但是許多終端模擬器并不支持這個(也可能默認(rèn)沒有啟用),而只是發(fā)送一個轉(zhuǎn)義序列作為代替。

      你可以這樣測試上面所提到的事情: vim -u NONE -N 然后輸入 i<c-v><left> ,你會看到一個以 ^[ 開頭的字符串,表明這是一個轉(zhuǎn)義序列,^[ 就是轉(zhuǎn)義字符。

      簡而言之,Vim 在區(qū)分錄入的 <esc> 和轉(zhuǎn)義序列的時候需要一定的時間。

      默認(rèn)情況下,Vim 用 :set timeout timeoutlen=1000,就是說它會用 1 秒的時間來區(qū)分有歧義的映射 以及 按鍵編碼。這對于映射來說是一個比較合理的值,但是你可以自行定義按鍵延時的長短,這是解決該問題最根本的辦法:

      set timeout           " for mappings
      set timeoutlen=1000   " default value
      set ttimeout          " for key codes
      set ttimeoutlen=10    " unnoticeable small value
      

      :h ttimeout 里你可以找到一個關(guān)于這些選項(xiàng)之間關(guān)系的小表格。

      而如果你在 tmux 中使用 Vim 的話,別忘了把下面的配置加入到你的 ~/.tmux.conf文件中:

      set -sg escape-time 0
      

      無法重復(fù)函數(shù)中執(zhí)行的搜索

      • 在命令中的搜索(/、:substitute 等)內(nèi)容會改變“上次使用的搜索內(nèi)容”。(它保存在/寄存器中,用 :echo @/ 可以輸出它里面的內(nèi)容)
      • 簡單的文本變化可以通過 . 重做。(它保存在 . 寄存器,用 :echo @. 可以輸出它的內(nèi)容)

      而在你在函數(shù)中進(jìn)行這些操作的時候,一切就會變得不同。因此你不能用 N/n 查找某個函數(shù)剛剛查找的內(nèi)容,也不能重做函數(shù)中對文本的修改。

      幫助文檔::h function-search-undo

      進(jìn)階閱讀

      參考資料

      posted @ 2024-01-16 16:32  LeslieQ  閱讀(118)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 久久亚洲国产精品五月天| 日本偷拍自影像视频久久| 99久久国产福利自产拍| 枣强县| 精品av一区二区三区不卡| 2021亚洲国产精品无码| 久久精品国产亚洲av麻豆小说| 97人人添人澡人人爽超碰| 国产福利视频区一区二区| 精品无码三级在线观看视频| 精品久久综合日本久久网| 丰满妇女强制高潮18xxxx| 起碰免费公开97在线视频| 色欲av无码一区二区人妻| 亚洲一区二区av观看| 亚洲真人无码永久在线| 亚洲精品专区永久免费区| 国产精品成人中文字幕| 北岛玲亚洲一区二区三区| 国产亚洲精品成人aa片新蒲金| 亚洲产在线精品亚洲第一站一| 国内精品久久人妻无码不卡| 国产中文一区卡二区不卡| 亚洲国产av永久精品成人| 国产成人无码A区在线观看视频| 麻豆久久久9性大片| 九九热在线视频只有精品| 国产午夜福利视频在线观看| 国产免费午夜福利蜜芽无码| 久久精品一区二区日韩av| 鲁丝一区鲁丝二区鲁丝三区| 亚洲色婷婷综合开心网| 91久久国产成人免费观看| 欧美牲交a欧美牲交aⅴ一| 午夜欧美精品久久久久久久| 一区二区三区四区激情视频| 久久中文字幕日韩无码视频| 日韩国产欧美精品在线| 国产精品色内内在线播放| 久久精品国产99久久六动漫| 在线a亚洲v天堂网2018|