跳转到内容

学习 vi 编辑器/Vim/程序员需要知道的实用技巧

来自 Wikibooks,开放世界中的开放书籍

学习 vi 编辑器: 熟悉基本任务简化工作高级任务细节Vi 克隆 (Vim基本导航模式技巧和窍门程序员需要知道的实用技巧增强 VimVim 在 Windows 上VimL 脚本语言, Vile, BB vi)vi 参考

程序员需要知道的实用技巧

[编辑 | 编辑源代码]

程序员应该了解一些关于 vim 的知识,这些知识会让他们的体验更加轻松。程序员可以通过使用有效的编辑器节省数小时甚至数周的人工时间。以下是一些 vim 提供的技巧和工具。随着你节省的时间,你可以加快工作速度,腾出时间快速进行 Quake 死亡竞赛,或者最终提高你的工作效率,从而帮助你获得更高的工资增长。

单词、变量、函数和行补全

[编辑 | 编辑源代码]

有时你输入的单词非常长。你不必把它们全部输入出来。如果它们在你的字典或当前文件中,你可以使用 <Ctrl-P><Ctrl-N> 节省大量时间。让我们仔细看看它是如何工作的

  • 单词/变量/函数名补全

通常,当前文件或同一 vim 实例中你正在编辑的其他任何文件(缓冲区)中的任何单词都将匹配补全。这意味着,一旦你输入一次,下次你就可以输入前几个字母,然后按 Ctrl-N(如果你需要循环浏览多个选项,可以按多次),直到找到你想要的单词。

从技术上讲,情况并非如此。你可以在 complete 函数中告诉 vim 在哪里查找单词。在 Vim 7 中,complete 函数通常会设置为找出你正在输入的内容的大量信息——从函数库中获取信息(截至本书的上次更新,作者知道 C 和 C++ 默认情况下受支持)。从 Vim 7 开始,关键字补全还会显示一个弹出菜单。

你也可以为自己定义一个字典来进行补全。有关更多详细信息,你可能需要参考 vim 帮助系统“:help complete”、“:help complete-functions”等等。

示例 1

例如,你可能会编辑一个 C 程序文件“blah.c”。你想要一个以“str”开头的函数,但你不记得它是什么。你首先输入“str”。它仍然是普通文本,直到你按下 <Ctrl-P><Ctrl-N>。在 vim 7 中,你会看到一个菜单出现,如下所示

你可以使用 <Ctrl-N><Ctrl-P> 循环浏览显示的条目。在 Vim 7 及更高版本中,你实际上可以使用箭头键循环浏览菜单中的条目。屏幕上一次可能显示的条目太多(你会注意到右侧的黑色方框代表灰色条上的滚动位置——在本例中,并非所有选项都显示在屏幕上)。将显示提取选项的文件,以帮助你决定是否是你想要的。

(你还会在本例中注意到,来自作者最近编辑的文件的单词也显示出来了,例如来自“cgi-bin/ftplist.pl”的“strict”——我们当然不希望这样。)

示例 2

现在,假设你需要正弦函数,但你知道它的名字很奇怪。你输入 sin 并按下 <Ctrl-P>,但它没有显示出来

你没有失败,只是还没有包含数学库。你只需要添加一行

#include <math.h>

然后重试。这次你会看到你想要的函数名(因为它的名字很奇怪,所以不太容易记住)

  • 行补全

如果你需要,你可以补全整行,虽然这种情况不太可能发生。 <Ctrl-X><Ctrl-L> 会将匹配的行(空格很重要!)加载到菜单中,然后你就可以使用箭头或 <Ctrl-P><Ctrl-N>(用于 Previous 和 Next)向前或向后移动。

Vim 可以找出如何缩进大多数常见的文件类型。

对于大多数流行的编程语言,vim 可以通过文件名扩展名检测文件类型,并据此决定如何缩进你的文件。如果你没有看到它自动为你创建正确的缩进,请尝试

:filetype indent plugin on

在 GUI 版本中,你可能可以在为该文件打开语法高亮的同时打开它。选择语法 -> 为此文件打开/关闭,或语法 -> 在菜单中显示文件类型,然后返回语法菜单并从列表中选择适当的文件类型。

你可能希望将上面提到的“:filetype …”行放在你的 vimrc 文件(前面已经讨论过)中,然后再次打开你的程序文件,虽然这实际上应该没有必要。

如果你仍然遇到问题,你可能需要检查你的 runtimepath 变量是否设置正确(:help runtimepath)。也有可能(虽然不太可能)你的编程语言很罕见,以至于还没有人为此编写缩进插件。vim 的官方网站 vim.org 可能有一个满足你需求的缩进插件文件,即使它没有包含在你默认的 vim 安装中。

当你粘贴了一些文本,并且缩进不正确时(你的缩进插件必须加载),你可以使用 = 命令。最简单的方法可能是输入“10=”重新缩进接下来的十行,或者使用可视模式并按下 <=>

如果你愿意,可以使用“>>”缩进行,使用“<<”取消缩进行。

如果你处于插入模式,请使用 <Ctrl-D><Ctrl-T> 更改行的缩进(<Ctrl-D> 将缩进减少一级,Ctrl-T 将缩进增加一级)。

如果你无法使特定于文件类型的缩进正常工作,你可能尝试设置以下一个或多个选项:smartindent、autoindent、cindent 和 copyindent。这些选项可能无法完全正常工作,因此 <Ctrl-D><Ctrl-T> 会更加重要。要打开 autoindent,请键入 :set autoindent。要关闭 autoindent,请键入 :set noautoindent

重复命令或多次执行相同命令

[编辑 | 编辑源代码]

如果你对 vim 感到满意,你可能会将你的按键记录到一个不可见的寄存器,并在以后重复它们。编写 vim 脚本,甚至使用另一个程序(例如 perl 脚本)过滤你的文件可能更容易,以执行更复杂的动作。

也就是说,有时记录命令并重复使用它,甚至在任何匹配的行上执行它确实更容易。对于更高级的执行模式(例如,在整个文件中执行一个命令),请参见下文。你也可以考虑创建映射(在下面讨论)或运行 :global 命令(也在下面讨论)。

重复最后一个单一命令

[编辑 | 编辑源代码]

假设我想在几行末尾加上一个分号,而我忘记了

cout << "Hello world\n"
i = j + k
cout << "i is " << i << endl

在第一行,我输入A;,然后按ESC键。我移动到下一行并按下.(句号告诉vim重复最后一个命令——不用担心,它不会重复移动命令)。

录制命令宏

[编辑 | 编辑源代码]

Vim 拥有强大的命令重复功能,可以通过宏来实现。用户可以将一系列命令录制到寄存器中,然后将该寄存器运行为宏。宏可以录制到 26 个寄存器中的任何一个(a 到 z)。

要开始录制宏,请按q,然后按一个寄存器名称(任何字母az——寄存器只由一个字母定义,所以只能使用一个字符作为存储缓冲区)。在执行一系列命令后,按q再次结束录制命令宏。例如,要开始录制到寄存器 z,请按qz,然后再次按q结束录制。

要从寄存器运行宏,请使用@x,其中x是包含所需宏录制的寄存器。寄存器q是宏录制的默认寄存器,因此,如果您已录制到寄存器q,则只需键入@@即可运行宏。

(注意:请记住,脚本或映射有时可能会使用任意寄存器——因此,如果您遇到冲突,尤其是在第三方脚本或映射中,您应该考虑录制到其他寄存器。您可以使用:registers命令查看寄存器的内容。)

作为一个简单的例子,假设您在缓冲区中有以下几行,并且您希望每行重复该行的最后一个单词。最初,缓冲区看起来像这样

The quick brown fox jumps over the lazy dog
The sly gray fox circles around the unsuspecting rabbit
The slow gray fox crawls under the rotting fence

您希望缓冲区看起来像这样:(其中新增内容以粗体突出显示)

The quick brown fox jumps over the lazy dog dog
The sly gray fox circles around the unsuspecting rabbit rabbit
The slow gray fox crawls under the rotting fence fence

要做到这一点,请使用qq开始录制到默认寄存器中,然后使用A追加该行,键入空格,然后按Ctrl-P,最后按ESC键。要结束录制,请再次按q。现在,宏已录制到寄存器q中。要重复该命令,请向下移动一行,并通过键入@@@q重复该命令。您可以使用@@运行此宏,因为 q 是宏的默认寄存器。

在另一个例子中,假设您在寄存器中拥有以下几行

The quick brown fox jumps over the lazy dog dog
The sly gray fox circles around the unsuspecting rabbit rabbit
The slow gray fox crawls under the rotting fence fence

您希望在动物名称(fox、dog 和 rabbit)周围添加 HTML 标签,使它们变为粗体(例如,fox 需要变为<b>fox </b>)。假设您希望使用寄存器a来存放宏。

要开始,请将光标移动到第一个动物名称——fox 上。将光标放在单词的某个位置,例如 fox 中的 'o' 上。通过键入qa开始录制。接下来,使用"bdaw将单词删除到寄存器b(有关此命令的解释,请参见:help aw:help d以及:help "。接下来,通过键入i进入插入模式,然后键入<b>,然后按Ctrl-O,然后按"bP(有关此命令的解释,请参见:help i_CTRL-o。接下来,键入</b>,然后按 ESC。最后,通过键入q停止录制。要重复该命令,请将光标移到您希望用 HTML 标签包围的下一个单词上,然后通过键入@a运行宏。您可以通过检查寄存器来查看宏的结构。为此,您可以运行命令:registers a。在这种情况下,vim 将显示以下输出

--- Registers ---
"a   "bdawi<b>^O"bP</b>^[

请注意,录制会记住您的所有移动命令,因此您需要在开始录制之前将光标放在正确的位置。

示例 2b:修复宏
[编辑 | 编辑源代码]

假设您在宏中犯了一个小错误,但宏相当复杂,您不想再次重复所有这些命令。我们希望修改寄存器的内容。为此,我们使用在转义模式下键入"x会使用寄存器x的内容进行下一次删除、粘贴或放置的功能。

假设我们使用寄存器a

  • 创建一个新行(此行将最终被删除),并在转义模式下使用"ap将寄存器的内容放在该行上。此命令将(注意命令中的 p)将寄存器 a(通过 "a)的内容粘贴到该行中。
  • 根据需要进行修改,然后
  • 将修改后的行放回寄存器a中,方法是移动到该行的开头(使用|),并在转义模式下键入"ad$。(不要使用"aD,因为 D 也会捕获缓冲区中的换行符。)
  • 测试宏以确保它正常工作,然后根据需要使用它。

执行命令宏

[编辑 | 编辑源代码]

要执行存储在寄存器q中的宏一次,您可以按@q。但是,您通常不会编写只执行一次的宏,而 Vim 的强大功能就在这里发挥作用。

要将命令应用于第 23 行到第 42 行,请使用:23,42norm! @q,要将命令应用于文档中的所有行,可以使用:%norm! @q

同样的方法也适用于您可以使用点访问的单个命令。如果您在文档中的一些行上忘记了分号,您只需执行A;,然后按ESC键。然后,命令:23,42norm! .会将相同的操作应用于第 23 行到第 42 行,并在每行的末尾插入分号。

映射命令

[编辑 | 编辑源代码]

映射新命令的优势之一是,您可以将映射放入您的 vimrc 文件中以供以后使用。我有以下映射

map <C-k> :!%:p<C-m>

这样做就是将normal命令 Ctrl-K 映射为运行当前文件作为脚本。您也可以使用此映射执行上面的第二个“录制命令”练习(将单词放在粗体标签中)

map <C-x>b "bdawi<b><C-o>"bp</b><ESC>

请注意,在这种情况下,我可以使用"<b>",因为它不匹配任何特殊字符名称。但是,如果我需要避免冲突(如果我想映射"<ESC>"的插入),我会对小于号和大于号使用<lt>和<gt>。(请参见 ":help key-codes")

如果您希望为插入模式映射命令,请使用 imap 而不是 map。

如果您希望阻止映射定义中的任何命令在其他映射中被解释,请使用 noremap(或在插入模式下使用 inoremap inoremap 代表insert mode no re-map


学习 vi 编辑器: 熟悉基本任务简化工作高级任务细节Vi 克隆 (Vim基本导航模式技巧和窍门程序员需要知道的实用技巧增强 VimVim 在 Windows 上VimL 脚本语言, Vile, BB vi)vi 参考

华夏公益教科书