Map (對應)

Nvim 的 :help 頁面,使用 tree-sitter-vimdoc 解析器,從 原始碼 產生


按鍵對應、縮寫和使用者定義的命令。
本主題在使用者手冊的 05.324.740.1 節中介紹。

1. 按鍵對應 mapping 巨集

按鍵對應用於更改輸入按鍵的意義。最常見的用途是為功能鍵定義一系列命令。範例:
:map <F2> a<C-R>=strftime("%c")<CR><Esc>
這會在游標後附加目前的日期和時間(在 <> 符號表示中 <>)。

1.1 MAP 命令 :map-commands

有一些命令可以輸入新的對應、移除對應和列出對應。請參閱 map-overview 了解各種「map」形式及其與模式的關係。
{lhs} 表示左手邊 {lhs}{rhs} 表示右手邊 {rhs}
:map {lhs} {rhs} mapmode-nvo :map
:nm[ap] {lhs} {rhs} mapmode-n :nm :nmap :vm[ap] {lhs} {rhs} mapmode-v :vm :vmap :xm[ap] {lhs} {rhs} mapmode-x :xm :xmap :smap {lhs} {rhs} mapmode-s :smap
:om[ap] {lhs} {rhs} mapmode-o :om :omap :map! {lhs} {rhs} mapmode-ic :map!
:im[ap] {lhs} {rhs} mapmode-i :im :imap :lm[ap] {lhs} {rhs} mapmode-l :lm :lma :lmap :cm[ap] {lhs} {rhs} mapmode-c :cm :cmap :tma[p] {lhs} {rhs} mapmode-t :tma :tmap 將按鍵序列 {lhs} 對應到 {rhs},用於 map 命令適用的模式。然後,結果(包括 {rhs})會被進一步掃描以尋找對應。這允許對應的巢狀和遞迴使用。注意:尾隨空格會包含在 {rhs} 中,因為空格是有效的 Normal 模式命令。請參閱 map-trailing-white
:nore :norem :no[remap] {lhs} {rhs} mapmode-nvo :no :noremap :nor :nn[oremap] {lhs} {rhs} mapmode-n :nn :nnoremap :vn[oremap] {lhs} {rhs} mapmode-v :vn :vnoremap :xn[oremap] {lhs} {rhs} mapmode-x :xn :xnoremap :snor[emap] {lhs} {rhs} mapmode-s :snor :snore :snoremap :ono[remap] {lhs} {rhs} mapmode-o :ono :onoremap :no[remap]! {lhs} {rhs} mapmode-ic :no! :noremap! :ino[remap] {lhs} {rhs} mapmode-i :ino :inor :inoremap :ln[oremap] {lhs} {rhs} mapmode-l :ln :lnoremap :cno[remap] {lhs} {rhs} mapmode-c :cno :cnor :cnoremap :tno[remap] {lhs} {rhs} mapmode-t :tno :tnoremap 將按鍵序列 {lhs} 對應到 {rhs},用於 map 命令適用的模式。禁止對 {rhs} 進行對應,以避免巢狀和遞迴對應。通常用於重新定義命令。注意:{rhs} 中的按鍵也不會觸發縮寫,除了 i_CTRL-]c_CTRL-] 以外。注意:<Plug> 出現在 {rhs} 中時,即使禁止重新對應,這部分也始終會應用。
:unm[ap] {lhs} mapmode-nvo :unm :unmap :nun[map] {lhs} mapmode-n :nun :nunmap :vu[nmap] {lhs} mapmode-v :vu :vunmap :xu[nmap] {lhs} mapmode-x :xu :xunmap :sunm[ap] {lhs} mapmode-s :sunm :sunmap :ou[nmap] {lhs} mapmode-o :ou :ounmap :unm[ap]! {lhs} mapmode-ic :unm! :unmap! :iu[nmap] {lhs} mapmode-i :iu :iunmap :lu[nmap] {lhs} mapmode-l :lu :lunmap :cu[nmap] {lhs} mapmode-c :cu :cun :cunmap :tunma[p] {lhs} mapmode-t :tunma :tunmap 移除 map 命令適用的模式中 {lhs} 的對應。該對應可能在其他適用的模式中仍然定義。當 {lhs} 符合對應的 {rhs} 時也有效。這用於縮寫應用時。注意:尾隨空格會包含在 {lhs} 中。請參閱 map-trailing-white
:mapc[lear] mapmode-nvo :mapc :mapclear :nmapc[lear] mapmode-n :nmapc :nmapclear :vmapc[lear] mapmode-v :vmapc :vmapclear :xmapc[lear] mapmode-x :xmapc :xmapclear :smapc[lear] mapmode-s :smapc :smapclear :omapc[lear] mapmode-o :omapc :omapclear :mapc[lear]! mapmode-ic :mapc! :mapclear! :imapc[lear] mapmode-i :imapc :imapclear :lmapc[lear] mapmode-l :lmapc :lmapclear :cmapc[lear] mapmode-c :cmapc :cmapclear :tmapc[lear] mapmode-t :tmapc :tmapclear 移除 map 命令適用的模式的 **所有** 對應。使用 <buffer> 參數來移除緩衝區區域對應 :map-<buffer>警告:這也會移除 預設對應
:map mapmode-nvo :nm[ap] mapmode-n :vm[ap] mapmode-v :xm[ap] mapmode-x :sm[ap] mapmode-s :om[ap] mapmode-o :map! mapmode-ic :im[ap] mapmode-i :lm[ap] mapmode-l :cm[ap] mapmode-c :tma[p] mapmode-t 列出 map 命令所適用模式的所有按鍵對應。請注意,":map" 和 ":map!" 最常用,因為它們包含其他模式。
:map {lhs} mapmode-nvo :map_l
:nm[ap] {lhs} mapmode-n :nmap_l
:vm[ap] {lhs} mapmode-v :vmap_l
:xm[ap] {lhs} mapmode-x :xmap_l
:sm[ap] {lhs} mapmode-s :smap_l
:om[ap] {lhs} mapmode-o :omap_l
:map! {lhs} mapmode-ic :map_l!
:im[ap] {lhs} mapmode-i :imap_l
:lm[ap] {lhs} mapmode-l :lmap_l
:cm[ap] {lhs} mapmode-c :cmap_l
:tma[p] {lhs} mapmode-t :tmap_l
列出在 map 命令適用的模式中,以 {lhs} 開頭的按鍵序列的按鍵對應。
這些命令用於將一個按鍵或按鍵序列對應到一個字串。您可以使用它將命令序列放在功能鍵下、將一個按鍵轉換為另一個按鍵等。請參閱 :mkexrc 了解如何儲存和還原目前的按鍵對應。
map-ambiguous
當兩個按鍵對應以相同的字元序列開頭時,它們會產生歧義。範例
:imap aa foo
:imap aaa bar
當 Vim 讀取 "aa" 時,它需要取得另一個字元,才能決定應該對應 "aa" 還是 "aaa"。這表示在輸入 "aa" 後,該對應不會立即展開,Vim 會等待另一個字元。如果您輸入一個空格,則會插入 "foo" 以及該空格。如果您輸入 "a",則會插入 "bar"。
尾隨空白
map-trailing-white
這個取消對應命令不起作用
:map @@ foo
:unmap @@ | print
因為它嘗試取消對應 "@@ ",包括命令分隔符 "|" 之前的空白。其他帶有尾隨空白的範例
unmap @@ 
unmap @@     " comment
會發出錯誤,但很難識別,因為 unmap @@ 中的尾隨空白字元是不可見的。
一個通用的解決方案是將命令分隔符 "|" 放在已對應的按鍵之後。之後可以接著空白和註解
unmap @@|    " comment

1.2 特殊引數 :map-arguments

"<buffer>"、"<nowait>"、"<silent>"、"<script>"、"<expr>" 和 "<unique>" 可以以任何順序使用。它們必須出現在命令之後、任何其他引數之前。
:map-local :map-<buffer> :map-buffer E224 E225 如果這些命令的其中一個的第一個引數是 "<buffer>",則該對應僅在目前的緩衝區中有效。範例
:map <buffer>  ,w  /[.,;]<CR>
然後您可以在另一個緩衝區中將 ",w" 對應到其他內容
:map <buffer>  ,w  /[#&!]<CR>
會先使用本機緩衝區對應,然後才是全域對應。請參閱下方的 <nowait>,以避免當存在較長的全域對應時,短的本機對應生效。"<buffer>" 引數也可以用於清除對應
:unmap <buffer> ,w
:mapclear <buffer>
當刪除緩衝區時,也會清除本機對應,但不會在卸載時清除。就像本機選項值一樣。另請參閱 map-precedence
:map-<nowait> :map-nowait 當為 "," 定義緩衝區本機對應時,可能會存在以 "," 開頭的全域對應。然後您需要輸入另一個字元,Vim 才知道是使用 "," 對應還是較長的對應。若要避免這種情況,請加入 <nowait> 引數。然後會在符合對應時使用該對應,Vim 不會等待輸入更多字元。但是,如果已輸入字元,則會使用這些字元。請注意,當 <nowait> 對應完全符合,且在任何部分符合之前找到時,此方式會運作。這會在以下情況下運作
只有一個符合的緩衝區本機對應,因為這些對應總是在全域對應之前找到。
存在另一個部分符合的緩衝區本機對應,但它定義得較早(最後定義的對應會先找到)。
:map-<silent> :map-silent 若要定義一個不會在命令列上回顯的對應,請加入 "<silent>" 作為第一個引數。範例
:map <silent> ,h /Header<CR>
使用此對應時不會回顯搜尋字串。不過,仍會顯示執行命令的訊息。若要也關閉這些訊息,請在執行命令中加入 ":silent"
:map <silent> ,h :exe ":silent normal /Header\r"<CR>
請注意,命令的效果也可能會被靜音,例如,當對應為命令列完成選擇另一個項目時,不會顯示它。仍會顯示提示,例如,用於 inputdialog()。可以為縮寫使用 "<silent>",但會導致命令列的重繪失敗。
:map-<script> :map-script 如果這些命令的其中一個的第一個引數是 "<script>",並且它用於定義新的對應或縮寫,則該對應只會使用以 "<SID>" 開頭的腳本本機定義的對應來重新對應 {rhs} 中的字元。這可用於避免腳本外部的對應干擾(例如,當在 mswin.vim 中重新對應 CTRL-V 時),但會使用腳本中定義的其他對應。注意:":map <script>" 和 ":noremap <script>" 會執行相同的動作。 "<script>" 會覆寫命令名稱。最好使用 ":noremap <script>",因為這樣更清楚表示已(大部分)停用重新對應。
:map-<unique> :map-unique E226 E227 如果這些命令的其中一個的第一個引數是 "<unique>",並且它用於定義新的對應或縮寫,則如果對應或縮寫已存在,命令將會失敗。範例
:map <unique> ,w  /[#&!]<CR>
定義本機對應時,也會檢查是否存在相等的全域對應。以下是將失敗的範例
:map ,w  /[#&!]<CR>
:map <buffer> <unique> ,w  /[.,;]<CR>
如果您想要對應一個按鍵,然後讓它執行原本對應的動作,請查看 maparg()
:map-<expr> :map-expression 如果這些命令的其中一個的第一個引數是 "<expr>",並且它用於定義新的對應或縮寫,則該引數會是一個運算式。會評估該運算式以取得所使用的 {rhs}。範例
:inoremap <expr> . <SID>InsertDot()
會插入 s:InsertDot() 函數的結果。它可以檢查游標之前的文字,並在符合某些條件時啟動 omni 完成。最好使用腳本本機函數,以避免污染全域命名空間。在 RHS 中使用 <SID>,以便可以找到定義對應的腳本。
對於縮寫,v:char 會設定為觸發縮寫所輸入的字元。您可以使用它來決定如何展開 {lhs}。您不應該插入或變更 v:char。
如果您希望對應不做任何動作,您可以讓運算式評估為空字串。如果發生需要 Vim 執行主迴圈的變更(例如,更新顯示),請傳回 "\<Ignore>"。這與「無」類似,但會使 Vim 從等待輸入的迴圈中返回。
請記住,運算式可能會在尋找預輸入時進行評估,在執行先前的命令之前。例如
func StoreColumn()
  let g:column = col('.')
  return 'x'
endfunc
nnoremap <expr> x StoreColumn()
nmap ! f!x
您會注意到 g:column 的值是執行 "f!" 之前的值,因為會在執行 "f!" 之前評估 "x"。這可以透過在運算式對應的字元之前插入 <Ignore> 來解決
nmap ! f!<Ignore>x
請務必小心副作用!運算式會在取得字元時進行評估,您很可能會使命令無法運作。因此,會封鎖 <expr> 對應的下列項目
變更緩衝區文字 textlock
編輯另一個緩衝區。
:normal 命令。
允許移動游標,但之後會還原游標。
如果變更了 cmdline,則會還原舊文字和游標位置。如果您希望對應執行這些操作中的任何一個,請讓傳回的字元執行該操作,或改用 <Cmd> 對應。
您可以使用 getchar(),如果有的話,它會取用預輸入。例如,如果您有這些對應
inoremap <expr> <C-L> nr2char(getchar())
inoremap <expr> <C-L>x "foo"
如果您現在輸入 CTRL-L,則不會發生任何事情,Vim 需要下一個字元才能決定要使用哪個對應。如果您輸入 'x',則會使用第二個對應並插入 "foo"。如果您輸入任何其他按鍵,則會使用第一個對應,getchar() 會取得輸入的按鍵並傳回它。
以下是一個範例,會插入一個會增加的清單編號
let counter = 0
inoremap <expr> <C-L> ListItem()
inoremap <expr> <C-R> ListReset()
func ListItem()
  let g:counter += 1
  return g:counter .. '. '
endfunc
func ListReset()
  let g:counter = 0
  return ''
endfunc
CTRL-L 會插入下一個數字,CTRL-R 會重設計數。CTRL-R 會傳回空字串,因此不會插入任何內容。
請注意,在其他文字之前使用 0x80 作為單一位元組不會運作,它會被視為特殊按鍵。
<Cmd> :map-cmd <Cmd> 偽按鍵會開始一個「命令對應」,它會直接執行命令而不改變模式。當你在對應的 {rhs} 中可能會使用 ":...<CR>" 時,你可以改用 "<Cmd>...<CR>"。範例:
noremap x <Cmd>echo mode(1)<CR>
這比在 Visual 和 Operator-pending 模式中使用 :<C-U>,或在 Insert 模式中使用 <C-O>: 更靈活,因為命令會直接在目前模式中執行,而不是總是跳到 Normal 模式。Visual 模式會被保留,因此不需要使用 gv 的技巧。命令可以直接在 Command-line 模式中調用(否則需要使用計時器 hacks)。在 Insert 模式中途使用 <Cmd> 的範例:
nnoremap <F3> aText <Cmd>echo mode(1)<CR> Added<Esc>
<expr> 對應不同,<Cmd> 命令沒有特殊限制:它的執行方式如同調用了(無限制的)自動命令或處理了非同步事件。
注意
由於 <Cmd> 避免了模式更改(與 ":" 不同),它不會觸發 CmdlineEnterCmdlineLeave 事件。這有助於提升效能。
基於相同原因,像是 <C-R><C-W>按鍵碼 會被解釋為單純、未對應的按鍵。
命令不會被 echo,不需要 <silent>
{rhs} 不受縮寫或其他對應影響,即使對應是遞迴的。
在 Visual 模式中,你可以使用 line('v')col('v') 來取得 Visual 區域的一端,游標在另一端。
E1255 E1136 <Cmd> 命令必須終止,也就是說,它們在對應定義的 {rhs} 中必須跟著 <CR>命令列模式永遠不會進入。要在 {rhs} 中使用字面意義的 <CR>,請使用 <lt>
有七組對應:
Normal 模式:當輸入命令時。
Visual 模式:當在 Visual 區域被選取時輸入命令。
Select 模式:與 Visual 模式類似,但輸入文字會取代選取範圍。
Operator-pending 模式:當運算符處於等待狀態時(在 "d"、"y"、"c" 等之後)。請參閱下方:omap-info
Insert 模式。這些也會在 Replace 模式中使用。
Command-line 模式:當輸入 ":" 或 "/" 命令時。
Terminal 模式:當在 :terminal 緩衝區中輸入時。
特殊情況:當在 Normal 模式中輸入命令的計數時,對應零會被停用。這使得對應零成為可能,而不會使輸入帶有零的計數變得不可能。
map-overview map-modes 哪個 map 命令在哪些模式中生效的概述。更多細節請見下方。
命令 模式
:map :noremap :unmap Normal、Visual、Select、Operator-pending :nmap :nnoremap :nunmap Normal :vmap :vnoremap :vunmap Visual 和 Select :smap :snoremap :sunmap Select :xmap :xnoremap :xunmap Visual :omap :onoremap :ounmap Operator-pending :map! :noremap! :unmap! Insert 和 Command-line :imap :inoremap :iunmap Insert :lmap :lnoremap :lunmap Insert、Command-line、Lang-Arg :cmap :cnoremap :cunmap Command-line :tmap :tnoremap :tunmap Terminal
相同資訊以表格呈現:map-table
模式 | Norm | Ins | Cmd | Vis | Sel | Opr | Term | Lang |
命令 +------+-----+-----+-----+-----+-----+------+------+
[nore]map | yes | - | - | yes | yes | yes | - | - | n[nore]map | yes | - | - | - | - | - | - | - | [nore]map! | - | yes | yes | - | - | - | - | - | i[nore]map | - | yes | - | - | - | - | - | - | c[nore]map | - | - | yes | - | - | - | - | - | v[nore]map | - | - | - | yes | yes | - | - | - | x[nore]map | - | - | - | yes | - | - | - | - | s[nore]map | - | - | - | - | yes | - | - | - | o[nore]map | - | - | - | - | - | yes | - | - | t[nore]map | - | - | - | - | - | - | yes | - | l[nore]map | - | yes | yes | - | - | - | - | yes |
命令 模式
Normal Visual+Select Operator-pending
:map :noremap :unmap :mapclear yes yes yes :nmap :nnoremap :nunmap :nmapclear yes - - :vmap :vnoremap :vunmap :vmapclear - yes - :omap :onoremap :ounmap :omapclear - - yes
:nunmap 也可以在修道院外使用。mapmode-x mapmode-s 有些命令在 Visual 和 Select 模式下都有效,有些則只在其中一種模式下有效。請注意,在同時適用 Visual 和 Select 模式的情況下,經常會提到「Visual」。 Select-mode-mapping 注意: 在 Select 模式中對應可列印字元可能會讓使用者感到困惑。最好明確地為可列印字元使用 :xmap 和 :smap。或者在定義對應後使用 :sunmap。
命令 模式
Visual Select
:vmap :vnoremap :vunmap :vmapclear yes yes :xmap :xnoremap :xunmap :xmapclear yes - :smap :snoremap :sunmap :smapclear - yes
mapmode-ic mapmode-i mapmode-c mapmode-l 有些命令在 Insert 模式和 Command-line 模式下都有效,有些則不然。
命令 模式
Insert Command-line Lang-Arg
:map! :noremap! :unmap! :mapclear! yes yes - :imap :inoremap :iunmap :imapclear yes - - :cmap :cnoremap :cunmap :cmapclear - yes - :lmap :lnoremap :lunmap :lmapclear yes* yes* yes*
* 如果 'iminsert' 為 1,請參閱下方的 language-mapping
原始的 Vi 沒有為 Normal/Visual/Operator-pending 模式和 Insert/Command-line 模式分別設定對應。因此,":map" 和 ":map!" 命令會輸入和顯示多種模式的對應。在 Vim 中,你可以使用 ":nmap"、":vmap"、":omap"、":cmap" 和 ":imap" 命令來為每個模式分別輸入對應。
omap-info
Operator-pending 對應可用於定義一個移動命令,該命令可以與任何運算符一起使用。簡單範例:
:omap { w
使得 "y{" 的運作方式如同 "yw",而 "d{" 的運作方式如同 "dw"。
若要忽略起始游標位置並選取不同的文字,你可以讓 omap 開始 Visual 模式以選取要操作的文字。範例,操作目前行中的函數名稱:
onoremap <silent> F :<C-U>normal! 0f(hviw<CR>
CTRL-U<C-U>)用於移除 Vim 可能插入的範圍。Normal 模式命令會找到第一個 '(' 字元並選取它之前的第一個單字。這通常是函數名稱。
要為 Normal 和 Visual 模式輸入對應,但不是 Operator-pending 模式,請先為所有三種模式定義它,然後取消 Operator-pending 模式的對應:
:map    xx something-difficult
:ounmap xx
同樣地,適用於 Visual 和 Operator-pending 模式,或 Normal 和 Operator-pending 模式的對應。
language-mapping
":lmap" 定義一個適用於以下的對應:
Insert 模式
Command-line 模式
當輸入搜尋模式時
接受文字字元的命令的參數,例如 "r" 和 "f"
對於 input() 行。一般來說:當要輸入的字元是緩衝區中文字的一部分,而不是 Vim 命令字元時。"Lang-Arg" 並不是真的另一種模式,它只是在這裡用於這種情況。載入一組相關語言對應的最簡單方法是使用 'keymap' 選項。請參閱 45.5。在 Insert 模式和 Command-line 模式中,可以使用 CTRL-^ 命令停用對應 i_CTRL-^ c_CTRL-^。這些命令會更改 'iminsert' 選項的值。當開始輸入一般命令列(不是搜尋模式)時,對應會被停用,直到輸入 CTRL-^ 為止。上次使用的狀態會分別針對 Insert 模式和搜尋模式記住。當輸入字元作為 "f" 或 "t" 等命令的參數時,也會使用 Insert 模式的狀態。語言對應永遠不會應用於已對應的字元。它們僅用於輸入的字元。這假設在輸入對應時已經完成了語言對應。相對地,語言對應會在錄製巨集時應用,而不是在應用它們時應用。

1.4 列出對應 map-listing

當列出對應時,前兩欄中的字元是:
字元 模式
<Space> Normal、Visual、Select 和 Operator-pending n Normal v Visual 和 Select s Select x Visual o Operator-pending ! Insert 和 Command-line i Insert l ":lmap" 對於 Insert、Command-line 和 Lang-Arg 的對應 c Command-line t Terminal-Job
{rhs} 之前可能會出現一個特殊字元:* 表示它不可重新對應 & 表示只有腳本本機對應可重新對應 @ 表示緩衝區本機對應
{lhs} 之後的第一個非空白字元到該行結尾(或 '|')的所有內容都被視為 {rhs} 的一部分。這允許 {rhs} 以空格結尾。
注意: 當使用 Visual 模式的對應時,你可以使用 "'<" 標記,它是目前緩衝區中上次選取的 Visual 區域的起點 '<
:filter 命令可用於選取要列出的對應。該模式會針對原始格式的 {lhs}{rhs} 進行比對。如果使用 nvim_set_keymap()nvim_buf_set_keymap() 新增了描述,則該模式也會針對它進行比對。
:map-verbose
'verbose' 不為零時,列出按鍵對應也會顯示它上次定義的位置。範例:
:verbose map <C-W>*
n  <C-W>*      * <C-W><C-S>*
        Last set from ~/.config/nvim/init.vim
更多資訊請參閱 :verbose-cmd

1.5 對應特殊按鍵 :map-special-keys

要對應功能鍵,請使用其內部代碼。要輸入此類對應,請輸入 CTRL-K,然後按下功能鍵,或使用 "<F2>"、"<F10>"、"<Up>"、"<S-Down>"、"<S-F7>" 等形式(請參閱按鍵的表格 key-notation,可以使用 <Up> 的所有按鍵)。

1.6 特殊字元 :map-special-chars

map_backslash map-backslash 請注意,這裡只提到 CTRL-V 作為映射和縮寫的特殊字元。當 'cpoptions' 不包含 'B' 時,反斜線也可以像 CTRL-V 一樣使用。此時可以完整使用 <> 符號 <>。但是你不能像 CTRL-V 那樣使用 "<C-V>" 來跳脫後續內容的特殊含義。
若要映射反斜線,或在 {rhs} 中使用反斜線字面值,可以使用特殊序列 "<Bslash>"。這可以避免在使用巢狀映射時需要使用雙反斜線的情況。
map_CTRL-C map-CTRL-C{lhs} 中使用 CTRL-C 是可行的,但只有在 Vim 等待按鍵時才會生效,當 Vim 忙於其他事情時則不會。當 Vim 忙碌時,CTRL-C 會中斷/打斷命令。當在 MS-Windows 上使用 GUI 版本時,可以將 CTRL-C 映射為允許複製命令到剪貼簿。使用 CTRL-Break 來中斷 Vim。
map_space_in_lhs map-space_in_lhs 若要在 {lhs} 中包含空格,請在其前面加上 CTRL-V (每個空格輸入兩次 CTRL-V)。 map_space_in_rhs map-space_in_rhs 如果你希望 {rhs} 以空格開頭,請使用 "<Space>"。為了完全相容 Vi (但可讀性不佳),請不要使用 <> 符號,在 {rhs} 前面加上單個 CTRL-V (你必須輸入兩次 CTRL-V)。 map_empty_rhs map-empty-rhs 你可以在輸入單個 CTRL-V 後不輸入任何內容 (你必須輸入兩次 CTRL-V) 來建立空的 {rhs}。不幸的是,你無法在 vimrc 檔案中執行此操作。 <Nop> 一個更容易獲得不產生任何動作的映射的方法,是將 "<Nop>" 用於 {rhs}。例如,若要停用功能鍵 8
:map  <F8>  <Nop>
:map! <F8>  <Nop>
map-multibyte
可以映射多位元組字元,但只能映射整個字元。你不能只映射第一個位元組。這樣做是為了防止在以下情況下發生問題
:set encoding=latin1
:imap <M-C> foo
:set encoding=utf-8
<M-C> 的映射使用 latin1 編碼定義,產生 0xc3 位元組。如果你在 UTF-8 編碼中輸入字元 á (0xe1 <M-a>),則它是兩個位元組 0xc3 0xa1。你不會希望 0xc3 位元組被映射,否則將無法輸入 á 字元。
<Leader> mapleader 若要定義使用 "g:mapleader" 變數的映射,可以使用特殊字串 "<Leader>"。它會被替換為 "g:mapleader" 的字串值。如果 "g:mapleader" 未設定或為空,則改用反斜線。範例
map <Leader>A  oanother line<Esc>
效果如同
map \A  oanother line<Esc>
但在
let mapleader = ","
之後,效果如同
map ,A  oanother line<Esc>
請注意,"g:mapleader" 的值是在定義映射時使用的。之後變更 "g:mapleader" 對於已定義的映射沒有影響。
<LocalLeader> maplocalleader <LocalLeader><Leader> 相同,不同之處在於它使用 "maplocalleader" 而不是 "mapleader"。<LocalLeader> 用於在緩衝區中為本地的映射。範例
:map <buffer> <LocalLeader>A  oanother line<Esc>
在全域外掛程式中應使用 <Leader>,而在檔案類型外掛程式中應使用 <LocalLeader>。"mapleader" 和 "maplocalleader" 可以相等。但是,如果你們讓它們不同,全域外掛程式的映射與檔案類型外掛程式的映射發生衝突的可能性會較小。例如,你可以將 "mapleader" 保留為預設的反斜線,並將 "maplocalleader" 設定為底線。
map-<SID>
在指令碼中,可以使用特殊按鍵名稱 "<SID>" 來定義指令碼本地的映射。請參閱 <SID> 以取得詳細資訊。
<Plug>
特殊按鍵名稱 "<Plug>" 可以用於內部映射,這不會與任何按鍵序列匹配。這在 使用-<Plug> 的外掛程式中很有用。
<MouseMove>
特殊按鍵名稱 "<MouseMove>" 可以用來處理滑鼠移動。它需要使用 'mousemoveevent' 來啟用。可以使用 getmousepos() 函數來取得滑鼠位置。
<Char> <Char-> 若要透過其十進位、八進位或十六進位數值來映射字元,可以使用 <Char> 結構:<Char-123> 字元 123 <Char-033> 字元 27 <Char-0x7f> 字元 127 <S-Char-114> 字元 114 ('r') shift 後 ('R') 這在 'keymap' 檔案中指定 (多位元組) 字元很有用。忽略大小寫差異。
map-comments
無法在這些命令之後放置註解,因為 " 字元被視為 {lhs}{rhs} 的一部分。但是,可以使用 |",因為這會以註解開始一個新的、空的命令。
map_bar map-bar 由於 '|' 字元用於將 map 命令與下一個命令分隔開來,因此你必須執行一些特殊操作才能在 {rhs} 中包含 '|'。有三種方法
use works when example
<Bar> always :map _l :!ls <Bar> more^M \| 'b' is not in 'cpoptions' :map _l :!ls \| more^M ^V| always :map _l :!ls ^V| more^M
(此處 ^V 代表 CTRL-V;若要取得一個 CTRL-V,你必須輸入兩次;你不能在此處使用 <> 符號 "<C-V>")。
當你使用 'cpoptions' 的預設設定時,這三種方法都有效。
當 'b' 出現在 'cpoptions' 中時,"\|" 將被識別為以 '\' 結尾的映射,然後是另一個命令。這與 Vi 相容,但與其他命令相比不合邏輯。
map_return map-return 當你的映射包含 Ex 命令時,需要在其後加上行終止符以執行它。建議使用 <CR> 來實現此目的 (請參閱 <>)。範例
:map  _ls  :!ls -l %:S<CR>:echo "the end"<CR>
若要避免映射你在插入或命令列模式中輸入的字元,請先輸入 CTRL-Vmap-error
請注意,當遇到錯誤 (導致錯誤訊息或可能導致嗶聲) 時,不會執行映射的其餘部分。這與 Vi 相容。
請注意,命令 @zZtTfF[]rm'`"v 和 CTRL-X 的第二個字元 (引數) 不會被映射。這樣做是為了能夠使用所有具名暫存器和標記,即使已映射同名的命令。

1.7 要映射哪些按鍵 map-which-keys

如果你要映射某些內容,你需要選擇要用於 {lhs} 的按鍵。你必須避免使用用於 Vim 命令的按鍵,否則你將無法再使用這些命令。以下是一些建議
功能鍵 <F2><F3> 等。以及 shift 後的功能鍵 <S-F1><S-F2> 等。請注意,<F1> 已用於說明命令。
Meta 鍵 (按下 ALT 鍵)。根據你的鍵盤,也可以使用帶重音符號的字元。 :map-alt-keys
使用 '_' 或 ',' 字元,然後使用任何其他字元。"_" 和 "," 命令在 Vim 中確實存在 (請參閱 _,),但你可能從未使用它們。
使用與其他命令同義的按鍵。例如:CTRL-PCTRL-N。使用額外的字元來允許更多映射。
<Leader> 和一個或多個其他按鍵定義的按鍵。這在指令碼中特別有用。 mapleader
請參閱檔案 "index",了解未使用的按鍵,因此可以在不遺失任何內建功能的情況下進行映射。你也可以使用 ":help {key}^D" 來找出按鍵是否用於某些命令。({key} 是你要查詢的特定按鍵,^D 是 CTRL-D)。

1.8 範例 map-examples

一些範例 (就像你輸入它們一樣:對於 "<CR>",你輸入四個字元)。
:map <F3>  o#include
:map <M-g> /foo<CR>cwbar<Esc>
:map _x    d/END/e<CR>
:map! qq   quadrillion questions
乘算計數
當你在觸發映射之前輸入計數時,就像計數是在 {lhs} 之前輸入的一樣。例如,使用此映射
:map <F4>  3w
輸入 2<F4> 將產生 "23w"。因此,不是移動 2 * 3 個單字,而是移動 23 個單字。如果要乘以計數,請使用表達式暫存器
:map <F4>  @='3w'<CR>
引號之間的部分是要執行的表達式。 @=

1.9 使用映射 map-typing

Vim 會將你輸入的內容與映射序列的開頭進行比較。如果有不完整的匹配,它會取得更多字元,直到有完整的匹配或根本沒有匹配為止。範例:如果你映射! "qq",第一個 'q' 不會在螢幕上顯示,直到你輸入另一個字元。這是因為 Vim 無法知道下一個字元是否為 'q'。如果 'timeout' 選項已啟用 (預設值),Vim 將只等待一秒鐘 (或使用 'timeoutlen' 選項指定的時間)。之後,它會假設 'q' 被解釋為這樣。如果你輸入速度緩慢,或系統速度緩慢,請重設 'timeout' 選項。然後你可能需要設定 'ttimeout' 選項。
map-precedence
緩衝區本機映射 (使用 :map-<buffer> 定義) 的優先順序高於全域映射。當緩衝區本機映射與全域映射相同時,Vim 將使用緩衝區本機映射。此外,如果使用 <nowait> 定義了完整的映射,即使較長的映射具有相同的前置詞,Vim 也會立即使用它。例如,假設有以下兩個映射
:map <buffer> <nowait> \a   :echo "Local \a"<CR>
:map                   \abc :echo "Global \abc"<CR>
當輸入 \a 時,將立即使用緩衝區本機映射。Vim 不會等待更多字元來查看使用者是否可能正在輸入 \abc。
map-keys-fails
在某些情況下,按鍵程式碼可能無法識別
Vim 只能讀取部分按鍵程式碼。大多數情況下,這只是第一個字元。這發生在某些 Unix 版本的 xterm 中。
按鍵程式碼在映射的字元之後。例如,"<F1><F1>" 或 "g<F1>"。
結果是按鍵程式碼在這種情況下無法識別,並且映射失敗。需要執行兩個動作來避免此問題
'cpoptions' 中移除 'K' 旗標。這將使 Vim 等待功能鍵的其餘字元。
當使用 <F1><F4> 時,產生的實際按鍵程式碼可能對應於 <xF1><xF4>。有從 <xF1><F1>、從 <xF2><F2> 等的映射,但在另一個半映射之後無法識別這些映射。請確保 <F1><F4> 的按鍵程式碼正確
:set <F1>=<type CTRL-V><type F1>
輸入 <F1> 時請使用四個字元。等號「=」後面的部分必須使用實際的按鍵輸入,而不是字面上的文字。另一種解決方案是在第二個特殊按鍵的對應中使用實際的按鍵代碼。
:map <F1><Esc>OP :echo "yes"<CR>
不要輸入真正的 <Esc>,Vim 會識別按鍵代碼,並將其替換為 <F1>
遞迴映射
如果將 {lhs} 包含在 {rhs} 中,則會產生遞迴映射。當輸入 {lhs} 時,它會被替換為 {rhs}。當遇到包含在 {rhs} 中的 {lhs} 時,它將被替換為 {rhs},依此類推。這使得無限次重複執行命令成為可能。唯一的問題是,停止此行為的唯一方法是導致錯誤。解決迷宮的巨集會使用此方法,請參考那裡的範例。有一個例外:如果 {rhs}{lhs} 開頭,則第一個字元不會再次映射(這與 Vi 相容)。例如
:map ab abcd
將執行 "a" 命令,並在文字中插入 "bcd" 。{rhs} 中的 "ab" 不會再次映射。
如果您想要交換兩個按鍵的含義,您應該使用 :noremap 命令。例如
:noremap k j
:noremap j k
這會交換游標向上和向下移動的命令。
使用一般的 :map 命令時,映射會持續進行,直到找到的文字不是 {lhs} 的一部分為止。例如,如果您使用
:map x y
:map y x
Vim 會將 x 替換為 y,然後將 y 替換為 x,依此類推。當這種情況發生 'maxmapdepth' 次(預設為 1000)時,Vim 會給出錯誤訊息「recursive mapping」(遞迴映射)。
:map-undo
如果您在映射的序列中包含一個 undo 命令,這會將文字還原到執行巨集之前的狀態。這與原始的 Vi 相容,只要映射的序列中只有一個 undo 命令(在映射的序列中有兩個 undo 命令在原始的 Vi 中沒有意義,您會回到第一個 undo 之前的文字)。

1.10 映射 ALT 鍵 :map-alt-keys

為了方便閱讀映射命令,可以使用 <A-k> 形式。請注意,<A-k><A-K> 是不同的,後者會使用大寫字母。實際上,<A-K><A-S-K> 是相同的。您可以使用 "M" 來代替 "A"。如果您有實際的 Meta 修飾鍵,請參閱 :map-meta-keys
在 GUI 中,Nvim 會自行處理 ALT 鍵,因此使用 ALT 映射按鍵應該總是能正常運作。但在終端機中,Nvim 會收到一連串位元組,並且必須判斷是否按下了 ALT 鍵。終端機可能會使用 ESC 來表示按下了 ALT 鍵。如果 ESC 後面跟著一個在 'ttimeoutlen' 毫秒內的 {key},則 ESC 會被解讀為:<ALT-{key}>,否則它會被解讀為兩個按鍵:<ESC> {key}

1.11 映射 META 鍵 :map-meta-keys

使用 Meta 修飾鍵映射按鍵與使用 Alt 鍵非常相似。您的鍵盤上哪個按鍵產生 Meta 修飾鍵取決於您的鍵盤和組態。
請注意,映射 <M-a> 實際上是為了使用 Alt 鍵。這可能會讓人感到困惑!它無法更改,否則會不向後相容。
對於 Meta 修飾鍵,會使用 "T" 字元。例如,要在插入模式中映射 Meta-b
:imap <T-b> terrible
1.12 映射 SUPER 鍵或 COMMAND 鍵 :map-super-keys :map-cmd-key
如果終端機或 GUI 支援,則可以使用 Super / Command 修飾鍵。字元 "D" 用於 Super / Command 修飾鍵。
例如,要在插入模式中映射 Command-b
:imap <D-b> barritone

1.13 映射運算符 :map-operator

運算符會在 {motion} 命令之前使用。要定義您自己的運算符,您必須建立一個映射,該映射首先設定 'operatorfunc' 選項,然後調用 g@ 運算符。在使用者輸入 {motion} 命令後,將會調用指定的函式。
g@ E774 E775 g@{motion} 調用 'operatorfunc' 選項設定的函式。「[」標記會定位在 {motion} 移動的文字開頭,「]」標記則在文字的最後一個字元上。此函式會使用一個字串引數來調用:「line」{motion}行式,「char」{motion}字元式,「block」{motion}區塊式視覺模式。類型可以強制執行,請參閱 強制移動
以下是一個使用 <F4> 計算空格數的範例
nnoremap <expr> <F4> CountSpaces()
xnoremap <expr> <F4> CountSpaces()
" doubling <F4> works on a line
nnoremap <expr> <F4><F4> CountSpaces() .. '_'
function CountSpaces(context = {}, type = '') abort
  if a:type == ''
    let context = #{
      \ dot_command: v:false,
      \ extend_block: '',
      \ virtualedit: [&l:virtualedit, &g:virtualedit],
      \ }
    let &operatorfunc = function('CountSpaces', [context])
    set virtualedit=block
    return 'g@'
  endif
  let save = #{
    \ clipboard: &clipboard,
    \ selection: &selection,
    \ virtualedit: [&l:virtualedit, &g:virtualedit],
    \ register: getreginfo('"'),
    \ visual_marks: [getpos("'<"), getpos("'>")],
    \ }
  try
    set clipboard= selection=inclusive virtualedit=
    let commands = #{
      \ line: "'[V']",
      \ char: "`[v`]",
      \ block: "`[\<C-V>`]",
      \ }[a:type]
    let [_, _, col, off] = getpos("']")
    if off != 0
      let vcol = getline("'[")->strpart(0, col + off)->strdisplaywidth()
      if vcol >= [line("'["), '$']->virtcol() - 1
        let a:context.extend_block = '$'
      else
        let a:context.extend_block = vcol .. '|'
      endif
    endif
    if a:context.extend_block != ''
      let commands ..= 'oO' .. a:context.extend_block
    endif
    let commands ..= 'y'
    execute 'silent noautocmd keepjumps normal! ' .. commands
    echomsg getreg('"')->count(' ')
  finally
    call setreg('"', save.register)
    call setpos("'<", save.visual_marks[0])
    call setpos("'>", save.visual_marks[1])
    let &clipboard = save.clipboard
    let &selection = save.selection
    let [&l:virtualedit, &g:virtualedit] = get(a:context.dot_command ? save : a:context, 'virtualedit')
    let a:context.dot_command = v:true
  endtry
endfunction
使用 <expr> 映射是為了能夠擷取任何前綴計數和暫存器。這也避免了使用命令列,而使用命令列會觸發 CmdlineEnter 和 CmdlineLeave 自動命令。
請注意,'selection' 選項會暫時設定為 "inclusive"(包含式),以便能夠從「[」標記到「]」標記使用視覺模式來精確地擷取正確的文字。
另請注意,'clipboard' 選項會暫時清空,以避免覆蓋 "*"+ 暫存器,如果其值包含項目 unnamedunnamedplus
mode() 函式會傳回套用運算符後將會呈現的狀態。
以下是一個使用 Lambda 函式建立一個正常模式運算符的範例,該運算符會在目前行中的文字周圍加上引號
nnoremap <F4> <Cmd>let &opfunc='{t ->
                        \ getline(".")
                        \ ->split("\\zs")
                        \ ->insert("\"", col("'']"))
                        \ ->insert("\"", col("''[") - 1)
                        \ ->join("")
                        \ ->setline(".")}'<CR>g@

2. 縮寫 abbreviation abbreviations Abbreviations

縮寫用於插入模式、取代模式和命令列模式。如果您輸入一個是縮寫的單字,它會被替換為它所代表的單字。這可用於節省輸入經常使用的長單字的時間。而且您可以使用它來自動更正明顯的拼寫錯誤。範例
:iab ms Microsoft :iab tihs this
縮寫有三種類型
full-id 「full-id」類型完全由關鍵字字元組成(字母和來自 'iskeyword' 選項的字元)。這是最常見的縮寫。
範例:「foo」、「g3」、「-1」
end-id 「end-id」類型以關鍵字字元結尾,但所有其他字元都不是關鍵字字元。
範例:「#i」、「..f」、「$/7」
non-id 「non-id」類型以非關鍵字字元結尾,其他字元可以是任何類型,但不包括空格和 Tab。
範例:「def#」、「4/7$」
不能作為縮寫的字串範例:「a.b」、「#def」、「a b」、「_$r」
只有當您輸入非關鍵字字元時,才會辨識縮寫。這也可以是結束插入模式的 <Esc> 或結束命令的 <CR>。結束縮寫的非關鍵字字元會在展開的縮寫後插入。此規則的例外是字元 <C-]>,它用於展開縮寫,而不插入任何額外字元。
範例
:ab hh        hello
"hh<Space>" 會展開為 "hello<Space>","hh<C-]>" 會展開為 "hello"
游標之前的字元必須符合縮寫。每種類型都有額外的規則
full-id 比對之前是一個非關鍵字字元,或這是行或插入開始的位置。例外:當縮寫只有一個字元時,如果前面有非關鍵字字元(空格或 Tab 除外),則不會辨識縮寫。但是,對於命令列,會忽略 "'<,'>" (或任何其他標記),就像命令列從它之後開始一樣。
end-id 比對前面是一個關鍵字字元,或空格或 Tab,或這是行或插入開始的位置。
non-id 比對前面是空格、Tab 或行或插入開始的位置。
範例:({CURSOR} 是您輸入非關鍵字字元的位置)
:ab foo   four old otters
" foo{CURSOR}" 會展開為 " four old otters"," foobar{CURSOR}" 不會展開,"barfoo{CURSOR}" 也不會展開
:ab #i #include
"#i{CURSOR}" 會展開為 "#include",">#i{CURSOR}" 不會展開
:ab ;; <endofline>
"test;;" 不會展開,"test ;;" 會展開為 "test <endofline>"
若要避免在插入模式中使用縮寫:在會觸發縮寫的字元之前輸入 CTRL-V。例如 CTRL-V <Space>。或者輸入縮寫的一部分,使用 <Esc> 離開插入模式,使用 "a" 重新進入插入模式,然後輸入其餘部分。
若要避免在命令列模式中使用縮寫:在縮寫中的某處輸入兩次 CTRL-V,以避免被替換。在正常字元前面的 CTRL-V 通常會被忽略。
可以在縮寫後移動游標
:iab if if ()<Left>
您甚至可以執行更複雜的操作。例如,要消耗在縮寫後輸入的空格
func Eatchar(pat)
   let c = nr2char(getchar(0))
   return (c =~ a:pat) ? '' : c
endfunc
iabbr <silent> if if ()<Left><C-R>=Eatchar('\s')<CR>
沒有預設的縮寫。
縮寫永遠不會是遞迴的。您可以毫無問題地使用 ":ab f f-o-o"。但是縮寫可以被映射。
:abbreviate-local :abbreviate-<buffer> 就像映射一樣,縮寫可以是緩衝區本機的。這主要用於 filetype-plugin 檔案中。C 插件檔案的範例
:abb <buffer> FF  for (i = 0; i < ; ++i)
:ab :abbreviate :ab[breviate] 列出所有縮寫。第一欄中的字元表示縮寫的使用模式:「i」表示插入模式,「c」表示命令列模式,「!」表示兩者皆可。這些與映射的模式相同,請參閱 map-listing
:abbreviate-verbose
'verbose' 不為零時,列出縮寫也會顯示上次定義它的位置。範例
:verbose abbreviate
!  teh                 the
        Last set from /home/abcd/vim/abbr.vim
更多資訊請參閱 :verbose-cmd
:ab[breviate] {lhs} 列出以 {lhs} 開頭的縮寫。您可能需要插入一個 CTRL-V(輸入兩次)來避免輸入的 {lhs} 被展開,因為命令列縮寫適用於此處。
:ab[breviate] [<expr>] [<buffer>] {lhs} {rhs}{lhs} 的縮寫新增到 {rhs}。如果 {lhs} 已經存在,則會將其替換為新的 {rhs}{rhs} 可能包含空格。關於可選的 <expr> 引數,請參閱 :map-<expr>。關於可選的 <buffer> 引數,請參閱 :map-<buffer>
:una :unabbreviate :una[bbreviate] [<buffer>] {lhs} 從清單中移除 {lhs} 的縮寫。如果找不到,則會移除 {lhs}{rhs} 相符的縮寫。這樣做的目的是讓您即使在展開後也能移除縮寫。若要避免展開,請插入一個 CTRL-V(輸入兩次)。
:norea :noreabbrev :norea[bbrev] [<expr>] [<buffer>] [lhs] [rhs] 與 ":ab" 相同,但此 {rhs} 不會重新映射。
:ca :cab :cabbrev :ca[bbrev] [<expr>] [<buffer>] [lhs] [rhs] 與 ":ab" 相同,但僅適用於命令列模式。
:cuna :cunabbrev :cuna[bbrev] [<buffer>] {lhs} 與 ":una" 相同,但僅適用於命令列模式。
:cnorea :cnoreabbrev :cnorea[bbrev] [<expr>] [<buffer>] [lhs] [rhs] 與 ":ab" 相同,但僅適用於命令列模式,且此 {rhs} 不會重新對應。
:ia :iabbrev :ia[bbrev] [<expr>] [<buffer>] [lhs] [rhs] 與 ":ab" 相同,但僅適用於插入模式。
:iuna :iunabbrev :iuna[bbrev] [<buffer>] {lhs} 與 ":una" 相同,但僅適用於插入模式。
:inorea :inoreabbrev :inorea[bbrev] [<expr>] [<buffer>] [lhs] [rhs] 與 ":ab" 相同,但僅適用於插入模式,且此 {rhs} 不會重新對應。
:abc :abclear :abc[lear] [<buffer>] 移除所有縮寫。
:iabc :iabclear :iabc[lear] [<buffer>] 移除插入模式的所有縮寫。
:cabc :cabclear :cabc[lear] [<buffer>] 移除命令列模式的所有縮寫。
使用 CTRL-V
可以在縮寫的 rhs 中使用特殊字元。必須使用 CTRL-V 來避免大多數不可列印字元的特殊含義。需要輸入多少個 CTRL-V 取決於您如何輸入縮寫。這也適用於映射。讓我們在這裡舉一個例子。
假設您想要將 "esc" 縮寫為輸入一個 <Esc> 字元。當您在 Vim 中輸入 ":ab" 命令時,您必須輸入以下內容:(這裡 ^V 是 CTRL-V,而 ^[ 是 <Esc>
您輸入:ab esc ^V^V^V^V^V^[
所有鍵盤輸入都受到 ^V 引號的解釋,因此第一個、第三個和第五個 ^V 字元僅允許將第二個和第四個 ^V 以及 ^[ 輸入到命令列中。
您看到:ab esc ^V^V^[
命令列在 ^[ 之前包含兩個實際的 ^V。如果您選擇使用這種方式,這就是它應該在您的 vimrc 檔案中顯示的方式。第一個 ^V 用於引用第二個 ^V;:ab 命令使用 ^V 作為其自己的引用字元,因此您可以在縮寫中包含引用的空白字元或 | 字元。 :ab 命令對 ^[ 字元沒有做任何特殊處理,因此不需要引用。(雖然引用沒有害處;這就是為什麼輸入 7 個 [但不是 8 個!] ^V 可以工作的原因。)
儲存為:esc ^V^[
解析後,縮寫的簡短形式 ("esc") 和長形式(兩個字元 "^V^[") 儲存在縮寫表中。如果您在沒有參數的情況下給出 :ab 命令,這就是縮寫的顯示方式。
稍後,當縮寫因為使用者輸入了 "esc" 這個詞而展開時,長形式會受到與鍵盤輸入相同類型的 ^V 解釋。因此,^V 保護 ^[ 字元不被解釋為「退出插入模式」字元。相反,^[ 會插入到文字中。
展開為:^[
[Steve Kirkendall 提供的範例]

3. 本機映射和函式 script-local

當使用多個 Vim 腳本檔案時,存在一個腳本中使用的映射和函式與其他腳本中使用的映射和函式同名的風險。為了避免這種情況,可以將它們設為腳本的本機。
<SID> <SNR> E81 字串 "<SID>" 可以在映射或選單中使用。如果您有一個想要從同一腳本中的映射呼叫的腳本本機函式,這非常有用。當執行 map 命令時,Vim 會將 "<SID>" 替換為特殊鍵碼 <SNR>,後跟一個對於腳本而言是唯一的數字和一個底線。例如
:map <SID>Add
會定義一個映射 "<SNR>23_Add"。
當在腳本中定義一個函式時,可以在名稱前面加上 "s:" 以使其成為腳本的本機函式。但是,當從腳本外部執行映射時,它不知道函式是在哪個腳本中定義的。為了避免這個問題,請使用 "<SID>" 而不是 "s:"。進行的轉換與映射的轉換相同。這使得可以在映射中定義對函式的呼叫。
當執行本機函式時,它會在定義它的腳本的上下文中執行。這意味著它定義的新函式和映射也可以使用 "s:" 或 "<SID>",並且它將使用與定義函式本身時相同的唯一編號。此外,可以使用 "s:var" 本機腳本變數。
當執行自動命令或使用者命令時,它會在定義它的腳本的上下文中執行。這使得命令可以呼叫本機函式或使用本機映射。
如果該值用於無法正確展開 <SID> 的上下文中,請使用 expand() 函式
let &includexpr = expand('<SID>') .. 'My_includeexpr()'
否則,在腳本上下文之外使用 "<SID>" 是一種錯誤。
如果您需要取得要在複雜腳本中使用的腳本編號,可以使用此函式
func s:ScriptNumber()
  return matchstr(expand('<SID>'), '<SNR>\zs\d\+\ze_')
endfunc
當列出函式和映射時,將會顯示 "<SNR>"。這對於找出它們被定義為何非常有用。
可以使用 :scriptnames 命令來查看已來源哪些腳本及其 <SNR> 編號。

4. 使用者定義的命令 user-commands

可以定義自己的 Ex 命令。使用者定義的命令可以像內建命令一樣運作(它可以具有範圍或引數,引數可以像檔案名稱或緩衝區名稱一樣完成等等),只是當命令被執行時,它會被轉換為正常的 Ex 命令,然後執行。
首先:請參閱使用者手冊中的 40.2 節。
E183 E841 user-cmd-ambiguous 所有使用者定義的命令都必須以大寫字母開頭,以避免與內建命令混淆。例外情況是以下內建命令: :Next 它們不能用於使用者定義的命令。
使用者命令的其他字元可以是大小寫字母或數字。當使用數字時,請注意其他接受數值引數的命令可能會變得模糊不清。例如,命令 ":Cc2" 可以是沒有引數的使用者命令 ":Cc2",也可以是帶有引數 "2" 的命令 ":Cc"。建議在命令名稱和引數之間放置一個空格,以避免這些問題。
當使用使用者定義的命令時,可以縮寫該命令。但是,如果縮寫不是唯一的,則會發出錯誤訊息。此外,內建命令將始終優先。
範例
:command Rename ...
:command Renumber ...
:Rena                                " Means "Rename"
:Renu                                " Means "Renumber"
:Ren                                " Error - ambiguous
:command Paste ...
建議在腳本中使用使用者定義命令的完整名稱。
:com[mand] :com :command 列出所有使用者定義的命令。當列出命令時,第一列的字元為:! 命令具有 -bang 屬性 " 命令具有 -register 屬性 | 命令具有 -bar 屬性 b 命令是當前緩衝區的本機命令(有關屬性的詳細資訊,請參閱下文)可以使用 :filter 過濾命令名稱的清單,例如,列出所有名稱中包含 "Pyth" 的命令
filter Pyth command
:com[mand] {cmd} 列出以 {cmd} 開頭的使用者定義命令
:command-verbose
'verbose' 不為零時,列出命令也會顯示上次定義它的位置和任何完成引數。例如
:verbose command TOhtml
名稱 引數 範圍 完成 定義
TOhtml 0 % :call Convert2HTML(<line1>, <line2>)
上次設定於 /usr/share/vim/vim-7.0/plugin/tohtml.vim
更多資訊請參閱 :verbose-cmd
E174 E182 :com[mand][!] [{attr}...] {cmd} {repl} 定義使用者命令。命令的名稱為 {cmd},其替換文字為 {repl}。命令的屬性(請參閱下文)為 {attr}。如果命令已存在,則會報告錯誤,除非指定了 !,在這種情況下,命令會被重新定義。有一個例外:當再次來源腳本時,先前在該腳本中定義的命令將被靜默地取代。
:delc[ommand] {cmd} :delc :delcommand E184 刪除使用者定義的命令 {cmd}
:delc[ommand] -buffer {cmd} E1237
刪除為當前緩衝區定義的使用者定義命令 {cmd}
:comc[lear] :comc :comclear 刪除所有使用者定義的命令。
命令屬性
command-attributes
Nvim 將使用者定義的命令視為任何其他 Ex 命令。它們可以具有引數,或指定範圍。引數可以像檔案名稱、緩衝區等一樣完成。這確切的工作方式取決於命令的屬性,這些屬性在定義命令時指定。
當在腳本中定義使用者命令時,它將能夠呼叫腳本內部的函數,並使用腳本內部的映射。當使用者調用該使用者命令時,它將在定義它的腳本的上下文中運行。如果命令中使用了 <SID>,這點很重要。
有一些屬性,分為四個類別:引數處理、補全行為、範圍處理和特殊情況。這些屬性將在下面按類別說明。
引數處理
E175 E176 :command-nargs 預設情況下,使用者定義的命令不接受任何引數(如果提供了任何引數,則會報告錯誤)。但是,可以使用 -nargs 屬性來指定該命令可以接受引數。有效的情況如下:
-nargs=0 不允許任何引數(預設值) -nargs=1 必須恰好有一個引數,其中包含空格 -nargs=* 允許任意數量的引數(0 個、1 個或多個),以空白字元分隔 -nargs=? 允許 0 或 1 個引數 -nargs=+ 必須提供引數,但允許任意數量
在此上下文中,引數被視為以(未轉義的)空格或 Tab 字元分隔,但當只有一個引數時,空白字元會成為引數的一部分。
請注意,引數被用作文字,而不是運算式。具體來說,"s:var" 將使用定義命令的腳本中的腳本局部變數,而不是調用它的位置!範例:script1.vim
:let s:error = "None"
:command -nargs=1 Error echoerr <args>
script2.vim
:source script1.vim
:let s:error = "Wrong!"
:Error s:error
執行 script2.vim 將會輸出 "None"。這不是你想要的!呼叫函數可能是一種替代方法。
補全行為
:command-completion E179 E180 E181 :command-complete
預設情況下,使用者定義的命令的引數不會進行補全。但是,透過指定以下屬性之一,可以啟用引數補全:
-complete=arglist 引數列表中的檔案名稱 -complete=augroup 自動指令群組 -complete=breakpoint :breakadd 子選項 -complete=buffer 緩衝區名稱 -complete=color 色彩配置 -complete=command Ex 命令(和引數) -complete=compiler 編譯器 -complete=diff_buffer diff 緩衝區名稱 -complete=dir 目錄名稱 -complete=dir_in_path 'cdpath' 中的目錄名稱 -complete=environment 環境變數名稱 -complete=event 自動指令事件 -complete=expression Vim 運算式 -complete=file 檔案和目錄名稱 -complete=file_in_path 'path' 中的檔案和目錄名稱 -complete=filetype 檔案類型名稱 'filetype' -complete=function 函數名稱 -complete=help 說明主題 -complete=highlight 突出顯示群組 -complete=history :history 子選項 -complete=keymap 鍵盤映射 -complete=locale 地區設定名稱(如同 locale -a 的輸出) -complete=lua Lua 運算式 :lua -complete=mapclear 緩衝區引數 -complete=mapping 映射名稱 -complete=menu 功能表 -complete=messages :messages 子選項 -complete=option 選項 -complete=packadd 可選套件 pack-add 名稱 -complete=runtime 'runtimepath' 中的檔案和目錄名稱 -complete=scriptnames 已載入的腳本名稱 -complete=shellcmd Shell 命令 -complete=shellcmdline 第一個是 Shell 命令,後續的是檔案名稱。行為與 :!cmd 相同 -complete=sign :sign 子選項 -complete=syntax 語法檔案名稱 'syntax' -complete=syntime :syntime 子選項 -complete=tag 標籤 -complete=tag_listfiles 標籤,按下 CTRL-D 時顯示檔案名稱 -complete=user 使用者名稱 -complete=var 使用者變數 -complete=custom,{func} 自訂補全,透過 {func} 定義 -complete=customlist,{func} 自訂補全,透過 {func} 定義
如果在沒有任何內容可補全時指定了補全(-nargs=0,預設值),則會收到錯誤 E1208注意:某些補全方法可能會展開環境變數。
自訂補全
:command-completion-custom
:command-completion-customlist E467 E468 可以透過 "custom,{func}" 或 "customlist,{func}" 補全引數定義自訂補全方案。{func} 部分應為具有以下簽名的函數:
:function {func}(ArgLead, CmdLine, CursorPos)
該函數不需要使用所有這些引數。該函數應將補全候選字作為回傳值提供。
對於 "custom" 引數,函數應回傳以換行符分隔的字串,每行一個補全候選字。
對於 "customlist" 引數,函數應將補全候選字作為 Vim 列表回傳。列表中非字串項目將被忽略。
函數引數為:ArgLead 目前正在補全的引數的前導部分 CmdLine 整行命令列 CursorPos 其中游標位置(位元組索引)。函數可以使用這些引數來判斷上下文。對於 "custom" 引數,沒有必要針對 ArgLead 中的(隱式模式)篩選候選字。Vim 將在函數回傳後使用其正規表示式引擎篩選候選字,在大多數情況下,這可能會更有效率。如果 'wildoptions' 包含 "fuzzy",則將使用 模糊匹配篩選候選字。對於 "customlist" 引數,Vim 不會篩選回傳的補全候選字,使用者提供的函數應篩選候選字。
以下範例會將使用者名稱列到 Finger 命令中:
:com -complete=custom,ListUsers -nargs=1 Finger !finger <args>
:fun ListUsers(A,L,P)
:    return system("cut -d: -f1 /etc/passwd")
:endfun
以下範例會補全 'path' 選項中指定的目錄中的檔案名稱:
:com -nargs=1 -bang -complete=customlist,EditFileComplete
                    \ EditFile edit<bang> <args>
:fun EditFileComplete(A,L,P)
:    return split(globpath(&path, a:A), "\n")
:endfun
此範例不適用於包含空格的檔案名稱!
範圍處理
E177 E178 :command-range :command-count 預設情況下,使用者定義的命令不接受行號範圍。但是,可以指定命令接受範圍(-range 屬性),或者它接受任意計數值,無論是在行號位置(-range=N,如 :split 命令)還是作為「計數」引數(-count=N,如 :Next 命令)。然後,該計數將在帶有 <count> 的引數中使用。
可能的屬性如下:
-range 允許範圍,預設為目前行 -range=% 允許範圍,預設為整個檔案 (1,$) -range=N 行號位置中指定的計數(預設為 N)(如 :split);允許零行號。 -count=N 在行號位置或作為初始引數指定的計數(預設為 N)(如 :Next)。 -count 作用類似 -count=0
請注意,-range=N 和 -count=N 是互斥的,只能指定一個。
:command-addr
範圍中的特殊字元(例如 .$%)(預設情況下分別對應於目前行、最後一行和整個緩衝區)可能與引數、(已載入的)緩衝區、視窗或索引標籤頁面相關。
可能的值如下(第二欄是清單中使用的簡稱):-addr=lines 行的範圍(這是 -range 的預設值) -addr=arguments arg 引數的範圍 -addr=buffers buf 緩衝區的範圍(也包括未載入的緩衝區) -addr=loaded_buffers load 已載入緩衝區的範圍 -addr=windows win 視窗的範圍 -addr=tabs tab 索引標籤頁面的範圍 -addr=quickfix qf 快速修復項目的範圍 -addr=other ? 其他類型的範圍;可以使用 "."、"$" 和 "%",就像 "lines" 一樣(這是 -count 的預設值)
遞增預覽
:command-preview {nvim-api} 命令可以透過定義預覽處理常式來顯示 'inccommand'(即時)預覽(僅限 Lua,請參閱 nvim_create_user_command())。
在執行預覽回呼之前,Nvim 會暫時停用 'cursorline''cursorcolumn',以避免突出顯示問題。
預覽回呼必須是具有此簽名的 Lua 函數:
function cmdpreview(opts, ns, buf)
其中 "opts" 的形式與提供給 nvim_create_user_command() 回呼的形式相同,"ns" 是突出顯示的預覽命名空間 ID,而 "buf" 是預覽常式將直接修改以顯示預覽結果的緩衝區(對於 "inccommand=split",或對於 "inccommand=nosplit" 為 nil)。
命令預覽常式必須實作此協定:
1. 根據預覽的需要修改目標緩衝區(請參閱 nvim_buf_set_text()nvim_buf_set_lines())。2. 如果提供預覽緩衝區,則將必要的文字新增至預覽緩衝區。3. 將必要的突出顯示新增至目標緩衝區。如果提供預覽緩衝區,則也將必要的突出顯示新增至預覽緩衝區。所有突出顯示都必須新增至作為預覽回呼的引數提供的預覽命名空間(請參閱 nvim_buf_add_highlight()nvim_buf_set_extmark(),以取得關於如何將突出顯示新增至命名空間的說明)。4. 回傳一個整數 (0, 1, 2),該整數控制 Nvim 的行為,如下所示:0:不顯示預覽。1:顯示預覽,但不顯示預覽視窗(即使使用 "inccommand=split")。2:顯示預覽並開啟預覽視窗(如果使用 "inccommand=split")。對於 "inccommand=nosplit",這與 1 相同。
預覽結束後,Nvim 會捨棄預覽期間對所有緩衝區所做的所有變更,並清除預覽命名空間中的所有突出顯示。
以下是一個用於修剪行尾空白的命令範例,該命令支援遞增命令預覽:
-- If invoked as a preview callback, performs 'inccommand' preview by
-- highlighting trailing whitespace in the current buffer.
local function trim_space_preview(opts, preview_ns, preview_buf)
  vim.cmd('hi clear Whitespace')
  local line1 = opts.line1
  local line2 = opts.line2
  local buf = vim.api.nvim_get_current_buf()
  local lines = vim.api.nvim_buf_get_lines(buf, line1 - 1, line2, false)
  local preview_buf_line = 0
  for i, line in ipairs(lines) do
    local start_idx, end_idx = string.find(line, '%s+$')
    if start_idx then
      -- Highlight the match
      vim.api.nvim_buf_add_highlight(
        buf,
        preview_ns,
        'Substitute',
        line1 + i - 2,
        start_idx - 1,
        end_idx
      )
      -- Add lines and set highlights in the preview buffer
      -- if inccommand=split
      if preview_buf then
        local prefix = string.format('|%d| ', line1 + i - 1)
        vim.api.nvim_buf_set_lines(
          preview_buf,
          preview_buf_line,
          preview_buf_line,
          false,
          { prefix .. line }
        )
        vim.api.nvim_buf_add_highlight(
          preview_buf,
          preview_ns,
          'Substitute',
          preview_buf_line,
          #prefix + start_idx - 1,
          #prefix + end_idx
        )
        preview_buf_line = preview_buf_line + 1
      end
    end
  end
  -- Return the value of the preview type
  return 2
end
-- Trims all trailing whitespace in the current buffer.
local function trim_space(opts)
  local line1 = opts.line1
  local line2 = opts.line2
  local buf = vim.api.nvim_get_current_buf()
  local lines = vim.api.nvim_buf_get_lines(buf, line1 - 1, line2, false)
  local new_lines = {}
  for i, line in ipairs(lines) do
    new_lines[i] = string.gsub(line, '%s+$', '')
  end
  vim.api.nvim_buf_set_lines(buf, line1 - 1, line2, false, new_lines)
end
-- Create the user command
vim.api.nvim_create_user_command(
  'TrimTrailingWhitespace',
  trim_space,
  { nargs = '?', range = '%', addr = 'lines', preview = trim_space_preview }
)
-bang 命令可以使用 ! 修飾符(例如 :q 或 :w) -bar 命令後面可以接 "|" 和另一個命令。命令參數中不允許出現 "|"。也會檢查是否有 " 來開始註解。 -register 命令的第一個參數可以是可選的暫存器名稱(例如 :del, :put, :yank)。 -buffer 命令僅在目前緩衝區中可用。 -keepscript 不要使用定義使用者命令的位置來顯示詳細訊息,請使用呼叫使用者命令的位置。
對於 -count 和 -register 屬性,如果提供了可選參數,它會從參數列表中移除,並單獨提供給替換文字使用。請注意,這些參數可以縮寫,但這是一個不建議使用的功能。對於新的腳本,請使用完整名稱。
替換文字
使用者定義命令的替換文字 {repl} 會掃描特殊跳脫序列,使用 <...> 表示法。跳脫序列會被替換為輸入命令行的值,所有其他文字則會照樣複製。產生的字串會作為 Ex 命令執行。若要避免替換,請使用 <lt> 來代替初始的 <。因此,若要包含字面上的 "<bang>",請使用 "<lt>bang>"。
有效的跳脫序列如下
<line1>
<line1> 命令範圍的起始行。<line2>
<line2> 命令範圍的結束行。<range>
<range> 命令範圍中的項目數量:0、1 或 2 <count>
<count> 提供的任何計數(如 '-range' 和 '-count' 屬性所述)。<bang>
<bang>(請參閱 '-bang' 屬性)如果命令執行時帶有 ! 修飾符,則展開為 !,否則展開為空。<mods> <q-mods> :command-modifiers <mods> 命令修飾符(如果已指定)。否則,展開為空。支援的修飾符為 :aboveleft:belowright:botright:browse:confirm:hide:horizontal:keepalt:keepjumps:keepmarks:keeppatterns:leftabove:lockmarks:noautocmd:noswapfile:rightbelow:sandbox:silent:tab:topleft:unsilent:verbose:vertical。請注意,:filter 不受支援。範例
command! -nargs=+ -complete=file MyEdit
            \ for f in expand(<q-args>, 0, 1) |
            \ exe '<mods> split ' .. f |
            \ endfor
function! SpecialEdit(files, mods)
    for f in expand(a:files, 0, 1)
        exe a:mods .. ' split ' .. f
    endfor
endfunction
command! -nargs=+ -complete=file Sedit
            \ call SpecialEdit(<q-args>, <q-mods>)
<reg> <register> <reg>(請參閱 '-register' 屬性)可選的暫存器(如果已指定)。否則,展開為空。<register> 是它的同義詞。<args>
<args> 命令參數,與提供的完全相同(但如上所述,任何計數或暫存器可能會消耗一些參數,這些參數就不會成為 <args> 的一部分)。<lt> 單個 '<'(小於)字元。如果你想要在展開中取得其中一個跳脫序列的文字副本,就需要使用此項 – 例如,若要取得 <bang>,請使用 <lt>bang>。
<q-args>
如果跳脫序列的前兩個字元是 "q-"(例如,<q-args>),則該值會被加上引號,使其成為在運算式中使用的有效值。這會將參數視為單個值。當沒有參數時,<q-args> 是一個空字串。請參閱下方的 q-args-example<f-args>
為了讓命令將其參數傳遞給使用者定義的函式,有一個特殊的形式 <f-args>(「函式參數」)。這會在空格和 Tab 字元處分割命令參數,個別為每個參數加上引號,並且 <f-args> 序列會被加上引號的參數的逗號分隔清單取代。請參閱下方的 Mycmd 範例。如果沒有給定參數,則會移除 <f-args>。若要將空白字元嵌入 <f-args> 的參數中,請加上反斜線。<f-args> 會將每對反斜線 (\\) 取代為一個反斜線。反斜線後接空白字元或反斜線以外的字元則不會修改。另請參閱下方的 f-args-example。概觀
命令 <f-args>
XX ab "ab" XX a\b 'a\b' XX a\ b 'a b' XX a\ b 'a ', 'b' XX a\\b 'a\b' XX a\\ b 'a\', 'b' XX a\\\b 'a\\b' XX a\\\ b 'a\ b' XX a\\\\b 'a\\b' XX a\\\\ b 'a\\', 'b' XX [nothing]
請注意,如果要處理「沒有參數」的情況,您必須確保函式可以在沒有參數的情況下呼叫。
使用者命令的範例
" Delete everything after here to the end
:com Ddel +,$d
" Rename the current buffer
:com -nargs=1 -bang -complete=file Ren f <args>|w<bang>
" Replace a range with the contents of a file
" (Enter this all as one line)
:com -range -nargs=1 -complete=file
      Replace <line1>-pu_|<line1>,<line2>d|r <args>|<line1>d
" Count the number of lines in the range
:com! -range -nargs=0 Lines  echo <line2> - <line1> + 1 "lines"
f-args-example
呼叫使用者函式(<f-args> 的範例)
:com -nargs=* Mycmd call Myfunc(<f-args>)
當執行為
:Mycmd arg1 arg2
這將會調用
:call Myfunc("arg1","arg2")
q-args-example
一個更實質的範例
:function Allargs(command)
:   let i = 0
:   while i < argc()
:          if filereadable(argv(i))
:             execute "e " .. argv(i)
:             execute a:command
:      endif
:      let i = i + 1
:   endwhile
:endfunction
:command -nargs=+ -complete=command Allargs call Allargs(<q-args>)
Allargs 命令會將任何 Vim 命令作為參數,並在參數列表中的所有檔案上執行它。使用範例(請注意使用 "e" 旗標來忽略錯誤,以及使用 "update" 命令來寫入修改後的緩衝區)
:Allargs %s/foo/bar/ge|update
這將會調用
:call Allargs("%s/foo/bar/ge|update")
主要
命令索引
快速參考