vim 被称为编辑器之神,学习难度很大,但是熟练掌握后可以更高效地敲代码,因此学一下。

安装与配置文件

vim 默认是命令行版本的,而 gvim 是 GUI 版本的 vim,这里我们使用的是 Git for Windows 里面附带的 vim(不含 GUI),可以按 Linux 风格进行配置和使用,感觉比直接下载Vim 官网的 Windows 版的 gvim 更方便,便于直接把配置应用到到 Linux 服务器上。

在 vim 中输入:version可以查看很多信息,例如

1
2
3
4
5
6
7
// vim的版本号
VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Nov 22 2021 19:31:05)
Included patches: 1-3582
Compiled by <https://www.msys2.org/>

// vim的安装模式(tiny,small,normal,big,huge等,huge的功能最全)
Huge version without GUI.

还有一个列表描述了当前编译的 vim 支持或不支持的功能列表,例如+clipboard 意味着剪贴板功能被编译支持了,-clipboard 意味着剪贴板特性没有被编译支持。

打开和关闭,保存

在命令行直接输入vim filename即可打开或新建指定的文件:

  • 对于已存在的文件会打开它;
  • 对于不存在的文件,会创建一个临时文件,如果退出时选择保存,则会真实地创建该文件。

注意,如果直接输入vim,不接文件名,则 vim 会给出如下的欢迎界面——帮助乌干达的贫困儿童。

其中行首的~占位,表示该行不存在。

在编辑完成之后,退出 vim 的操作首先要明确所处的模式,假设当前处于命令模式中(输入:会进入底线命令模式),有如下几种退出方式:

  • :q 直接退出(quit),只适合于当前文件没有被改动时,如果文件有改动,则会报错无法退出,因为必须处理对文件的修改;
  • :wq 保存并退出(write and quit),也可以拆成两个命令:保存:w,退出:q
  • :q! 加感叹号表示强制退出,如果不希望保存文件的改动,则可以强制进行不保存的退出。

使用:x也可以保存并退出,而且和:wq相比有细微的差别,它仅仅会在文件真正改动时才写入文件。 使用:w newfilename可以把改动另存为新的文件。 使用:w n1,n2 newfilename可以把 n1 行到 n2 行的内容截断存储到新的文件中。

对于不熟悉 vim 的用户,几乎不可能体面地关闭 vim,不管你按什么按键。一个冷笑话是:如何生成一串完全随机字符串? 让新手退出 vim。

工作模式

vim 主要包括三种模式:

  • 命令模式(Command mode)
  • 插入(编辑)模式(Insert mode)
  • 底线命令模式(Last line mode)

启动 vim 会直接进入命令模式,此时的按键不会被视作输入字符,而是视作命令,例如输入i会切换到插入(编辑)模式,进行正常的文本编辑状态(下方会显示-- INSERT --);输入英文冒号:会切换到底线输入模式,此时在最底行输入复杂命令(命令模式只支持一些基本的命令)

三个模式的转换如下图,其中命令模式相当于中枢,其他模式按 Esc 键会返回命令模式。

vim 的命令繁琐比较难记,有很多类似的速查图帮助记忆:

不论在命令模式还是编辑模式,在打开的文本中都存在一个可移动的光标,从命令模式变成编辑模式,有如下几种方法:

  • 插入:i在光标所在字符前开始插入(光标所处的字符会被挤到后面);I 在光标所在行的行首开始插入,如果行首有空格则在空格之后插入。
  • 添加:a在光标所在字符后开始插入(光标会自动后移一格);A 在光标所在行的行尾开始插入。
  • 删除插入:s删除光标所在的字符并开始插入;S 删除光标所在行并开始插入

大小写的操作都是相关的,小写的操作通常是字符尺度的,大写的操作通常是行尺度的。 此外还有:o光标所在行的下面创建新行插入;在光标所在行的上面创建新行开始插入。

光标移动

不论是在命令模式还是编辑模式,都可以使用上下左右方向键来移动光标。 在底线命令模式中,光标锁定在底线等待复杂命令的输入,可以左右移动调整光标,也可以上下翻页命令的历史记录。 但是在命令模式中,我们不希望离开主键区,使用下面的 4 个按键来移动光标

  • h 左移;
  • j 下移;
  • k 上移;
  • l 右移;

可以配合数字使用,例如nh代表光标左移 n 个字符,nj代表光标下移 n 行(如果目标行足够长,则保持列数不变,长度不足时则变成行尾,行数不足时停在文件尾行)。在命令模式中,还可以使用gi来直接返回在编辑模式中最后的光标位置,直接以插入的方式进入编辑模式。

光标可以在当前行快速移动:

  • 0 移动到当前行首;
  • $ 移动到当前行尾;
  • w 移动到(下一个)单词的首字母;(可以使用nw一次性移动 n 个单词)
  • e 移动到(当前)单词的尾字母;(可以使用ne一次性移动 n 个单词)
  • n<space> 数字加空格,光标向后移动 n 个字符;(相当于nl
  • n<enter> 数字加回车,光标向下移动 n 行到达非空字符位置;(相当于nj

0$在vim的很多操作中都具有开头和结尾的语义。

可以根据非空字符来移动光标:

  • ^ 移动到当前行的第一个非空字符;
  • +shift+=) 移动到上一行的非空字符位置;
  • - 移动到下一行的非空字符位置;

可以在整个文件中移动:

  • 命令模式中
    • gg 移动到当前文件的第一行;
    • nggnG 移动到当前文件的第 n 行;
    • G 移动到当前文件的最后一行;
    • n% 移动到当前文件对应 n 比例的位置,例如30%
  • 底线命令模式中,还有如下的命令(需要加回车来执行):
    • :0 移动到当前文件的第一行;
    • :n 移动到当前文件的第 n 行;
    • :$ 移动到当前文件的最后一行;

可以在屏幕尺度下进行移动:

  • H 移动到屏幕顶端的行;
  • M 移动到屏幕中部的行;
  • L 移动到屏幕底部的行;

还有:

  • ctrl+uctrl+d:保持光标在屏幕中的相对位置,将文本上移和下移,移动行数约为屏幕显示行数的一半;
  • zzztzb:将光标所在的行移动到屏幕中间,顶部和底部。(如果位置允许的话)

常用功能

在命令模式下,支持如下的撤销操作:

  • 撤销功能u(undo)
  • 撤销对整行的操作U
  • 重做 ctrl+r
  • 重复当前动作 . (句号)

注意:在命令模式下,backspace 键仅仅是光标的回退而不会删除字符,enter 键也不会换行

删除:(理解为剪切也可以)

  • 删除光标所在的字符 x,连续删除 n 个字符 nx
  • 删除光标之前的一个字符 X
  • 删除一整个单词 dw,删除连续的 n 个单词 ndwdnw好像也一样)
  • 删除直到当前单词的尾部 de(和dw很类似,但是不包括单词尾部的空格)
  • 删除光标所在的一整行 dd,删除(向下的)连续的 n 行 ndd
  • 删除光标之前的(当前行)所有字符 d0
  • 删除光标字符以及之后的(当前行)所有字符 d$
  • 删除光标所在行直到文件末尾行的所有字符 dG
  • 删除光标所在行直到文件开头行的所有字符 d1G

替换:

  • 替换当前字符为<a>r<a>
  • 连续替换多个字符:R(逐个输入进行替换,直到esc)
  • 删除直到当前单词结尾,并进入插入模式:cw
  • 删除直到当前行结尾,并进入插入模式:c$

复制:

  • 复制当前字符 y
  • 复制整行 yyY,复制(向下的)连续的 n 行 nyy
  • 复制光标之前的(当前行)所有字符 y0
  • 复制光标字符以及之后的(当前行)所有字符 y$
  • 复制光标所在行直到文件末尾行的所有字符 yG
  • 复制光标所在行直到文件开头行的所有字符 y1G

粘贴:

  • 把复制(或删除)的字符片段粘贴到当前行之后 p(小写)
  • 把复制(或删除)的字符片段粘贴到当前行之前 P(大写)

查找:

  • /abc 向后查找 abc 字符串
  • ?abc 向前查找 abc 字符串
  • n 继续(或切换为)向后搜索
  • N 继续(或切换为)向前搜索

查找替换:

  • :s/abc/xyz 替换当前行的 abc 字符串为 xyz(仅替换第一个匹配项)
  • :s/abc/xyz/g 替换当前行的 abc 字符串为 xyz(g代表替换所有匹配项)
  • :%s/abc/xyz/g 替换所有行的 abc 字符串为 xyz(%代表针对当前文件的所有行)
  • :%s/abc/xyz/gc 替换所有行的 abc 字符串为 xyz(c代表交互式确认每一处的替换,可以执行、跳过或退出)
  • :10,20s/abc/xyz/g 替换指定范围内(两个数字代表起止行号)的 abc 字符串为 xyz

括号匹配:将光标放在括号上,使用%可以自动跳转到匹配的括号。

执行外部命令::!<cmd>可以利用shell执行外部命令,支持传递参数,提供一个临时界面展示命令的输出。

插入文件内容::r <file>可以直接将指定文件的内容插入到当前位置。

缩进:>><<可以对当前行或选择的多行设置缩进。

可视模式:v进入可视模式,选择要复制或处理的内容,光标移动会显示选中效果,使用V进入的是整行操作的可视模式。 对于选中的片段可以进行很多操作:

  • 输入:(会自动补充为:'<,'>)和w filename可以另存到文件中。
  • 输入y可以复制选择的内容
  • 输入d可以删除选择的内容

获取帮助:

  • :help <cmd>可以获取指定命令的帮助,例如关于按键的;
  • :xxx 输入一些单词后可以使用ctrl+d获取命令补全提示。

补充:使用q:可以查看命令行的历史记录;使用q会开启宏录制,用于简化重复操作,暂时用不上,再次按q退出录制宏。

配置与配置文件

我们可以设置显示绝对行号:set number(或者简写为:set nu),效果如下图

可以设置:set nonumber关闭行号。(一般的配置项都可以通过加no前缀来取消) 可以使用:set number?来查询当前行号是开启还是关闭的,会显示numbernonumber。(一般的配置项都可以通过加?查询状态)

还可以设置显示相对行号:set relativenumber,光标所在的行记作 0,上下相邻的行记作 1,以此类推,效果如下图

绝对行号和相对行号可以同时出现,效果如下图

:set cursorline可以高亮光标所在的行,这里的高亮有可能是改成红色背景,有可能是整行添加下划线。

:set filetype=c(:set ft=c)可以设置文件类型,默认情况下可以自动识别文件类型。

:! command可以暂时返回命令行界面执行指令,然后回车可以回到 vim,常用:! ls快速查询目录。

:set nocompatible可以不兼容 vi 的操作命令,默认开启。

:set showmode可以提示当前是命令模式还是插入模式,默认开启。

在底线命令模式中,可以输入相关的设置命令,但仅仅对于当前窗口有效,如果希望在每次打开 vim 时都自动采用某些设置,则应该写入配置文件中,配置文件的位置和优先级可以通过:version查找,通常用户自定义的配置文件为~/.vimrc(对于 Windows 的 gvim,可能叫做_vimrc)。在配置文件中,以双引号"开头的行被视作注释。

vim 的内容实在是太多了,包括丰富的插件系统,可以实现各种个性化的功能,最终甚至达到一个 IDE 的效果,但是我现在并不需要,只是轻量级的使用,因此入门的笔记就到此为止了。

不使用插件的纯净vim配置文件存放在fenglielie/dotfiles仓库,注意.vimrc配置文件的回车不是 CRLF 而是 LF。

与外部的复制粘贴

vim本身有自己的复制粘贴机制,非常复杂不想讨论。

有的版本还支持与Linux系统的剪切板进行交互,但是需要一些配置,而且系统自带的版本通常都不支持,可以用下面的命令查看支持情况

1
vim --version | grep clipboard

对于文本文件的大段复制,还是直接用less查看,然后用鼠标进行选择复制算了,比较省事。对于文本文件的大段粘贴,如果直接ctrl+v会出现很多异常:

  • 例如如果当前不是insert模式,那么在开头的部分字符可能会被丢弃,直到出现ia等字符才会生效。
  • 例如vim可能产生异常的缩进,还可能将某些行自动注释掉。

这是因为vim将字符流视为用户从键盘进行的输入行为。可以通过下面的选项将vim设置为粘贴模式,此时就可以保持原样进行粘贴

1
:set paste

在执行ctrl+v之前,最好让vim保持在如下模式

1
-- INSERT (paste) --

在粘贴完成后关闭这个选项即可

1
:set nopaste