Vim 基本概念和基础命令:应对简单的编辑任务

好,现在请查看下面的键盘图。简单说明一下,这张图上展示了一个键盘。图中的“•”表示,单个字母不是完整的命令,必须再有进一步的输入。比如,单个“g”没有意义,而“gg”表示跳转到文件开头。(对于命令后面明确跟一个动作的,如“c”,我们不使用“•”。)一个键最多有三排内容:最底下是直接按键的结果,中间是按下 Shift 的结果(变大写),上面偏右的小字是按下 Ctrl 的结果。我们还用了一些特殊符号来表示操作的位置,如果你已经了解了这些命令的功能,你也自然就明白它们的意义了。

Vim 命令速查(教程版)

这张图里没有写出 Vim 的命令行命令。你现在应该已经掌握了以下这些:

  • “:q!”:退出 Vim
  • “:wq”:存盘退出
  • “:s”:执行替换
  • “:!”:执行外部命令
  • “:edit”(一般缩写为 “:e”):编辑文件
  • “:w”:写文件
  • “:r”:读文件
  • “:help”:查看帮助

使用键 Ctrl-D 和 Tab 来进行命令行补全

Vim 的模式

  • 正常(normal)模式(也称为普通模式),缺省的编辑模式;如果不加特殊说明,一般提到的命令都直接在正常模式下输入;在任何其他模式中,都可以通过键盘上的 Esc 键回到正常模式。
  • 插入(insert)模式,输入文本时使用;比如在正常模式下键入 i(insert)或 a(append)即可进入插入模式。
  • 可视(visual)模式,用于选定文本块;教程中已经提到可以用键 v(小写)来按字符选定,Vim 里也提供其他不同的选定方法,包括按行和按列块。
  • 命令行(command-line)模式,用于执行较长、较复杂的命令;在正常模式下键入冒号(:)即可进入该模式;使用斜杠(/)和问号(?)开始搜索也算作命令行模式。命令行模式下的命令要输入回车键(Enter)才算完成。

下面的命令是在 Vim 里输入“:set ft?<CR>”(用来显示当前编辑文件的文件类型):

:set ft?

Vim 的选项和配置

作为一个可以越用越顺手的应用程序,Vim 是需要配置的。我们才刚开始学习,所以目前我们的配置文件是相当简单的,但随着课程的进展和你使用 Vim 越来越多,你的 Vim 配置文件必然会越变越复杂。

Vim 配置文件分为系统配置文件和用户配置文件:

  • 系统配置文件位于 Vim 的安装目录(默认路径为 /etc/.vimrc);
  • 用户配置文件位于主目录 ~/.vimrc,即通过执行 vim ~/.vimrc 命令即可对此配置文件进行合理修改。通常情况下,Vim 用户配置文件需要自己手动创建。

备份和撤销文件

上面的基本设置会产生一个有人喜欢、但也有很多人感到困惑的结果:你修改文件时会出现结尾为“~”的文件,有文件名后面直接加“~”的,还有前面加“.”后面加“.un~”的。这是因为在示例配置里,Vim 自动设置了下面两个选项:

vim ~/.vimrc
set backup
set undofile

前一个选项使得我们每次编辑会保留上一次的备份文件,后一个选项使得 Vim 在重新打开一个文件时,仍然能够撤销之前的编辑(undo),这就会产生一个保留编辑历史的“撤销文件”(undofile)了。

 我的通常做法是,不产生备份文件,但保留跨会话撤销编辑的能力;因为有了撤销文件,备份其实也就没有必要了。同时,把撤销文件放在用户个人的特定目录下,既保证了安全,又免去了其他目录下出现不必要文件的麻烦。

要达到这个目的,我在 Linux/macOS 下会这么写:

set nobackup
set undodir=~/.vim/undodir

无论哪种环境,你都需要创建这个目录。我们可以用下面的命令来让 Vim 在启动时自动创建这个目录:

if !isdirectory(&undodir)
  call mkdir(&undodir, 'p', 0700)
endif

&undodir 代表 undodir 这个选项的值

这个跨会话撤销的能力,我还真不知道其他哪个编辑器也有。更妙的是,Vim 还有撤销树的概念,可以帮助你回到任一历史状态。这个我们以后会和相关的插件一起讨论。

在 Vim 中使用“:help”命令(大部分环境下也可以使用 <F1> 功能键),尝试查看命令说明

对于一次移动超过一个字符的情况,Vim 支持使用 b/w 和 B/W,来进行以单词为单位的跳转。它们的意思分别是 words Backward 和 Words forward,用来向后或向前跳转一个单词。小写和大写命令的区别在于,小写的跟编程语言里的标识符的规则相似,认为一个单词是由字母、数字、下划线组成的(不严格的说法),而大写的命令则认为非空格字符都是单词。

Vim 跳转到行首的命令是 0,跳转到行尾的命令是 $,这两个命令似乎没什么特别的原因,一般用 <Home> 和 <End> 也没什么不方便的,

对于写文字的情况,比如给开源项目写英文的 README,下面的光标移动键也会比较有用:

( 和 ) 移到上一句和下一句

{ 和 } 移到上一段和下一段

文本修改

在 Vim 的教程里,我们已经学到,c 和 d 配合方向键,可以对文本进行更改。本质上,我们可以认为 c(修改)的功能就是执行 d(删除)然后 i(插入)。在 Vim 里,一般的原则就是,常用的功能,按键应尽可能少。因此很多相近的功能在 Vim 里会有不同的按键。不仅如此,大写键也一般会重载一个相近但稍稍不同的含义:

  • d 加动作来进行删除(dd 删除整行);D 则相当于 d$,删除到行尾。
  • c 加动作来进行修改(cc 修改整行);C 则相当于 c$,删除到行尾然后进入插入模式。
  • s 相当于 cl,删除一个字符然后进入插入模式;S 相当于 cc,替换整行的内容。
  • i 在当前字符前面进入插入模式;I 则相当于 ^i,把光标移到行首非空白字符上然后进入插入模式。
  • a 在当前字符后面进入插入模式;A 相当于 $a,把光标移到行尾然后进入插入模式。
  • o 在当前行下方插入一个新行,然后在这行进入插入模式;O 在当前行上方插入一个新行,然后在这行进入插入模式。
  • r 替换光标下的字符;R 则进入替换模式,每次按键(直到 <Esc>)替换一个字符。
  • u 撤销最近的一个修改动作;U 撤销当前行上的所有修改。

熟练掌握这些按键需要一定的记忆和练习。但是,当你熟练掌握之后,大部分编辑操作只需要按一两个按键就能完成;而在你还没有做到熟练掌握之前,记住最简单、最有逻辑的按键也可以让你至少能够完成需要的编辑任务。

文本对象选择

到现在,我们已经学习过,可以使用 c、d 加动作键对这个动作选定的文本块进行操作,也可以使用 v 加动作键来选定文本块(以便后续进行操作),我们也学习了好些移动光标的动作。不过,还有几个动作只能在 c、d、v 这样命令之后用,我们也需要学习一下。

这些选择动作的基本附加键是 a 和 i。其中,a 可以简单理解为英文单词 a,表示选定后续动作要求的完整内容,而 i 可理解为英文单词 inner,代表后续动作要求的内容的“内部”。这么说,还是有点抽象,我们来看一下具体的例子。

假设有下面的文本内容:

if (message == "sesame open")

我们进一步假设光标停在“sesame”的“a”上,那么:

  • dw (理解为 delete word,会删除当前光标直至该单词+尾部的空格)会删除 ame␣,结果是 if (message == "sesopen")
  • diw(理解为 delete inside word,会删除当前光标内的单词全部字符)会删除 sesame,结果是 if (message == " open")
  • daw(理解为 delete a word,会删除当前光标内的整个单词+尾部的空格(其中不包括标点符号)会删除 sesame␣,结果是 if (message == "open")
  • diW 会删除 "sesame,结果是 if (message == open")
  • daW (会删除当前光标内的整个单词以及+尾部空格+前部相连的标点符号)会删除 "sesame␣,结果是 if (message == open")
  • di" (会删除当前行 小括号内的所有字符)会删除 sesame open,结果是 if (message == "")
  • da" 会删除 "sesame open",结果是 if (message ==)

di( 或 di) 会删除 message == "sesame open",结果是 if ()

da( 或 da) 会删除 (message == "sesame open"),结果是 if␣

上面演示了 a、i 和 w、双引号、圆括号搭配使用,这些对于任何语言的代码编辑都是非常有用的。实际上,可以搭配的还有更多:

搭配 s(sentence)对句子进行操作——适合西文文本编辑

搭配 p(paragraph) 对段落进行操作——适合西文文本编辑,及带空行的代码编辑

搭配 t(tag)对 HTML/XML 标签进行操作——适合 HTML、XML 等语言的代码编辑

搭配 ` 和 ' 对这两种引号里的内容进行操作——适合使用这些引号的代码,如 shell 和 Python

搭配方括号(“[”和“]”)对方括号里的内容进行操作——适合各种语言(大部分都会用到方括号吧)

搭配花括号(“{”和“}”)对花括号里的内容进行操作——适合类 C 的语言

搭配角括号(“<”和“>”)对角括号里的内容进行操作——适合 C++ 的模板代码

再进一步,在 a 和 i 前可以加上数字,对多个(层)文本对象进行操作。下面图中是一个示例:

修改往上第 2 层花括号内的所有内容

你看,无论你使用什么语言,这些快捷的文本对象选择方式是不是总会有一种可以适用?我个人觉得这些功能绝对是 Vim 的强项了,所以,我再敲一次黑板,这部分内容是重点,不要嫌内容多,挨个儿用一用、练一练,你会发现这个功能非常实用,在写代码的时候常常会用得上。

更快地移动

除了这讲开头提到的光标移动功能外,还有一些通常不和操作搭配的光标和屏幕移动功能。我们在这节里会快速描述一下。

我们仍然可以使用 <PageUp> 和 <PageDown> 来翻页,但 Vim 更传统的用法是 <C-B> 和 <C-F>,分别代表 Backward 和 Forward。

除了翻页,Vim 里还能翻半页,有时也许这种方式更方便,需要的键是 <C-U> 和 <C-D>,Up 和 Down。

如果你知道出错位置的行号,那你可以用数字加 G 来跳转到指定行。类似地,你可以用数字加 | 来跳转到指定列。这在调试代码的时候非常有用,尤其适合进行自动化。

下图中展示了 iTerm2 中捕获输出并执行 Vim 命令的过程(用 vim -c 'normal 5G36|' 来执行跳转到出错位置第 5 行第 36 列):

捕获错误信息并自动通过 Vim 命令行来跳转到指定位置

(如果你用 iTerm2 并对这个功能感兴趣,我设置的正则表达式是 ^([_a-zA-Z0-9+/.-]+):([0-9]+):([0-9]+): (?:fatal error|error|warning|note):,捕获输出后执行的命令是 echo "vim -c 'normal \2G\3|' \1"。)

你只关心当前屏幕的话,可以快速移动光标到屏幕的顶部、中间和底部:用 H(High)、M(Middle)和 L(Low)就可以做到。

顺便提一句,vimrc_example 有一个设定,我不太喜欢:它会设 set scrolloff=5,导致只要屏幕能滚动,光标就移不到最上面的 4 行和最下面的 4 行里,因为一移进去屏幕就会自动滚动。这同样也会导致 H 和 L 的功能发生变化:本来是移动光标到屏幕的最上面和最下面,现在则变成了移动到上数第 6 行和下数第 6 行,和没有这个设定时的 6H 与 6L 一样了。所以我一般会在 Vim 配置文件里设置 set scrolloff=1(你也可以考虑设成 0),减少这个设置的干扰。

只要光标还在屏幕上,你也可以滚动屏幕而不移动光标(不像某些其他编辑器,Vim 不允许光标在当前屏幕以外)。需要的按键是 <C-E> 和 <C-Y>。

另外一种可能更实用的滚动屏幕方式是,把当前行“滚动”到屏幕的顶部、中部或底部。Vim 里的对应按键是 zt、zz 和 zb。和上面的几个滚动相关的按键一样,它们同样受选项 scrolloff 的影响。

光标移动和屏幕滚动

重复,重复,再重复

今天的最后,我来带你解决一个你肯定会遇到的问题,那就是如何更高效地解决重复的操作。

我们已经看到,在 Vim 里有非常多的命令,而且很多命令都需要敲好几个键。如果你要重复这样的命令,每次都要再手敲一遍,这显然是件很费力的事。作为追求高效率的编辑器,这当然是不可接受的。除了我们以后要学到的命令录制、键映射、自定义脚本等复杂操作外,Vim 对很多简单操作已经定义了重复键:

; 重复最近的字符查找(f、t 等)操作

, 重复最近的字符查找操作,反方向

n 重复最近的字符串查找操作(/ 和 ?)

N 重复最近的字符串查找操作(/ 和 ?),反方向

. 重复执行最近的修改操作

有了这些,重复操作就非常简单了。要掌握它们的方法就是多练习,多用几次自然就会了。

内容小结

好了,今天的内容就讲完了,我们来做个小结。我们讨论了更多的一些常用 Vim 命令,包括:

基本光标移动命令(可配合 c、d 和 v)

文本修改命令小汇总

文本对象命令(c、d、v 后的a 和 i)

更快的光标和屏幕移动功能

重复功能

今天讲的内容不难,重点是文本对象。你知道吗?我见到的 Vim 命令速查表里通常也没有它们,因而连很多 Vim 的老用户都不知道这些功能呢。所以,掌握了这部分内容,我们就已经走在很多 Vim 用户的前面了。请一定要多加练习,用好这个功能会大大提升你的代码编辑效率。

最后,提醒你去 GitHub 上看配置文件。配置文件我们有一处改动。类似地,适用于本讲的内容标签是 l3-unix 和 l3-windows。


首先,如果我们要查找某个函数,该怎么做呢?简单,按下 /,然后输入函数名,回车,不就行了?

错。这种方式对函数名是部分匹配,你搜 begin 还会得到 begin1、_begin 之类的结果。正确的方法是,要在前后加上匹配单词头尾的标记,如,\<begin\>。

顺便说一句,被誉为最有用的 Vim 提示,是把光标移到希望搜索的关键字上,然后按下 * 键。Vim 会提取光标下的关键字,并自动添加 \< 和 \> 进行搜索。

也有些时候,我们已经做完了搜索或替换,和模式匹配的文本内容仍然还高亮着,非常碍眼。有些人就会随便搜索一个不存在的字符串来取消加亮,但这显然不是一种高效的处理方式。事实上,Vim 有一个专门命令来取消搜索加亮,这个命令就是 :nohlsearch,不要高亮搜索。

猜你喜欢

转载自blog.csdn.net/qq_31941921/article/details/121504058