*map.txt* For Vim version 7.2. 最後更新: 2008年6月
VIM 參考手冊 作者: Bram Moolenaar
譯者: con<[email protected]>
http://vimcdoc.sf.net
鍵映射、縮寫和使用者定義的指令。
本主題在使用者手冊 |05.3|,|24.7| 和 |40.1| 中有過介紹。
1. 鍵映射 |key-mapping|
1.1 映 射 命 令 |:map-commands|
1.2 特殊參數 |:map-arguments|
1.3 映射與運作模式 |:map-modes|
1.4 列出映射 |map-listing|
1.5 映射特殊鍵 |:map-special-keys|
1.6 特殊字元 |:map-special-chars|
1.7 映射哪些鍵 |map-which-keys|
1.8 示例 |map-examples|
1.9 使用映射 |map-typing|
1.10 映射 ALT 鍵 |:map-alt-keys|
1.11 映射操作符 |:map-operator|
2. 縮寫 |abbreviations|
3. 局部映射和函數 |script-local|
4. 使用者定義的指令 |user-commands|
==============================================================================
1. 鍵映射 *key-mapping* *mapping* *macro*
鍵映射用于改變輸入鍵的含義。最常見的用途是把功能鍵定義為一系列的指令。比如: >
:map <F2> a<C-R>=strftime("%c")<CR><Esc>
這個映射會在光标之後追加目前的日期和時間 (用 <> 記法 |<>|)。
1.1 映 射 命 令 *:map-commands*
有很多指令用于定義新的映射,删除映射和列出目前的映射。可以從 |map-overview| 參
考 "映射" 指令的不同形式及其與模式的關系。
{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* *:lmap*
:cm[ap] {lhs} {rhs} |mapmode-c| *:cm* *:cmap*
在映射指令作用的模式中把鍵系列 {lhs} 映射為 {rhs}。并
且映射後的 {rhs} 也被進行映射掃描。這個特性可以用來進
行映射的嵌套和遞歸。
:no[remap] {lhs} {rhs} |mapmode-nvo| *:no* *:noremap*
: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* *:snoremap*
:ono[remap] {lhs} {rhs} |mapmode-o| *:ono* *:onoremap*
:no[remap]! {lhs} {rhs} |mapmode-ic| *:no!* *:noremap!*
:ino[remap] {lhs} {rhs} |mapmode-i| *:ino* *:inoremap*
:ln[oremap] {lhs} {rhs} |mapmode-l| *:ln* *:lnoremap*
:cno[remap] {lhs} {rhs} |mapmode-c| *:cno* *:cnoremap*
在映射指令作用的模式中把鍵序列 {lhs} 映射為 {rhs} 。禁
止對映射後的 {rhs} 進行映射掃描。這個特性可以避免映射
的嵌套和遞歸。通常用于重定義一個指令。{Vi 無此功能}
: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* *:cunmap*
在映射指令作用的模式中删除 {lhs} 的映射。該映射仍然可
以在其它模式中保留其定義。
備注: {lhs} 包含末尾的空格。該映射取消操作_不會_生效:
:map @@ foo
:unmap @@ | print
: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*
在映射指令作用的模式中删除_所有_的映射。{Vi 無此功能}
警告: 同時也會删除預設的映射。
: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|
在映射指令作用的模式中列出所有的鍵映射。注意 ":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*
在映射指令作用的模式中列出以 {lhs} 開頭的鍵映射的鍵系
列。 {Vi 無此功能}
這些指令用于把一個鍵或鍵系列映射成一個字元串。可以用來在功能鍵裡放置一系列命
令,把一個鍵轉換成另一個,等等。如何儲存和恢複目前映射可以參考 |:mkexrc|。
*map-ambiguous*
當兩個映射以相同的字元順序開始,它們是有二義性的。例如: >
:imap aa foo
:imap aaa bar
當 Vim 讀入 "aa" 後,它需要取得另外一個字元才能決定應該映射 "aa" 還是 "aaa"。
這意味着輸入 "aa" 後映射還不會展開,Vim 還在等待另一個字元。如果你接着輸入一個
空格,那麼将插入 "foo" 加上空格。如果你輸入一個 "a",那麼将插入 "bar"。
{Vi 不允許有二義性的映射}
1.2 特 殊 參 數 *:map-arguments*
"<buffer>","<silent>","<special>"、"<script>"、"<expr>" 和 "<unique>" 可以按
任意順序使用。它們必須緊跟在指令的後邊,而在其它任何參數的前邊。
*:map-local* *:map-<buffer>* *E224* *E225*
如果這些指令的第一個參數是 "<buffer>",映射将隻局限于目前的緩沖區内。例如: >
:map <buffer> ,w /[.,;]<CR>
然後你可以在另一個緩沖區内把 ",w" 作另外的映射: >
:map <buffer> ,w /[#&!]<CR>
局部緩沖區映射在全局映射之前被應用。
"<buffer>" 參數也可以用于清除映射: >
:unmap <buffer> ,w
:mapclear <buffer>
當一個緩沖區被删除時局部映射也會被清除,但是在它被解除安裝時不會。就象局部選項值的
情況一樣。
*:map-<silent>* *:map-silent*
要在定義一個映射時不在指令行上回顯該映射,可以使用 "<silent>" 作為第一個參數,
例如: >
:map <silent> ,h /Header<CR>
在使用這個映射時搜尋字串将不回顯。不過被執行指令的資訊仍然會。要把它也關掉,可
以在執行的指令裡加入一個 ":silent": >
:map <silent> ,h :exe ":silent normal /Header\r"<CR>
仍然會給出提示,比如使用 inputdialog() 的時候。
在縮寫上使用 "<silent>" 是可以的,但它的作用是使指令行不進行重繪。
*:map-<special>* *:map-special*
定義映射時,特殊鍵可用 <> 記法,即使 'cpoptions' 包含了 "<" 标志位也沒問題。這
可用于不希望看到設定 'cpoptions' 時出現的副作用的場合。例如: >
:map <special> <F12> /Header<CR>
<
*:map-<script>* *:map-script*
如果給用于定義新映射或縮寫的指令的第一個參數是 "<script>",該映射隻使用通過以
"<SID>" 開頭來定義的的腳本局部映射來重映射 {rhs} 中的字元。這可以用于避免來自
外部的腳本的幹擾 (舉例來說,在 mswin.vim 中 CTRL-V 被重新映射的時候就是如此),
但是又需要使用該腳本中定義的其它映射的情形。
備注: ":map <script>" 和 ":noremap <script>" 做同樣的事情。這裡 "<script>" 超
越指令名。不過,更推薦使用 ":noremap <script>",因為它更清晰地表示了重映射已被
(大多數時候) 禁止。
*: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> . InsertDot()
會插入 InsertDot() 函數的傳回值。這可以用來檢查光标之前的文本并在一定條件下啟
動全能 (omni) 補全。
要非常小心副作用!計算表達式的同時正在擷取字元,是以很有可能你使得該指令不再可
用。為此原因禁止以下行為:
- 改變緩沖區文本 |textlock|
- 編輯其它緩沖區
- |:normal| 指令
- 可以移動光标,但事後光标會被恢複
- 你可以使用 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 複位計數且傳回空字元串,這樣就不會插入任何内容。
注意 要使特殊鍵工作并轉義文本中的 CSI 位元組需要一些特殊處理。|:map| 指令已經做
好了,是以你應該避免做重複的操作。這樣不行: >
:imap <expr> <F3> "<Char-0x611B>"
因為 <Char- 序列作為 |:imap| 的參數被轉義,而 <expr> 又做一次。這樣就可以: >
:imap <expr> <F3> "\u611B"
在其它文本之前使用單個位元組出現的 0x80 是不行的。它會被看作一個特殊鍵。
1.3 映 射 與 運 行 模 式 *:map-modes*
*mapmode-nvo* *mapmode-n* *mapmode-v* *mapmode-o*
有五種映射存在
- 用于普通模式: 輸入指令時。
- 用于可視模式: 可視區域高亮并輸入指令時。
- 用于操作符等待模式: 操作符等待中 ("d","y","c" 等等之後)。
見下: |omap-info|。
- 用于插入模式: 也用于替換模式。
- 用于指令行模式: 輸入 ":" 或 "/" 指令時。
特殊情況:當在普通模式裡為一個指令輸入一個計數時,對 0 的映射會被禁用。這樣在
輸入一個帶有 0 的計數時不會受到對 0 鍵映射的幹擾。
*map-overview* *map-modes*
關于每個映射指令對應的工作模式的概況:
指令: 模式: ~
普通 可視+選擇 操作符等待 ~
:map :noremap :unmap :mapclear 是 是 是
:nmap :nnoremap :nunmap :nmapclear 是 - -
:vmap :vnoremap :vunmap :vmapclear - 是 -
:omap :onoremap :ounmap :omapclear - - 是
修道院之外也有 :nunmap (譯者注: nun,修女)。
*mapmode-x* *mapmode-s*
有的指令能同時用于可視和選擇模式,有的隻能用于其中一個。注意 很常見的情況是提
到 "可視" 的時候實際同時适用可視和選擇兩種模式。|Select-mode-mapping|
指令: 模式: ~
可視 選擇 ~
:vmap :vnoremap :vunmap :vmapclear 是 是
:xmap :xnoremap :xunmap :xmapclear 是 -
:smap :snoremap :sunmap :smapclear - 是
*mapmode-ic* *mapmode-i* *mapmode-c* *mapmode-l*
有的指令同時支援插入模式和指令行模式,有的不是:
指令: 模式: ~
插入 指令行 Lang-Arg ~
:map! :noremap! :unmap! :mapclear! 是 是 -
:imap :inoremap :iunmap :imapclear 是 - -
:cmap :cnoremap :cunmap :cmapclear - 是 -
:lmap :lnoremap :lunmap :lmapclear 是* 是* 是*
原來的 Vi 沒有針對普通/可視/操作符等待模式和針對插入/指令行模式的獨立映射。因
此 ":map" 和 ":map!" 指令為多個模式定義和回顯映射。在 Vim 中你可以使用
":nmap"、":vmap"、:omap"、":cmap" 和 ":imap" 指令來對每個不同的模式分别定義映
射。
*omap-info*
操作符等待映射可以用來定義和任何操作符一起使用的移動指令。簡單例子:
":omap { w" 會使 "y{" 等同于 "yw","d{" 也等同于 "dw"。
要忽略光标原來所在的位置并選擇另外的文本,你可以使 omap 進入可視模式來選擇要操
作的文本。例如,要在位于目前行的函數名上操作: >
onoremap <silent> F :<C-U>normal! 0f(hviw<CR>
CTRL-U (<C-U>) 用于删除指令行上 Vim 可能插入的範圍。普通模式指令尋找第一個 '('
字元并選擇之前的第一個單詞。通常那就是函數名了。
要為普通和可視模式但不包括操作符等待模式輸入一個映射,首先在所有的三個模式中定
義該映射,然後在操作符等待模式中取消該映射: >
:map xx something-difficult
:ounmap xx
對于一個同時用于可視和操作符等待模式、或同時用于普通和操作符等待模式的映射也可
照此辦理。
*language-mapping*
":lmap" 定義一個應用于以下情況的映射:
- 插入模式
- 指令行模式
- 輸入一個搜尋模式時
- 接受一個文本字元作為參數的指令,比如 "r" 和 "f"
- 對于 input() 行
更一般地: 任何輸入的字元是緩沖區文本的一部分而非一個 Vim 指令字元的時候。
"Lang-Arg" 不是真正的另外一個模式,它僅用來表示這些情況的存在。
載入一個相關語言映射集合的最簡單的方法是通過使用 'keymap' 選項。
參考 |45.5|。
在插入模式和指令行模式中可用 CTRL-^ 指令來關閉映射 |i_CTRL-^| |c_CTRL-^|。
普通指令行 (非模式搜尋) 開始輸入時,映射被關閉直到輸入 CTRL-^ 為止。而插入模式
和模式搜尋卻會分别記住上次使用的狀态。需要輸入一個字元作為參數的指令,如 "f"
或 "t" 之類,也使用插入模式的狀态。
語言映射永遠不能應用于已經映射的字元上。它們僅用于鍵入的字元上。這意味着輸
入映射時,語言映射已經完成。
1.4 列 出 映 射 *map-listing*
當列出映射時,前面兩欄的字元表示 (可有多個):
字 符 模 式 ~
<Space> 普通、可視、選擇和操作符等待
n 普通
v 可視和選擇
s 選擇
x 可視
o 操作符等待
! 插入和指令行
i 插入
l 插入、指令行和 Lang-Arg 模式的 ":lmap" 映射
c 指令行
{rhs} 之前可能顯示一個特殊字元:
* 表示它不可重映射
& 表示僅腳本的局部映射可以被重映射
@ 表示緩沖區的局部映射
從 {lhs} 以後的第一個非空字元到行的末尾 (或 '|') 都被認為是 {rhs} 的一部分。這
允許 {rhs} 以一個空格結尾。
注意: 在可視模式裡使用映射時,你可以使用 "'<" 位置标記,它表示目前緩沖區中最後
被選中的可視區域的開始 |'<|。
*:map-verbose*
如果 'verbose' 非零,列出鍵映射的同時可以顯示它在哪裡定義。例如: >
:verbose map <C-W>*
n <C-W>* * <C-W><C-S>*
Last set from /home/abcd/.vimrc
|:verbose-cmd| 說明詳情。
1.5 映 射 特 殊 鍵 *:map-special-keys*
有三種方法來映射一個特殊鍵:
1. Vi 相容的方法: 對鍵碼進行映射。通常這是一個以 <Esc> 開頭的序列。要輸入一個
這樣的映射先輸入 ":map " 然後再敲入功能鍵之前得先輸入一個 CTRL-V。注意如果
鍵碼在 termcap (t_ 開頭的選項) 裡,它會被自動轉換到内碼并變成映射的第二種方
法 (除非 'cpoptions' 裡包括了 'k' 标志位)。
2. 第二種方法是使用功能鍵的内碼。要輸入這樣的映射輸入 CTRL-K 并敲要映射的功能
鍵,或者使用 "#1","#2",.. "#9","#0","<Up>","<S-Down>","<S-F7>" 等等的
形式 (參考鍵表 |key-notation|,所有從 <Up> 開始的鍵都可以使用)。頭十個功能
鍵能以兩種方式被定義: 僅用數字,比如 "#2";或者使用 "<F>",如 "<F2>"。兩種
都代表功能鍵 F2。"#0" 表示功能鍵 F10,由選項 't_f10' 定義,它在某些鍵盤上可
能是 F0。<> 的形式在 'cpoptions' 包含 '<' 标志位時不能使用。
3. 使用 termcap 條目,以 <t_xx> 的形式出現,這裡 "xx" 是 termcap 條目的名字。
可以使用任何字元串條目。例如: >
:map <t_F3> G
< 把功能鍵 13 映射成 "G"。'cpoptions' 包括 '<' 标志位時不能使用這種方式。
第二種和第三種方法的優點是不加修改就可以在不同的終端上使用 (功能鍵會被轉換成相
同的内碼或實際的鍵碼,不論使用何種終端都是如此。termcap 必須正确才能正常工作,
并且必須使用相同的映射)。
細 節: Vim 首先檢查是否從鍵盤輸入的序列是否已被映射。否的話将試圖使用終端鍵碼
(參考 |terminal-options|)。如果找到終端編碼,它會被替換成内碼。然後再次檢查一
個映射是否已完成 (是以你也能把一個内碼映射成其它東西)。在腳本檔案中寫入什麼東
西取決于何者被識别。如果終端鍵碼被識别為映射,寫入鍵碼本身;如果它被識别為一個
終端編碼,則在腳本中寫入内碼。
1.6 特 殊 字 符 *:map-special-chars*
*map_backslash*
注意這裡僅提及 CTRL-V 可以作為用于映射和縮寫的特殊字元。當 'cpoptions' 不包含
'B' 時,反斜杠也可起到 CTRL-V 一樣的作用,這時可以完全地使用 <> 記法 |<>|。但
你不能期望 "<C-V>" 像 CTRL-V 那樣轉換後來者的特殊含義。
要映射一個反斜杠,或者在 {rhs} 中使用一個字面意義的反斜杠,可以使用特殊字元序
列 "<Bslash>" 。這可以避免在使用嵌套映射時使用雙反斜杠的需要。
*map_CTRL-C*
{lhs} 裡可以使用 CTRL-C,但隻有在 Vim 等待輸入鍵時才可以,Vim 忙着做别的事情的
時候不行。如果 Vim 在忙,CTRL-C 總是中斷/打斷該指令。
使用 MS-Windows 上的 GUI 版本時 CTRL-C 能被映射以允許複制到剪貼闆的指令。使用
CTRL-Break 來中斷 Vim。
*map_space_in_lhs*
要在 {lhs} 中包含一個空格,在前面輸入一個 CTRL-V (每個空格之前實際要輸入兩個
CTRL-V)。
*map_space_in_rhs*
如果你需要 {rhs} 以空格開頭,使用 "<Space>"。要與 Vi 完全相容 (但不可讀),不要
使用 |<>| 記法,在 {rhs} 前面先輸入一個單獨的 CTRL-V (你必須輸入 CTRL-V 兩
次)。
*map_empty_rhs*
你可以通過在一個單獨的 CTRL-V (你必須輸入 CTRL-V 兩次) 後面什麼也不輸入來建立
一個空的 {rhs}。不幸的是在 vimrc 檔案中你不能使用這種方式。
*<Nop>*
得到什麼都不做的映射的更容易的方法是在 {rhs} 中使用 "<Nop>"。僅當 |<>| 記法允
許時這種方法才生效。例如確定功能鍵 F8 什麼事情都不做:
: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*
要定義一個使用 "mapleader" 變量的映射,可以使用特殊字串 "<Leader>"。它會被
"mapleader" 的字串值所替換。如果 "mapleader" 未設定或為空,則用反斜杠代替,例
如:
:map <Leader>A oanother line<Esc>
和下面一樣: >
:map \A oanother line<Esc>
但是當: >
:let mapleader = ","
時,又相當于: >
:map ,A oanother line<Esc>
注意 "mapleader" 的值僅當定義映射時被使用。後來改變的 "mapleader" 不會影響已定
義的映射。
*<LocalLeader>* *maplocalleader*
<LocalLeader> 和 <Leader> 類似,除了它使用 "maplocalleader" 而非 "mapleader"
以外。<LocalLeader> 用于局部于緩沖區的映射,例如: >
:map <LocalLeader>q \DoItNow
<
在一個全局插件裡應該使用 <Leader> 而在一個檔案類型插件裡應該用 <LocalLeader>。
"mapleader" 和 "maplocalleader" 可以是相同的。盡管如此,如果你把它們設為不同,
全局插件和檔案類型插件的映射沖突的機會是不是會小一點呢?例如,你可以保持把
"mapleader" 設定為預設的反斜杠,而設定 "maplocalleader" 為下劃線。
*map-<SID>*
在一個腳本中有一個特殊關鍵字叫 "<SID>" 能被用來定義一個局部于腳本中的映射。
具體細節請參考 |<SID>|。
*<Plug>*
叫做 "<Plug>" 的特殊關鍵字可以用于一個内部映射,它不與任何鍵的序列比對。這在插
件中有用 |using-<Plug>|。
*<Char>* *<Char->*
要根據一個字元的十進制,八進制或十六進制數字形式進行映射,可以使用 <Char> 來構
造:
<Char-123> 字元 123
<Char-033> 字元 27
<Char-0x7f> 字元 127
它可以用來在一個 'keymap' 檔案裡指定一個 (多位元組) 字元。大小寫的差別此處不計。
*map-comments*
在這些指令的後面不可能放置注釋,因為 '"' 字元被認為是 {lhs} 或 {rhs} 的一部
分。
*map_bar*
因為字元 '|' 用來分隔映射指令和後面的指令,是以包括 '|' 的 {rhs} 要做一些特殊
的處理,有三種方法:
使用 可用于 示例 ~
<Bar> '<' 不在 'cpoptions' 裡 :map _l :!ls <Bar> more^M
\| 'b' 不在 'cpoptions' 裡 :map _l :!ls \| more^M
^V| 總可以,Vim 和 Vi 都行 :map _l :!ls ^V| more^M
(這裡 ^V 表示 CTRL-V;要輸入一個 CTRL-V 你必須按鍵兩次;在這裡不能使用 <> 記法
"<C-V>")。
當你使用 'cpoptions' 的預設設定時三種方式都可以正常工作。
當 'b' 出現在 'cpoptions' 中時,"\|" 會被認為是一個映射的結束,後面的是另一個
指令。這是為了和 Vi 相容,但是和其它指令比較時有點不合常理。
*map_return*
當你的映射包含 Ex 指令時,你需要在其後放置行終結符才能讓它執行。在這裡推薦使用
<CR> (參考 |<>|)。例如: >
:map _ls :!ls -l %<CR>:echo "the end"<CR>
在插入或指令行模式中輸入時要避免字元被映射,可以先輸入一個 CTRL-V。在插入模式
中如果 'paste' 選項被打開的話,映射也會被禁止。
注意 當遇到錯誤時 (會導緻一個錯誤資訊或蜂鳴) 剩下的映射将不會被執行。這是為了
保持和 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-P 和 CTRL-N。使用一個附加的字元可以定
義更多的映射。
參考檔案 "index" 可以知道哪些鍵沒有被使用,進而使映射不會覆寫任何内建的功能。
也可使用 ":help {key}^D" 來找出是否一個鍵已經用于某些指令。 ({key} 用于指定你
要尋找的鍵,^D 是 CTRL-D)。
1.8 示 例 *map-examples*
以下是一些例子 (照字面輸入它們,對于 "<CR>" 你輸入四個字元;為此 '<' 标志位不
應出現在 'cpoptions' 中)。 >
:map <F3> o#include
:map <M-g> /foo<CR>cwbar<Esc>
:map _x d/END/e<CR>
:map! qq quadrillion questions
計數相乘
如果你在激活映射前輸入計數,實際效果就像是該計數在 {lhs} (譯者注: 疑為 {rhs})
之前輸入一樣。例如,對下面的映射: >
:map <F4> 3w
輸入 2<F4> 會得到 "23w"。不是移動 2 * 3 個單詞,而是 23 個單詞。
如果你希望得到計數相乘的效果,可使用表達式寄存器: >
:map <F4> @='3w'<CR>
引号之間的部分是待執行的表達式。 |@=|
1.9 使 用 映 射 *map-typing*
當你輸入一個被映射序列的頭部時 Vim 開始比較你的輸入。如果比對尚不完全,它會等
待更多的字元輸入直到可以确定是否比對。例如: 如果你映射了 map! "qq",然後你輸入
的第一個 'q' 将不會顯示在螢幕上,直到你輸入另一個 'q' 或其它字元。如果打開了
'timeout' 選項 (這是預設選項) Vim 僅會等待一秒鐘 (或任何 'timeoutlen' 指定的時
間)。之後,它假定 'q' 已經不會再被輸入。如果你的輸入很慢,或者你的系統很慢,複
位 'timeout' 選項。這時,你可能還需要是否置位 'ttimeout' 選項。
*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>。
另一個問題可能是保持 ALT 或 Meta 的時候,終端在前面附加 ESC 而不是給第 8 位置
位。見 |:map-alt-keys|。
*recursive_mapping*
如果 {rhs} 中包括了 {lhs},那麼你定義了一個遞歸映射。當 {lhs} 被輸入,它會被替
換成 {rhs}。當遇到 {rhs} 中包含的 {lhs} 又會被替換成 {rhs},依此類推。
這可用來使一個指令重複無數次。這種情況唯一的問題是出錯是停止它的唯一方法。解決
迷宮的宏會用到這個,去那裡找找例子吧。有一個例外: 如果 {rhs} 以 {lhs} 開始,第
一個字元不會被再次映射 (這與 Vi 相容)。
例如: >
:map ab abcd
将執行 "a" 指令并且在文本中插入 "bcd"。{rhs} 中的 "ab" 不會被再次映射。
如果你要交換兩個鍵的含義,應該使用 :noremap 指令。例如: >
:noremap k j
:noremap j k
這會交換光标上移和光标下移指令。
如果使用普通 :map 指令,并且 'remap' 選項被打開,映射一直進行直到文本不再是某
個 {lhs} 的一部分。例如,如果你用: >
:map x y
:map y x
Vim 将把 x 替換成 y,并把 y 替換成 x,等等。這種情況會發生 'maxmapdepth' 次
(預設為 1000),然後 Vim 會給出錯誤資訊 "recursive mapping" (遞歸映射)。
*:map-undo*
如果你在一個被映射的序列中包含了一個 undo 指令,将會把文本帶回宏執行前的狀态。
這和原始的 Vi 是相容的,隻要被映射的序列僅包含一個 undo 指令 (原始的 Vi 中被映
射的序列有兩個 undo 指令是無意義的,你會得到第一個 undo 之前的文本)。
1.10 映 射 ALT 鍵 *:map-alt-keys*
GUI 上,Vim 自己處理 Alt 鍵,是以用 ALT 鍵的映射應該總沒有問題。但在終端上,
Vim 得到位元組的序列,它必須自己判斷是不是按了 ALT 鍵。
Vim 預設假設按下 ALT 鍵等于置位輸入字元的第 8 位。多數正常的終端如此工作,包括
xterm、aterm 和 rxvt。假如你的 <A-k> 映射不能工作,可能的原因是你的終端用在字
符前加上 ESC 字首的方法。但是你本來也可能在字元前輸入 ESC,這時 Vim 就不知道到
底發生了什麼 (隻能檢查字元間的延遲,但這并不可靠)。
在此文寫作時,有些主流的終端,如 gnome-terminal 和 konsole,使用 ESC 字首。沒
有辦法讓它們用置位第 8 位來代替。Xterm 預設應該沒有問題。Aterm 和 rxvt 啟動時
如果使用 "--meta8" 參數也可以如此。你也可以修改資源來達到目的:
"metaSendsEscape"、"eightBitInput" 和 "eightBitOutput"。
Linux 控制台上,可以用 "setmetamode" 指令切換此行為。記住不使用 ESC 字首可能和
其它程式發生沖突。確定你的 bash 把 "convert-meta" 選項設為 "on",確定 Meta 鍵
盤綁定仍然工作 (這是預設的 readline 行為,除非你的系統配置專門作了改變)。為
此,你需要加入這行: >
set convert-meta on
到你的 ~/.inputrc 檔案。如果你建立此檔案,可能想把: >
$include /etc/inputrc
放在第一行,如果此檔案在你的系統中存在的話。這樣可以保持全局的選項設定。不過,
這可能會使 umlaut 這樣的特殊字元的輸入有問題。這時,輸入字元前用 CTRL-V 前導。
要知道有報告說 convert-meta 使得 UTF-8 locale 的使用有問題。在 xterm 這樣的終
端裡,可以在 "Main Options" 菜單裡随時切換 "metaSendsEscape" 資源,或者終端上
按 Ctrl-LeftClick 也可以;如果你需要給 Vim 之外的其它應用程式發送 ESC,這是最
後應急的方法。
1.11 映 射 操 作 符 *:map-operator*
操作符應用于 {motion} 指令之前。要定義你自己的操作符,你需要先建立映射來設定
'operatorfunc' 選項,然後調用 |[email protected]| 操作符。這樣使用者輸入 {motion} 指令後,會調
用指定的函數。
*[email protected]* *E774* *E775*
[email protected]{motion} 調用 'operatorfunc' 選項設定的函數。
'[ 位置标記定位在 {motino} 跨越的文本的開始處,而 ']
位置标記在此文本的結束處。
函數調用時,帶一個字元串參數:
參數 如果
"line" {motion} 本是 |linewise|
"char" {motion} 本是 |characterwise|
"block" {motion} 本是 |blockwise-visual||
不過,"block" 很少出現,因為它隻能來自可視模式,那裡
"[email protected]" 不是很有用。
{僅當編譯時加入 +eval 特性才有效}
這裡是一例,<F4> 來計算空格數目: >
nmap <silent> <F4> :set opfunc=CountSpaces<CR>[email protected]
vmap <silent> <F4> :<C-U>call CountSpaces(visualmode(), 1)<CR>
function! CountSpaces(type, ...)
let sel_save = &selection
let &selection = "inclusive"
let reg_save = @@
if a:0 " 在可視模式裡調用,使用 '< 和 '> 位置标記。
silent exe "normal! `<" . a:type . "`>y"
elseif a:type == 'line'
silent exe "normal! '[V']y"
elseif a:type == 'block'
silent exe "normal! `[\<C-V>`]y"
else
silent exe "normal! `[v`]y"
endif
echomsg strlen(substitute(@@, '[^ ]', '', 'g'))
let &selection = sel_save
let @@ = reg_save
endfunction
<
注意 'selection' 選項暫時設為 "inclusive",以便可視模式下用 '[ 到 '] 位置标記
可以抽出正确的文本。
也要 注意 這裡為可視模式提供了專用的映射。它先删除 ":" 在可視模式裡插入的
"'<,'>" 範圍,然後調用函數,調用時使用了 visualmode() 和一個額外的參數。
==============================================================================
2. 縮寫 *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" 類型以一個非關鍵字字元結尾,其它字元可以是任意類型,除了空
格和制表。{Vi 不支援這種類型}
例如: "def#","4/7$"
不能被縮寫的字串例子: "a.b","#def","a b","_$r"
僅當你輸入一個非關鍵字字元時縮寫才會被識别,這也包括用 <Esc> 退出插入模式或用
<CR> 結束一個指令的情形。結束縮寫的非關鍵字字元被插入到縮寫的擴充後面。一個例
外是字元 <C-]>,它用來擴充一個縮寫,但不插入任何附加字元。
例如: >
:ab hh hello
< "hh<Space>" 被擴充為 "hello<Space>"
"hh<C-]>" 被擴充為 "hello"
光标前的字元必需和縮寫比對。每種類型還有附加規則:
full-id 比對的前面是一個非關鍵字字元,或者是在行或插入的開始。例外: 當縮寫僅
有一個字元時,如果它前面有一個非關鍵字字元則不會被識别,除非那是空格
和制表。
end-id 比對的前面是一個關鍵字字元,或者空格或制表,或者行或插入的開始。
non-id 比對的前面是一個空格、制表或者行或插入的開始。
例如: ({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>"
要在插入模式中避免縮寫: 輸入縮寫的一部分,以 <Esc> 退出插入模式,再用 'a' 重新
進入插入模式并輸入剩下的部分。或者在縮寫之後的字元前面輸入 CTRL-V。
要在指令行模式中避免縮寫: 在縮寫的某處輸入 CTRL-V 兩次來避免它被替換。不然,一
個普通字元前面的 CTRL-V 通常會被忽略。
縮寫進行之後移動光标是可能的: >
:iab if if ()<Left>
如果 'cpoptions' 裡面包含 '<' 标志位時,這不能正常工作。|<>|
你甚至可以做更複雜的事情。例如,要消滅一個縮寫後面輸入的空格: >
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" 而不會有任何問題。但是縮寫能被映
射。{一些版本的 Vi 支援遞歸縮寫,這毫無道理}
'paste' 選項打開時,縮寫被禁止。
*: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} 開頭的縮寫
:ab[breviate] [<expr>] {lhs} {rhs}
增加一個從 {lhs} 到 {rhs} 的縮寫。如果 {lhs} 已經存在
則它會被替換成新的 {rhs}。{rhs} 可包含空格。
|:map-<expr>| 說明可選的 <expr> 參數。
*:una* *:unabbreviate*
:una[bbreviate] {lhs} 從清單中删除 {lhs} 的縮寫。如果找不到,删除 {rhs} 比對
這裡的 {lhs} 參數的縮寫。這是為了友善你删除擴充後的縮
寫。要避免擴充,插入 CTRL-V (記住輸入兩次)。
*:norea* *:noreabbrev*
:norea[bbrev] [<expr>] [lhs] [rhs]
與 ":ab" 一樣,但 {rhs} 不進行重映射。{Vi 無此功能}
*:ca* *:cabbrev*
:ca[bbrev] [<expr>] [lhs] [rhs]
與 ":ab" 一樣,但僅在指令行模式中使用。{Vi 無此功能}
*:cuna* *:cunabbrev*
:cuna[bbrev] {lhs} 與 ":una" 一樣,但僅在指令行模式中使用。{Vi 無此功能}
*:cnorea* *:cnoreabbrev*
:cnorea[bbrev] [<expr>] [lhs] [rhs]
與 ":ab" 一樣,但僅在指令行模式中使用并且 {rhs} 不進行
重映射。{Vi 中無此功能}
*:ia* *:iabbrev*
:ia[bbrev] [<expr>] [lhs] [rhs]
與 ":ab" 一樣,但僅在插入模式中使用。{Vi 無此功能}
*:iuna* *:iunabbrev*
:iuna[bbrev] {lhs} 與 ":una" 一樣,但僅在插入模式中使用。{Vi 無此功能}
*:inorea* *:inoreabbrev*
:inorea[bbrev] [<expr>] [lhs] [rhs]
與 ":ab" 一樣,但僅在插入模式中使用并且 {rhs} 不進行重
映射。{Vi 無此功能}
*:abc* *:abclear*
:abc[lear] 删除所有的縮寫。{Vi 無此功能}
*:iabc* *:iabclear*
:iabc[lear] 為插入模式删除所有的縮寫。{Vi 無此功能}
*:cabc* *:cabclear*
:cabc[lear] 為指令行模式删除所有的縮寫。{Vi 無此功能}
*using_CTRL-V*
在一個縮寫的 {rhs} 中使用特殊字元是可能的。CTRL-V 可以用來避免多數不可顯示字元
的特殊含義。需要輸入多少個 CTRL-V 取決于你如何輸入縮寫。此處讨論同樣适用于映
射。這裡使用一個例子說明。
假設你需要把 "esc" 縮寫為輸入一個 <Esc> 字元。當你在 Vim 中輸入 ":ab" 指令,你
必需這樣輸入: (這裡 ^V 是一個 CTRL-V 并且 ^[ is <Esc>)
你輸入: ab esc ^V^V^V^V^V^[
所有的鍵盤輸入都經過 ^V 引用解釋,是以第一個,第三個,和第五個 ^V 字元
隻是為了把第二個、第四個 ^V 和 ^[ 輸入到指令行裡。
你看到: ab esc ^V^V^[
指令行裡在 ^[ 之前包含兩個實際的 ^V。如果你采用這種方法,這是該行在你
的 .exrc 檔案應該出現的樣子。第一個 ^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>" 能用于映射或菜單。這要求 'cpoptions' 中沒有 '<' 标志位。
當執行映射指令時,Vim 将把 "<SID>" 替換成特殊鍵碼 <SNR>,後跟一個每個腳本唯
一的數字編号,和一個下劃線。例如: >
:map <SID>Add
會定義一個映射 "<SNR>23_Add"。
當在一個腳本中定義一個函數的時候,可以在名字的前面用一個 "s:" 來使它局部于腳本
中。但當一個映射 (譯者注: 似應為函數) 從腳本外面被執行時,它不知道該函數在哪個
腳本中被定義。為了避免這種情況,使用 "<SID>" 來代替 "s:"。映射也做同樣的變換。
這使得在映射裡可以定義一個函數調用。
當一個局部函數被執行時,它在定義腳本的上下文中運作。這意味着,它定義的新函數和
映射也可以使用 "s:" 或 "<SID>",并且使用和函數本身定義時相同的唯一數字編号。
此外,也能用 "s:var" 腳本局部變量。
當執行一個自動指令或一個使用者指令時,它将在定義腳本的上下文中運作。這使得該指令
可以調用一個局部函數或者使用一個局部映射。
除此以外,在腳本上下文之外使用 "<SID>" 是錯誤的。
如果你需要在一個複雜的腳本中取得腳本的數字編号,使用此函數: >
function s:SID()
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$')
endfun
列出函數和映射時會顯示 "<SNR>"。可以用來它們在哪裡被定義。
指令 |:scriptnames| 可以用來檢視哪些腳本已經被讀入以及它們的 <SNR> 數字編号。
這些都是 {Vi 無此功能} 并且 {僅當編譯時加入 +eval 特性才有效}。
==============================================================================
4. 使用者定義的指令 *user-commands*
可以定義你自己的 Ex 指令。使用者自定義指令可以和内建指令一樣運作 (它可以有範圍或
參數,參數可以是自動補全的檔案名或緩沖區名,等等),除了當該指令執行時,它會被
轉換成一個普通的 ex 指令然後再被執行以外。
對于初學者來說: 參考使用者手冊中的 |40.2| 。
*E183* *user-cmd-ambiguous*
所有使用者定義的指令都必須以大寫字母開頭,來避免與内建指令的沖突。(要注意的是,
有少數内建指令比如 :Next,:Print and :X,也以大寫字母開頭。在這些情況下内建的
指令總是優先執行的)。使用者指令的其它字元可以是大寫字母,小寫字母或數字。當使用
數字時,小心會和其它以數字作為參數的指令混淆。例如,指令 ":Cc2" 可能是不帶參數
的使用者指令 ":Cc2",也可能是參數為 "2" 的指令 "Cc"。建議在指令名和參數之間放置
一個空格來避免這些問題。
當使用一個使用者定義的指令時,該指令可以縮寫。但是,如果縮寫不唯一,會發生錯誤。
此外,内建指令總是優先執行。
例如: >
:command Rename ..。
:command Renumber ..。
:Rena " 意味着 "Rename"
:Renu " 意味着 "Renumber"
:Ren " 錯誤 - 有二義性
:command Paste ..。
:P " 内建的 :Print
建議在腳本中使用使用者自定義指令的全名。
:com[mand] *:com* *:command*
列出所有使用者自定義指令。在列出指令時,
前兩欄的字元表示
! 指令有 -bang 屬性
" 指令有 -register 屬性
b 指令局部于目前緩沖區
(下面給出屬性的較長的描述)
:com[mand] {cmd} 列出以 {cmd} 開頭的使用者指令
*:command-verbose*
如果 'verbose' 非零,指令列出的同時顯示它最近定義的位置。例如: >
:verbose command TOhtml
< Name Args Range Complete Definition ~
TOhtml 0 % :call Convert2HTML(<line1>, <line2>) ~
Last set from /usr/share/vim/vim-7.0/plugin/tohtml.vim ~
|:verbose-cmd| 介紹詳情。
*E174* *E182*
:com[mand][!] [{attr}...] {cmd} {rep}
定義一個使用者指令。指令的名字是 {cmd},而替換的文本是
{rep}。該指令的屬性 (參考下面) 是 {attr}。如果該指令已
存在,報錯,除非已經指定了一個 !,這種情況下指令被重定
義。
:delc[ommand] {cmd} *:delc* *:delcommand* *E184*
删除使用者定義指令 {cmd}。
:comc[lear] *:comc* *:comclear*
删除所有使用者定義指令。
指令屬性
Vim 和任何其它 ex 指令一樣對待使用者自定義指令。它能有參數,也可以指定範圍。參數
可以進行檔案名,緩沖區等補全。具體的工作方式取決于指令的屬性,屬性在指令被定義
時被指定。
屬性可分四大類: 參數處理、補全行為、範圍處理和特殊情況。下面分類描述之。
參數處理 *E175* *E176* *:command-nargs*
預設時,使用者自定義指令不接受參數 (如果使用了任何參數會報錯)。但通過使用 -nargs
屬性可以允許指令接受參數。有效的值為:
-nargs=0 不允許有參數 (預設情況)
-nargs=1 要求一個參數
-nargs=* 允許任何數目的參數 (0,1 或更多)
-nargs=? 允許 0 或 1 個參數
-nargs=+ 必需給出參數,但是數目任意
這個上下文中認為 (未轉義的) 空格或制表用來分隔參數。
注意 參數被作為文本使用,不是表達式。特别是,"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=augroup 自動指令組
-complete=buffer 緩沖區名
-complete=command Ex 指令 (及其參數)
-complete=dir 目錄名
-complete=environment 環境變量名
-complete=event 自動指令事件
-complete=expression Vim 表達式
-complete=file 檔案和目錄名
-complete=shellcmd 外殼指令
-complete=function 函數名
-complete=help 幫助主題
-complete=highlight 高亮組
-complete=mapping 映射名
-complete=menu 菜單
-complete=option 選項
-complete=tag 标簽
-complete=tag_listfiles 标簽,但敲入 CTRL-D 時顯示檔案名
-complete=var 使用者變量
-complete=custom,{func} 使用者定制的自動補全,通過 {func} 來定義
-complete=customlist,{func} 使用者定制的自動補全,通過 {func} 來定義
使用者定制的自動補全 *: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 将用它的正規表達式引擎來進行過濾,這種方
式在大多數情況下效率更高。對于 "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:ArgLead), "\n")
:endfun
<
範圍處理 *E177* *E178* *:command-range*
*:command-count*
預設時,使用者定義的指令不接受一個行号範圍。不過,可以使指令接受一個範圍 (-range
屬性),或者接受一個任意的數量值,該數量可以出現在指定行号的位置 (-range=N,類
似于 |:split| 指令的風格),也可以來自一個 "count" 參數 (-count=N,類似于
|:Next| 指令的風格)。此時計數可以用 |<count>| 從參數裡得到。
可能的屬性有:
-range 允許使用範圍,預設為目前行
-range=% 允許使用範圍,預設是整個檔案 (1,$)
-range=N 出現在行号位置的一個數量 (預設是 N) (類似于 |:split|)
-count=N 出現在行号位置或者作為首個參數的一個數量 (預設是 N) (類似
于 |:Next|)。
指定 -count (不設預設值) 等價于 -count=0。
注意 -range=N 和 -count=N 是互斥的,隻應該指定其中的一個。
特殊情況 *:command-bang* *:command-bar*
*:command-register* *:command-buffer*
有如下特殊情況:
-bang 這些指令可以使用一個 ! 修飾符 (和 :q 或 :w 類似)
-bar 這些指令可以跟随一個 "|" 和其它指令。那麼指令參數中就
不允許有 "|" 。用一個 " 可以開始一個注釋。
-register 給這些指令的第一個參數可以是一個可選的寄存器名
(和 :del,:put,:yank 類似)。
-buffer 這些指令僅在目前緩沖區裡有效。
-count 和 -register 屬性的情況,如果提供了可選的參數,它會被從參數清單中删除,
并且和替換文本分别處理。
替換文本
使用者自定義指令的替換文本掃描使用 <...> 記法的特殊轉義序列。指令行輸入的值中,
轉義序列被替換,其它文本不變。最終字元串被作為 Ex 指令來執行。要避免替換,使用
<lt> 代替初始的 <。這樣,要按本義包含 "<bang>",請使用 "<lt>bang>"。
有效的轉義序列有
*<line1>*
<line1> 指令處理範圍的開始行。
*<line2>*
<line2> 指令處理範圍的末尾行。
*<count>*
<count> 提供的數量 (在 '-range' 和 '-count' 屬性中描述)。
*<bang>*
<bang> (參考 '-bang' 屬性) 如果指令執行時帶了 ! 修飾符,擴充為 !,否
則什麼也不擴充。
*<reg>* *<register>*
<reg> (參考 '-register' 屬性) 如果指令行上指定,可選的寄存器名。否則
什麼也不擴充。<register> 是它的一個同義詞。
*<args>*
<args> 指令的參數,和實際提供的完全相同 (但正如上面提到過的,數量或寄
存器會消耗若幹參數,它們不再是 <args> 的一部分)。
<lt> 一個單獨的 '<' (小于号) 字元。擴充轉義序列時,如果需要以上轉義
序列按字面意義出現的版本時有用。- 例如,要獲得 <bang>,使用
<lt>bang>。
*<q-args>*
如果一個轉義序列的最前兩個字元是 "q-" (例如,<q-args>) 那麼該值用引号括起,使
之在表達式裡使用時成為合法的值。這種方式把參數當做單個值。如果沒有參數,
<q-args> 是空字元串。
*<f-args>*
要允許指令把參數傳送給使用者定義的函數,有一種特殊的形式 <f-args> ("function
args",函數參數)。它在空格和制表處分割指令行參數,每個參數分别用引号括起,然後
把 <f-args> 序列替換為括起參數用逗号分隔的清單。參考下面的 Mycmd 示例。沒有參
數時,<f-args> 被删除。
要在 <f-args> 的參數中嵌入空白字元,在前面加上反斜杠。<f-args> 把每對反斜杠
(\\) 用單個反斜杠替代。反斜杠後如跟非空白或反斜杠字元,保持不變。總覽如下:
指令 <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'
示例 >
" 删除從這裡到末尾的所有東西
:com Ddel +,$d
" 把目前緩沖區改名
:com -nargs=1 -bang -complete=file Ren f <args>|w<bang>
" 用一個檔案的内容來替換某個範圍内的内容
" (請用一行輸入本指令)
:com -range -nargs=1 -complete=file
Replace <line1>-pu_|<line1>,<line2>d|r <args>|<line1>d
" 計算範圍内的行數
:com! -range -nargs=0 Lines echo <line2> - <line1> + 1 "lines"
" 調用一個使用者函數 (<f-args> 的示例)
:com -nargs=* Mycmd call Myfunc(<f-args>)
當執行: >
:Mycmd arg1 arg2
時,它将調用: >
:call Myfunc("arg1","arg2")
:" 一個更實用的例子
: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")
<
在腳本裡定義使用者指令時,它可以調用局部于腳本中的函數和使用局部于腳本的映射。用
戶調用使用者指令時,該指令将運作在定義它的腳本的上下文裡,如果一個指令中使用了
|<SID>|,這一點很重要。
vim:tw=78:ts=8:ft=help:norl:
轉載位址:https://github.com/chagel/vimrc/blob/master/doc/map.cnx