實踐中學習vim之按鍵序列映射

來源:互聯網
上載者:User

【術語說明】

本文對於vim中所有能引起動作的字元序列統稱為“命令”,這不僅僅包含以:開頭的命令列模式下的命令,也包括其他模式下的按鍵序列。

【注意】

由於vim各個部分相互關聯緊密,簡單起見,本文中描述時不會完全考慮與之相聯絡的其他主題,由此會造成不準確的描述。

1 vim每時每刻都工作於某一模式下

Vim採用了“不同模式”設計思想,它擁有很多模式,常見的是 normal(一般模式),insert(插入模式),visual(可視模式),command(命令列模式),replace(替換模式)。

不同模式之間相互隔離,這也是這種設計方法的最大優點。這樣就可以做到不同模式下使用相同的命令名稱而不衝突。

2 vim中一切輸入都是命令與其他編輯器不同,vim中所有的按鍵序列都可能是命令,即使是在insert模式下仍然成立。比如在插入模式下,使用者通過鍵盤輸入了a這個字元,vim首先識別使用者輸入的字元是否是已經定義的命令,如果不是則原樣插入到緩衝區中。
vim中使用者輸入的基本處理流程為:(1)使用者輸入(2)vim識別使用者輸入是否是命令名稱,如果是則(3),如果不是則(4)(3)執行這條命令,轉到(5)(4)預設動作(對於,插入模式就是把輸入插入到緩衝區,對於其他模式則不進行任何操作)(5)完成本次輸入3 vim內建命令和使用者定義的命令3.1 vim在各個模式下都有內建命令,insert模式是個例外不同的模式下,vim都內建了一些必不可少的命令。如normal模式下大家熟悉的移動游標命令j、k、h、l,刪除一行的命令dd,粘貼命令p等;命令列模式下的寫入檔案命令:w,退出命令:q,尋找命令/something等;有一些內建命令能夠工作在多個模式下,如複製命令yy技能在normal模式下工作,也能在visual模式下工作。比較特殊的是,在insert模式下,vim幾乎沒有什麼內建命令,也許原樣插入就是insert模式下最重要的功能了。3.2 使用者自訂命令是vim的強大所在除了內建的命令,vim一開始就支援使用者自訂命令,這正是vim之所以能成為vim的原因。針對不同模式,vim提供了兩種自訂方式:針對命令列模式,使用:command 進行定義;針對其他模式,使用:map 進行定義。本文中,我們只描述了:map這種方式。3.2.1插入模式下自訂命令的小例子先來個小例子。前面說過,vim的insert模式下,好像沒有內建的命令。所以我們首先拿它開刀,自訂一個insert模式下的命令。在vim中輸入如下: :imap tks thanks 【說明】其中i表示insert模式,map標識映射,tks是自訂使用者命令名,thanks是映射到的命令名或字元序列。
然後在insert模式下輸入tks,看看效果。我們會看到的現象是:(1)當輸入t後,游標仍然在t下面,而沒有移動到t後面;(2)當繼續輸入k後,k出現在t的位置上,t被覆蓋,游標仍然不移動;(3)當繼續輸入s後,thanks出現在輸入的位置上,游標移動到後面。3.2.2 執行過程分析下面,分析一下這個過程:(1)當輸入t後,vim會識別到t是使用者自訂命令tks的開頭,但此時不能斷定使用者像輸入的是tks命令,所以繼續等待後續輸入進行進一步判斷;(2)當繼續輸入k後,vim識別到目前使用者輸入的tk是命令tks的一部分,但此時仍不能斷定使用者的意圖,所以繼續等待後續輸入;(3)當繼續輸入s後,vim識別到目前使用者輸入的tks就是命令tks,所以執行這個命令,這個命令的動作是把輸入thanks這個序列;(4)vim繼續識別thanks是否是個命令的名稱,由於沒有名為thanks的命令,所以原樣把thanks插入緩衝區,重新整理輸出顯示,使用者看到了thanks這幾個字元。3.2.3 死迴圈的問題可以看出,map完成的命令映射的功能,即把一個命令映射為另一個命令或字元序列。另外,map會遞迴進行,也就是說如果映射結果是個命令,則繼續執行這個結果命令。如下 :imap a b :imap b c 然後在insert模式下輸入a,得到輸出結果不是b,而是c。這種方式會帶來經典的死迴圈問題,如下: :imap a b :imap b c :imap c a 好在vim自身能夠識別這種死迴圈,會提示E223: recursive mapping。但是實際工作中,一定要注意避免這種死迴圈的出現。vim也為我們提供了避免的方式,那就是:noremap命令,如下: :inoremap a b :inoremap b c :inoremap c a 使用:noremap進行映射時,映射結果會直接當作字串輸出,不在當作命令來解釋。所以上述映射的結果是,輸入a得到的是b,輸入b得到的是c,輸入c得到的是a。3.2.4 命令名最左最長原則定義如下兩個命令。 :imap a oneA :imap aa twoA 那麼當我們輸入aa的時候,vim會把aa解釋成一個aa命令呢,還是兩個a命令呢?實驗證明,vim採用了長度優先的原則,當輸入一個a後,vim不能確定使用者的意圖,只能等待,當繼續輸入的字元還是a時,此時vim已經能夠確定使用者輸入的就是aa命令(因為不存在以aa開頭的其他命令了),所以執行aa命令,輸出twoA,如果使用者輸入的第二個字元不是a,那麼vim也能夠確定使用者輸入的就是a命令,所以會輸出oneA然後輸出使用者輸入的第二個字元。實際工作中盡量不要讓不同的命令有相同的起始部分,以提高vim的反應速度。
4 映射操作需要注意的其他問題前面討論的映射執行過程,死迴圈問題,命令名最長原則,適用於所有模式下的自訂命令。下面探討幾個其他需要注意的問題。4.1 特殊按鍵的表示進行映射時,經常需要對特殊按鍵進行使用,如功能鍵F1-F12,Ctrl, Alt, Enter等等。vim為方便使用者,提供了便捷的表示方法,如<F1>表示F1鍵,<CR>表示斷行符號鍵,<Esc>表示Esc鍵。詳細列表,請參考vim協助線上手冊。舉一個小例子,在normal模式下,按下F2鍵,會在當前行的下一行輸入hello並返回normal模式。 :nmap <F2> ohello<Esc> 【解釋】o建立一行,並進入insert模式,hello直接插入,<Esc>返回normal模式。
4.2 命令執行次數對自訂命令同樣適用例如,在normal模式下,輸入10然後按下F2鍵,則會輸入10行hello。
4.3 盡量不要在insert模式下定義命令儘管前面的例子中使用imap定義了insert模式下的自訂命令,但是這是個不好的做法,因為insert模式本來就應該是原樣完成輸入,否則會讓使用者感到不舒服。同樣的功能,完全可以在normal模式下自訂命令來完成。
4.4 盡量不要覆蓋內建命令vim採用的是後來者居上的方式,後定義的同名命令可以覆蓋掉先定義的同名命令,就連內建命令也可以被覆蓋。如: :nmap j <Nop> 之後,導航用的j就會失效。雖然vim為使用者提供了無限自訂的權利,但是保持基本的內建命令的一致性是vim使用者之間交流的基礎。所以,不要覆蓋內建命令!否則,vim將會面目全非!4.4 其他映射相關操作(1)查看已經有的自訂命令使用不帶參數的map類命令,如查看一般模式下的現有自訂命令: :nmap (2)刪除自訂命令,使用unmap類命令,如刪除前面定義的j: :nunmap j 之後,j又可以完成內建的導航功能了。 mapclear類命令則會刪除所有的自訂命令,如刪除insert模式下所有的自訂命令: :imapclear
4.5 其他未盡事宜命令作用範圍不僅受模式的影響,也受緩衝區buffer的影響,定義在一個緩衝區中的命令,在另一個緩衝區中不起作用。自訂命令還可以調用內建函數和使用者自訂函數,這將在“自訂命令列模式下的命令”時再做分析。自訂命令不僅能以互動方式進行,還可以寫入vim的設定檔或外掛程式檔案中(也許這才是更有用的方式)。編寫vim外掛程式本身就是一個很大的主題。本文僅僅是vim自訂命令的一個簡單入門指引,如果能給讀者帶來一點受益,那就謝天謝地了。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.