想法子記憶Vi/Vim常用操作及指令

本筆記有特殊目錄,點擊開啟:

在Linux系統中編輯文本總是離不開一位老幫手——Vi。而因為其誕生的年代有些久遠,有些操作在現在看來可能有點「反直覺」。

於是我決定寫這樣一篇小筆記,記錄一下我記憶Vi的這些這些 常用 操作和指令的方法(主要靠的是英語和圖示了)。

當然,正如「好記性不如爛筆頭」所言,多實踐才是熟練掌握技能的王道。

002-2022-04-02

關於Vi/Vim名詞本身

  • Vi代表的可能是Visual Instrument(可視工具)Visual Interface(可視介面)亦或就是Visual(可視化的)單詞本身。

  • Vim倒是很明顯,代表的是Vi IMproved(Vi改進版)

編輯器模式

Vi而言:

  1. 命令模式 (Command mode) ,剛進入Vi編輯器時的默認模式。在此模式下能輸入Vi的合法指令(通常是一些字元)來進行操作。

  2. 插入(輸入)模式 (Insert mode) ,顧名思義,是直截了當地編輯文本的模式。

  3. 末行(底線)模式 (Last-line mode) ,也是接受指令的一種模式,更偏向於文件的管理。
    之所以叫 「末行」 是因為指令的輸入在窗口最下方:

    lastLineMode-2022-04-07

VimVi的增強版,因此Vim完全可以兼容Vi的操作,不過它的模式名可能略有差別:

  1. 正常模式 (Normal mode) ,是啟動Vim後的默認模式。

  2. 插入模式 (Insert mode) ,這個和Vi的一致。

  3. 命令(行)模式 (Command-line mode),類似Vi的末行模式。

  4. 可視模式 (Visual mode) ,和普通模式類似,不同的是可以高光選擇文字的一部分進行命令操作

    包括上述幾種模式,Vim總共有12種模式(這個說法來自Wikipedia)。但最常用的還是上面這四種,一般情況下夠用了。

    015-2022-04-06

模式切換

展開閱讀

Vi的三種模式而言,要在其間互相切換,需要借默認模式——命令模式作為一個中轉(對於Vim來說就是正常模式)。

  • 命令模式

    作為進入Vi的默認模式,我們可以把這兒當作一個小家,
    無論在哪個模式下Esc(可以記成Escape [v.]逃離。逃回家了)都可以回到命令模式。(家是永遠的港灣啊)

    EscGoHome-2022-04-06

    再提一嘴,在Vim里這個模式稱為正常模式

  • 插入模式

    通過以下按鍵指令能進入插入模式。這些按鍵通常是大小寫成對的,小寫對應的指令略顯 「溫和」大寫對應的就比較 「走極端」 了。

    InsertModeUpperAndLower-2022-04-07

    1. i / I 插入 (記作Insert [v]插入;嵌入;(在文章中)添加

      小寫的i,就是在游標所在位置進入插入模式:

      lowerInsert-2022-04-07

      大寫的I則有點「極端」,會跳轉到當前游標所在行的開頭進入插入模式:

      upperInsert-2022-04-07

    2. a / A 附加 (記作Append [v]增補,追加

      小寫的a,就是在游標所在位置之後一位進入插入模式,即所謂的「附加」:

      lowerAppend-2022-04-07

      顯而易見,大寫的A就會跳轉到當前游標所在行的末尾進入插入模式(在尾部附加):

      upperAppend-2022-04-07

    3. o / O 新增一行 (暫且記作Open new line)

      都是新增行,差別無非是往下新增還是往上新增了。

      小寫的o,就是在游標所在行的之後新建一行,然後進入插入模式:

      newLineAfter-2022-04-07

      大寫的O呢,就比較蠻橫,會把游標所在行及其以下的行整體往下頂,在原位置新建一行(相對來說就是在游標所在行上面新建一行),然後進入插入模式:

      newLineBefore-2022-04-07

    4. s / S 剪切(取代) (可以直接記刪的拼音Shan,也可以記成Substitute [v]取代

      小寫的s,會剪切游標所在位置右邊的字元,然後進入插入模式:

      subWord-2022-04-07

      大寫的S就很暴躁了,會剪切游標所在行,然後進入插入模式:

      subLine-2022-04-07

      Substitute的話,可以理解為這個操作是剪切原有字元/行後進行插入,取代原有的字元/行

      💡 Scc 指令的功能是相同的!這個在下面的「剪切一行」這一節中也提到了。

    上面這些按鍵指令都是在命令模式/正常模式下輸入的,通過在指令前附加數字,能重複這個指令的操作:

    • 3s -> 刪除游標後3個字元

      repeatSubstitute-2022-04-07

    • 4a -> 在游標下一位附加內容,操作結束後(Esc)把這個內容重複4

      appendFourTimes-2022-04-07

  • 替換模式

    這個模式和插入模式一樣是用於編輯文本的,不同的是替換模式下輸入所至之處會覆蓋一切。

    記作 Replace [v]取代;代替。

    輸入大寫R進入替換模式:

    replaceMode-2022-04-07

    有了大寫R,那麼小寫r呢?小寫r的功能是將游標後面的字元替換為指定字元。比如我們先輸入r,再輸入a:

    replaceChr-2022-04-07

    當然,這些操作一樣是可以重複進行的:

    repeatReplace-2022-04-07

    (指令分別是3rp3R->hello->Esc)

  • 末行模式(Vim中的命令行模式)

    輸入 Shift+: 進入末行模式(事實上我們一般都是這樣打出冒號來的)

    末行模式在Vim中被稱為命令(行)模式

  • 可視模式

    可視模式是Vim中新引入的模式,支援在高光選擇下進行指令操作。

    可視模式即 Visual Mode,進入可視模式的按鍵則是v / V

    其中 v 鍵能普通地進入可視模式:

    visualNormal-2022-04-07

    V 在進入可視模式後會保持高光選擇到游標所在行可視行模式):

    visualLine-2022-04-07

    還有一種便是使用 Ctrl+V/v 進入可視模式了,這種模式叫可視塊模式,如字面所言,是選擇「一塊文字」:

    visuallySelectBlock-2022-04-23

命令模式/正常模式

這是進入Vi/Vim後所處的默認模式,和文本處理是靠的非常近的,我決定先記一下這部分。

  1. 模式切換

  2. 基本游標移動(上下左右)

    在互動式字元介面下沒有能動的滑鼠,只有閃爍的游標來標註位置。要編輯文本,真得先掌握移動游標的指令。

    PS: 下方涉及的游標上下移動都是針對換行符\n分隔的行的,游標會從一行移動到上方或下方的行:

    展開查看示例

    jkLine-2022-04-08

    👆 jk將游標從一行的指定位置移動到另一行的指定位置

    enterDash-re-2022-04-08

    👆 Enter-,將游標移動到下一行或上一行的行首

    • 「經典」款

      h 向左移動游標
      l 向右移動游標
      k 向上移動游標
      j 向下移動游標

      之所以這樣設計,因為在早期終端機上,鍵盤是這個樣的:

      hjklOnTerminal-2022-04-08

      記憶方法:現代鍵盤上鍵在中間,而鍵在兩側,而HJKL也正是兩側的KL代表橫向移動,中間的JK代表縱向移動(HJKL四個鍵連在一起的設計一直保留到了今天)。

      hjkl-remarked-2022-04-08

    • 現代款

      向左移動游標
      向右移動游標
      向上移動游標
      向下移動游標

    • 「隱藏」款

      Backspace(退格鍵) 向左移動游標
      Space(空格鍵) 向右移動游標

      👆記憶方法:在插入模式下,BackspaceSpace是分別用於刪去字元和增加空格的,與之對應的游標分別是往左移動往右移動的。


      Enter 把游標移動到下一行行首
      + 把游標移動到下一行行首
      - 把游標移動到上一行行首

      👆記憶方法:插入模式下 Enter 起到了換行作用,換行後游標會處於行首。
      - 就記成「減去一行」(老實說我也不太知道這個怎麼記了,JK其實也夠用了),
      +- 記在一起就行。


    PS: 游標移動是在命令模式/正常模式下的指令,當然是支援重複的啦!

    在上面所有指令的前面加上重複的次數(數字)即可,比如我要往下翻233行: 233j233↓

  3. 行內游標移動

    這裡記錄一下在一行文本中游標的移動指令:

    • 跳到行首

      0 回到行首,列數=1的地方
      Home 同上👆
      ^ 回到行首,第一個不為空白符的字元處(對於加了縮進的行可謂是非常有用)

      👆記憶方法0記為「歸零」;
      ^的話,正則表達式里是用於匹配字元串首部的,可以一起記,另外其還形如一個頂部,可以記成一行中的「頂頭」部分。

    • 跳到行尾

      $ 回到行尾最後一個字元的地方
      End 同上👆
      g_ 回到行尾最後一個不為空白符的字元處

      👆記憶方法$在正則表達式里是用於匹配字元串尾部的,可以和正則表達式一起記;
      g_可以記成go __形如一個輸入游標,這樣記成跳轉到行尾最後一個非空白字元。

  4. 螢幕可見行中移動游標

    上面所說的「行」取決於換行符\n的位置,但這裡的螢幕可見行是取決於窗口大小的:

    screenLine-2022-04-10

    (圖中標註的即為一個螢幕可見行

    針對這樣的一個行,也是有指令可用於行內移動的:

    • g^ 跳轉到行首第一個不是空白符的字元處

      👆記憶方法g^可以記成go ^,去往當前的頂頭部分。

    • g0 跳轉到行首字元處

    • gm 跳轉到行中間的字元處

      👆記憶方法gm可以記成go midst,去往當前的中間部分。

    • g$ 跳轉到行尾字元處

    完全是可以結合前面的0^$一起記的。當然,g + Homeg + End也是可以的。


    再展開想想,既然g開頭的指令在這裡看的是螢幕可見行,我是不是可以用gj(或g↓)指令從一個螢幕中的行移動到另一個行呢?

    JLOperation-2022-04-10

    👆這個主要是用j)指令進行的游標移動

    gjOperation-2022-04-10

    👆而這個主要是用gjg↓)指令進行的游標移動。

    利用g+移動指令,可以實現在螢幕中的行之間移動。當然,3gj這種移動多行的指令也是支援的哦~


    針對螢幕可見行,還有幾個指令:

    • 大寫 H 用於將游標移動到螢幕可見最上面一行(這個判定有點怪,可能不太準確!)

      👆記憶方法H可以記成Head,去往可見區的頭部。

    • 大寫 M 用於將游標移動到螢幕可見最中間行(同樣判定很怪)

      👆記憶方法M可以記成Middle,去往可見區的中間部分。

    • 大寫 L 用於將游標移動到螢幕可見最下面一行

      👆記憶方法L可以記成Last,去往可見區的最後一行。

  5. 文件內游標移動

    除了上述幾種移動外,還有幾個常用指令能按詞、按句、按段等移動游標:

    • 按詞移動

      w 跳轉到下一個詞的開頭部分(考慮標點符號),演示如下👇

      wordNext-2022-04-10

      W 跳轉到下一個詞的開頭部分(只考慮空格分隔) ,演示如下👇

      wordNext-CAPS-2022-04-10

      b 跳轉到上一個詞的開頭部分(考慮標點符號)。

      B 跳轉到上一個詞的開頭部分(只考慮空格分隔)。

      這裡的bBwW的操作就是反著來的

      👆記憶方法w可以記成word next,下一個單詞;
      b則記成behind word,後一個單詞。
      WB則比較「激進」,不會考慮標點符號。


      e 跳轉到當前游標所在詞詞尾,如果游標在詞尾,就跳轉到下一個詞的詞尾考慮標點符號)。

      E 同上👆,但是只考慮空格分隔

      👆記憶方法e可以記成end of word,詞尾。

    • 按句移動

      ( 移動到游標所在句子的開頭部分,如果已經在開頭,就移動到上一個句子的開頭部分

      ) 移動到下一個句子的開頭部分

      👆記憶方法:寫程式碼的時候會用半形括弧()把表達式括起來,可以理解為「一句」。

    • 按段落移動

      { 移動到游標所在段落的開頭部分,如果已經在開頭,就移動到上一個段落的開頭部分

      } 移動到下一個段落的開頭部分

      👆記憶方法:寫程式碼的時候會用半形大括弧{}把程式碼塊括起來,也就成為了一「段」程式碼,可以理解為一個段落。

    值得注意的是,上面這些按詞、句、段落移動游標的操作,主要是針對英文句式的。如果操作對象是中文的話,可能並不能如願。
    (最明顯的就是按詞移動 W,中文裡一般是不會用空格分隔每個詞的,所以會直接跳轉到一段的末尾!)


    • 在整個文件中跳轉游標

      ⚠️ 下面的指令全部都會使游標跳轉到行首第一個不為空白符的字元處。

      gg 跳轉到文件最開頭的一行,相當於1G

      G 跳轉到文件最末尾的一行

      [row]G 跳轉到文件第[row]行(row代表數字)。

      GJump-2022-04-10

      👆 分別演示了 ggG2G 的操作。

      記憶方法:上面三個指令本質都和G有關,G可以直接記憶為Goto 轉到,跳轉

      nGJump-2022-04-10

  6. 自定義跳轉標記

    在這一坨文本中進行移動時,我經常要使用指令反覆橫跳。有一個地方我經常跳轉過去,如果一步步來實在很麻煩!此時就可以用自定義跳轉標記來解決。

    • 設置標記

      指令非常簡單:

      ma

      這樣就設置了一個名為a的標記!

      經過測試發現 m 後面可以接 a-zA-Z0-9 之中的任意字元!

      也就是說m1, mA, mO, mz這些都是合法的指令!

      👆記憶方法:m 可以直接記憶為 Mark [v]標示,標記

    • 跳轉到標記處

      `a

      這樣就能跳轉到a標記處~

      標記名是大小寫敏感的

      💡 可以和下面的y, c, d指令聯合使用。

    • 跳轉到標記所在行的行首

      'a

      使用單引號 ' 加標記名能跳轉到該標記所在行的行首第一個不為空白符的字元處!

      jump2markedLine-2022-04-12

      這樣是不是就相當於標記了一個行的行首呢?

    • 刪除標記

      ma可以設置名為a的標記,刪除的話其實在前面加個del即可:

      delm adelmarks a

      Delete Marks

      同時支援刪除多個標記。比如我要刪除a,b,c三個標記,可以寫成:

      delm abcdelmarks a b c

      也就是說刪除標記的時候標記名之間有沒有間隔是無所謂的

    💡 在進行了縮進操作後,標記的位置仍然在文本的相應位置,無需擔心。

    末行模式/命令行模式下可以查看標記資訊:marks

  7. 翻頁

    • 後空翻

      Ctrl + b 往回翻一整頁
      PageUp 往回翻一整頁
      Ctrl + u 往回翻半頁

      👆記憶方法b 代表 Backward,也就是往回;
      u則代表Up,也就是往上(在介面上往回翻就如同往上翻);
      PageUp不多贅述,在現在的大多系統中都是支援的。

    • 前空翻

      Ctrl + f 往前翻一整頁
      PageDown 往前翻一整頁
      Ctrl + d 往前翻半頁

      👆記憶方法f 代表 Forward,也就是往前;
      d則代表Down,也就是往下(在介面上往前翻就如同往下翻)。

    Ctrl鍵代表Control,在這裡可以理解為控制頁面滾動。

    PS: 再記憶一下,命令模式/正常模式下的指令是可以重複的。在這裡如果我要向前翻3整頁:3PageDown3Ctrl+f

  8. 複製

    複製是文本的經典便捷操作之一。

    • 複製一行

      yy 複製游標所在行(到暫存器中)
      Y 同上

      👆記憶方法yy 中的 y代表yank [v]猛拉;猛拽,複製其實就是把對應的文本給「拽走」了。

    • 多行複製

      2yy 複製游標所在行以及下一行,共2
      2Y 同上
      10yy 複製游標所在行以及下面9行,共10

      本質上其實就是命令模式/正常模式下的指令重複(在指令前面加數字前綴)。

    • 打一套複製組合拳!(選區複製)

      y其實可以和很多游標移動指令結合使用!利用好這套「組合拳」,效率倍增有木有!

      yankBoxing-2022-04-10

      比如 ye 就能複製游標所在位置到單詞尾部的部分,

      y^ 能複製游標所在位置到行首第一個非空白符的單詞部分,

      再者 y↓yj 能實現同2yy一樣的功能:複製游標所在行以及下一行

      甚至 y( 都是可以的,複製游標所在位置游標所在句開頭

      也就是說 y{, y}, yk ,yl ,y$ ,yg^, y`a 等等其實都是可以的!
      另外還可以複製多行,比如3ygj


      🤩 總結一下就是:

      y 可以和很多游標移動指令結合使用達成部分複製的效果,

      通常以游標所在位置為起點,直到游標移動指令執行後的游標位置為止作為選區進行複製。

      yankGoTest-2022-04-11

      👆示例ygj的效果。游標所在位置是字前面,執行gj後游標位於字前面,所以複製選區就是:

      語人曰:「此當有大手筆事。」俄而帝崩,哀冊說議皆淘所

  9. 剪切

    有了複製,就不得不提到複製並移除——剪切了。通過這些指令移除的文本會被存進暫存器,可用於粘貼

    • 剪切一行

      dd 剪切游標所在行
      cc 剪切游標所在行,並且進入插入模式
      S 同上👆,這個其實在模式切換這一節裡面寫了

      👆記憶方法dd 中的 d記為delete [v]刪除
      cc中的c記為change[v]改變,亦可記成Chi 吃
      S可以記成Shift [v]轉移,剪切就像是在轉移文本的位置,亦可記成Shan 刪

    • 剪切多行

      這一部分和複製多行真的相差無幾,可以說會用多行複製了,肯定是會剪切多行的。

      2dd 剪切游標所在行下面一行,共2
      6dd 剪切游標所在行下面5行,共6
      3cc 剪切游標所在行及下面2行,並進入插入模式
      3S 同上👆

    • 剪切一個字元

      x 剪切游標右邊的一個字元 (相當於dld→
      s 剪切游標右邊的一個字元,並且進入插入模式

      👆記憶方法x 中的 x記為畫個叉叉刪掉字元
      s則可以記為shan 刪

    • 行內剪切

      和複製不同的是,大寫 DC 的作用並不等同於 ddcc

      D 剪切從游標所在位置游標所在行的行末部分
      C 完成上述操作👆,並且進入插入模式

      C相對D仍然是多出了個進入插入模式的功能

    • 組合剪切(選區剪切)

      複製y能打組合拳,我堂堂剪切為什麼不行!

      確實,剪切 dc 都是可以和游標操作指令進行結合的,
      他倆不同的地方在於 d 只是普通的剪切,c 還附贈了切換到插入模式服務!

      arrogantCandD-2022-04-11

      djd↓ 的效果就等同於2dd
      cjc↓ 的效果就等同於2cc,會進入插入模式
      5x 能剪切游標右邊的5個字元
      5s 能剪切游標右邊5個字元且進入插入模式
      3cgj 能剪切從當前游標3螢幕可見行後的相應位置部分
      dw 剪切從當前游標位置下一個單詞前的部分
      cw 在進行上面的操作👆後,會進入插入模式
      d^ 剪切從當前游標位置本行頭部一個不是空白符的字元的部分
      c^ 在進行上面的操作👆後,會進入插入模式
      d`a 剪切從當前游標位置到a標記位置的部分

      3dgj-2022-04-11

      👆演示了一下 3dgj 。從游標所在位置 開始,到執行了3gj之後的游標位置為止作為選區,進行剪切。也就是這一部分:

                                    語人曰:「此當有大手
      筆事。」俄而帝崩,哀冊說議皆淘所草。釋義用來讚譽寫作才
      能極高,並用來稱頌著名的作家和作品、故事東晉的文士王玖
      從小才思敏捷,膽量很大,散文和詩
      

      🤩 總結一下就是:

      d / c 可以和很多游標移動指令結合使用達成部分剪切的效果,

      通常以游標所在位置為起點,直到游標移動指令執行後的游標位置為止作為選區進行剪切。

      💡 應該和複製結合記憶!

  10. 粘貼

    Copy和Cut都記了,接下來咱要想辦法粘貼(Paste)內容咯~

    粘貼的指令其實非常簡單!( ´・ω・)ノ

    • p (向下一行/向右)粘貼文本一次(記為 Paste [v]粘貼

    • 大寫 P (向上一行/向左)粘貼文本一次(記為 Upper(大寫,同時也有「上邊」的意思) Paste


    暫存器中的內容是一行或多行文本(開頭有換行符\n)時:

    • p會把文本粘貼到當前游標所在行下一行

    • 大寫 P 會把文本粘貼到當前游標所在行上一行

    • 👇舉例:先利用yy複製一行文本,然後分別用 pP 進行粘貼

      pasteAndUpperPaste-2022-04-11

      很明顯能看到使用p時,該行文本會被粘貼到line2這一行的下方;
      而使用P時,該行文本會被粘貼到line2這一行的上方。


    暫存器中的內容是不足一行的文本開頭沒有換行符\n)時:

    • p會把文本粘貼到當前游標所指字元右邊

    • 大寫 P 會把文本粘貼到當前游標所指字元左邊

    • 👇舉例:先執行ygj複製開頭沒有換行符的一段文本,然後分別用 pP 進行粘貼

      ygjPasteAndUpperPaste-2022-04-11

      粘貼的時候游標指向的字元n。使用p粘貼時,內容粘貼在n的右方;而使用P粘貼時,內容粘貼在n的左方。


    🌟 命令模式/正常模式下指令可加數字前綴重複執行,這裡也是一樣的。比如 4p 就是把暫存器的文本在游標右邊/下一行粘貼四次

  11. Vim上下文編輯

    Vim在複製y,剪切cd這些操作的基礎上復用了ia指令用於對上下文進行操作:

    👆記憶方法:i 記作 inner 內部的,在下面使用這個指令,操作不會考慮周圍的空格或符號
    a 記作 around 周圍,這個則會考慮周圍的空格或符號。具體視情況而定。

    • 針對單詞w / W

      ⭐ 記作Word

      diw 剪切游標所在的單詞(不考慮標點符號)

      diW 剪切游標所在的單詞(考慮周圍的標點符號,也就是說剪切的時候會把周圍的標點符號一併算進去)

      i (inner) 在這裡的意思是操作的部分不包括單詞周圍的空格

      dawdaW 也是剪切游標所在的單詞wW區別不再多贅述)

      a (around) 在這裡的意思是操作的部分包括單詞周圍的空格

      ※ 下面演示一下diwdaw的區別:

      diwAnddaw-2022-04-11

      很明顯能看到,使用diw時,剪切後遺留的文本是 of ,(單詞左邊的空格保留了);
      使用daw時,剪切後遺留的文本是 of,(單詞左邊的空格被一同剪切了) 。

      💡 像 y, c, d 一類指令都是可以這樣用的,比如yaw, yiW, ciw, caW 等等…


    • 針對句子s

      ⭐ 記作Sentence。注意,這裡沒有大寫 S 的用法!

      其上下文操作和上面單詞的是一樣的!比如:

      yis 複製游標所在的句子i不考慮周圍的空格)
      yas 複製游標所在的句子a考慮周圍的空格)
      cas 剪切游標所在的句子,並進入插入模式
      dis 剪切游標所在的句子
      …and so on

      💡 注意,這裡只有小寫s的用法。


    • 針對段落p

      ⭐ 記作Paragraph。注意,這裡沒有大寫 P 的用法!

      這裡的用法也和上面是一樣的:

      cap 剪切游標所在的段落,並進入插入模式(a考慮周圍的空格)
      dip 剪切游標所在的段落i不考慮周圍的空格)
      yip 複製游標所在的段落
      …and so on

      💡 這裡同樣只有小寫p的用法。


    • 針對單/雙引號' / "

      很明顯,這一部分操作是用來處理單/雙引號引起來的文本的,和上面的wWsp不同的是這裡的 i / a 的含義:

      i (inner) 在這裡的意思是操作的部分不包括兩側的引號
      a (around) 在這裡的意思是操作的部分包括兩側的引號

      di" 剪切游標所在的雙引號引起來的同行文本(i代表不包括兩側的引號) 👇

      diQuoted-2022-04-12

      da' 剪切游標所在的單引號引起來的同行文本(a代表包括兩側的引號) 👇

      daQuoted-2022-04-12

      💡 yc 也是一樣的用法


    • 針對括弧( ), < >, [ ], { }

      這一部分用來處理括弧括起來的文本

      📌 注意,這裡的操作是支援多行的!!

      i (inner) 在這裡的意思是操作的部分不包括兩側的括弧
      a (around) 在這裡的意思是操作的部分包括兩側的括弧

      di(di) 剪切游標所在的小括弧( )括起來的文本(i代表不包括兩側的括弧) 👇

      diBracket-2022-04-12

      da{da} 剪切游標所在的大括弧{ }括起來的文本(a代表包括兩側的括弧) 👇

      daBracket-2022-04-12

      💡 yc 也是一樣的用法,適用於多種括弧。

    quoteAndBracketComic-2022-04-12

  12. 雙引號指定暫存器

    默認情況下使用複製粘貼似乎用的都是一個公共的暫存器(Registers),Vim實際上是支援寄存多條文本的,只需要在指令前指定暫存器名即可。

    • 默認的暫存器被系統記為 " ,一個雙引號

      當執行yy時,會將目標文本行存入 " 暫存器,操作等同於:

      ""yy

      💡 其中第一個單引號代表引用暫存器,第二個單引號便是默認暫存器的名字

      於是粘貼指令也可以改寫成:""p,即從默認暫存器中取出文本進行粘貼。


    • 指定暫存器名字

      把上述第二個單引號改成 a-z小寫字母即可!這樣就相當於得到了26個「剪貼板」呢~

      比如將當前行複製到a暫存器中:

      "ayy

      那麼粘貼該內容的指令也顯而易見了:

      "ap


    • 往已命名暫存器中附加內容

      上面寫到用小寫字母對暫存器進行命名,那麼大寫字母呢?

      大寫字母用於往暫存器中附加內容

      "Ay$ 將游標位置到行尾的文本附加到a暫存器中 👇

      AppendToRegisterA-2022-04-12

    這裡主要記錄一下複製粘貼方面的暫存器引用方法。Vim暫存器儲存的內容遠不止這麼一點,還包括操作歷史記錄等資訊,就不多贅述了。

    👆記憶方法:" 就像個圖釘📌,標明是哪一個暫存器。

    末行模式/命令行模式下可以查看暫存器資訊:reg[isters]

  13. 縮進

    Vi/Vim 常用於編輯程式碼,縮進功能當然也是比較常用的了。

    • 增加縮進

      >>游標所在行增加縮進
      4>>游標所在行以及下面3行增加縮進,共4

    • 減少縮進

      <<游標所在行減少縮進
      5<<游標所在行以及下面4行減少縮進,共5

    👆記憶方法:> 可以看作在往右邊「頂」文本,而 < 可以看作在往左邊「拉」文本。

  14. 撤銷與重做

    文本編輯必不可少的便是撤銷與重做功能了!

    • 撤銷

      u 撤銷上一步操作

      大寫 U 撤銷游標所在行所有操作

      👆記憶方法:u直接記成 undo [v]撤銷,取消 即可。
      一定要辨別小寫u和大寫U的操作區別!

    • 重做

      Ctrl + r 或者 Ctrl + R

      重做操作和小寫u的操作是反向的!重新執行撤銷掉的操作。

      👆記憶方法:r直接記成 redo [v]重做 即可。
      為什麼多了個Ctrl呢?因為r已經被替換模式佔用了!

  15. 數字快捷增減

    要修改一個數值的時候可以進入插入模式,移動游標到數值上進行修改,這樣可能略嫌麻煩了。在命令模式/普通模式下提供了對數值進行遞增遞減的操作指令:

    • Ctrl + aCtrl + A亦可)

      對游標指針所在數值進行遞增操作。如果游標沒有指向數值,會向右查找數值進行遞增。

      💡 記憶方法: a 可以記成 ascend [v]上升;升高;遞增
      亦可以記成 accumulate [v]積累;逐漸增加
      之所以有 Ctrl ,是因為a已經被用於切換插入模式了!

      ascendingNum-2022-04-12

      👆 示例中可以看到,當游標右方沒有數值時會螢幕閃爍提示指令無效。


    • Ctrl + xCtrl + X亦可)

      對游標指針所在數值進行遞減操作。如果游標沒有指向數值,同樣會向右查找數值進行遞減。

      💡 記憶方法: x 可以記成 叉掉數字,從而讓數值減小
      之所以有Ctrl也是因為x已經被用於剪切字元


    • 重複指令

      設想一下,如果我要增加10億,難不成要一直按住按鍵不動?當然不是這樣啦!

      再記憶一遍,命令模式/普通模式下的指令可以加數字前綴進行重複,在這裡只需要這樣輸入指令即可快速遞增指定數值:

      1000000000Ctrl + a

      ascendBillionTimes-2022-04-12

      Ctrl + x 同理!

      rocketAscending-2022-04-12

    • 進位的表示方法

      0x 前綴表示十六進位 (記hexx

      0 前綴表示八進位 (記octalo,雖然這裡是0

      0b0B 前綴表示 二進位


    💡 Vim支援進行增減的類型有:二進位數(binary),八進位數(octal),十進位數(decimal,默認支援),十六進位數(hexadecimal),無符號數(unsigned),字母(alphabetical)。

    👆 具體配置見末行模式/命令(行)模式nrformats配置一節。

  16. 字母大小寫切換

    數字增減有了,字母其實也是可以「隨地大小變」的!

    • gu後接游標移動指令

      將從游標位置開始到執行移動指令後游標的位置結束作為選區,
      將選區內的所有字母轉換為小寫!

      guiw-2022-04-16

      👆 演示了guiw指令。iw選擇的是游標所在單詞FLOOD,執行gu後將單詞所有字母轉換為小寫flood

    • gU後接游標移動指令

      將選區內的所有字母轉換為大寫

    💡 記憶方法:gugU中一個是小寫u,一個是大寫U。大寫U可以記成UPPERCASE 大寫,而當U小寫成為u,對應的便是小寫了。g仍然可以記成gogo UPPERCASE

    • ~ (波浪符)

      波浪符將游標所在的字母進行大小寫交換,比如b會轉換為BB則會轉換為b

      這個指令可以用於轉換游標所在行自游標往後的字母大小寫

      tilde-2022-04-16

      👆 50~,將本行中自游標往後50個字元進行大小寫轉換。

    • g~後接游標移動指令

      上面的~只能對游標所在行的字元進行大小寫交換,如果要涉及一個選區呢?

      於是,g~他來了!在g~後接游標移動指令,將游標當前位置開始到執行指令後游標所在位置為止之間的字元進行大小寫交換。

      gT2gj-2022-04-17

      👆 g~2gj,將從游標位置開始到游標向下移動兩個螢幕行為止的部分字元大小寫交換。

    💡 記憶方法:波浪線可以看作是一條,隨著波的傳播,同一個地方的波峰波谷交替出現,在這裡就記成大寫小寫的交替

    caseInversion-2022-04-17

  17. 重複最後一次更改

    .

    ↑ 沒錯,指令就是一個句點!

    比如,之前我輸入了3dd剪切了三行文本,之後再按一次 . 會再往下剪切三行;

    又比如,我先輸入了x剪切游標所指的字元,之後輸入 3. 就會再剪切三個字元。

    但是!,如果我先輸入3j讓游標往下移動3行,再按 . 是沒有效果的,因為j指令僅僅是移動了游標,沒有對文本造成任何更改!

    ⚠ 注意! . 重複的是最後一次更改,而不是最後一次指令!

    👆 記憶方法:硬背

  18. 行連接指令

    • 大寫 J

      這個指令能將游標所在行和其下面一行連接成一行,之間用一個空格間隔

      LinesJoin-2022-04-17

      4J 的話則是將游標所在行和下面3行進行連接,每行之間用空格隔開。一共4行

      💡 記憶方法:直接記 Join [v]加入;連接 即可。

    • gJ

      同樣是連接行。和上面J不同的是,這個指令在連接行之後不會在之間添加空格!

      💡 記憶方法:可以記成gross Joingross總的;粗魯的的意思,gross Join就可以記成 「連接成一個總體」 或者 「粗魯地直接連在一起」。

末行模式/命令(行)模式

在這個模式中涉及到了最基礎的文件保存 / 退出編輯器等操作。

  1. :w 寫入 (記為Write [v]寫文件

    顧名思義,這個指令會將自開始編輯以來的更改寫入文件中:

    write-2022-04-07

    writeFile-2022-04-07

    文件保存總讓人想起桌面軟體的「另存為」功能,當然Vi也是能實現的:

    :w filename

    writeToAnother-2022-04-08

    writeAnotherFile-2022-04-08

    除了上面針對單一文件的寫入指令,還可以同時寫入多個文件,下面這個指令適用於Vim編輯器中同時打開多個文件的情況:

    :wa

    👆 將所有打開的文件進行寫入保存。(可以記成Write All 寫入所有

    WriteAll-2022-04-17

    如果只想保存文本中的一部分呢?Vim還支援指定行寫入文件:

    :<line1>,<line2> w filename

    👇 比如我想寫入第13至第14行的文本(共兩行)::13,14 w filename

    writeSpecificLines-remake-2022-04-18

    輸出文件效果:

    SpecificLines-2022-04-18

  2. :q 退出(記為Quit [v]離開;關閉

    文本編輯器必備操作——關閉文件。

    :q 指令會退出當前編輯的文件(如果只打開了一個文件,這個操作同時會退出編輯器

    :qa 指令則會退出所有打開的文件,並且退出編輯器

    👆 記憶方法:Quit All 關閉所有

    注意:上面這兩個指令執行的前提是當前文件自打開後沒有任何更改,也就是說文件緩衝區中沒有任何新增內容,不然編輯器會警告文件尚未保存更改。
    怎麼強制退出呢?下面就將寫到…..

  3. 聯合使用 wq

    wCombineWithQ-2022-04-18

    既然未保存沒法正常關閉文件,那麼保存後關閉不就行了嘛!

    :wq

    👆 雙劍合璧,數據無憂!這個指令會將緩衝區中的編輯內容寫入文件,並且關閉文件。(針對當前正在編輯的文件

    當然,也有針對編輯器所有打開的文件的操作:

    :wqa

    👆 寫入並關閉所有打開的文件,這之後會退出編輯器。(Write & Quit All

  4. 感嘆號 ! 強制執行指令

    有些情況下末行模式指令的執行可能會被拒絕,比如上面的:q在文件保存前不能直接執行。(這一點其實也是為了數據安全)

    ⭐ 然而,只需要在這些指令末尾加上感嘆號 ! 就可以強制執行了!

    比如未保存強制退出編輯器就可以用: :qa!

    forcedQuitAll-remake-2022-04-18

    此外我覺得文件強制寫入也是值得記錄一下的::w!

    👆 這個指令會嘗試強制寫入文件,即使文件是只讀(Read-only)的,前提是用戶得要有修改文件屬性的許可權

    ⚠ 強制執行指令時一定要再三考慮,防止數據丟失等問題。

  5. :r 在下一行讀入文件 (記成 Read [v]讀取

    在編輯文本的時候可能需要將另一個文件的文本插入進來,這個時候就輪到:r大顯身手了。

    :r 能夠讀取一個文件,並將文件內容追加到游標所在行的後一行

    appendFileContent-2022-04-18

    👆 左邊是待讀取的文件,右邊是正在編輯的文件。利用:r指令,成功將文件內容插入到游標後一行。

  6. :e 開啟新buffer或刷新當前buffer (記成 Edit [v]編輯

    當編輯文件編輯到一半,想要推翻當前的所有修改,該怎麼辦呢?

    一種方法是使用 :q!,強制退出文件;

    另一種方法則是 :e!,強制刷新當前buffer

    • 文件在Vi/Vim中未經修改但是在別的軟體中受到了修改時,可以直接使用 :e 在編輯器里刷新(重新載入)文件內容

    • 文件做了修改後,也可以用 :e! 強制重載文件內容,也就是拋棄文件開啟以來的所有修改。

      forcedRefreshBuffer-2022-04-22

    buffer可以理解為文件的一個緩衝區,文件在編輯器中被編輯實際上也就是臨時buffer在被編輯。當寫入文件的時候就是把buffer中的內容寫入到原文件中,以達成編輯的效果。


    除了刷新當前文件的buffer外,:e指令還可以用於打開新的文件並創建buffer。

    • :e <filename> 打開文件(如果存在的話),創建buffer

      👆 前提:目前在編輯的文件已經保存或者未經修改。

    • :e! <filename> 無論當前文件是否保存(寫入),強制打開新文件

  7. :buffers:bn, :bp 以及 :b<id>

    • :buffers

      列出所有buffer,在這裡可以看到buffer的ID(最左邊一列)。

      viewBuffers-2022-04-22

    • :b<id>

      既然拿到了buffer的ID,我就可以在buffer之間跳轉了,比如:

      :b2 跳轉到id為2的buffer

      注意:這個操作也要求當前編輯的文件不能有未保存的修改。

    • :bn:bp

      就算不知道buffer的ID,利用這兩個指令也能在buffer間互相切換:

      :bn —> 切換到下一個buffer

      :bp —> 切換到上一個buffer

      注意:這個操作也要求當前編輯的文件不能有未保存的修改。

      💡 記憶方法:bnbuffer next 下一個bufferbpbuffer previous 上一個buffer

  8. :help [command]:h [command] 查看幫助

    就像Linux中的man指令一樣,Vi/Vim的末行模式/命令行模式也有個:help指令用來查看編輯器使用幫助。

    ⭐ 直接使用 :help 時會打開幫助文件,並將游標移動到頂部。

    ⭐ 指令形如:help [command]時,在開啟文件後游標會跳轉到對應的指令幫助資訊。

    比如要看暫存器指令的幫助資訊::help reg:help registers:h reg 當然也行 )

  9. :registers:reg 查看暫存器

    這一部分可以結合命令模式/正常模式雙引號指定暫存器一起記。

    ⭐ 直接使用 :registers:reg 時會展示所有的暫存器 👇

    registers-2022-04-18

    也可以在後面指定要查詢的暫存器名,這些名稱可以用空格分開,也可以連在一起寫:

    ⭐ 比如 :reg[isters] a b c:reg[isters] abc ,可以篩選查詢a,b,c暫存器 👇

    specifyRegisters-2022-04-18

    關於暫存器更多用法這裡就不多贅述了~

    009-2022-04-18

  10. :marks 查看標記資訊

    這個和上面:reg[isters]的使用很類似,所以咱給寫一起了。

    這一部分可以結合命令模式/正常模式自定義跳轉標記一起記。

    ⭐ 直接使用 :marks 能查詢到所有現有的標記

    和:registers一樣,在後接查詢的標記名,能篩選結果:

    ⭐ 比如 :marks a b c:marks abc ,可以篩選查詢a,b,c標記

  11. :set 設置項

    這個指令用於設置一些配置項,這裡就記幾個比較常用的(因為配置項有非常多,全寫出來太累贅了)

    • 開啟/關閉行號顯示

      :set number:set nu 可以在行首顯示行號

      :set nonumber:set nonu 則可以關閉行號顯示

      此外 :set nu!:set number! 可以在開啟行號/關閉行號之間互相切換。

      lineNumbers-2022-04-19

      👆 記憶方法:直接記 Number [n]號碼 [v]標號

    • 開啟/關閉相對行號顯示

      :set relativenumber:set rnu 可以顯示相對行號

      :set nonumber:set nonu 則可以關閉相對行號顯示

      此外 :set rnu!:set relativenumber! 可以在開啟相對行號/關閉相對行號之間互相切換。

      relativeNumber-2022-04-19

      👆 可以看到,相對行號以游標所在行為第0行,向上或向下標出相對的行號。

      這個特性可以用於輔助涉及多行的指令,比如 y3j, 3k, 2>> 等。

      💡 記憶方法:按字面記,即 Relative Number 相對 號碼

    • 識別數字進位的配置

      上面已經寫過Ctrl+xCtrl+a快捷減增數字。不過呢,Vim怎麼識別增減的類型呢? 這就涉及到下面這個配置項了:

      • :set nrformats:set nf

        直接輸入這個指令會查詢該配置項當前的設置

        queryNrformats-2022-04-19

        上面也寫過Vim能識別的增減類型。這裡的octal,hex 則代表會嘗試識別八進位十六進位以及十進位的數字。(十進位是默認支援的)

      • 使用 +=-= 進行配置

        這種寫法其實可以理解為一些程式語言中的運算賦值操作:

        :set nrformats+=bin

        :set nrformats+=bin,alpha

        (或者 set nf+= ... )

        👆 多個可以用逗號分隔,會「附加」到配置項的末尾。

        然而,移除的時候就要注意了,一定要按配置中的順序來:

        :set nrformats-=bin

        :set nrformats-=bin,alpha

        👆 這樣寫的話必須保證配置項中也有bin,alpha這個字串!

        removeNf-2022-04-19

        ↑ 沒有bin,alpha這個字串,無法移除。

        successfullySetNf-2022-04-19

        ↑ 移除octal,alpha的話就很成功,因為配置項中有這個字串。

      • 直接使用 = 進行配置

        同樣可以按程式語言里的賦值來理解,會直接改變整個配置

        :set nrformats=octal,hex

        👆 多個值一樣是用逗號分隔

      💡 記憶方法:nrformats可以看成number recognizing formats,也就是數字識別格式。取nf即為nf,因此nf也可以簡單記為number format

  12. 執行Shell指令

    編輯文本到一半突然想執行一個Shell指令。我之前可能會利用:wq先退出編輯器,輸入執行指令後再重新打開編輯器。

    實際上在末行模式/命令行模式下Vi/Vim也是能快捷切換到Shell執行指令的:

    • :! <command> 暫時離開編輯介面,在Shell下執行指令並列印結果

      temporaryShell-2022-04-19

      👆 臨時跳轉到命令行執行清屏查詢日期指令並展示結果。

      💡 :! 還有很多神奇的用法,比如執行指令後將返回的結果插入下一行::r! <command>
      又比如將文本2125行進行升序排序,並替換原文本::21,25! sort,這裡就很像Shell中管道符的用法了。

      sortByShell-2022-04-19

      👆 演示 :21,25! sort

      更多用法在這裡就不多贅述了╮(╯3╰)╭

    • :sh 創建一個新的Shell會話

      這個指令就比較簡單粗暴了,在執行後會創建一個新的Shell會話,我可以直接在Shell中執行指令!

      createNewShell-2022-04-19

      這個Shell是一個非登入Shell,所以需要使用 exit 指令退出。

      該Shell退出後會回到編輯器介面!

      exitShell-2022-04-19

      👆 這個直接記憶 Shell 就行

  13. 重複上一條指令

    命令模式/正常模式下我可以使用 . 句點來重複上一次更改。在末行模式/命令行模式下也有類似的方法。

    • 經典方法

      末行模式/命令行模式下輸入 : 後會進入末行模式/命令行模式,此時可以通過:

      , , PageUp, PageDown

      來瀏覽之前的輸入歷史

      scrollHistory-2022-04-19

      💡 可以在 : 後面輸入一些字元以加快檢索

      scrollHistoryWithHint-2022-04-19

      👆 輸入:s後,能快速瀏覽:s開頭的歷史指令記錄;:se則能快速瀏覽:se開頭的歷史指令。

    • @: 方法

      命令模式/正常模式下輸入:

      @:

      能重新執行上一條末行模式/命令行模式指令

      👆 記憶方法:把 : 末行指令給at出來!

      雖然我把這個方法寫在末行模式這裡了,但實際上其可以算是命令模式/正常模式的指令。

      因此也是可以重複執行的!

      repeatLastLine-2022-04-19

      👆 演示:先用:d刪除一行,然後再用3@:重複執行:d三次以繼續刪除下面三行。

    however-2022-04-19

    有點累了…喝口水…

基本搜索替換

  1. 搜索

    前提:在命令模式/正常模式下:

    /<搜索模式> 自游標向後查找

    ?<搜索模式> 自游標向前查找

    👆 其實末行模式/命令行模式下也不是不行,也就多了個冒號::/<搜索模式>:?<搜索模式>。不過接下來這兩個指令就不行了 ↓

    n —> 這個指令會重複上一次搜索動作

    • 比如/....是往游標後搜索,按下n就是在游標後再次搜索
    • ?....是往游標前搜索,那麼按下n就是在游標前再次搜索

    N —> 這個指令和 n 的操作相反

    👆 記憶方法:n可以記成 next [a]下一個的 ,正如o和O操作相反一樣,Nn操作相反。


    這裡的搜索模式實際上就是正則表達式,不過和普通的正則略微有些不同!

    1. 當然是可以直接搜索字串的

      searchStr-2022-04-21

    2. 大小寫不敏感搜索

      一般在寫正則表達式時要進行大小寫不敏感匹配我一般會在正則表達式末尾加上i標記,但是在搜索模式里是不行的,需要用到特殊轉義標記:

      \c

      這個標記寫在搜索模式的中間(不要寫在中括弧[]里!)一般也是可以的,但我覺著還是放在末尾好辨別一些。

      caseInsensitivelySearch-2022-04-21

      caseInsensitiveSearch-2022-04-21

      👆 記憶方法:這裡的 \c 可以記成 case [n]大小寫

    3. 利用正則表達式進行搜索

      這裡使用正則表達式和在程式語言里有些小區別,這裡簡單寫一下:

      • 採用 <> 分別匹配單詞詞首單詞詞尾,而不是\b

      • 部分元字元要發揮元字元的作用的話,需要先轉義。這裡列個表格:

        元字元 用途 在搜索模式中的用法
        + 匹配1次或多次 \+
        ? 匹配0或1次(非貪婪模式在Vim中另有元字元) \?
        {n,m} 匹配n到m次 \{n,m}
        {n,} 匹配n次或更多次 \{n,}
        {n} 匹配n次 \{n}
        {,m} 匹配0到m次 \{,m}
        < 匹配單詞首部 \<
        > 匹配單詞尾部 \>
        ( 子模式(捕獲組)開始標誌 \(
        ) 子模式(捕獲組)結束標誌 \)
        | 兩項之間任意匹配一個 \|
        % 用於修飾非捕獲組 \%
        @<=, @<!, @=, @! 向後預查,向前預查 \@<=, \@<!, \@=, \@!

        💡 這種情況是基於Vim默認設置magic模式的,其他模式不多贅述。
        默認情況下這些元字元如果不轉義,就代表匹配這個字元本身

        除此之外的元字元大多是可以直接使用的,下面是一些示例:

        regexSearch1-2022-04-21 regexSearch2-2022-04-21 regexSearch3-2022-04-21 regexSearch4-2022-04-21 regexSearch5-2022-04-21

        另外也是支援引用子模式的匹配結果(分組)的:

        regexSearch6-2022-04-22

    4. 神奇的非貪婪模式

      Vim這裡的非貪婪模式用的就不是元字元 ? 了,取而代之借用了一下大括弧 {...,...}

      官方說明可以在末行模式/命令行模式下輸入:help non-greedy查看。

      { 後面緊接了一個連字元(Hyphen) - 時,就相當於採用了非貪婪匹配,下面舉些例子:

      e\{2,3} 匹配 eeeee,如果有更長的eee就優先匹配(也就是貪婪匹配

      e\{-2,3} 匹配 eeeee,優先匹配更短的ee(也就是非貪婪匹配

      non-greedyMatch-2022-04-21

      👆 這個例子中在{後緊接-後會往少的匹配,也就是只匹配一個paprika


      如果在 - 後面沒有指定匹配次數,就有點類似 * 了。形如:

      \{-} 匹配0-任意次,但是非貪婪匹配,匹配次數盡量少。

      \{-,3} 匹配0-3次,但是非貪婪匹配,匹配次數盡量少。

      例:用模式 ke\{-} 匹配字串keep只匹配到了k,因為\{-}代表匹配0-任意次,但是非貪婪匹配,所以這裡e匹配了0次。

    5. 非捕獲組與向前/向後預查

      在程式語言使用的正則表達式中,非捕獲組一般用(?:模式)來表示,這一個子模式不會參與分組。


      然鵝在Vi/Vim搜索模式中,非捕獲組用的是:

      \%(子模式\)\%\(子模式\) 也行)

      來表示的。下面就是一個示例:

      nonCapturingGroup-2022-04-22

      可以看到accept並未參與分組,\1引用的是第二個子模式的匹配結果after


      接著,在程式語言中的向後/向前預查(?<=), (?=), (?<!), (?!) 在Vi/Vim中也是有特殊的表示方法的:

      預查內容↓ \ 方向→ 向後(左) 向前(右)
      存在 \(子模式\)\@<= \(子模式\)\@=
      不存在 \(子模式\)\@<! \(子模式\)\@!

      💡 預查即預先檢查子模式,看看這個子模式是否存在於待匹配的字串前/後,預查子模式是不會出現在最終的匹配結果中的

      lookBehindPositive-2022-04-22

      👆 匹配 paprika,前提是 paprika後面(左邊)必須要匹配到paprika

      lookAheadPositive-2022-04-22

      👆 匹配paprika,前提是paprika前面(右邊)必須要匹配到 pepper

      lookAheadNegative-2022-04-22

      👆 匹配paprika,前提是paprika前面(右邊)不能匹配到pepper

    6. 搜索游標下的單詞

      這一小節的操作是在命令模式/正常模式下的:

      • * 往後搜索游標目前指向的單詞,只匹配一整個單詞

      • # 向前搜索游標目前指向的單詞,只匹配一整個單詞

        searchWordUnderCursor-2022-04-21

        從這個例子可以看到,實際上Vim是把游標指向的單詞轉換成了搜索語句。* 對應 /\<accept\># 對應 ?\<\accept\>

      • g* 往後搜索游標目前指向的單詞,單詞可作為字串的一部分被匹配。

      • g# 向前搜索游標目前指向的單詞,單詞可作為字串的一部分被匹配。

        searchWordPartUnderCursor-2022-04-21

        可以看到 * 對應 /accept# 對應 ?accept,單詞可作為字串的一部分被匹配。

      💡 因為這幾個指令被轉換為末行搜索操作了,所以在搜索中可以用的nN這一類指令也是可以用的。

    7. 開啟搜索高光顯示

      上面的圖示中搜索匹配項都會「黃的發光」,這種匹配結果高光顯示是可以作為配置項使用 :set 進行設置的:

      • :set hlsearch:set hls 開啟搜索結果高光顯示

      • :set nohlsearch:set nohls 關閉搜索結果高光顯示

        highlightSearch-2022-04-21

      雖然高亮顯示一目了然,但是開了之後游標就不明顯了,高光咱已經看夠了,怎麼關掉目前結果的高光展示呢?

      • :nohlsearch:noh 關閉目前的高光顯示

        nohlsearch-2022-04-21

        可以看到輸入:noh後會取消目前的高亮,但是這並不影響重新開始搜索時高亮展示匹配。

      💡 記憶方法:hlsearchHighlight SearchHighlight [v]突出,強調Search [n]搜索

      hlsearch-2022-04-21

  2. 替換

    替換的指令就是在末行模式/命令行模式下輸入的了,

    其完全可以結合搜索指令一起記憶:

    :[作用範圍] s/<搜索模式>/<替換模式>/<替換flag>

    💡 很明顯了,這裡的s代表的就是substitute [v]取代,替代

    1. 作用範圍

      這裡直接列表直觀展示一下:

      作用範圍 說明
      不寫 默認游標所在行
      . 同樣代表游標所在行
      n (整數) 代表n。比如233代表第233行
      $ 代表最後一行
      'a 代表a標記所在行(關於設定跳轉標記可以看自定義跳轉標記
      上述符號±相對行數 比如'a+2就代表a標記所在行的下面第二行;.-1 就代表游標所在行的上面一行
      上述符號1,上述符號2 代表從上述符號1代表的行到上述符號2代表的行。比如.,$代表從游標所在行到最後一行。
      % 代表從第一行到最後一行(整個文本),和1,$相同
      '<,'> 可視模式下輸入 : 進入末行模式/命令行模式會自動填充,代表**可視模式下選定的範圍

      replaceInTheRange-2022-04-22

      👆 示例:.,+3 代表從游標所在行到游標所在行的下面第三行作為範圍進行替換

    2. 搜索模式

      同上面的搜索模式

      💡 值得一提的是這裡可以留空。如果留空的話默認使用上一次搜索的匹配。

      比如我先搜索了/\<paprika\>,然後我想替換全文的/\<paprika\>/pepper,在替換時可以這樣寫::%s//pepper/g(省略了搜索模式)。

    3. 替換模式

      替換模式當然可以是任意字元串

      同時也可以引用搜索結果中的部分

      replaceWithReference-2022-04-22

      👆 使用 \1, \2 引用搜索結果中的第一個和第二個捕獲組的內容。

      replaceWithReference2-2022-04-22

      👆 使用 & 引用搜索匹配結果

      replaceWithReference3-2022-04-22

      👆 很巧妙的用法,利用捕獲組引用交換順序

    4. 替換flag

      一般正則表達式末尾會加上修飾符以控制匹配行為。而Vim這裡的替換flag也是類似修飾符,控制替換行為的。

      下面列出幾個比較常用的:

      Flag 說明 記憶
      g 全局替換(在指定的作用範圍內) global [a]全局的
      i 忽略大小寫 ignore-case 忽略大小寫
      I 大小寫敏感 i意義相反
      n 並不會真正替換,而是顯示匹配的數目 numerate [v]計算
      c 在替換前讓用戶確認 confirm [v]確認

      💡 值得一提的是 i——忽略大小寫。
      之前在搜索模式中提到過在模式中加入 \c 能忽略大小寫進行搜索,而這裡替換也是用的搜索模式,
      因此在這裡就算不用修飾符i,轉而在搜索模式中加入\c也是完全可以的。

      replaceIgnoreCase-2022-04-22

      👆 不使用修飾符而是在搜索模式中使用了\c


      numerateMatches-2022-04-22

      👆 使用 n 修飾符,並不會實際替換文本,而是顯示匹配的數量


      confirmReplace-2022-04-22

      👆 使用 c 修飾符,在替換前讓用戶確認

      其中提示輸入的 (y/n/a/q/l/^E/^Y) 中,分別代表:

      輸入指令 說明 記憶
      y 確認替換當前游標所在匹配 yes [v]確認
      n 不替換當前匹配 no [v]不
      a 確認替換所有匹配 all [v]所有
      q 不進行替換並退出 quit [v]退出
      l 替換當前匹配並退出 instead [adv]頂替

      (另還有Ctrl+ECtrl+Y,是游標移動指令)

除了這些,搜索替換可能還有一些其他的用法尚未提到,另外還有:g這種末行指令。這裡就主要記錄一下基礎的用法啦~

exhausted-2022-04-22

簡單多窗口編輯

一個文件一個文件地打開編輯老累了,幸運的是,Vim支援多窗口編輯。

  • 打開新窗口

    1. :new [filename]

      使用:new指令能在編輯器頂部新建一個橫向窗口(原本的文件窗口會下移

      如果有指定文件名,則會在新窗口打開指定文件(文件不存在就是單純的創建buffer)

      newWindow-2022-04-22

    2. :sp[lit] [filename] (也就是:sp:split都可以)

      這個指令行為上和:new挺類似的,都會新建一個橫向窗口,使原本的窗口下移

      不同的是,沒有指定文件名時會在新窗口打開當前編輯的文件

      splitWindow-2022-04-22

      👆 split [v]劃分,分割

    3. :vs[plit] [filename]

      這個指令和:sp[lit]類似,但是:vs[plit]是新建一個縱向窗口,使原本的窗口右移

      :sp[lit]一樣的是,沒有指定文件名時會在新窗口打開當前編輯的文件

      verticalSplitWindow-2022-04-22

      👆 :vsplitvertical split [v]垂直分割

  • 在窗口之間切換

    開了這麼多窗口,得想個法子來回切換哈!

    1. Ctrl+wCtrl+W ( 可以記成 Control Window 指揮窗口

      連按兩次 Ctrl+w/W 可以在窗口之間循環切換

      switchWindow-2022-04-22

    2. Ctrl+w/W+方向控制鍵

      對於分割成上下關係的窗口,可以使用 Ctrl+w/W+↑/↓Ctrl+w/W+k/j 來進行上下切換

      switchSplitWindow-2022-04-22

      而對於分割成左右關係的窗口,就可以用 Ctrl+w/W+←/→Ctrl+w/W+h/l 來進行左右切換

      switchVSplitWindow-2022-04-22

  • 調整窗口尺寸

    在調整終端尺寸的時候,Vim里的這些窗口可能並不會如意調整展示尺寸。這裡記錄一些改變窗口尺寸的指令:

    1. 調整窗口高度

      :res[ize] [±][height]

      :res[ize]指令有兩種調整窗口高度的方法。

      第一種是設置絕對高度,比如:res 5,將窗口高度設置為5行:

      resizeWindow-2022-04-23

      第二種是設置相對高度,比如:res +5,將窗口高度增加5行:

      resizeWindowRelatively-2022-04-23

    2. 調整窗口寬度

      :vert[ical] res[ize] [±][width]

      :res[ize]類似,:vert[ical] res[ize]也是能相對/絕對地調整窗口寬度的:

      vresizeWindow-2022-04-23

    💡 這個記起來可能有點反直覺,
    vertical resize 垂直方向上調整,可以記作此時只有垂直高度固定的窗口,所以調整的是寬度
    而普通的resize則是調整的窗口高度,可以記作此時只有水平寬度是固定的窗口

  • 退出窗口

    末行模式/命令行模式下的 :q 退出

可視模式

前面的筆記有幾個地方涉及到了可視模式

可視模式下的操作可謂是簡化版的命令模式/正常模式了,顯而易見,「簡化」的就是「選擇文本」的操作了。


在高光選擇了文本後可以進行以下操作:

  • 拷剪粘三件套

    cutYankPaste-2022-04-23

    這裡和命令模式/正常模式的不同之處就在於文本已經選擇完畢,只需要輸入一個指令就可以完成簡單的編輯操作。

    • y 輸入一次即可拷貝選擇的文本,而Y則是拷貝所有選擇文本所在的行Yank

    • d 輸入一次即可剪切選擇的文本D也是會剪切所有選擇文本所在的行的。(Delete

    • xd操作一致 (給文本畫叉叉)

    • cd操作一樣,不過剪切完之後會進入插入模式

    • p 在選擇的區域中粘貼文本Paste

  • 替換

    r<字元> 將所選文本替換為<字元>Replace )

    visualReplace-2022-04-23

    👆 ra將所選塊文本全部替換為了a

  • 行連接

    這一部分和命令模式/正常模式下的行連接指令幾乎是一樣了。

    • J 將所選文本對應的行連接成一行,用空格間隔Join

      spaceJoinedRow-2022-04-23

    • gJ 將所選文本對應的行連接成一行,沒有間隔

      directlyJoinedRow-2022-04-23

  • 執行末行模式/命令行模式指令

    在可視模式下選擇文本後輸入 : 進入末行模式,會自動填充成 :'<,'>,這代表在所選文字中進行末行語句操作

    之前的搜索替換中就有提到過:基本搜索替換->作用範圍

  • 程式碼縮進

    命令模式/正常模式下要對一行程式碼進行縮進操作,往往需要輸入兩次><

    而在可視模式下只需要輸入一次:

    visuallyIndent-2022-04-23

    👆 > 將所選文本增加一次縮進

    visuallyIndent2-2022-04-23

    👆 < 將所選文本減少一次縮進(因為選擇不完全,只減少了一部分)

    visuallyIndent3-2022-04-23

    👆 > 將所選文本增加2次縮進

  • 大小寫轉換

    這一部分和命令模式/正常模式下的大小寫轉換指令是很類似的:

    • u 將所選文本轉換為小寫

    • U 將所選文本轉換為大寫UPPERCASE

    • ~ 將所選文本中的大寫小寫分別轉換為小寫大寫

    caseSwitchInVisualMode-2022-04-23

    👆 演示了一下使用~進行大小寫轉換

可視模式還有很多用法,這裡就不再寫更多了(再寫更多就成語法手冊了喂!)

In the end

回過頭來…我又寫了這麼長一篇筆記…稍後我會完善一下目錄功能以增加閱讀體驗。

這篇筆記雖然寫得多,但是涉及的內容實際上還是比較淺層的,畢竟這篇筆記主要目的是為了記憶常用方法。也就是說,Vi/Vim的使用技巧遠不止這麼一點,更多高級的操作還需日常多加使用才能更加熟練!

因個人能力極其有限,可能文章中會出現部分錯誤。如果有寫錯的地方,也請大家多指教!

最後…感謝你讀到這裡,再會~

bye-2022-04-23

Tags: