MAP

*map.txt*       For Vim version 7.0.  最后更新: 2006年4月


                  VIM 参考手册    作者: Bram Moolenaar
                                  译者:  con<con@netease.com>
                                  VCD主页: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}">{lhs}* {rhs} 表示右手边 *{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}进行映射扫描。这个特性可以避免映射 的嵌套和递归。通常用于重定义一个命令。 {not in 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* 在映射命令作用的模式中删除所有的映射。 {not in 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} 开头的键映射的键系列。 {not in 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>" 并且它用于定义一个新的映射或缩写, 该映射将仅仅重映射 {rhs} 中使用被一个以 "<SID>" 开头的脚本局部定义的映射中的字 符。它可以用于避免来自外部的脚本的干扰 (举例来说,在 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| 命令 - 可以移动光标,但事后光标会被恢复 如果希望映射完成这些操作,让返回的字符做这些事情。 这里是插入递增的列表编号的例子: 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 返回空字符串,确保不插入任何内 容。 注意 要使特殊键和转义的 CSI 字节工作需要一些技巧。|:map| 目录已经做好了,所以 你应该避免做两次操作。这样不行: :imap <expr> <F3> "<Char-0x611B>" 因为 <Char- 序列作为 |:imap| 的参数被转义,而 <expr> 又做一次。这样就可以: :imap <expr> <F3> "\u611B" 在其它文本之前使用单个字节出现的 0x80 是不行的。它会被看作一个特殊键。 1.3 映 射 与 运 行 模 式 *:map-modes* 有五种映射存在 - 对于普通模式: 当输入命令时。 - 对于可视模式: 当输入命令并且可视区域已被设置为高亮时。 - 对于操作符等待模式: 当一个操作符正在进行中 ("d","y","c" 等等之后) 例如: ":omap { w" 会使 "y{" 和 "yw" 一样,"d{" 和 "dw"一样。 - 对于插入模式: 也被用于替换模式。 - 对于命令行模式: 当输入一个 ":" 或 "/" 命令时。 特殊情况:当在普通模式里为一个命令输入一个数时,对 0 的映射就会禁用。这样 在输入一个带有0的数字时不会受到对 0 键映射的干扰。 *map-overview* *map-modes* 每个映射命令工作的模式概况: *mapmode-nvo* *mapmode-n* *mapmode-v* *mapmode-o* 命令: 模式: 普通 可视+选择 操作符等待 :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" 命令来对每个不同的模式分别定义输入映射。 要为普通和可视模式但不包括操作符等待模式输入一个映射,首先在所有的三个模式中定 义该映射,然后在操作符模式中取消该映射: :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 可视 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-Vs)。 *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解码中输入 á (0xea <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*<Leader> 类似,除了它使用 "maplocalleader" 而非 "mapleader"。 <LocalLeader> 用来针对局部于一个缓冲的映射多所使用,例如: :map <LocalLeader>q \DoItNow 在一个全局插件里应该使用 <Leader> 而在一个 filetype 插件里应该使用 <LocalLeader>。"mapleader" 和 "maplocalleader" 可以是相同的。尽管如此,如果你 把它们设置为不同,全局插件和filetype插件的映射冲突的机会也是很小的。例如,你 可以保持把 "mapleader" 设置为缺省的反斜杠,并且设置 "maplocalleader" 设置为 下划线。 *map-<SID>* 在一个脚本中有一个特殊关键字叫 "<SID>" 能被用来定义一个局部于脚本中的映射。 具体细节请参考 |<SID>|。 *<Plug>* 叫做 "<Plug>" 的特殊关键字可以用于一个内部映射,它不于任何键顺序匹配。 这在插件中有用 |using-<Plug>|。 *<Char>* *<Char->* 要以一个字符的十进制,八进制或十六进制数字映射,可以使用 <Char> 来构造: <Char-123> character 123 <Char-033> character 27 <Char-0x7f> character 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> 在Command-line模式中输入时要避免字符被映射,可以先输入一个 CTRL-V。 在Insert模式中如果 '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-PCTRL-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 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 也可以;这是最后一个可以使用的好资源,用它你可以发送 ESC 其它应 用程序,但在 VIM 里不如此。 1.11 映 射 操 作 符 *:map-operator* {motion} 命令前使用操作符。要定义你自己的操作符,你需要先创建映射来设置 'operatorfunc' 选项,然后调用 |g@| 操作符。这样用户输入 {motion} 命令后,会调 用指定的函数。 *g@* *E774* *E775* g@{motion} 调用 'operatorfunc' 选项设置的函数。 '[ 位置标记定位在 {motino} 跨越的文本的开始处,而 '] 位置标记在此文本的结束处。 函数调用时,带一个字符串参数: "line" {motion} 本是 |linewise| "char" {motion} 本是 |characterwise| "block" {motion} 本是 |blockwise-visual|| 不过,"block" 很少出现,因为它只能来自可视模式,那里 "g@" 不是很有用。 {only 仅当编译时加入 +eval 特性才有效} 这里是一例,<F4> 来计算空格数目: nmap <silent> <F4> :set opfunc=CountSpaces<CR>g@ 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" 类型以一个非关键字字符结尾,其它字符可以是任意类型,除了空 格和 Tab。 {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 匹配的前面是一个非关键字字符,或者是在行或插入的开始。例外: 当缩写仅 有一个字符时,如果它前面有一个非关键字字符则不会被识别,除了空格和 <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>" 要避免在插入模式中避免缩写: 输入缩写的一部分,以 <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} 的缩写 *:norea* *:noreabbrev* :norea[bbrev] [<expr>] [lhs] [rhs] 与 ":ab" 一样,但是不为这个 {rhs} 重映射。 {not ni Vi} *:ca* *:cabbrev* :ca[bbrev] [<expr>] [lhs] [rhs] 与 ":ab" 一样,但仅在命令行模式中使用。 {not in Vi} *:cuna* *:cunabbrev* :cuna[bbrev] {lhs} 与 ":una" 一样,但仅在命令行模式中使用。 {not in Vi} *:cnorea* *:cnoreabbrev* :cnorea[bbrev] [<expr>] [lhs] [rhs] 与 ":ab" 一样,但仅在命令行模式中使用并且不为这个 {rhs} 重映射。 {Vi 中没有} *:ia* *:iabbrev* :ia[bbrev] [<expr>] [lhs] [rhs] 与 ":ab" 一样,但仅在插入模式中使用。 {not in Vi} *:iuna* *:iunabbrev* :iuna[bbrev] {lhs} 与 ":una" 一样,但仅在插入模式中使用。 {not in Vi} *:inorea* *:inoreabbrev* :inorea[bbrev] [<expr>] [lhs] [rhs] 与 ":ab" 一样,但仅在插入模式中使用并且 不为这个 {rhs} 重映射。 {not in Vi} *:abc* *:abclear* :abc[lear] 删除所有的缩写。 {not in Vi} *:iabc* *:iabclear* :iabc[lear] 为插入模式删除所有的缩写。 {not in Vi} *:cabc* *:cabclear* :cabc[lear] 为命令行模式删除所有的缩写。 {not in 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 作为它自己引用的字符, 所以你能在缩写中包含被引用的空白字符或 | 字符。: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 无此功能} 并且 {only 仅当编译时加入 +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 " Means "Rename" :Renu " Means "Renumber" :Ren " Error - ambiguous :command Paste ..。 :P " The built-in :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* 缺省时,一个用户定义的命令将不接受参数 (如果使用了任何参数会报错)。 但是指定命令可以接受参数是可能的,使用 -nargs 属性,有效的情况有: -nargs=0 不允许有参数 (缺省情况) -nargs=1 要求一个参数。 -nargs=* 允许任何数目的参数 (0,1 或更多) -nargs=? 允许 0 或 1 个参数 -nargs=+ 必需给出参数,但是数目任意 在这个上下文里,参数被认为是以空格或Tab来分隔的。 自动补全行为 *:command-completion* *E179* *E180* *E181* 缺省时,用户定义命令的参数不进行自动补全。但是,通过指定以下的一个或多个属性 后,参数可以进行自动补全 -complete=augroup autocmd 组 -complete=buffer 缓冲名 -complete=command Ex 命令 (及其参数) -complete=dir 目录名 -complete=environment 环境变量名 -complete=event autocommand 事件 -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 将用它的正则表达式引擎来进行过滤,这 种方式在大多数情况下效率更高。对于 "cusotmlist" 参数,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* 缺省时,用户定义的命令不接受一个行号范围。但是,也可以指定命令能够接受 一个范围 (-range 熟悉),或者接受一个任意的数量值,可以是行号位置 (-range=N,与 |:split| 命令类似) 或者作为一个 "数量" 参数 (-count=N,与 |:Next| 命令类似)。可能的属性有: -range 允许使用范围,缺省为当前行 -range=% 允许使用范围,缺省是整个文件 (1,$) -range=N 一个数量 (缺省是 N) 用来指定行号位置 (与 |:split|类似) -count=N 一个数量 (缺省是 N) 用来指定行号位置,或者是作为一个初始 参数 (与 |:Next| 类似) 指定一个 -count (不设缺省值) 和 -count=0 一样 注意 -range=N 和 -count=N 是互斥的 - 只应该指定其中的一个。 特殊情况 有一些特殊情况: -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> ("function args")。它在空格和Tab的地方分裂命令行参数,分别用引号括起每个参数, 并且 <f-args> 序列被逗号分隔的括起的参数列表所替换。参考下面的 Mycmd 示例。 当没有参数时,删除 <f-args>。 示例 " 删除从这里到末尾的所有东西 :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:

Generated by vim2html on 2006年 06月 24日 星期六 00:27:59 UTC