insert

insert.txt 适用于 Vim 9.0 版本。 最近更新: 2022年7月 VIM 参考手册 by Bram Moolenaar 译者: Willis、tocer Insert Insert-mode 插入和替换文本 mode-ins-repl 本文件主要讨论插入和替换模式。最后讨论一些其它方式插入文本的命令。 最常用的命令的总览可以在用户手册第 24 章 usr_24.txt 找到。 1. 特殊键 ins-special-keys 2. 特殊的特殊键 ins-special-special 3. 'textwidth''wrapmargin' 选项 ins-textwidth 4. 'expandtab''smarttab''softtabstop' 选项 ins-expandtab 5. 替换模式 Replace-mode 6. 虚拟替换模式 Virtual-Replace-mode 7. 插入模式补全 ins-completion 8. 插入模式命令 inserting 9. Ex 插入命令 inserting-ex 10. 插入文件 inserting-file 关于如何移动光标到没有字符的位置,另见 'virtualedit'。对编辑表格有用。

1. 特殊键 ins-special-keys

在插入和替换模式里,以下字符有特殊含义;其它字符被直接插入。要插入这些特殊字符 到缓冲区里,在前面加上 CTRL-V。要插入 <Nul> 字符,使用 "CTRL-V CTRL-@" 或者 "CTRL-V 000"。在有的系统上,你必须使用 "CTRL-V 003" 来插入 CTRL-C注意: 如果 CTRL-V 被映射,你也许会经常使用 CTRL-Q 来代替 i_CTRL-Q 。 如果插入时你在特殊的语言模式下工作,参见 'langmap' 选项 'langmap' 了解如何避 免反复进出这些模式。 如果置位了 'insertmode'<Esc> 和一些其它的键有另外的含义。见 'insertmode'字符 动作

i_CTRL-[ i_<Esc> <Esc>CTRL-[ 结束插入或替换模式,回到普通模式。结束缩写。 注意: 如果你很难在键盘上敲上 <Esc> 键,训练自己使用 CTRL-[。 如果 Esc 不能用而你使用的是 Mac,试试 CTRL-Esc。或者在辅助功能 里关闭收听。 i_CTRL-C CTRL-C 退出插入模式,回到普通模式。不检查缩写。不激活 InsertLeave 自动命令事件。 i_CTRL-@ CTRL-@ 插入最近插入的文本,并停止插入。 i_CTRL-A CTRL-A 插入最近插入的文本。 i_CTRL-H i_<BS> i_BS <BS>CTRL-H 删除光标前的字符 (关于连接行,见 i_backspacing )。 如果你的 <BS> 键不正确,见 :fixdel i_<Del> i_DEL <Del> 删除光标下的字符。如果光标在行尾,并且 'backspace' 选项包括 "eol",删除 <EOL>;下一行就此附加于当前行之后。 如果你的 <Del> 键不正确,见 :fixdel i_CTRL-W CTRL-W 删除光标前的单词 (关于连接行,见 i_backspacing )。关于单词的 定义,见 word-motions 关于 "单词动作" 的定义。 i_CTRL-U CTRL-U 删除当前行上光标前的所有输入字符。如果没有新输入的字符而 'backspace' 不为空,删除当前行上光标前的所有字符。 打开 C-缩进时,如果行被清空,调整缩进。 关于连接行,见 i_backspacing i_CTRL-I i_<Tab> i_Tab <Tab>CTRL-I 插入制表。如果打开 'expandtab' 选项,等价数目的空格被插入 (使 用 CTRL-V <Tab> 避免这种扩展: 如果 CTRL-V 被映射,可以使用 CTRL-Q <Tab>i_CTRL-Q )。另见 'smarttab' 选项和 ins-expandtab i_CTRL-J i_<NL> <NL>CTRL-J 开始新行。 i_CTRL-M i_<CR> <CR>CTRL-M 开始新行。 i_CTRL-K CTRL-K {char1} [char2] 输入二合字母 (见 digraphs )。当 {char1} 为特殊字符时,该键的 键码以 <> 形式插入。例如字符串 "<S-Space>" 可以这样输入: <C-K><S-Space> (两个键)。两个键都不考虑映射。 CTRL-N 查找下一个关键字 (见 i_CTRL-N )。 CTRL-P 查找上一个关键字 (见 i_CTRL-P )。 CTRL-R {register} i_CTRL-R 插入寄存器内容。在输入 CTRL-R 和第二个字符之间,'"' 会显示出 来,以提示你需要输入寄存器的名字。文本插入方式和直接输入相同, 但不使用映射和缩写。如果设置了 'textwidth''formatoptions''autoindent',插入的结果会受到影响。这和使用 "p" 命令和用鼠标 粘贴文本不同。 特殊寄存器: '"' 无名寄存器,包含最近删除或抽出的文本 '%' 当前文件名 '#' 轮换文件名 '*' 剪贴板内容 (X11: 主选择) '+' 剪贴板内容 '/' 最近的搜索模式 ':' 最近的命令行 '.' 最近插入的文本 '-' 最近的行内 (少于一行) 删除 i_CTRL-R_= '=' 表达式寄存器;你会被提示输入一个表达式 (见 expression ) 注意 0x80 (十进制 128) 用于特殊键。例如,你可 以这样移动光标向上: CTRL-R ="\<Up>" 用 CTRL-R CTRL-R 可以按本义插入文本。 如果结果是 List ,里面的项目被看作行,之间以 换行符连接。 如果结果是浮点数,自动转化为字符串。 调用 append() 或 setline() 会打断撤销序列。 关于寄存器见 registersCTRL-R CTRL-R {register} i_CTRL-R_CTRL-R 插入寄存器内容。和单个 CTRL-R 类似,但是文本按本义插入,而不是 像键盘输入那样。这意味着如果寄存器包含 <BS> 这样的字符,结果会 不同。例如,如果寄存器包含 "ab^Hc": CTRL-R a 产生 "ac"。 CTRL-R CTRL-R a 产生 "ab^Hc"。 'textwidth''formatoptions' 等等选项仍然适用。如果你连这些都 想避免,使用 CTRL-R CTRL-O,见下。 '.' 寄存器 (最近插入的文本) 依然如同键盘输入那样的方式插入。 此命令后,'.' 寄存器包含该寄存器的文本,如同键盘输入那样的方式 插入。 CTRL-R CTRL-O {register} i_CTRL-R_CTRL-O 按本义插入寄存器内容,并且不进行自动缩进。和鼠标粘贴文本相同 <MiddleMouse> 。如果寄存器是面向行的,在当前行之上插入文本, 类似于 P。 不会替换字符! '.' 寄存器 (最近插入的文本) 依然如同键盘输入那样的方式插入。 此命令后,'.' 寄存器包含键入的命令而不是文本,也就是本义值 "^R^O" 而不是寄存器的文本。 CTRL-R CTRL-P {register} i_CTRL-R_CTRL-P 按本义插入寄存器内容,修正缩进,和 [<MiddleMouse> 类似。 不会替换字符! '.' 寄存器 (最近插入的文本) 依然如同键盘输入那样的方式插入。 此命令后,'.' 寄存器包含键入的命令而不是文本,也就是本义值 "^R^P" 而不是寄存器的文本。 i_CTRL-T CTRL-T 在当前行开始处插入一个 shiftwidth 的缩进。缩进总是取整到 'shiftwidth' 的倍数 (这是 vi 兼容的)。 i_CTRL-D CTRL-D 在当前行开始处删除一个 shiftwidth 的缩进。缩进总是取整到 'shiftwidth' 的倍数 (这是 vi 兼容的)。 i_0_CTRL-D 0 CTRL-D 删除所有当前行的缩进。 i_^_CTRL-D ^ CTRL-D 删除当前行的所有缩进。缩进在下一行上恢复。这可以用于插入卷标。 i_CTRL-V CTRL-V 如果下一个是非数字,按本义插入。对特殊键而言,插入其终端代码。 不然,输入的是字符的十、八或十六进制值。 i_CTRL-V_digitCTRL-V 之后紧接着输入的字符不经过映射。 注意: 当 CTRL-V 被映射时 (例如,用来粘贴文本),你可能经常需要 使用 CTRL-Q 来代替 i_CTRL-Q 。 如果打开 modifyOtherKeys ,特殊转义序列被转换回没有 modifyOtherKeys 时的样子,除非同时按住 Shift 键。 i_CTRL-Q CTRL-QCTRL-V注意: 有的终端连接会吃掉 CTRL-Q,导致该快捷键无效。在 GUI 版本 里就不会出现这样的问题。 CTRL-SHIFT-V i_CTRL-SHIFT-V i_CTRL-SHIFT-Q CTRL-SHIFT-Q 与 CTRL-V 类似,除非激活了 modifyOtherKeys ,此时插入带修饰符 的键的转义序列。 CTRL-X 进入 CTRL-X 模式,一个子模式。那里你可以给出命令来补全单词或者 滚动窗口。见 i_CTRL-Xins-completion i_CTRL-E CTRL-E 插入光标下面的字符。 i_CTRL-Y CTRL-Y 插入光标上面的字符。 注意 CTRL-ECTRL-Y 不使用 'textwidth',从而可以从长行里复制 字符。 i_CTRL-_ CTRL-_ 切换语言,如下: - 在从右到左的窗口里,切换 revins 和 nohkmap,因为在这种情况 下英语的输入可能就是倒过来的。 - 在非从右到左的窗口里,切换 revins 和 hkmap。因为希伯来语等 语种可能是倒过来输入的。 CTRL-_ 移动光标到输入文本的尾部。 该命令只有在 'allowrevins' 选项置位的时候才有效。 请参考 rileft.txt ,那里可以了解到更多有关从右到左模式的信 息。 只有在编译时加入 +rightleft 特性才有效。 i_CTRL-^ CTRL-^ 切换语言字符输入的使用方式。 如果定义了语言映射 :lmap : - 'iminsert' 为 1 (使用 langmap 映射) 时变成 0 (不使用 langmap 映射)。 - 'iminsert' 为其它值时变成 1,从而打开 langmap 映射。 如果没有定义语言映射: - 'iminsert' 为 2 (使用输入方法 (Input Method)) 时变成 0 (不使 用输入方法)。 - 'iminsert' 为其它值时变成 2,从而打开输入方法。 如果 为 1,"b:keymap_name" 变量的值、'keymap' 选项或者 "<lang>" 出现在状态行上。 这些语言映射通常用来输入键盘上不能直接产生的字符。'keymap' 选 项用来安装若干完整的这样的映射表。 i_CTRL-] CTRL-] 触发缩写,不插入字符。 i_<Insert> <Insert> 在插入和替换模式间切换。

i_backspacing <BS>CTRL-WCTRL-U 的效果决定于 'backspace' 选项 (除非置位了 'revins')。这 时一个逗号分隔的项目列表: 项目 动作 indent 允许退格删除自动缩进 eol 允许退格删除换行符 (连接行) start 允许退格删除插入开始之前的位置;CTRL-WCTRL-U 在开始位置停止 如果 'backspace' 为空,则使用 Vi 兼容的退格方式。不能退格删除自动缩进、回到第 一列之前、或者超过插入开始的地方。 为了后向兼容起见,取值 "0"、"1"、"2" 和 "3" 也是允许的,见 'backspace' 。 如果 'backspace' 选项的确包含 "eol",光标在第一列,而使用了这三个键中的一个, 当前行会和上一行连接。这实际上删除了光标之前的 <EOL> i_CTRL-V_digit 使用 CTRL-V,可以通过十、八、十六进制值来直接输入字符。这样你可以输入除了换行 符 (<NL>,其值为 10) 以外的任何字符。有五种输入字符值的方法: 首个字符 模式 最大字符数 最大值 (无) 十进制 3 255 o 或 O 八进制 3 377 (255) x 或 X 十六进制 2 ff (255) u 十六进制 4 ffff (65535) U 十六进制 8 7fffffff (2147483647) 通常你要输入最大数目的字符数。要输入空格 (值为 32) 的时候需要键入 <C-V>032。开 头的零可以忽略,但此时数字之后的字符必须不能再是数字。其它模式也一样: 一旦输入 了在该模式下不合法的字符,那么这之前的值就会被使用,而 "非法" 的这个字符会以正 常的方式继续处理。 输入的值为 10 时,在文件中最后会以 0 出现。10 是 <NL>,内部它被用来代表 <Nul> 字符。而写入文件时,<NL> 字符被翻译成 <Nul>。每行的最后会写入 <NL>。所以,如果 你确实想在文件中插入 <NL> 字符,请使用换行。 另见 'fileformat' i_CTRL-X insert_expand CTRL-X 进入一个子模式,那里可以使用若干命令。绝大多数命令执行关键字补全;见 ins-completion 。 有两个命令可以在不退出插入模式的前提下上下滚动窗口: i_CTRL-X_CTRL-E CTRL-X CTRL-E 窗口滚动上移一行。 补全时看这里: complete_CTRL-E i_CTRL-X_CTRL-Y CTRL-X CTRL-Y 窗口滚动下移一行。 补全时看这里: complete_CTRL-Y 按了 CTRL-X 以后,每个 CTRL-E (CTRL-Y) 滚动窗口上 (下) 移一行,除非这使得光标 不得不离开当前文件中所在的位置。一旦按了另外一个键,CTRL-X 模式就会退出,而回 到插入模式下解释该键。

2. 特殊的特殊键 ins-special-special

以下的键是特殊的。它们停止当前的插入,做一些事情,然后重新插入。这意味着你可以 不脱离插入模式的情况下做一些事情。这适合于经常使用插入模式的用户,就像编辑器没 有单独的普通模式一样。也可以考虑设置 'backspace' 选项为 "indent,eol,start" 还 有置位 'insertmode' 选项。如果你想把功能键映射到命令上,可以使用 CTRL-O。 可以分别撤销这些键之前和之后的改动 (字符的插入或者删除)。只有最后的改动可以重 做,这和 "i" 命令的行为相当。 字符 动作

<Up> 光标上移一行 i_<Up> <Down> 光标下移一行 i_<Down> CTRL-G <Up> 光标上移一行,到插入开始时所在的列 i_CTRL-G_<Up> CTRL-G k 光标上移一行,到插入开始时所在的列 i_CTRL-G_k CTRL-G CTRL-K 光标上移一行,到插入开始时所在的列 i_CTRL-G_CTRL-K CTRL-G <Down> 光标下移一行,到插入开始时所在的列 i_CTRL-G_<Down> CTRL-G j 光标下移一行,到插入开始时所在的列 i_CTRL-G_j CTRL-G CTRL-J 光标下移一行,到插入开始时所在的列 i_CTRL-G_CTRL-J <Left> 光标左移一个字符 i_<Left> <Right> 光标右移一个字符 i_<Right> <S-Left> 光标反向一个单词 (类同 "b" 命令) i_<S-Left> <C-Left> 光标反向一个单词 (类同 "b" 命令) i_<C-Left> <S-Right> 光标正向一个单词 (类同 "w" 命令) i_<S-Right> <C-Right> 光标正向一个单词 (类同 "w" 命令) i_<C-Right> <Home> 光标移到该行首个字符 i_<Home> <End> 光标移到该行末个字符之后 i_<End> <C-Home> 光标移到该文件首个字符 i_<C-Home> <C-End> 光标移到该文件末个字符之后 i_<C-End> <LeftMouse> 光标移动鼠标点击处 i_<LeftMouse> <S-Up> 上翻窗口一页 i_<S-Up> <PageUp> 上翻窗口一页 i_<PageUp> <S-Down> 下翻窗口一页 i_<S-Down> <PageDown> 下翻窗口一页 i_<PageDown> <ScrollWheelDown> 窗口向下滚动三行 i_<ScrollWheelDown> <S-ScrollWheelDown> 窗口向下滚动一个整页 i_<S-ScrollWheelDown> <ScrollWheelUp> 窗口向上滚动三行 i_<ScrollWheelUp> <S-ScrollWheelUp> 窗口向上滚动一个整页 i_<S-ScrollWheelUp> <ScrollWheelLeft> 窗口向左滚动六列 i_<ScrollWheelLeft> <S-ScrollWheelLeft> 窗口向左滚动一个整页 i_<S-ScrollWheelLeft> <ScrollWheelRight> 窗口向右滚动六列 i_<ScrollWheelRight> <S-ScrollWheelRight> 窗口向右滚动一个整页 i_<S-ScrollWheelRight> CTRL-O 执行命令,然后返回到插入模式 i_CTRL-O CTRL-\ CTRL-O 类似于 CTRL-O,但不移动光标 i_CTRL-\_CTRL-O CTRL-L 置位 'insertmode' 时: 转到普通模式 i_CTRL-L CTRL-G u 打断撤销序列,开始新的改变 i_CTRL-G_u CTRL-G U 只要光标停在同一行,下个左/右光标移动不打断 i_CTRL-G_U 撤销

备注: 如果光标键把你带出了插入模式,查查 'noesckeys' 选项。 CTRL-O 命令有时有副作用: 如果光标在行尾之外,它会先被移动该行最后一个字符上。 在映射里,通常更好的方法是使用 <Esc> (先在文本中放一个 "x",<Esc> 这时总会把光 标放到它的上面)。或者使用 CTRL-\ CTRL-O,不过这时要注意光标可能移到行尾之外的 位置。注意 CTRL-\ CTRL-O 后跟的命令仍然可以移动光标,光标不会自动恢复到原来的 位置。 CTRL-O 命令带你到普通模式,此时如使用了进入插入模式的命令,插入模式通常不会嵌 套。因而,输入完 "a<C-O>a" 然后按 <Esc>,你会立即回到普通模式,不需要按 <Esc> 两次。一个例外是此命令如果不是直接键入而是在比如执行映射或执行脚本时,嵌套仍然 会发生。只有这样,短暂切换到插入模式的映射才可以工作。 不是在所有的终端上都能用 Shift + 光标键。 另外一个副作用是 "i" 或 "a" 命令之前指定的计数会被忽略。这是因为要实现 CTRL-O 之后的命令的重复执行太复杂了。 一个使用 CTRL-G u 的例子: :inoremap <C-H> <C-G>u<C-H> 它重定义退格键使之开始新的撤销序列。现在可以用 CTRL-O u 来撤销退格键的效果,而 不会改变你之前输入的内容。另一例: :inoremap <CR> <C-]><C-G>u<CR> 这样,每行之后都会打断撤销序列。在此之前也扩展缩写。 一个使用 CTRL-G U 的例子: inoremap <Left> <C-G>U<Left> inoremap <Right> <C-G>U<Right> inoremap <expr> <Home> col('.') == match(getline('.'), '\S') + 1 ? \ repeat('<C-G>U<Left>', col('.') - 1) : \ (col('.') < match(getline('.'), '\S') ? \ repeat('<C-G>U<Right>', match(getline('.'), '\S') + 0) : \ repeat('<C-G>U<Left>', col('.') - 1 - match(getline('.'), '\S'))) inoremap <expr> <End> repeat('<C-G>U<Right>', col('$') - col('.')) inoremap ( ()<c-g>u<left> 这样,插入模式下使用光标键就不会打断撤销序列,. (重做) 命令因此才会正常工作。 还有,输入以下的文本 (使用上述的 "(" 映射): Lorem ipsum (dolor 就可以用 . 重做,以出现以下的期待结果 Lorem ipsum (dolor) CTRL-O 的使用分割撤销: 之前和之后的输入的文本被分别撤销。如果不想如此 (比如用 在映射里),可能可用 CTRL-R = i_CTRL-R 。例如,要调用函数: :imap <F2> <C-R>=MyFunc()<CR> 正确设置 'whichwrap' 选项的话,在一行的首个/末个字符上按 <Left><Right> 键 会使光标回绕到上一行/下一行。 CTRL-G j 和 CTRL-G k 命令可用来在同一列前插入文本。例如: int i; int j; 把光标定位在第一个 "int" 上,输入 "istatic <C-G>j "。结果是: static int i; int j; 要在每行的同一列之前插入相同的文本,可用可视列块命令 "I" v_b_I

3. 'textwidth''wrapmargin' 选项 ins-textwidth

'textwidth' 选项可以用来在行变得很长之前自动断行。设置 'textwidth' 选项为希望 的最大行长。如果你输入更多字符 (不是空格或者制表),最后一个单词会放在一个新行 上 (除非这是该行唯一一个单词)。如果你设置 'textwidth' 为 0,该特性被关闭。 'wrapmargin' 选项做的事情基本相同。区别在于 'textwidth' 是一个固定的宽度,而 'wrapmargin' 根据屏幕的宽度设置。设置 'wrapmargin' 等价于 'textwidth' 设为 (columns - 'wrapmargin'),其中 columns 是屏幕的宽度。 如果同时设置 'textwidth''wrapmargin',使用 'textwidth'。 如果你并不真的想断开行,而只是想文本行在合适的位置回绕,见 'linebreak' 选项。 文本行只有在插入模式下或者附加到行后的时候才会自动断开。在替换模式下,只要行的 长度没有变,就不会断行。 长行在你输入一个出现在边界之后的非空白字符的时候断开。在 'formatoptions' 选项 里加入如下字母可以限制断行的时机: "l" 只有当插入开始时文本行的长度不超过 'textwidth',断行才会发生。 "v" 只在当前插入命令中输入的一个空白字符上断行。这是和 Vi 最兼容的行为。 "lv" 只有当插入开始时文本行的长度不超过 'textwidth',并且在当前插入命令中输入 的一个空白字符上断行才会发生。和 "l" 唯一的不同在于跨越 'textwidth' 边界 时输入的都是非空白字符的时候。 通常使用内部函数来决定在哪里断行。如果你想用不同的方法,设置 'formatexpr' 选项 为处理换行的表达式。 如果想排版文本块,可用 "gq" 操作符。输入 "gq" 紧跟一个移动光标到块尾的移动命 令。在许多情况下,命令 "gq}" 会做你想要做的事情 (排版直到段落尾部)。也可用 "gqap" 来排版整个段落而不管光标当前在哪个位置。也可用可视模式: 敲击 "v",移动 到块尾,然后输入 "gq"。另见 gq

4. 'expandtab''smarttab''softtabstop' 选项 ins-expandtab

如果打开 'expandtab' 选项,空格可以用来填充制表键的空白位置。如果你需要输入真 正的 <Tab>,先输入 CTRL-V (如果 CTRL-V 被映射的话可用 CTRL-Q i_CTRL-Q ) 再 做。 缺省关闭 'expandtab' 选项。注意 替换模式下,一个字符会被多个空格字符所代替。结 果是行内的字符数会增加。退格键一次删一个空格键。只有一个空格 (最后一个) 上的退 格才能得回原来的字符。 ins-smarttab 打开 'smarttab' 选项时,<Tab> 在行首插入 'shiftwidth' 个位置,而在其它地方插 入 'tabstop' 个位置。这意味着插入的常常是空格而不是 <Tab> 字符。而关闭 'smarttab' 时,<Tab> 总是插入 'tabstop' 个位置,只有在 ">>" 和类似命令中才会用 到 'shiftwidth' ins-softtabstop 如果 'softtabstop' 选项不为零,<Tab> 插入 'softtabstop' 个位置,而过去用来删除 空格的 <BS>,现在会删除 'softtabstop' 个位置。感觉上,'tabstop' 被设成了 'softtabstop' 的值,但实际上一个真正的 <Tab> 字符还是占据 'tabstop' 个位置。从 而,你的文件在别的应用程序里看起来还是正确的。 如果 'softtabstop' 不为零,<BS> 会试图删除尽量多的空白,以便能够回到往前 'softtabstop' 的位置,除非前面一个插入的字符正好就是一个空格,这时它只会删除光 标前的那个字符。否则,你不一定总能删除光标前的一个字符。你将不得不先删除 'softtabstop' 个字符,然后再输入额外的空格,以到达你想要的地方。

5. 替换模式 Replace Replace-mode mode-replace

普通模式下输入 "R" 命令进入替换模式。 替换模式下,输入的每个字符会删除行内的一个字符。如果没有字符可以删了 (在行 尾),则附加输入的字符 (此时和插入模式一样)。这样,直到到达行尾前,行内的字符数 保持不变。如果输入的是 <NL>,插入换行符,但不会删除任何字符。 要小心 <Tab> 字符。如果在其上输入一个正常的可显示字符,字符数仍然一样,但是列 数看起来少了。 如果你在替换模式下删除字符 (用 <BS>CTRL-WCTRL-U),实际发生的事是你删除了 改变。被替换的字符被复原了。如果你的输入超过已有的部分,新增的字符会被删除。实 际上,这可以看作是一次一个字符的撤销。 如果打开了 'expandtab' 选项,<Tab> 会用多个空格替换一个字符。结果是行内的字符 数会增加。退格键只能一次删一个空格。只有一个空格 (最后一个) 上的退格才能得回原 来的字符。

6. 虚拟替换模式 vreplace-mode Virtual-Replace-mode

在普通模式里输入 "gR" 命令进入虚拟替换模式。 {仅当编译时加入 +vreplace 特性才会有效} 虚拟替换模式和替换模式类似,但不是替换文件里的实际字符,而是替换屏幕的领地。这 样,文件里的字符看起来不会移动。 所以,如果你输入了 <Tab>,它会替换多个普通的字符,而如果你在 <Tab> 上输入字 母,它可能什么都没有代替,因为 <Tab> 还是会占据相同的位置。 输入 <NL> 还是不会导致文件后面的字符看起来移动过。当前行的后面部分被 <NL> 所替换 (也就是,它们被删除了),而替换继续在下一行进行。 会插入新行,除非 你到达文件尾部之后。 输入 CTRL-TCTRL-D 会看到有趣的效果。光标前面的字符跟平常一样向一边移动,但 是光标后面的字符保持不动。CTRL-T 会隐藏被移动字符遮盖的部分旧行,而 CTRL-D 会 重新让它们显现出来。 和替换模式一样,使用 <BS> 等会恢复被替换的字符。即使和 'smartindent'CTRL-TCTRL-D'expandtab''smarttab''softtabstop' 等一起使用的效果也是如此。 在 'list' 模式下,虚拟替换模式的行为和不在 'list' 模式下一样,除非 'cpoptions' 里设置了 "L"。 注意 在此模式下,光标之后的字符看起来在移动的情况仅有列表模式 'list' ,置位 'wrap' 时偶尔也会出现 (当行改变了长度,使得比屏幕宽度更窄或者更宽时)。其他情况 下空格会被插入,以防止之后的字符移动。 该模式对编辑 <Tab> 分隔表格列的时候很有用,因为输入新的数据时同时还能保持所有 的列对齐。

7. 插入模式补全 ins-completion

在插入和替换模式下,有若干命令可以补全输入的部分关键字或者行。这可以用于使用复 杂关键字的场合 (例如,函数名里有大写字母或者下划线)。 补全可以是针对: 1. 整行 i_CTRL-X_CTRL-L 2. 当前文件内的关键字 i_CTRL-X_CTRL-N 3. 'dictionary' 的关键字 i_CTRL-X_CTRL-K 4. 'thesaurus' 的关键字,同义词风格 i_CTRL-X_CTRL-T 5. 当前文件及其头文件内的关键字 i_CTRL-X_CTRL-I 6. 标签 i_CTRL-X_CTRL-] 7. 文件名 i_CTRL-X_CTRL-F 8. 定义或宏 i_CTRL-X_CTRL-D 9. Vim 命令 i_CTRL-X_CTRL-V 10. 用户定义的补全 i_CTRL-X_CTRL-U 11. 全能 (omni) 补全 i_CTRL-X_CTRL-O 12. 拼写建议 i_CTRL-X_s 13. 'complete' 的关键字 i_CTRL-N i_CTRL-P 此外, i_CTRL-X_CTRL-Z 停止补全而不改动现有的文本。 除了 CTRL-NCTRL-P 以外,所有这些都通过 CTRL-X 模式完成。这是插入和替换模式 的一个子模式。你可以键入 CTRL-X 后跟一个 CTRL-X 命令来进入 CTRL-X 模式。要退出 CTRL-X 模式,输入非合法的 CTRL-X 模式命令就行了。合法的键包括 CTRL-X 命令自 身, CTRL-N (后一个) 和 CTRL-P (前一个)。 想得到当前补全的信息,可用 complete_info() 。 如果你想调整匹配的大小写,另见 'infercase' 选项。 complete_CTRL-E 如果补全处于激活状态,可以用 CTRL-E 来停止补全并回到原来录入的文字。CTRL-E 本 身不会被插入。 complete_CTRL-Y 如果显示了弹出菜单,可以使用 CTRL-Y 停止补全并接受当前的选择项。CTRL-Y 本身不 会被插入。键入空格、回车或者其他不可显示字符将离开补全模式并插入键入的字符。 显示弹出菜单时,有一些特殊键可用,见 popupmenu-keys注意: CTRL-X 模式下合法的键不经过映射。这使得 ":map ^F ^X^F" 能够工作 (其中 ^F 是 CTRL-F 而 ^X 是 CTRL-X)。能够使得 CTRL-X 模式退出的键 (任何不是合法 CTRL-X 模式命令的键) 则经过映射。另外,通过 'complete' 的补全也应用映射。 E565 注意: 补全激活时,不能递归使用插入模式,也不能改变缓冲区文本。以某种方式调用 ":normal i.." 的映射将产生 E565 错误。 建议使用以下映射来使得输入补全命令简单一点 (不过它们可能屏蔽其它的命令): :inoremap ^] ^X^] :inoremap ^F ^X^F :inoremap ^D ^X^D :inoremap ^L ^X^L 一个特例是,执行寄存器插入的 CTRL-R (见 i_CTRL-R ) 不会退出 CTRL-X 模式。这主 要是为了允许通过使用 '=' 寄存器来调用若干函数来决定下一个操作。如果该寄存器的 内容 (或者 '=' 寄存器计算的结果) 不是合法的 CTRL-X 模式键,那么就会退出 CTRL-X 模式,如同键盘输入这些内容一样。 例如,下面的程序会如此映射 <Tab>: 如果当前行只有空白,就插入 <Tab>,不然就开始 或继续 CTRL-N 补全操作: function! CleverTab() if strpart( getline('.'), 0, col('.')-1 ) =~ '^\s*$' return "\<Tab>" else return "\<C-N>" endif endfunction inoremap <Tab> <C-R>=CleverTab()<CR> 补全整行 compl-whole-line i_CTRL-X_CTRL-L CTRL-X CTRL-L 反向搜索和当前行光标前字符序列完全相同的行。忽略缩进。 找到的行插入在光标的前面。 'complete' 选项用来决定匹配在哪个缓冲区里搜索,已载入 和未载入的缓冲区都被使用。 CTRL-LCTRL-P 反向搜索前一个匹配行。替换上一次匹配的行。 CTRL-N 正向搜索下一个匹配行。替换上一次匹配的行。 CTRL-X CTRL-L 在扩展一行以后,你可以通过接着输入 CTRL-X CTRL-L 得到 紧接着匹配行之后的行,直到见到两个 CTRL-X 为止。只能用 于已载入的缓冲区。 补全当前文件内的关键字 compl-current i_CTRL-X_CTRL-P i_CTRL-X_CTRL-N CTRL-X CTRL-N 正向搜索以光标前面的关键字开始的单词。找到的关键字插入 在光标的前面。 CTRL-X CTRL-P 反向搜索以光标前面的关键字开始的单词。找到的关键字插入 在光标的前面。 CTRL-N 正向搜索下一个匹配的关键字。替换上一次匹配的关键字。 CTRL-P 反向搜索前一个匹配的关键字。替换上一次匹配的关键字。 CTRL-X CTRL-NCTRL-X CTRL-P 继续使用 CTRL-X CTRL-NCTRL-X CTRL-P 会复制上次本类 型补全在其它上下文里扩展的单词之后紧跟的单词,直到见到 两个 CTRL-X 为止。 如果在光标的前面有一个关键字 (由字母字符和 'iskeyword' 指定的字符组成的名字), 它的前面再加上 "\<" (含义: 单词开始) 就被用作搜索模式。否则 "\<\k\k" 被用作搜 索模式 (任何包含至少两个字符的关键字的开始)。 在替换模式下,替换的字符数目决定于匹配字符串的长度。这和直接在替换模式下键盘输 入经过替换的字符串类似。 如果光标前面不是一个合法的关键字字符,则匹配任何至少有两个字符的关键字。 例如,要得到: printf("(%g, %g, %g)", vector[0], vector[1], vector[2]); 只需输入: printf("(%g, %g, %g)", vector[0], ^P[1], ^P[2]); 搜索会在文件末尾回绕,这里不使用 'wrapscan' 的值。 跳过多次重复的相同的补全内容;这样每次 CTRL-NCTRL-P 都会插入不同的匹配 (除 非只有一个匹配的关键字)。 永远不会得到单个字符的匹配,因为它们通常不是你真想要的。 例如,要得到: printf("name = %s\n", name); 或者: printf("name = %s\n", n^P); 甚至: printf("name = %s\n", ^P); '\n' 中的 'n' 被跳过。 在扩展完一个词后,你可以使用 CTRL-X CTRL-PCTRL-X CTRL-N 得到紧跟在扩展词 之后的单词。这些序列搜索刚刚扩展的文本,并且继续扩展之,使之包括另外一个词。这 可以用于你需要重复一系列复杂的单词的场合。尽管 CTRL-PCTRL-N 只会找至少两个 字符的字符串,CTRL-X CTRL-PCTRL-X CTRL-N 可以用来扩展只有一个字符的单词。 例如,要得到: M&eacute;xico 你可以输入: M^N^P^X^P^X^P CTRL-N 开始一个扩展,而 CTRL-P 回到单个字符 "M",然后后面的两个 CTRL-X CTRL-P 分别得到 "&eacute" 和 ";xico"。 如果上次的扩展因为超过 'textwidth' 被分割,则只会使用当前行的文本。 如果匹配在行尾,那么会插入下一行的首个单词,而且显示消息 "Word from other line"。如果该词被接受,那么下个 CTRL-X CTRL-P 或者 CTRL-X CTRL-N 会搜索那些以 该单词开始的行。 补全 'dictionary' 的关键字 compl-dictionary i_CTRL-X_CTRL-K CTRL-X CTRL-K 根据 'dictionary' 选项给出的文件搜索光标前关键字开始的 单词。这和 CTRL-N 类似,只不过搜索的是字典文件,而不是 当前文件。在光标之前插入找到的关键字。这可能很慢,因为 在用到第一个匹配之前,会先找到所有的匹配。缺省, 'dictionary' 选项为空。 关于哪里能找到单词列表的建议,见 'dictionary' 选项。 适用 'ignorecase''smartcase''infercase'CTRL-KCTRL-N 正向搜索下一个匹配的关键字。替换前次匹配的关键字。 CTRL-P 反向搜索下一个匹配的关键字。替换前次匹配的关键字。 补全 'thesaurus' 的单词 compl-thesaurus i_CTRL-X_CTRL-T CTRL-X CTRL-TCTRL-X CTRL-K 类似,但稍有不同。它使用 'thesaurus' 选项,而不是 'dictionary'。如果在同义词字典里找到匹 配,同一行里其余单词也会被列为匹配,即使它们并不补全单 词。这样一个单词可以被完全替换。 CTRL-TCTRL-N 正向搜索下一个匹配的关键字。替换前次匹配的关键字。 CTRL-P 反向搜索下一个匹配的关键字。替换前次匹配的关键字。 'thesaurus' 选项使用的文件中,每行应该包含相近意思的单词,以非关键字字符分隔 (建议使用空白)。最大的行长为 510 个字节。 举一个例子,假想 'thesaurus' 文件有一行形如: angry furious mad enraged 把光标放在字母 "ang" 之后并输入 CTRL-X CTRL-T 会匹配单词 "angry";继续按会把单 词改为 "furious"、"mad" 等等。 其它的用法包括在两种语言之间的翻译,或者用关键字给 API 函数归类等等。 此 github 议题附加了英语单词列表: https://github.com/vim/vim/issues/629#issuecomment-443293282 解包 thesaurus_pkg.zip,把 thesaurus.txt 文件放在某处,如 ~/.vim/thesaurus/english.txt,然后把 'thesaurus' 选项设为此文件名。 用 'thesaurusfunc' 补全关键字 compl-thesaurusfunc 如果设置了 'thesaurusfunc' 选项,执行用户指定函数来生成补全匹配的列表,忽略 'thesaurus' 选项。 complete-functions 有关于如何调用函数和返回何种值的说明。 以下是使用 "aiksaurus" 命令的例子 (Magnus Groß 提供): func Thesaur(findstart, base) if a:findstart return searchpos('\<', 'bnW', line('.'))[1] - 1 endif let res = [] let h = '' for l in systemlist('aiksaurus ' .. shellescape(a:base)) if l[:3] == '=== ' let h = '(' .. substitute(l[4:], ' =*$', ')', '') elseif l ==# 'Alphabetically similar known words are: ' let h = "\U0001f52e" elseif l[0] =~ '\a' || (h ==# "\U0001f52e" && l[0] ==# "\t") call extend(res, map(split(substitute(l, '^\t', '', ''), ', '), {_, val -> {'word': val, 'menu': h}})) endif endfor return res endfunc if exists('+thesaurusfunc') set thesaurusfunc=Thesaur endif 补全当前文件及其头文件内的关键字 compl-keyword 'include' 选项指定如何找到含有头文件名字的行。'path' 选项用来搜索头文件。 i_CTRL-X_CTRL-I CTRL-X CTRL-I 搜索当前文件及其头文件里第一个以光标前面的字母序列开始 的关键字。在光标的前面插入找到的关键字。 CTRL-N 正向搜索下一个匹配的关键字。替换前次匹配的关键字。 注意: CTRL-I<Tab> 相同,而这可能会在成功的补全之后 输入,因此不使用 CTRL-I 来搜索下一个匹配。 CTRL-P 反向搜索下一个匹配的关键字。替换前次匹配的关键字。 CTRL-X CTRL-I 继续使用 CTRL-X CTRL-I 会复制上次本类型补全在其它上下 文里扩展的单词之后紧跟的单词,直到见到两个 CTRL-X 为 止。 补全标签 compl-tag i_CTRL-X_CTRL-] CTRL-X CTRL-] 搜索第一个以光标前面的字母序列开始的标签。在光标前面插 入匹配的标签。标签名可以包含字母字符和由 'iskeyword' 决定的字符 (这和关键字相同)。另见 CTRL-]'showfulltag' 选项可以用来增加标签定义前后的上下文。 CTRL-]CTRL-N 正向搜索下一个匹配的标签。替换前次匹配的标签。 CTRL-P 反向搜索下一个匹配的标签。替换前次匹配的标签。 补全文件名 compl-filename i_CTRL-X_CTRL-F CTRL-X CTRL-F 搜索第一个以光标前面的字母序列开始的文件。在光标前面插 入匹配的文件。文件名可以包含字母字符和由 'isfname' 决 定的字符。注意,(目前) 这里不使用 'path' 选项。 CTRL-FCTRL-N 正向搜索下一个匹配的文件名。替换前次匹配的文件名。 CTRL-P 反向搜索下一个匹配的文件名。替换前次匹配的文件名。 补全定义或宏 compl-define 'define' 选项用来指定包含定义的行。'include' 选项用来指定包含头文件名的行。 'path' 选项用来搜索头文件。 i_CTRL-X_CTRL-D CTRL-X CTRL-D 搜索当前和头文件里第一个以光标前面的字母序列开始的 定义 (或宏)。在光标的前面插入找到的定义名。 CTRL-DCTRL-N 正向搜索下一个匹配的定义。替换前次匹配的定义。 CTRL-P 反向搜索下一个匹配的定义。替换前次匹配的定义。 CTRL-X CTRL-D 继续使用 CTRL-X CTRL-D 会复制上次本类型补全在其它上下 文里扩展的单词之后紧跟的单词,直到见到两个 CTRL-X 为 止。 补全 Vim 命令 compl-vim 这里,补全是上下文敏感的,和命令行上的情况相似。它既能补全 Ex 命令,又能补全它 的参数。可用于编写 Vim 脚本。 i_CTRL-X_CTRL-V CTRL-X CTRL-V 猜测光标前的项目的条目,并找到第一个匹配。 注意: 如果 CTRL-V 被映射,你通常可以用 CTRL-Q 来代替 i_CTRL-QCTRL-VCTRL-N 正向搜索下一个匹配。替换前次匹配。 CTRL-P 反向搜索下一个匹配。替换前次匹配。 CTRL-X CTRL-V 继续使用 CTRL-X CTRL-VCTRL-V 一样。这允许键映射执 行 Vim 命令补全,例如: :imap <Tab> <C-X><C-V> 用户定义补全 compl-function 命令补全可以由用户通过 'completefunc' 选项自定义一个函数来完成。下面说明如何调 用此函数,并提供示例 complete-functions i_CTRL-X_CTRL-U CTRL-X CTRL-U 猜测光标前面项目的类型,并寻找它的第一个匹配。 CTRL-UCTRL-N 正向搜索下一个匹配。替换前次匹配。 CTRL-P 反向搜索下一个匹配。替换前次匹配。 全能 (omni) 补全 compl-omni 命令补全可以由用户通过 'omnifunc' 选项自定义一个函数来完成。这通常用于特定文件 类型的补全。 下面说明如何调用此函数,并提供示例 complete-functions 。 关于特定文件类型的说明,见 compl-omni-filetypes 。 将来会有更多补全脚本,欢迎查阅 www.vim.org。目前已经有了 C++ 的首个版本。 i_CTRL-X_CTRL-O CTRL-X CTRL-O 猜测光标前面项目的类型,并寻找它的第一个匹配。 CTRL-OCTRL-N 正向搜索下一个匹配。替换前次匹配。 CTRL-P 反向搜索下一个匹配。替换前次匹配。 拼写建议 compl-spelling 定位光标所在或之前的单词,然后提出正确拼写的单词作为建议进行替代。如果该行里有 一个错误拼写的单词在光标之前或之下,移动光标到它后面。否则,使用刚刚在光标之前 的那个单词来提出建议,即使该单词没有拼写错误。 NOTE: 很多 Unix 终端上,CTRL-S 暂停显示。这时用 's' 可以代替。如果显示暂停,输 入 CTRL-Q 会继续显示。 i_CTRL-X_CTRL-S i_CTRL-X_s CTRL-X CTRL-SCTRL-X s 定位光标之前的单词,并寻找它的第一个拼写建议。 CTRL-SCTRL-N 正向搜索下一个建议。替换前次的建议。 注意 这里不能用 's'。 CTRL-P 反向搜索下一个建议。替换前次的建议。 从不同的来源补全关键字 compl-generic i_CTRL-N CTRL-N'complete' 选项给出的地方搜索下一个以光标前面的关键 字开始的单词。在光标的前面插入找到的关键字名。 i_CTRL-P CTRL-P'complete' 选项给出的地方搜索上一个以光标前面的关键 字开始的单词。在光标的前面插入找到的关键字名。 CTRL-N 正向搜索下一个匹配的关键字。替换前次匹配的关键字。 CTRL-P 反向搜索下一个匹配的关键字。替换前次匹配的关键字。 CTRL-X CTRL-NCTRL-X CTRL-P 继续使用 CTRL-X CTRL-NCTRL-X CTRL-P 会复制上次本类 型补全在其它上下文里扩展的单词之后紧跟的单词,直到见到 两个 CTRL-X 为止。 停止补全 compl-stop i_CTRL-X_CTRL-Z CTRL-X CTRL-Z 停止补全而不改变原有的文本。 寻 找 补 全 的 函 数 complete-functions 这里指 'completefunc''thesaurusfunc''omnifunc'。 函数被调用两次,使用不同的方式: - 首先,调用函数以寻找补全文本的开始位置。 - 然后,调用函数以寻找实际的匹配。 第一次调用时,参数是: a:findstart 1 a:base 空 函数必须返回补全开始位置的列数,这个数字必须在零到光标所在列 "col('.')" 之间。 过程应该检查光标之前的字符,并包含那些可能成为补全项一部分的字符。该列到光标列 之间的文本将来会被匹配结果替换。如果返回值大于光标列,则使用光标列。 负返回值: -2 安静的撤销,留在补全模式。 -3 安静的撤销,退出补全模式。 其它负值: 补全从光标列开始 第二次调用时,参数是: a:findstart 0 a:base 补全必须匹配的文本;即第一次调用定位的文本 (可以为空) 函数必须返回匹配单词的列表。这些匹配通常包含 "a:base" 文本。如果没有匹配,返回 空列表。注意 第一次调用后,光标可能移动过,文本也可能有所改动。 要知道关于匹配词的信息,返回包含匹配列表的一个字典。字典包含以下项目: words 包含匹配单词的列表 (必需)。 refresh 用于控制函数重新启动的字符串 (可选)。 目前唯一支持的值是 "always"。效果是每次前导文本改变时 都会调用函数。 如果不想看空返回值引起的警告信息,可返回 v:none 。可用于通过 complete() 来 实现异步补全。 忽略其他项目。 要在补全结束之后有动作,参见 CompleteDonePreCompleteDone 自动命令事 件。 例如,函数里可以这么做: let matches = ... 单词列表 ... return {'words': matches, 'refresh': 'always'} complete-items 每个列表项可以是字符串或者字典类型。如果是字符串,直接用作补全文本。如果是字 典,可以包含以下各项: word 需要插入的文本,必需 abbr "word" 的缩写;如果非空,菜单里使用它而不是 "word" menu 用于弹出菜单的补充文本,在 "word" 或 "abbr" 之后显示 info 关于补全项的更多信息,能够在预览或弹出窗口显示 kind 代表补全类型的单个字母 icase 如果非零,比较项目是否等同时忽略大小写;如果省略就假定 为零,这时可以同时加入只有大小写有差异的匹配项 equal 如果非零,总是在比较时把此项当成相等。这意味着, "equal=1" 关闭此项的过滤。 dup 如果非零,那么即使和此匹配包含相同单词的匹配项已经存在 也无妨。 empty 如果非零,匹配项即使是空字符串也会加入 user_data 和项目相关联的定制数据,可从 v:completed_item 得到; 可以是任何类型;缺省为空串 除了 "icase"、"equal"、"dup" 和 "empty" 以外,其它各项必须是字符串。如果有一项 不合要求,报错,而列表的其余项目也不再使用。你可以在返回列表中混用字符串和字典 项目。 "menu" 项目用于弹出菜单且可能被截短,所以它应该尽量简短。"info" 项目可以稍长。 如果在 'completeopt' 中包含 "preview",使用预览窗口来显示该项信息,如果在 'completeopt' 中包含 "popup",则使用弹出窗口。在预览窗口中关闭弹出菜单后, "info" 项目将保留显示,这对录入函数参数很有用。用单个空格设置 "info" 可以清除 预览窗口现存的文本。预览窗口的大小缺省是三行,但在 'previewheight' 为 1 或 2 时使用其值。 complete-popup 如果 'completeopt' 中有 "popup",使用弹出窗口显示 "info"。这时 'completepopup' 选项指定弹出的属性,在 info 弹出建立时使用。此选项是逗号分隔的值列表: height 弹出的最大高度 width 弹出的最大宽度 highlight 弹出的高亮组 (缺省是 PmenuSel) align "item" (缺省) 或 "menu" border "on" (缺省) 或 "off" 例如: :set completepopup=height:10,width:60,highlight:InfoPopup 如果 "align" 值是 "item",弹出的位置靠近选择的项目。改变选择也会移动弹出。如果 "align" 是 "menu",如果菜单在文本之下,弹出和菜单顶部对齐,否则和菜单底部对 齐。 info 弹出被创建后,可在 popup_findinfo() 里找到,其属性可由 popup_setoptions() 改变。 complete-popuphidden 如果是通过异步获取弹出的信息,在 'completeopt' 中用 "popuphidden"。info 弹出会 先被隐藏,一旦 info 被填充,必须调用 popup_show() 。可通过 CompleteChanged 自动命令完成,就像这样: set completeopt+=popuphidden au CompleteChanged * call UpdateCompleteInfo() func UpdateCompleteInfo() " 取消任何进行中的 info 获取 let item = v:event.completed_item " 开始获取项目的 info,然后调用 ShowCompleteInfo(info) endfunc func ShowCompleteInfo(info) let id = popup_findinfo() if id call popup_settext(id, 'async info: ' .. a:info) call popup_show(id) endif endfunc complete-item-kind "kind" 项目用单一字母表示补全类型。用它可以指定补全的不同显示方式 (不同颜色或 者图标)。目前,可用如下类型: v 变量 f 函数或方法 m 结构或类成员 t typedef d #define 或宏 如果搜索匹配耗时较长,可以调用 complete_add() 向总列表中增加每个匹配。不要在 返回的列表里包含这些匹配!搜索匹配的同时,时不时地调用 complete_check() 来使 得用户仍然可以按键。如果该函数返回非零,搜索停止。 E840 该函数可以移动光标,结束后光标会恢复。 该函数不允许移动到其他窗口,也不允许删除文本。 一个补全月份名的示例: fun! CompleteMonths(findstart, base) if a:findstart " 定位单词的开始处 let line = getline('.') let start = col('.') - 1 while start > 0 && line[start - 1] =~ '\a' let start -= 1 endwhile return start else " 寻找匹配 "a:base" 的月份 let res = [] for m in split("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec") if m =~ '^' .. a:base call add(res, m) endif endfor return res endif endfun set completefunc=CompleteMonths 功能同上,但是现在假设搜索比较慢: fun! CompleteMonths(findstart, base) if a:findstart " 定位单词的开始处 let line = getline('.') let start = col('.') - 1 while start > 0 && line[start - 1] =~ '\a' let start -= 1 endwhile return start else " 寻找匹配 "a:base" 的月份 for m in split("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec") if m =~ '^' .. a:base call complete_add(m) endif sleep 300m " simulate searching for next match if complete_check() break endif endfor return [] endif endfun set completefunc=CompleteMonths 插 入 补 全 弹 出 菜 单 ins-completion-menu popupmenu-completion Vim 可以用更简单的弹出菜单来显示匹配。 当下面条件符合时使用弹出菜单: - 'completeopt' 选项包含 "menu" 或 "menuone"。 - 显示终端至少支持 8 色。 - 至少有两条匹配项。如果使用 "menuone",一条匹配也可以。 选项 'pumheight' 用于设置最大高度。默认值是使用全部有效空间。 选项 'pumwidth' 用于设置最小宽度。默认值是 15 个字符。 有三个状态: 1. 插入了完整的匹配,例如在 CTRL-NCTRL-P 之后。 2. 用光标键选择其它匹配项。此时不插入该匹配项,只在弹出菜单中高亮选中的条目。 3. 只插入了部分匹配文本,并且已经输入字符或者使用了退格键,这时匹配项列表根据 光标前的内容进行调整。 开始时你通常处于状态一并插入第一个匹配。如果 'completeopt' 包含了 "longest" 而 且有多个匹配项,那么开始于状态三。 如果选择其它匹配项,例如键入 CTRL-NCTRL-P,就进入了状态一。这不会改变匹配 项列表。 如果退回到原文,就会处于状态三。要立即进入该状态,可以使用快捷键映射方法,该映 射在补全开始后立即使用 CTRL-P: :imap <F7> <C-N><C-P> popupmenu-keys 在状态一下,这些键有特别的含义: <BS>CTRL-H 删除一个字符,查找光标前单词的匹配项。这会减少列表中匹配项的 数目,常常到只有一个项目,然后切换到状态二。 其它非特殊字符: 停止补全,不改变匹配,然后插入输入的字符。 在状态二和状态三下,这些键有特别的含义: <BS>CTRL-H 删除一个字符,并查找光标前变短的单词的匹配项。这可能会发现更 多的匹配项。 CTRL-L 从当前匹配项中增加一个字符,可能会减少匹配项的数量。 任何可显示的非空白字符: 加入该字符,减少匹配项的数量。 在全部三个状态下,可以使用以下这些键: CTRL-Y 是 (Yes): 接受当前选择的匹配项并停止补全。 CTRL-E 结束 (End) 补全,回退到选择匹配前原有的内容 (原先输入的或者 最长的公共字符串)。 <PageUp> 反向若干项选择一个匹配项,但不插入。 <PageDown> 正向若干项选择一个匹配项,但不插入。 <Up> 选择前一个匹配,同 CTRL-P,但不插入。 <Down> 选择后一个匹配,同 CTRL-N,但不插入。 <Space><Tab> 停止补全,不改变匹配,插入键入的字符 <Enter> 键的行为取决于你现在所处的状态: 状态一: 使用现有的文本,然后插入换行符。 状态二: 插入当前选择项。 状态三: 使用现有的文本,然后插入换行符。 换句话说: 如果你只使用光标键在匹配项列表中选择其它条目,按 <Enter> 键将插入该 匹配。如果键入其它字符,按 <Enter> 键将插入换行符。 下面的高亮组能够改变菜单颜色: Pmenu 普通项 hl-Pmenu PmenuSel 选中项 hl-PmenuSel PmenuSbar 滚动条 hl-PmenuSbar PmenuThumb 滚动条拇指 (thumb) hl-PmenuThumb 显示弹出窗口时,没有专门的映射。但你可以使用插入模式映射并检查 pumvisible() 函数的返回值以进行不同的处理。例如: :inoremap <Down> <C-R>=pumvisible() ? "\<lt>C-N>" : "\<lt>Down>"<CR> 映射中用 <expr> 可以在键入某字符或者满足某些条件时弹出菜单。例如,键入 '.': inoremap <expr> . MayComplete() func MayComplete() if (can complete) return ".\<C-X>\<C-O>" endif return '.' endfunc 详见 :map-<expr> 。 特 定 文 件 类 型 全 能 补 全 的 补 充 说 明 compl-omni-filetypes 文件类型 {filetype} 使用的是 'runtimepath' 的 autoload/{filetype}complete.vim 文件。比如对于 "java",就是文件 autoload/javacomplete.vim。 C ft-c-omni C 代码补全需要标签文件。你应该使用 Universal/Exuberant ctags 软件,因为它会加 入补全所需要的额外信息。你可以在这里找到它: Universal Ctags: https://ctags.io Exuberant Ctags: http://ctags.sourceforge.net 推荐使用 Universal Ctags,Exuberant Ctags 已不再开发。 对 Exuberant ctags 而言,建议使用 5.6 或更新版本。对于 5.5.4 版本,你应该打上 增加 "typename:" 字段的补丁: ftp://ftp.vim.org/pub/vim/unstable/patches/ctags-5.5.4.patch 可以在这里找到 MS-Windows 上已经编译好的可执行版本: http://ctags.sourceforge.net/ https://github.com/universal-ctags/ctags-win32 如果你想补全系统函数,可以用 ctags 生成包含所有系统头文件的标签文件: % ctags -R -f ~/.vim/systags /usr/include /usr/local/include 在 vimrc 文件中,把这个标签文件增加到 'tags' 选项中: set tags+=~/.vim/systags 如果在不包含 "." 或 "=" 的名字后面用 CTRL-X CTRL-O,会直接从标签文件中补全。这 适用于任何标识符,包括函数名。如果你想补全标签文件没有的局部变量名,用 CTRL-P 代替。 如果在包含 "." 或 "=" 的名字后面用 CTRL-X CTRL-O,Vim 会试图识别变量类型并指出 它所含的成员。这意味着只会列出该变量的有效成员。 如果成员名字已经完整,CTRL-X CTRL-O 会为复合类型加上 "." 或 "->"。 Vim 没有包含 C 编译器,它只能识别使用明确格式的声明。预处理器指令可能会引起混 淆。如果在多个位置里定义了同样的结构名,所有可能的结构成员都会被包括。 CSS ft-css-omni 遵循 CSS 2.1 标准来补全属性和相应的值。 HTML ft-html-omni XHTML ft-xhtml-omni CTRL-X CTRL-O 能够补全 (X)HTML 文件的各种元素。它是为了支持编写 XHTML 1.0 Strict 文件而设计的,但也可用于其它 HTML 版本。特性: - "<" 之后,根据上下文补全标签名 (在标签内部,不给出 div 标签建议);'/>' 表明 空标签 - 在标签中,补全合适的属性 (不包括标签的 width 属性);同时显示属性类型;'*' 表 明必需的属性 - 如果属性只有有限的几个可能值,用它们来补全 - 补全实体 (entity) 名 - 根据 <style> 标签和包含的 CSS 文件里提取的数据,补全 "class" 和 "id" 属性值 - 对 "style" 属性值或在 "style" 标签内部补全时,切换到 ft-css-omni 补全 - 对事件属性值或在 "script" 标签内部补全时,切换到 ft-javascript-omni 补全 - "</" 之后,CTRL-X CTRL-O 会关闭最近打开的标签 备注: 如果是第一次使用,补全菜单的显示会有少许延迟--这点时间用于数据文件载入。 备注: 补全可能会在错误格式的文档中失效。在这种情况下,请尝试运行 :make 命令 检查格式问题。 HTML 类型 html-flavor 默认的 HTML 补全机制依赖于文件类型: HTML 文件使用 HTML 4.01 Transitional 标准 ('filetype''html'),XHTML 使用 XHTML 1.0 Strict 标准 ('filetype''xhtml')。 如果在任何标签的外部进行补全,你可以选择 DOCTYPE,然后载入合适的数据文件,并用 于后面所有的补全操作。 关于数据文件格式更多的信息见 xml-omni-datafile 。vim 的线上站点 ( www ) 可以 找到一些数据文件。 注意 b:html_omni_flavor 可以指向任何使用 XML 数据的文件。这就使混合 PHP ( ft-php-omni ) 和任何 XML 方言的补全成为可能 (假设你有相应的数据文件)。如果该 变量没有设置,使用 XHTML 1.0 Strict 标准。 JAVASCRIPT ft-javascript-omni 补全绝大部分 JavaScript 语言和 DOM 元素。 补全: - 变量 - 函数名;显示函数参数 - 函数参数 - 变量属性,试图检测变量类型 - 根据上下文补全 DOM 对象和属性 - 语言中的关键字 补全机制可以用于单独的 JavaScript 文件 (&ft==javascript)、(X)HTML 的 <script> 标签内部和事件的属性值 (包含对外部文件的扫描)。 DOM 兼容性 当前 (2006 年初) 有两种主要浏览器 - MS Internet Explorer 和 Mozilla Firefox。 这两个软件市场占有率达到 90% 以上。理论上,W3C 组织 (http://www.w3c.org) 建立 标准,但是这些标准并没有完全遵守和实现。 IE FF W3C 全能补全 +/- +/- + + + + - + + - - - - + - - 不管浏览器的实现进度如何,补全插件总是把标准定义的元素放入建议列表。两个主要浏 览器都实现但标准没有覆盖的元素也作为建议。而其它的元素则不出现于建议列表。 PHP ft-php-omni PHP 代码的补全需要标签文件才能对外部文件的数据和类进行补全。应该使用 Universal/Exuberant ctags 5.5.4 版本或更新的版本。在这里可以找到它: Universal Ctags: https://ctags.io Exuberant Ctags: http://ctags.sourceforge.net 脚本对以下项目进行补全: - $ 变量名之后 - 如果变量声明为对象,加上 "->",如果标签文件有效,显示类名 - 在 "->" 之后,只补全给定类中的函数和变量名。为了查找类的位置和内容,需要标 签文件。因为 PHP 不是强类型的语言,用户可以使用 @var 标签来声明类: /* @var $myVar myClass */ $myVar-> 不过,要找到 myClass 的内容,仍然需要标签文件。 - 带有附加信息的函数名: - 如果是内建函数,列出可能的参数,在 | 之后列出函数返回的数据类型 - 如果是用户函数,列出参数和函数定义所在的文件名 (如果不是当前文件) - 常量名 - 在 "new" 声明之后的类名 注意: 如果第一次调用补全功能,Vim 会把所有需要的数据载入内存。这可能需要几秒 钟。下次补全时,就几乎感觉不到延迟了。 脚本检测光标是否在 <?php ?> 标签内。如果不是,会自动切换到 HTML/CSS/JavaScript 补全。注意: 和原始 HTML 文件不同,标签补全 (也仅对标签补全而言) 和上下文无关。 RUBY ft-ruby-omni Ruby 代码的补全需要 Vim 编译时带 +ruby 特性。 Ruby 补全会因需分析你的缓冲区以提供补全列表。它会从 'require' 载入的和当前缓冲 区定义的模块里提取补全。 CTRL-X CTRL-O 提供的补全是上下文相关的: 上 下 文 提 供 的 补 全 1. 不在类定义中 类名、常量和全局变量 2. 类定义中 这个类所定义的方法或常量 3. '.'、'::' 或者 ':' 之后 被解除参照的对象所适用的方法 4. ':' 或者 ':foo' 之后 符号名 ('foo' 起始的那些) 备注: - Vim 会载入/执行程序代码,以便提供补全。这可能会导致部分代码被执行。这一点也 许值得关注。缺省行为不再打开这一功能。如果需要此特性,加上 let g:rubycomplete_buffer_loading = 1 - 在第 1 点中,Vim 可以解析整个缓冲区以获得用作补全结果的类名列表。默认关闭此 功能。要使其生效,在 vimrc 里加入 let g:rubycomplete_classes_in_global = 1 - 在第 2 点中,不支持匿名类。 - 在第 3 点中,Vim 会试图判断对象所支持的方法。 - Vim 可以检测和载入 Rails 环境并用于 rails 项目的文件。默认关闭此特性。要使 其生效,在 vimrc 里加入 let g:rubycomplete_rails = 1 SYNTAX ft-syntax-omni Vim 能够对将近 500 种语言进行语法高亮。高亮支持的一部分是需要知道构成语言的关 键字。许多文件类型已经有专门的补全脚本,而对其它的文件类型而言,syntaxcomplete 脚本可以提供基本的补全。实现的方法是用 Vim 知道如何色彩高亮的那些文本来构造全 能补全列表。它适用于任何文件类型,并可以提供基本但和语言相关的补全机制。 要打开语法打开补全: setlocal omnifunc=syntaxcomplete#Complete 你可以把下列语句放到 .vimrc 中 (要在任何 ":filetype" 命令之后),使其自动生 效: if has("autocmd") && exists("+omnifunc") autocmd Filetype * \ if &omnifunc == "" | \ setlocal omnifunc=syntaxcomplete#Complete | \ endif endif 只有在针对特定文件类型的插件不存在的情况下,上述语句才对脚本设置补全操作。 每个文件类型可能有很多语法项目。此插件允许你定制从列表里包含或排除哪些语法组。 让我们看看 PHP 文件类型如何处理。 如果你正在编辑一个 index.php 文件,运行如下命令: syntax list 首先你将看到有许多不同的语法组。PHP 语言可以包含来自不同语言的元素,比如 HTML、 JavaScript 和许多其它语言。这种情况下,syntax 插件只包含由文件类型 "php" 开头的语法组。例如,缺省 PHP 包含这些语法组: phpEnvVar、phpIntVar、 phpFunctions。 如果希望包括非本文件类型指定的其他语法项目,可用正则表达式语法 (autoload/syntaxcomplete.vim 的 13.0 版本加入) 来加入项目。编辑 PHP 文件时查看 ":syntax list" 的输出,我可以看到如下一些项目: htmlArg,htmlTag,htmlTagName,javaScriptStatement,javaScriptGlobalObjects 要在编辑 PHP 文件时时使用 Javascript 和 HTML 关键字语法高亮组,可以指定三个正 则表达式,每种语言分别一个。也可以简单限制包含组为特写值,而无需正则表达式: let g:omni_syntax_group_include_php = 'php\w\+,javaScript\w\+,html\w\+' let g:omni_syntax_group_include_php = 'phpFunctions,phpMethods' 这个变量的基本形式是: let g:omni_syntax_group_include_{filetype} = '逗号,分隔的,列表' PHP 语言可以进行语法高亮的项目非常多,而这些项目在全能补全列表里都会出现。 有些人可能觉得这个列表不实用或者只对某些项感兴趣。(如有必要) 有两种方法可以裁 剪这个列表。如果不想显示特定语法组,有两种不同的方法来标识这些组。第一个具体列 出这些语法组的名字。第二个使用正则表达式来指定所有想要的语法组。在 vimrc 中增 加两者之一即可: let g:omni_syntax_group_exclude_php = 'phpCoreConstant,phpConstant' let g:omni_syntax_group_exclude_php = 'php\w*Constant' 该列表可以加入多个语法组,以逗号分隔。这个变量的基本形式是: let g:omni_syntax_group_exclude_{filetype} = '逗号,分隔的,列表' 可以建立任意多个这些变量,只要变量名尾部的文件类型不同就行了。 此插件使用 isKeyword 选项来决定用于语法项目的单词边界。例如,Scheme 语言的补全 应该包含 "-",call-with-output-file。取决于你的文件类型,此方法未必能提供你期 待的单词。设置 g:omni_syntax_use_iskeyword 选项为 0 会强制语法插件在单词字符上 断开。在 vimrc 可以加如下行进行控制: let g:omni_syntax_use_iskeyword = 0 为了插件开发者着想,本插件提供了公共函数 OmniSyntaxList。本函数可用于提供语法 项目的列表。编辑 SQL 文件时 (:e syntax.sql),可以用 ":syntax list" 命令看到各 种组和语法项目。示例: syntax list 返回的数据类似如此: sqlOperator xxx some prior all like and any escape exists in is not or intersect minus between distinct links to Operator sqlType xxx varbit varchar nvarchar bigint int uniqueidentifier date money long tinyint unsigned xml text smalldate double datetime nchar smallint numeric time bit char varbinary binary smallmoney image float integer timestamp real decimal 这里列出两个语法组: sqlOperator 和 sqlType。要得到语法项目的列表,可用几种不同 的方式调用 OminiSyntaxList。要得到不分组的所有语法项目: echo OmniSyntaxList( [] ) 要得到 sqlOperator 语法组的所有语法项目: echo OmniSyntaxList( ['sqlOperator'] ) 要得到 sqlOperator 和 sqlType 两个组的所有语法项目: echo OmniSyntaxList( ['sqlOperator', 'sqlType'] ) 也可用正则表达式: echo OmniSyntaxList( ['sql\w\+'] ) 在插件中,通常可以把输出结果赋给一个列表: let myKeywords = [] let myKeywords = OmniSyntaxList( ['sqlKeyword'] ) SQL ft-sql-omni SQL 语言的补全包括语句、函数和关键字。还可以动态地补全表、过程、视图和列的列 表,此时数据直接从数据库里提取。详细的指令和教程见 omni-sql-completion 。 SQL 补全插件可以和其它补全插件一起使用。例如,PHP 文件类型有它自己的补全插件。 因为 PHP 常用来生成访问数据库的动态网站,也可以同时打开 SQL 补全插件。这样就可 以同时补全 PHP 代码和 SQL 代码。 XML ft-xml-omni Vim 7 为 XML 文件中提供上下文相关的补全机制。它依赖于特殊的数据文件 xml-omni-datafile 和两个命令: :XMLns:XMLent 。特性如下: - "<" 之后,根据上下文补全标签名 - 标签内部补全合适的属性 - 如果属性只有有限的几个可能值,用它们来补全 - 补全实体 (entity) 名 ( xml-omni-datafile 里的定义加上当前文件 "<!ENTITY" 的 声明) - "</" 之后,CTRL-X CTRL-O 会关闭最后打开的标签 XML 数据文件的格式 xml-omni-datafile XML 数据文件保存在 'runtimepath' 下的 "autoload/xml" 目录中。Vim 发布在 "$VIMRUNTIME/autoload/xml" 目录下提供了示例数据文件。这些文件名有特别含义,命 令里使用会使用这些名字。文件名应该唯一,否则以后会产生冲突。例如,xhtml10s.vim 代表 XHTML 1.0 Strict 标准的数据文件。 每个文件包含一个名字形如 g:xmldata_xhtml10s 的变量。它由两个部分组成: 1. "g:xmldata_" 通用前缀,所有数据文件都是如此 2. "xhtml10s" 文件名,描述 XML 的方言;会用作 :XMLns 命令的参数 第二部分必须和文件名完全一样。 该变量为字典 Dictionary 类型。键是标签名,而值是两个元素的 List 。列表中第 一个元素也是列表,包含可能的子元素名称,第二个元素是字典 Dictionary ,键是属 性名,而值是属性的可能值。例如: let g:xmldata_crippled = { \ "vimxmlentities": ["amp", "lt", "gt", "apos", "quot"], \ 'vimxmlroot': ['tag1'], \ 'tag1': \ [ ['childoftag1a', 'childoftag1b'], {'attroftag1a': [], \ 'attroftag1b': ['valueofattr1', 'valueofattr2']}], \ 'childoftag1a': \ [ [], {'attrofchild': ['attrofchild']}], \ 'childoftag1b': \ [ ['childoftag1a'], {'attrofchild': []}], \ "vimxmltaginfo": { \ 'tag1': ['Menu info', 'Long information visible in preview window']}, \ 'vimxmlattrinfo': { \ 'attrofchild': ['Menu info', 'Long information visible in preview window']}} 该例应放到 "autoload/xml/crippled.vim" 文件中。可用于编写下述文件: <tag1 attroftag1b="valueofattr1"> <childoftag1a attrofchild> &amp; &lt; </childoftag1a> <childoftag1b attrofchild="5"> <childoftag1a> &gt; &apos; &quot; </childoftag1a> </childoftag1b> </tag1> 从该例中,我们可以看到四种特殊元素: 1. "vimxmlentities" - 特殊键,包含此 XML 方言的所有实体的列表。 2. 如果这个包含属性可能值的列表只有一个元素,而该元素和属性名一样,那么该属性 被看作逻辑值,插入时使用 'attrname' 而不是 'attrname="'。 3. "vimxmltaginfo" - 特殊键,包含键为标签名、值为两元素列表的字典。值列表包含 附加的菜单信息和长描述。 4. "vimxmlattrinfo" - 特殊键,包含键为属性名、值为两元素列表的字典。值列表包含 附加的菜单信息和长描述。 注意: 数据文件里的标签名 必须 不能包含命名空间的描述。示例见 xsl.vim。 注意: 所有的数据和函数都作为全局变量/函数可以在任何地方访问,所以它们可以用于 个人编辑用的函数。 DTD -> Vim dtd2vim www 上有个脚本 dtd2vim ,能够解析 DTD 并为 Vim XML 全能补全建立 XML 数据文 件。 dtd2vim: http://www.vim.org/scripts/script.php?script_id=1462 查看文件开始部分的详细用例。 该脚本需要 Perl 和: perlSGML: http://savannah.nongnu.org/projects/perlsgml 命令 :XMLns {name} [{namespace}] :XMLns Vim 需要知道要使用的数据文件和命名空间。 :XMLns 命令可以载入数据文件并把数据 连接到合适的命名空间。第一个 (必需的) 参数是数据名 (xhtml10s、xsl)。第二个参数 是命名空间编码 (h,xsl)。如果不使用第二个参数,那么将使用默认值--不声明命名空 间。例如在 .xsl 文件中使用 XML 补全: :XMLns xhtml10s :XMLns xsl xsl :XMLent {name} :XMLent 缺省,根据默认命名空间的数据文件补全实体 (entity) 。如果没有默认命名空间,应该 用 XMLent 命令: :XMLent xhtml10s 用法 在下述情况下 (在前一部分的声明之后,| 代表当前光标位置): <| 补全合适的 XHTML 标签。而: <xsl:| 补全合适的 XSL 标签。 由 autoload 机制提供的 xmlcomplete.vim 脚本定义了函数 xmlcomplete#GetLastOpenTag(),在 XML 文件中,这个函数可用于取得最后打开的标签 名 (下例必须先定义 b:unaryTagsStack): :echo xmlcomplete#GetLastOpenTag("b:unaryTagsStack")

8. 插入模式命令 inserting

下列命令可以用来在缓冲区里插入新的文本。它们都可以撤销,也可以通过 "." 命令重 复。 a a 在光标后附加文本 [count] 次。如果光标在空行的第一列, 启动插入模式。但在置位了 'virtualedit' 以后就不是! A A 在行尾附加文本 [count] 次。 可在可视列块中用 "A",参见 v_b_A<insert> i insert <Insert> i 在光标前插入文本 [count] 次。在插入模式里使用 CTRL-O 的时候, i_CTRL-O 不支持计数。 I I 在本行第一个非空白字符之前插入文本 [count] 次。 如果 'cpoptions' 里有 'H' 标志位而本行只有空白,在最后 一个空白前插入。 可在可视列块中用 "I",参见 v_b_I gI gI 在第一列插入文本 [count] 次。 gi gi 在当前缓冲区最近一次插入模式停止的位置继续插入文本。 该位置记在 '^ 位置标记里。如果标记在行末之后,和 "`^i" 有所差异。 该位置在插入/删除行时会自动修正。但 在插入/删除字符 时被修正。 使用 :keepjumps 命令修饰符时,不改变 '^ 位置标记。 o o 在光标下方开启新行,并插入文本,重复 [count] 次。 如果 'cpoptions' 里有 '#' 标志位,忽略计数。 O O 在光标上方开启新行,并插入文本,重复 [count] 次。 如果 'cpoptions' 里有 '#' 标志位,忽略计数。 这些命令用以开始插入文本。你可以用 <Esc> 退出插入模式。关于插入模式里的其它特 殊字符,见 mode-ins-repl[count] 的效果只有在退出插入模式以后才会发生。 如果打开 'autoindent',新行的缩进从上一行得到。打开 'smartindent''cindent' 时,行的缩进根据 C 程序的要求自动调整。 可设置 'formatoptions',开启新行时自动复制注释头部。 'textwidth' 可以设置一行的最大宽度。如果一行过长,在添加字符时会自动添加换行 符。

9. Ex 插入命令 inserting-ex

:a :append :{range}a[ppend][!] 在指定行下方添加若干行。如果没有给出 {range},文本会在 当前行之后插入。 加入 [!] 切换此命令执行时的 'autoindent'。 此命令在 Vim9 脚本里不支持,因为它太容易和变量名混淆 了。 :i :in :insert :{range}i[nsert][!] 在指定行上方添加若干行。如果没有给出 {range},文本会在 当前行之前插入。 加入 [!] 切换此命令执行时的 'autoindent'。 此命令在 Vim9 脚本里不支持,因为它太容易和变量名混淆 了。 这两个命令会继续要求行,直到你输入了只包含 "." 的一行。小心反斜杠开始的行,见 line-continuation 。 Ex 模式 (见 -e ) 下,行尾的反斜杠可用来插入 NUL 字符。所以要使一行以反斜杠结 尾,用两个反斜杠。也就是说仅在行尾情况下,反斜杠数目减半。 注意: 这些命令不能和 :global:vglobal 一起使用。":append" 和 ":insert" 在 ":if" 和 ":endif"、":for" 和 ":endfor" 还有 ":while" 和 ":endwhile" 之间不 能很好的工作。 :start :startinsert :star[tinsert][!] 在执行完本命令后,启动插入模式。和普通模式下输入 "i" 类似。如果包含 !,和 "A" 类似,附加到行后。否则,就从 光标当前位置开始插入。 注意 在函数或者脚本里使用本命令时,插入只会在函数和脚 本结束的时候才会开始。 此命令不能在 :normal 里使用。 :stopi :stopinsert :stopi[nsert] 尽快停止插入模式。和在插入模式时输入 <Esc> 类似。可以 用在自动命令里。示例: :au BufEnter scratch stopinsert replacing-ex :startreplace :startr[eplace][!] 在执行完本命令后,启动替换模式。和普通模式下输入 "R" 类似。如果包含 !,和 "$R" 类似 (也就是,从行尾开始替换 模式)。否则,从光标当前位置开始替换。 注意 在函数或者脚本里使用本命令时,替换只会在函数和脚 本结束的时候才会开始。 :startgreplace :startg[replace][!] 和 :startreplace 完全类似,用虚拟替换模式,和使用 gR 类似。

10. 插入文件 inserting-file

:r :re :read :r[ead] [++opt] [name] 在光标下方插入文件 [name] (缺省: 当前文件)。 ++opt 说明 [++opt] 可能的取值。 :{range}r[ead] [++opt] [name] 在指定行下方插入文件 [name] (缺省: 当前文件)。 ++opt 说明 [++opt] 可能的取值。 :r! :read! :[range]r[ead] [++opt] !{cmd} 执行 {cmd} 并把它的标准输出插入到光标下方。临时文件会 建立来保存命令输出的结果,并被读到缓冲区里。 'shellredir' 用来保存命令的输出结果,它可以设置是否包 含标准错误的输出。{cmd} 的执行和 ":!{cmd}" 类似,任何 的 '!' 会被替换成以前的命令 :!++opt 说明 [++opt] 可能的取值。 这些命令插入文件的内容,或者命令的输出结果到缓冲区里。两者都可以撤销。但不能用 "." 命令重复。它们是基于行工作的,插入从光标所在行或指定行的下方开始。要在第一 行之上插入文本,使用命令 ":0r {name}"。 在 ":read" 命令之后,光标留在第一个新行的第一个非空白处。和 Ex 模式不一样。那 里光标留在最后一个新行上 (对不起,那是为了和 Vi 兼容)。 如果文件名字通过 ":r" 给出,它成为轮换文件。这可以用来,比如说,你想编辑那个文 件的时候: ":e! #"。该特性可以通过删除 'cpoptions' 选项里的 'a' 标志位来关闭。 [++opt] 参数里,有一个是 ":read" 专用的: ++edit 参数。当 ":read" 命令就像编辑 文件一样把文件读入到缓冲区时,这个参数很有用。在空缓冲区上使用如下命令: :read ++edit filename 效果是 'fileformat''fileencoding''bomb' 等选项根据 "filename" 的检测进行设 置。注意 会留下一行空行,你也许想把它删掉。 file-read 'fileformat' 选项设置文件的 <EOL> 风格: 'fileformat' 字符 名称 "dos" <CR><NL><NL> DOS 格式 "unix" <NL> Unix 格式 "mac" <CR> Mac 格式 以前使用 'textmode'。现在已经废弃了。 如果 'fileformat' 为 "dos",在 <NL> 之前的 <CR> 被忽略,而在文件尾部的 CTRL-Z 被忽略。 如果 'fileformat' 为 "mac",文件里的 <NL> 被内部表示为 <CR>。这是为了避免和用 来表示 <NUL><NL> 引起混淆。见 CR-used-for-NL 。 如果 'fileformats' 选项不为空,Vim 试图识别 <EOL> 的类型 (见 file-formats )。 不过,'fileformat' 选项的值不会被改变,检测到的格式只会在读入文件时使用。 'fileencodings' 与此情形类似。 非 Win32 系统上,读入 DOS 格式的文件时给出消息 "[dos format]",以提醒你发生了 不寻常的事情。 Macintosh 和 Win32 系统上,读入 Unix 格式的文件时给出消息 "[unix format]"。 非 Macintosh 的系统上,读入 Mac 格式的文件时给出消息 "[mac format]"。 关于如何使用 ":r !" 的一个例子: :r !uuencode binfile binfile 该命令读入 "binfile",用 uuencode 进行编码,并读入当前缓冲区。可以用于编辑包含 附带的二进制的文件的 e-mail。 read-messages 在读入文件时,Vim 会显示消息,显示读入文件的相关信息。以下的表格给出一些项目的 解释。其它的项目都不言自明。使用长格式还是短格式取决于 'shortmess' 选项的设 置。 长 短 含义 [readonly] {RO} 文件被写保护 [fifo/socket] 使用流 [fifo] 使用 fifo 流 [socket] 使用套接字 (socket) 流 [CR missing] 使用 "dos" 'fileformat' 读入文件的时候 出现没有前导的 CR 的 NL [NL found] 使用 "mac" 'fileformat' 读入文件的时候 出现 NL (可能是 "unix" 格式) [long lines split] 至少一行以上被分割 [NOT converted] 期待从 'fileencoding''encoding' 的 转换但是做不到 [converted]'fileencoding''encoding' 的转换 完成 [crypted] 文件被解密 [READ ERRORS] 不是文件所有部分都被成功读入 vim:tw=78:ts=8:noet:ft=help:norl: