那就是 Vimprovement!更好的 vi
默认情况下,Vim 以 vi 兼容模式启动。这意味着许多高级功能都被关闭了。要开启这些 Vim 的改进功能,您需要创建一个 $HOME/.vimrc 文件。
列表 1 包含一个示例 .vimrc 文件。如果您有 .exrc 文件,也可以通过复制它来创建一个。一个零长度的文件也可以。
Vim 编辑器有两种风格。命令 vim 启动控制台版本的编辑器。在这个版本中,您在执行命令的终端窗口内进行编辑。gvim 命令会创建自己的窗口。第二个命令是首选的,因为您可以获得控制台版本中没有的功能,例如命令菜单和工具栏。
Vim 最有用的创新之一是在线集成帮助。
:help 命令显示帮助窗口。对于特定帮助,:help / 显示搜索 (/) 命令的帮助文本(见图 1)。
您可以使用正常的编辑命令(如 h、j、k、l、<Page-Up>、<Page-Down> 等)在文本中移动。
当您滚动浏览文本时,您会看到一些看起来像这样的行
/<CR> Search forward for the [count]'th latest used pattern |last-pattern| with latest used |{offset}|.
竖线 (|) 括起来的文本是 Vim 超链接。将光标放在这些项目之一(例如 |last-pattern|)上,然后按 CTRL-]。这将使屏幕跳转到给定的主题。
要返回到跳转前的位置,请使用命令 CTRL-T。
要退出帮助系统,请使用正常的 Vim 退出命令 :q 或 ZZ。
要了解一些新的 Vim 命令如何帮助您,请首先创建一个包含以下文本的简单程序文件
#include "even.h" int even(int value) { if (value & 1) == 1) // Deliberate mistake return (1); return (0); }
首先要注意的是文本颜色的变化。这被称为语法高亮。程序的每个组成部分(关键字、字符串、常量、预处理器指令等)都有不同的颜色。在我们的初始化文件中,这是由 :syntax on 命令启用的。如果您执行 :syntax off,高亮就会消失。
接下来要注意的是,当您键入文件时,您不必进行任何缩进。所有行都会自动为您缩进。这是因为 magic lines 开启了 cindent 选项
:autocmd FileType c,cpp :set cindent
这仅适用于 C 和 C++ 文件。(不幸的是,关于自动命令的全面讨论超出了本文的范围。您可以执行 :help autocmd 以获得完整说明。)
注意:示例 .vimrc 文件中的实际命令比本节中介绍的命令稍微复杂一些,但它们的作用相同。
现在,让我们来玩一下。将光标放在其中一个 return 语句的 “r” 上,然后键入 xxxxxx。“return” 消失了。现在键入 “u” 以撤销上次更改。“n” 返回了。
旧的 vi 编辑器只有一个级别的撤销。Vim 有很多。再次键入 “u”,您会注意到您已经恢复了 “rn”。再键入四次 “u”,整个单词都返回了。
那么如何撤销撤销呢?通过新的 “重做” 命令:CTRL-r。通过键入几次这个命令,您就可以重做删除操作,这会导致 “return” 的部分内容消失。
现在您有了一个 C 文件,您应该创建一个头文件。如果能够将原型从 C 文件复制并粘贴到头文件中,那就太好了。使用 vi 您无法做到这一点。使用 Vim,这很容易。
首先,在编辑器中调出两个文件。命令 :split even.h 将当前窗口分成两半。上半部分显示 even.h 文件,下半部分显示 even.c 文件(见图 2)。
要将光标从顶部窗口移动到底部窗口,请使用命令 CTRL-Wj。要向上移动窗口,请使用命令 CTRL-Wk。
要关闭窗口,请使用 ZZ 或 :quit 命令。
Vim 有一个新的主要模式:可视模式。在可视模式下,高亮显示您要编辑的文本,然后键入编辑命令。在本例中,您需要从底部窗口复制函数 even 的第一行,并将其粘贴到顶部窗口。
首先,将光标发送到底部窗口 (CTRL-Wj),并将其定位在函数 even 的第一行。接下来,通过键入 V 命令进入行可视模式。当前行被高亮显示,这表明该行将受到您键入的任何编辑命令的影响。此时,您可以使用光标命令向下移动几行。当您移动光标时,您经过的文本会被高亮显示。向上移动光标,它会取消高亮显示。如果您越过起点,则上方的文本将被高亮显示。
高亮显示是逐行完成的。那是因为您已进入可视行模式。如果您键入了 v,则为字符可视模式,您可以逐字符高亮显示文本。最后,还有块可视模式 (CTRL-V),它高亮显示屏幕上的一个矩形。如果您正在处理文本表格,这将非常有用,因为您可以操作屏幕上的数字列。
现在,要将一行从底部窗口复制到顶部窗口,请使用行可视模式 (V) 并高亮显示该行。然后使用 yank y 命令将其复制到未命名寄存器中。接下来转到顶部窗口并执行 p 以粘贴文本到顶部窗口。您现在只需在行尾添加一个 “;”,您就得到了一个 even 头文件。图 3 显示了这些命令的实际操作。
为了编译我们的程序,我们需要一个 Makefile。(此练习留给读者完成。)
一旦我们的 Makefile 准备就绪,我们就可以使用 Vim 与 make 的集成来编译程序。我们只需要在 Vim 中发出 :make 命令,编辑器就会运行 make 并捕获输出。
我们的程序包含一个错误
even.c:4: parse error before `=='
Vim 捕获 :make 命令的输出并对其进行解析。由此可见,我们在 even.c 的第 4 行有一个错误,因此它将光标移动到这一行,并在屏幕底部显示错误消息。(如果需要定位错误,它甚至会切换文件。)
这使得修复错误变得容易。要查看下一个错误,请发出 :cn 命令。如果您想再次查看当前错误,请使用 :cc 命令。上一个错误 :cp。最后,如果您完成了此文件的编辑,并想查看下一个文件中的第一个错误,请使用 :cnf 命令。
Vim 在错误位置方面很智能。当您在文件开头添加或删除行时,Vim 会调整文件末尾错误的位置以反映这些更改。这避免了您在使用像 vi 这样的传统编辑器时遇到的问题,即修复文件开头的错误会使文件中其余部分的行号偏移。
grep 命令非常适合找出函数在哪里被使用和定义。只需输入命令
$ grep -n even *.c
您将获得一个打印输出,其中包含每个包含单词 even 的行。
Vim 有一个 :grep 命令,它的作用相同。实际上,此命令与 :make 命令非常相似。它运行 grep,捕获输出,并允许您使用 :cn、:cp、:cc 和 :cnf 浏览文件——就像 :make 一样。
如果您开启 cindent 选项,Vim 将在您插入新文本时正确缩进您的程序。但是对于已经存在的文本呢?这就是 = command 的用武之地。
它将通过 Vim 的内部缩进程序运行文本块。(实际上,您可以通过 equalprog 选项选择要用于缩进的程序。)
让我们看看这如何用于缩进基本的 C 语句块。有两种调用 = command 的方法。第一种是使用 ={motion}。第二种是进入可视模式,选择一个文本块,然后按 =。
因此,缩进代码块的一种方法是转到块的第一个 “{”。现在输入 =%。= 告诉 Vim 缩进从此处到下一个命令将光标移动到的位置的文本。在本例中,下一个命令是 %,它告诉 Vim 转到匹配的 “}”。
如果您想使用可视模式进行操作,您需要将光标定位在第一个 “{” 上,然后使用 V 命令进入行可视模式。接下来,使用任何可以将您带到那里的命令集,将光标定位在相应的 “}” 上。最后,高亮显示的块将使用 = command 进行缩进。
Vim 有一些有趣的搜索选项。第一个是增量搜索选项,它通过以下命令启用
:set incsearch
通常,当您进行搜索时,例如搜索 include,您需要输入完整命令:/include<CR>,Vim 将开始搜索字符串。当启用增量搜索时,Vim 会在您键入搜索的第一个字符时开始搜索。换句话说,当您键入 /i 时,Vim 会在文本中搜索第一个 “i”。键入下一个字符 “n”,即 /in,Vim 会查找 “in”。当您键入每个字符时,搜索会(如果需要)继续查找您到目前为止键入的字符串。
搜索中的另一个主要创新是高亮显示搜索 (hlsearch) 选项。如果启用此选项,则当 Vim 找到与搜索匹配的字符串时,它会高亮显示它。不仅当前匹配项被高亮显示,而且所有匹配项都被高亮显示。
如果您正在搜索拼写错误的变量名或单词,这将非常有用,因为所有不正确的单词出现的位置都会被高亮显示。
如果您想临时取消高亮显示,您可以发出 :nohl 命令。这将清除高亮显示,直到输入下一个搜索命令。
Vim 还维护搜索历史记录。假设您已经完成了一些搜索。现在按 / 开始搜索,然后按 <UP> 键。将显示上一次搜索。再次按 <UP>,您将获得下一个最旧的搜索。因此,使用 <UP> 和 <DOWN> 键,您可以滚动浏览一组您最近的搜索。
Vim 中最强大的命令之一是 .(点)命令。它重复您上次的编辑。但是此命令是有限制的。它只会重复单个命令。
但是,如果您有更复杂的事情要做怎么办?这就是 Vim 的键盘宏的用武之地。它们允许您在寄存器中记录一系列命令,然后执行它们。
要了解它是如何工作的,假设您有以下几行要编辑
stdio.h time.h unistd.h stdlib.h
您想将这些行中的每一行都变成 #include 行,例如,#include <stdio.h>
您首先输入命令 qa。这将导致所有后续命令都记录在寄存器 a 中。(可以使用从 a 到 z 的任何寄存器。)
接下来进行编辑。转到行首 (^) 插入 #include <,然后通过在行尾添加 > 来完成。最后,下移一行,为下一次编辑做好准备。
所有这些命令现在都记录在 a 寄存器中。q 命令告诉 Vim 停止记录。文本现在看起来像
#include <stdio.h> time.h unistd.h stdlib.h
光标位于第二行。要执行宏,请使用命令 @a。结果是
#include <stdio.h> #include <time.h> unistd.h stdlib.h@ 命令接受重复次数,因此您可以使用 2@a 命令完成我们的工作。
#include <stdio.h> #include <time.h> #include <unistd.h> #include <stdlib.h>
命令 ctags(Vim 自带)可用于为一组 C 文件生成程序目录。(这现在是一个标签文件。)
一个典型的 ctags 命令是
ctags *.c
这将创建一个标签文件,其中包含当前目录中 C 文件中所有函数的位置。
一旦生成,标签文件对于使用 Vim 进行编辑的人来说非常有用。
假设您正在编辑一个文件,并且正在查看 read_paragraph 函数。当您浏览代码时,您发现 read_paragraph 调用了 read_sentence。您想看看这个函数是做什么的。
如果您将光标放在函数名称上,然后按 CTRL-],Vim 将跳转到该函数的定义。您很快发现 read_sentence 调用了 read_word,因此您将光标放在 read_word 上并按 CTRL-]。编辑器再次跳转到该函数的定义。
Vim 通过使用标签堆栈来跟踪您去过的位置。要查看您在此列表中的位置,请使用 :tags 命令。
:tags # TO tag FROM line in file/text 1 1 read_sentence 3 read_sentence(); 2 1 read_word 8 read_word(); >
在本例中,我们从 read_word(未列出)转到 read_sentence,然后转到 read_word。要返回,请使用 CTRL-T 命令。它将您在标签堆栈中向上弹出一个级别。
假设您在一个目录中有五六个小程序,并且您想跳转到其中一个 main 函数的定义。如果您执行
:tag main
命令,编辑器将跳转到它可以找到的第一个 main 定义。这可能不是您想要的那个。
:tselect 命令显示与给定名称匹配的所有标签,并让您选择您想要的那个。例如
:tselect main # pri kind tag file > 1 F C f main a_test.cpp int main( int argc, char* argv[] ) 2 F f main acp.cpp int main( int argc, char* argv[] ) 3 F f main add.cpp int main(int argc, char* argv[]) Enter nr of choice (<CR> to abort): 3
如果您只知道名称的一部分怎么办?换句话说,您想转到名称为 “something-process-something-data” 的函数。:tags 命令可以接受正则表达式。在这种情况下,命令
:tag /process.*data转到与此表达式匹配的第一个标签。如果多个函数与该表达式匹配,您可以使用 :tselect 转到正确的函数。
程序包含代码和注释。代码有自己的结构。您不希望编辑器在您编写代码时自动换行。但是注释只是文本,可以换行。事实上,在大多数情况下,非常希望编辑器能够自动换行长文本行。
Vim 编辑器理解命令和代码之间的区别。它可以配置为自动换行注释,而让代码保持原样。这可以通过将以下行放在我们的 .vimrc 文件中来完成
:autocmd FileType c,cpp \ set formatoptions=croql cindent \ comments=sr:/*,mb:*,ex:*/,://
(注意:延续行在 *begin* 中以 \ 开头。)
:autocmd 命令告诉 Vim,每当它确定它正在处理 C 或 C++ 文件时,都将执行这些命令。(文件名以 .c 或 .cpp 结尾。)
formatoptions 告诉 Vim 我们要自动换行注释,但不希望代码被换行。下一行
set comments=sr:/*,mb:*,ex:*/,://
告诉 Vim 注释是什么样的。在本例中,我们定义了标准 C 注释 (/*, */) 和 C++ 注释 (//)。我们还告诉 Vim,如果我们处于 C 样式注释的中间,请在每行开头添加一个 “*”。
设置这些选项后,当您键入 /*<RETURN> 时,Vim 会自动输入一个 “ *” 以开始下一行。鉴于本文允许的篇幅有限,我真正能告诉您的是,这是一个非常棒的功能,您应该尝试一下。如果您需要更多详细信息,您可以查看在线帮助文本。
Vim 是一个非常通用的编辑器。在本文中,我们触及了这个编辑器的一些更有趣的功能。但我们只是触及了表面。还有数百个我们尚未讨论的命令和选项。您可以通过阅读帮助文本和编辑器附带的其他文档来了解这些内容。
通过向您介绍 Vim 中的一些新功能,我们为您更有效地编辑提供了一个起点。您从这里走多远取决于您自己。
