1. 程式人生 > 其它 >vim 從嫌棄到依賴(14)——快速跳轉

vim 從嫌棄到依賴(14)——快速跳轉

之前介紹過眾多的motion,根據移動範圍來排序的話有 lewj等等,但是面對那麼長的程式碼檔案,僅僅使用這幾個簡單的motion不知道要移動多少次才能找到我想要的程式碼,這個速度有時候還不如我用滑鼠移動游標。vim作為編輯器之神當然提供了快速移動游標的方式了,這篇文章我們就來了解一下如何使用vim在程式碼間進行快速跳轉。

利用標籤,快速跳轉

vim中提供了標籤的方式進行跳轉,事先可以在對應位置設定標籤,後面通過標籤訪問該標籤所在位置

可以使用m{a-z} 來在任意位置設定標記,而後使用`{a-z}來回到對應標記位置。該命令可以回到之前設定標籤時游標所在行和列。


vim可以支援從a到z的26個位置標記,一般來說我們用不到這麼多,即使你能全部用到,可能早就忘了前面標記的在哪個位置了。這種方式有一個最大的問題就是在標記之後從顯示上無法知道我們的標記位於何處。

除了由使用者主動使用m 來設定位置標記以外,vim還會自動為我們設定標記,例如上次修改、上次跳轉、上次高亮等等。

下表列舉出了,如何回到這些vim自動標記所在位置

位置標記 含義
`` 當前檔案中上次跳轉動作之前所處的位置
`. 上次修改的地方
`^ 上次進入插入模式的位置
`[ 上次修改或者複製的起始位置
`] 上次修改或者複製的結尾位置
`< 上次高亮選區的起始位置
`> 上次高亮選區的結尾位置

在匹配的括號間進行跳轉

可以使用 % 在一組括號中使用,可以跳轉到下一個匹配的()[]{}。例如下列操作

我們可以配合operator 來使用,刪除括號中的內容。例如下面的程式碼

var foo = {
    "obj":{
       "test": "1",
       "arr": [1, 2, 3]
    }
}


可以使用將游標移動到對應的位置,然後使用d% 就可以刪除對應的內容了。當然也可以使用文字物件來進行

跳轉列表

瀏覽器中會記錄瀏覽歷史,並且提供了去到上一頁和下一頁的功能。vim中也提供了類似的功能,vim會記錄我們每一次的跳轉,可以通過相關命令來跳轉到上一次跳轉和下一次跳轉的位置。

我們先介紹什麼是跳轉。跳轉似乎很容易理解,似乎游標每次的移動都算是一次跳轉。但是vim中的跳轉並不是這樣的。我們可以先這樣理解,motion 允許我們在一個檔案中進行移動。而跳轉則是不同檔案間的移動。就像在瀏覽器中從一個頁面開啟另一個頁面。為了類比瀏覽器的操作,你也可以把每次跳轉記錄理解成歷史訪問檔案的記錄。

可以使用:jumps 來檢視跳轉記錄。

從上圖中可以看到這樣幾個現象:

  1. 跳轉列表中記錄了所在檔案以及上次游標所在的行和列。最後幾行由於我們處在當前檔案中,所以沒有列出檔名稱來,而是直接給出游標所在行的文字內容,由於我這裡開啟檔案之後立即查看了跳轉列表,游標處於第0行這個虛擬行,所以會顯示空白內容。
  2. 它記錄了游標所在的行列,所以後面我們在恢復的時候可以直接定位到具體位置。
  3. 與瀏覽器類似,之前開啟vim的時候訪問檔案的記錄也在裡面,它並沒有隨著vim的關閉而被清除。
  4. 任何能改變當前視窗中活動檔案的命令都可以作為跳轉命令,像findedit 之類的。

瞭解了跳轉列表之後,我們現在來訪問一下這個跳轉列表。可以使用<Ctrl + i> 來訪問前一個跳轉,<Ctrl + o> 來訪問後一個跳轉。
nvim-config 中隨意開啟一個檔案,然後使用edit 開啟另一個,接著就可以使用<Ctrl + i><Ctrl + o> 在兩個檔案中切換了


我們再來聯想一下瀏覽器中的歷史記錄,我們發現有時候訪問同一個頁面的不同位置可能會產生多條歷史記錄。例如訪問同一頁面的不同錨點。那麼我們之前說的將跳轉理解為歷史檔案訪問記錄可能就不對了,同一個檔案也可以產生多個跳轉記錄。 例如gg(G)%\{a-z}等等。而h j k l w f之類的就不作為一次跳轉。用一句話來總結就是大範圍的游標移動才會被作為一次跳轉。什麼會被作為大範圍的移動呢?我個人的理解是一次移動有能力移動至少半屏,而像50j 之類的雖然也可以移動50行,也達到半屏以上,但是前面加數字表示的是重複,它是重複了多次,並不算一次移動。

我們使用 split 或者 vsplit 再開啟一個新的視窗,然後在兩個視窗中分別使用:jumps 發現二者並不相同。vim可以維護多套跳轉列表,每個視窗都有自己的一套獨立的跳轉列表。這個與瀏覽器中的也類似,新視窗並不能進行前進和後退操作,而且只兩個操作也只能跳轉到由這個視窗開啟的網頁上。

改變列表

回憶一下,我們不管在檔案的哪個位置,使用u撤銷修改的時候游標總能跳轉到對應修改的位置,或者使用\. 能回到上次修改的位置。如果以前沒有注意這個細節的,也可以現在試試。

vim在會話期間會維護一張表,表裡記錄了每個緩衝區的每一次修改。這個就是所謂的改變列表。可以使用:changes 來檢視這個列表

這個列表與跳轉列表類似,都標記了行號與列號。我們可以通過g;g, 來訪問下一個和上一個記錄。你可以拿;, 來類比記憶。這兩個操作符是配合f來使用的。; 移動到下一個匹配位置,, 移動到下一個匹配位置。

我們可以使用\.來跳轉到上一次修改的位置,而 `^則更具體一點。它代表的是上一次退出插入模式游標所在位置。如果我們在做出修改並且退出插入模式之後,移動游標查看了下其他類似程式碼的實現,然後想快速回到之前編輯的位置繼續編輯,可以使用 `^將游標移動到對應位置,然後使用i進入插入模式,當然也可以使用gi 一步到位,直接從上次編輯位置進入插入模式。

需要注意的是,vim會為每一個開啟的視窗維護一個跳轉列表,但是更新列表只有一個,而且跳轉列表並不會隨著vim的退出而消失,但是改變列表則會隨著vim的退出而被清空。

跳轉到游標下的檔案

在我們將當前專案所在的所有路徑加入到path中之後(即在專案根目錄中執行:set path+=./**)可:set 以將游標移動到對應表示相對路徑的程式碼上,執行gf 即可跳轉到對應檔案。

在上面的例子中,我們只寫了settings 這樣的檔案,它是如何知道要開啟 settings.lua 檔案的呢,或者說如果有類似的settings.h 或者 settings.js 在同一個位置的話,它該開啟哪一個呢?

比如說我們新建一個settings.h 在同樣的目錄中,再次執行之前的操作,發現它還是能夠正確的開啟settings.lua

vim 中有一個suffixesadd 變數,它儲存的當前緩衝區中執行gf操作時,可以使用的擴充套件。我們可以像設定path 一樣,例如:set suffixesadd+=.java 來允許開啟java檔案。

使用gf 也是一個跳轉,也會被記錄到跳轉列表中,後續我們可以使用之前介紹的<Ctrl + o><Ctrl + i> 來回的在兩個檔案中切換。

使用全域性書籤在檔案間跳轉

之前介紹過在檔案中可以使用標記,在檔案不同位置進行跳轉。那個時候說到使用小寫字母設定標記,小夥伴們可能會產生疑惑,那大些字母去哪了呢,為什麼只能使用小寫字母,而大寫字母被空著呢?文章寫到這裡了,我可以告訴大家,大寫字母被用到了全域性書籤裡面。

全域性書籤與之前介紹的標記使用方式一模一樣,只是一個使用大寫字母,一個使用小寫字母。例如在上面一個例子中,我們在跳轉到settings.lua 之前先使用mIinit.lua中一個標籤,在跳轉之後使用 `I 快速跳轉回來。

好了,本篇內容就到這裡了。下一次將介紹暫存器相關內容。再次感謝大家的閱讀