138. VIM's World
各系统下安装方法
安装这个主题让这篇文章看起来更客观. 方法: google一下!
Red Hat 和 CentOS 系列
在 Red Hat Linux 和 CentOS Linux 上,默认安装的 Vim 可能是一个最小功能的版本。虽然这个版本启动速度很快,但它缺少了很多对开发有用的功能,如语法加亮、Python 集成和图形界面。一般情况下,应至少安装更全功能版本的 Vim;如果能使用 X Window 的话,则应安装图形界面版本。
你可以通过下面的命令来查看已经安装的 Vim 版本:
1 | yum list installed | grep vim |
如果输出只有下面这样的内容的话,就说明安装的 Vim 版本只有基本功能:
1 | vim-minimal.x86_64 2:8.0.1763-13.el8 @System |
建议使用 sudo yum install vim-X11
来安装图形界面的 Vim,或至少使用 sudo yum install vim-enhanced
来安装增强版本的 Vim(如果你不在这台机器上进行图形界面登录的话)。
只要你使用图形界面,一般而言,你都应该安装有图形界面支持的 Vim。总体而言,图形界面 Vim 的功能更丰富,并且即使你只在终端里使用 Vim,含图形界面支持的 Vim 会带剪贴板支持,跟整个图形环境的交互也就比较容易。当然,如果你只是远程通过 SSH 使用 Vim 的话,那确实图形界面支持就没有意义了。
Debian 和 Ubuntu 系列
在 Debian、Ubuntu 等使用 apt 的 Linux 发行版上,Vim 同样有着不同功能版本的区别,而且选择更多。我们可能会看到:
- vim
- vim-athena
- vim-gnome
- vim-gtk
- vim-gtk3
- vim-nox
- vim-tiny
它们中有编译进最小功能的 Vim 包(vim-tiny),有较全功能的文本界面 Vim 包(vim-nox),有适用于老的 X-Window 界面的版本(vim-athena),有适用于 KDE 环境的 GTK2 版本(vim-gtk),等等。
如果你不确定要装什么版本的话,那可以遵循我下面的建议:
- 如果你使用标准的 GNOME 桌面环境的话(大部分的情况),安装 vim-gtk3 或 vim-gnome。
- 如果你使用 KDE 桌面的话,安装 vim-gtk。
- 如果你只使用文本界面的话,安装 vim-nox。
- 都不是?那你是个爱自己定制的家伙,也就不需要我告诉你该安装什么了。
你可以通过下面的命令来查看已经安装的 Vim 版本:
1 | apt list --installed | grep vim |
我们先执行 sudo apt update
来确保更新环境,然后使用 sudo apt install vim-gtk3
安装 GTK3 版本的 Vim(或者其他你需要的版本)。如果你安装了图形界面的版本,不必单独再另外安装其他版本的 Vim,因为图形版本的 Vim 也是可以纯文本启动的。事实上,在 Ubuntu 上,vim
和 gvim
都是指向同一个应用程序的符号链接,且 gvim
的执行效果和 vim -g
相同。

手工编译
如果你用的 Linux 发行版较老的话,你可能会希望手工编译 Vim 来得到最新的版本。此时需要注意的是,Vim 有很多的编译配置选项,有些缺省是不打开的。对于这个课程来讲,我们会希望至少加上 Python 支持和图形界面支持。
你首先需要确保自己已经安装了所需的开发包(可以参考这个网上的回答)。然后,我们可以使用下面的命令来配置 Vim 和编译(根据需要,“auto”也可以替换成“gtk3”等其他需要的数值):
1 | ./configure --enable-pythoninterp \ |
如果上述步骤正常没有出错,Vim就被成功安装到 /usr/local 下了。你可以用 which vim
来检查系统是否会自动优先选择你的 vim:如果不是的话,你可能需要调整 PATH 里的顺序,或者设置别名来优先启动 /usr/local/bin/vim)。然后,你可以使用 vim --version
命令来输出 vim 的版本信息。我们希望能在输出里看到:
1 | Huge version with … GUI |
目前 Python 2 已经停止支持,所以你最好可以确保上面的输出中包含“+python3”(很多 Vim 的插件已经开始要求 Python 3、不再支持 Python 2 了);没有“+python”(即 Python 2)则没什么关系(有没有“dyn”关系也不大)。

macOS 下的安装
在 macOS 中一般已经内置了 vim,并提供了除图形界面外的较完整功能集。如果你希望使用图形界面,则需要自行安装 MacVim,一个跟现代 macOS 融合较好的独立 Vim 版本。安装 MacVim 有两种常用方式:
- 使用 Homebrew。我推荐你使用这种方式,这样的话,以后升级也会比较容易。
- 使用 MacVim 的独立安装包。如果你之前没有在用 Homebrew 的话,或处于不方便使用 Homebrew 的网络环境中,这种方式也可以。
由于使用 Homebrew 已经足够简单,日后升级也非常方便,个人觉得我们没必要自己去编译 MacVim。
使用 Homebrew 安装 MacVim
首先,如果你没有 Homebrew,那你需要先安装 Homebrew。安装信息可以在 Homebrew 的主页 上找到(这个网站是支持中文的)。
在安装了 Homebrew 之后,一般情况下,你需要修改你的 .bash_profile
(如果使用 Bash 的话)、.zprofile
(如果使用 Zsh 的话)或是相应的 shell 的配置文件,调整 PATH,把 /usr/local/bin
放到 /usr/bin
前面。我个人在 .bash_profile
里是这样配置的:
1 | if [[ $PATH != "$HOME/bin"* ]]; then |
这样,可以确保个人的路径优先于 /usr/local
,而 /usr/local
下的路径又优先于系统的路径。
如果你这样配置的话,那只要执行 brew install macvim
,然后在等待安装完成之后,你用 vim
启动的就是 MacVim 了。缺省用 vim
运行的仍然是纯文本界面的 Vim,但跟 Linux 一样,你可以用 vim -g
或 gvim
(还有仅用在 Mac 上的 mvim
)来启动 Vim 的图形界面。
跟 Homebrew 里的其他软件一样,你以后要升级 MacVim 的话,只需要输入命令 brew upgrade macvim
即可。是不是很简单?这就是为什么我比较推荐这种安装方式,后期升级真的更容易。
使用安装包安装 MacVim
跟大部分的 Mac 软件一样,你也可以直接使用 DMG 安装包来安装 MacVim。目前可从以下网址下载 MacVim 的安装包:下载地址
等待下载完成后,双击下载的文件,然后会打开一个访达(Finder)窗口。你只需要把 MacVim 拖拽复制到应用程序文件夹即可。
在这种安装方式下,手工键入 vim
、gvim
或 mvim
命令是无法启动 MacVim 的。你需要手工创建这些命令的符号链接(symlink)或别名(alias)才行。假设你的 MacVim 是直接安装在应用程序文件夹里的话,这些命令本身可以在 /Applications/MacVim.app/Contents/bin 文件夹里找到;使用下面的命令可以在你自己的 bin 目录下创建这些命令的符号链接:
1 | [ -d ~/bin ] || mkdir ~/bin |
QA
brew 安装报错不支持pre-release version
1 | echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.ustc.edu.cn/homebrew-bottles' >> ~/.zshrc |
Windows 下的安装
最后,我们来看在 Windows 下怎么安装。课程开头我提到了,Windows 上缺省是没有 Vim 的。我们可以从 Vim 的网站下载 Windows 下的安装包:下载地址
在 Linux 和 macOS 上,64 位应用程序已经成为主流。而与此不同的是,在 64 位Windows上,32 位应用程序仍然很常见。默认的 Vim 8 的安装包安装的仍然是一个 32 位的应用程序。不过,32 位的 Vim 也足够满足一般需求了,除非你需要编辑 2 GB 以上的大文件。
安装界面会有一个选择组件的步骤,如下图所示:

这个界面中,下面几项我们可以关注一下:
- “安装批处理文件”(Create .bat files):对于用 Vim 的开发者来说,通常命令行是刚需,所以我们一般需要勾上这项。
- “创建图标”(Create icons for Vim):根据你自己的需要进行选择,通常我会去掉展开子项里的“桌面图标”(On the Desktop),不在桌面上创建 Vim 的图标。
- “创建默认配置文件”(Create Default Config):去掉这项——我们马上会创建配置文件。
- “安装多语言支持”(Native Language Support):这项功能使得 Vim 的菜单可以显示中文的命令,但实际上还是有点鸡肋,因为 Vim 的主要功能不是靠菜单驱动的,安装程序安装的帮助文件也只有英文版。所以,这项选和不选关系不大,你可以自由选择。
然后我们点“下一步”(Next),不需要修改安装目标文件夹,完成安装即可。
完成安装后,Vim 会缺省打开一个 README 文件。在这个窗口中,我们应当键入“:e ~\_vimrc
”,回车键,然后把下面的内容粘贴进去(这些配置项的意义我们以后会讨论):
1 | set enc=utf-8 |
然后键入“ZZ
”(大写)存盘退出即可。
注意
由于历史上的文件系统限制,在 Windows 下 Vim 的配置文件名称是
_vimrc
而不是.vimrc
(虽然 Windows 命令行不支持像 Unix 一样用“~
”代表用户的主目录,在 Vim 里我们仍然可以使用“~\_vimrc
”或“~/_vimrc
”这样的写法)。这是 Unix 和 Windows 下的 Vim 配置的区别之一。其他的主要区别是以下两点:
- 点打头的 Vim 文件都成了“
_
”打头,如.viminfo
也成了_viminfo
- 点打头的 Vim 配置目录
.vim
在 Windows 下则成了vimfiles
除此之外,Vim 的配置在 Windows 下和 Unix 下(如 Linux 和 macOS)并没有根本不同。Windows 上的主要麻烦在于,由于 Vim 的生态主要在 Unix 上,某些 Vim 的插件在 Windows 上安装配置需要花费更大的力气。但就一般的文本和程序编辑而言,Vim 在 Windows 下和 Linux 下没有本质的不同。甚至 Windows 下还有一个小小的优势:Unix 下虽然 Vim 可以编译成支持 Python 2 和 Python 3,但在 Vim 里一旦执行了 Python 2 的代码,就不能再执行 Python 3 的代码了;反之亦然。Windows 下则没有这个限制。
有没有注意到我只在 Windows 的安装部分讨论了配置?这是因为 Unix 下主流的缺省编码已经是 UTF-8 了,而 Vim 只能在内码是 UTF-8 的情况下才能处理多语言的文本。而我们有自己的配置文件,是为了确保启用一些最为基本的配置选项,来保证基本行为的一致性。
Windows 上可以把 Vim 配置成跟普通的编辑器行为差不多,包括支持 Ctrl-A
全选,选择内容后输入任何内容替换选择的内容,等等。但是,这种行为跟 Vim 的标准行为是冲突的。我们要学习 Vim,还是忘了这些 Windows 特有的功能为好,去学习掌握 Vim 的跨平台标准功能。上面的配置文件也同样没有启用 Windows 下的特有行为。
Cygwin/MSYS2
Windows 有 Cygwin 和 MSYS2,可以提供类似于 Linux 的 POSIX shell。在这些环境里,Vim 都是标准组件,按这些环境的标准方式来安装 Vim 就行。如果你使用 Git Bash 的话,里面就直接包含了 MSYS2 的终端、Bash 和 Vim。
唯一需要提一句的是,这些类 POSIX 环境里面的 Vim 配置应当参照 Linux 终端来,而不是 Windows 下的标准方式(也就是说,个人配置目录和配置文件是 .vim
和 .vimrc
,而非 vimfiles
和 _vimrc
)。我以后对这种情况就不再单独描述了。
远程使用 Vim
还有一种常用的环境恐怕是使用 mintty、PuTTY、SecureCRT 之类的软件在 Windows 上远程连接到 Linux 机器上。在这种情况下,需要特别注意的,是远程终端软件的远程字符集(如 PuTTY 中的“Windows > Translation > Remote character set”)应当设置成 UTF-8。这个设定跟具体的软件及其版本有关,我就不详细说明了;请自行查看你所使用的远程终端软件的设定和相关文档。
学习 Vim
一些 Vim 的学习资料,帮助你进入 Vim 的世界。你应该仔细看一下你所使用的平台上的 Vim 安装信息(其他平台的可以略过),并且应该自己打开 Vim 教程练习一遍(除非这些基础知识你都了解了)。键盘配置相关信息属于可选,可以根据自己的兴趣和需要决定是否了解一下。
中文帮助文件
Vim 内置了完整的英文帮助文件。如果你想要中文帮助文件的话,有个好消息是,有网友同步翻译了最新的帮助文件,而且安装过程在 Vim 8 (或将来的版本)里是非常简单的。以 Unix 下为例(Windows 下类似,但路径 .vim
需要修改为 vimfiles
):
1 | cd ~/.vim |
如果你不需要以后利用 Git 来快速升级文档的话, 也可以在这个 Vim 中文文档计划的下载页面下载 tar 包,然后自行解压到 ~/.vim/pack/my/start
目录下(或 Windows 用户目录下的 vimfiles\pack\my\start
目录下)。
Windows 用户有一个简单的安装程序(当前为 vimcdoc-2.3.0-setup-unicode.exe),可以自动帮你完成中文帮助文件的安装任务。如果你的机器上没有 git
和 tar
可执行程序的话,那这个方式最简单。

Vim 教程
Vim 在安装中自带了一个教程,可供快速入手使用。如果你对 Vim 的基本操作不熟的话,建议你完整学习一下,我也就不必多费笔墨介绍一些最基础的用法了。
Vim 教程支持多语言,可使用命令 vimtutor
来启动。如果启动的教程的语言不是你希望的,你可以使用环境变量 LANG 来设定希望的语言。比如,下面的命令可以在 Unix 环境中启动一个中文的 Vim 教程:
1 | LANG=zh_CN.UTF-8 vimtutor |
Windows 下你可以在开始菜单里找到 Vim tutor。但我测试下来它有一个问题。虽然我提交的解决方法已经作为补丁(8.2.0412)合并,但目前(Vim 8.2)安装程序安装的文件多半仍然是有问题的,你会无法成功地创建一个 tutor 文件的副本供编辑使用。我建议手工创建一个这个教程的副本。可以在命令提示符下输入:
1 | vim --clean -c "e $VIMRUNTIME/tutor/tutor.zh_cn.utf-8" -c "w! TUTORCOPY" -c "q" |
这样即可在当前目录下创建一个教程的副本。然后我们可以用 gvim TUTORCOPY
来打开这个副本进行学习。
键盘重配置
最后,有些重度的 Vim 用户会重新配置键盘,把使用频度较低的大写锁定键(Caps Lock)重新映射成 Esc 或 Ctrl 键。对于这个问题,如果你需要的话,网上很容易就能找到攻略,如:
- Linux下将大写锁定键(CapsLock)键映射为Ctrl键(Ubuntu, Manjaro,CentOS)
- mac book更改caps lock键为esc键/ctrl键
- windows交换大写锁定键与ESC键(注册表修改)
- 在任何操作系统上,如何禁用或者重新分配 Caps Lock键
这当然是一件非常个人化的事情,而且有一个风险,你一旦跑到别人的机器上操作,你的“肌肉记忆”可能会让你常常按错键。鉴于你目前可能只是个 Vim 的初学者,现在不一定需要这么去做。等到你觉得按 Esc
太麻烦了,再想起这个可能性去修改键盘配置也来得及。
基本概念与基础命令
键盘图

图中的“•”表示,单个字母不是完整的命令,必须再有进一步的输入。比如,单个“g”没有意义,而“gg”表示跳转到文件开头。(对于命令后面明确跟一个动作的,如“c”,我们不使用“•”。)一个键最多有三排内容:最底下是直接按键的结果,中间是按下 Shift 的结果(变大写),上面偏右的小字是按下 Ctrl 的结果。我们还用了一些特殊符号来表示操作的位置,如果你已经了解了这些命令的功能,你也自然就明白它们的意义了。
Vim 的命令行命令
命令 | 说明 |
---|---|
:q! |
退出 Vim |
:wq |
存盘退出 |
:s |
执行替换 |
:! |
执行外部命令 |
:edit(一般缩写为 “:e) |
编辑文件 |
:w |
写文件 |
:r |
读文件 |
:help |
查看帮助 |
Ctrl-D 和 Tab |
进行命令行补全 |
Vim模式
普通模式:Vim 启动后的默认模式,用来移动光标、删除文本、覆盖输入文本、恢复操作、粘贴文本等等。
插入模式:输入 i 或 a 进入插入模式,在这个模式下敲击键盘会往文字缓冲区增加文字,相当于普通编辑器的编辑模式。
可视模式:选择文本,可以行选、块选和依次选择,选择后可以进行复制、删除、排序等操作。
命令模式: 执行内部和外部命令。通过
:
/
?
:!
可以进入命令模式, 分别对应的是:符号 说明 :
执行内部命令 /
向下搜索 ?
向上搜索 :!
执行外部命令
Vim 最特别的地方就是它的模式了。与其他大部分编辑器不同,进入 Vim 后,缺省状态下键入的字符并不会插入到所编辑的文件之中。 Vim 的模式(mode,可以简单地理解为“状态”)是它的麻烦所在,但同时也是它的威力所在。
我们需要知道,Vim 有以下四种主要模式:
正常(normal)模式(也称为普通模式),缺省的编辑模式;如果不加特殊说明,一般提到的命令都直接在正常模式下输入;在任何其他模式中,都可以通过键盘上的 Esc 键回到正常模式。用来移动光标、删除文本、覆盖输入文本、恢复操作、粘贴文本等等。
插入(insert)模式,输入文本时使用;比如在正常模式下键入 i(insert)或 a(append)即可进入插入模式。
可视(visual)模式,用于选定文本块;教程中已经提到可以用键 v(小写)来按字符选定,Vim 里也提供其他不同的选定方法,包括按行和按列块,选择后可以进行复制、删除、排序等操作。。
命令行(command-line)模式,用于执行较长、较复杂的命令;在正常模式下键入冒号(:)即可进入该模式;使用斜杠(/)和问号(?)开始搜索也算作命令行模式。命令行模式下的命令要输入回车键(Enter)才算完成。
通过
:
/
?
:!
可以进入命令模式, 分别对应的是:符号 说明 :
执行内部命令 /
向下搜索 ?
向上搜索 :!
执行外部命令
此外,Vim 也有个选择(select)模式,与普通的 Windows 编辑器行为较为接近,选择内容后再输入任何内容,将会替换选择的内容。在以可视模式和选择模式之一选定文本块之后,可以使用 Ctrl-G 切换到另一模式。这个模式主要是为了模拟 Windows 编辑器的行为,并不是 Vim 的主要用法,使用它反而会给 Vim 里的自动化带来麻烦,所以我们也就不多作介绍了。
关于 Vim 的模式,我们重点掌握正常模式就可以了,刚刚也说过,Vim 里的大部分操作会在正常模式下完成。如果你做编辑工作时有超过几秒的停顿,就应当考虑按下 Esc 键,回到正常模式。记住,正常模式就是正常情况下你应当处于的模式。
Vim 的键描述体例
清楚了 Vim 模式之后,我们来对 Vim 里的按键作一下清晰的体例描述,毕竟,Vim 里的键真的有点多。
从现在开始,会使用 Vim 里的标准键描述方式来讲解。根据 Vim 的一般习惯,我们使用尖括号来描述特殊的输入序列。下面我会提供一个列表,给出常用键的表示方式及在动图中的显示方式。这部分内容不需要记住,你用的时候作为参考就行。
键 | 说明 | 显示 |
---|---|---|
<Esc> |
表示 Esc 键; | 显示为⎋ |
<CR> |
表示回车键; | 显示为↩ |
<Space> |
表示空格键; | 显示为␣ |
<Tab> |
表示 Tab 键; | 显示为⇥ |
<BS> |
表示退格键; | 显示为⌫ |
<Del> |
表示删除键; | 显示为⌦ |
<lt> |
表示 < 键; |
显示为< |
<Up> |
表示光标上移键; | 显示为⇡ |
<Down> |
表示光标下移键; | 显示为⇣ |
<Left> |
表示光标左移键; | 显示为⇠ |
<Right> |
表示光标右移键; | 显示为⇢ |
<PageUp> |
表示 Page Up 键; | 显示为⇞ |
<PageDown> |
表示 Page Down 键; | 显示为⇟ |
<Home> |
表示 Home 键; | 显示为↖ |
<End> |
表示 End 键; | 显示为↘ |
<F1>- <F12> |
表示功能键 1 到 12; | 显示为F1 到“F12 ” |
<S-…> |
Shift 组合键; | 显示为⇧ (较少使用,因为我们需要写 ! 而不是 <S-1> ;和特殊键组合时仍然有用) |
<C-…> |
Control 组合键; | 显示为⌃ |
<M-…> |
Alt 组合键; | 显示为⌥ (对于大部分用户,它的原始键名 Meta 应该只具有历史意义) |
<D-…> |
Command 组合键; | 显示为⌘ (Mac 键盘) |
现在回到前面的模式部分,我们提到的 Esc
、Enter
、v
、V
和 Ctrl-V
,按我们现在的描述惯例,以后就会写成 <Esc>
、<CR>
、v
、V
和 <C-V>
。这也是以后在 Vim 里对键进行重映射的写法。
强调一下,对“<
”的特殊解释仅在描述输入时生效。在描述命令行和代码时,我们写“<CR>
”仍表示四个字符,而非回车键。特别是,如果我们描述的命令行首是“:
”,表示这是一个输入 :
开始的 Vim 命令行模式命令(以回车键结束);如果行首是“/”或“?”,表示这是一个输入 /
或 ?
开始的搜索命令(以回车键结束);如果行首是“$
”,表示这是一个在 shell 命令行上输入的命令(以回车键结束),“$
”(和后面的空格)不是命令的一部分,通常后续行也不是命令的一部分,除非行尾有“\
”或“^
”字符,或行首有“$
”字符。
也就是说,下面的命令是在 Vim 里输入“:set ft?<CR>
”(用来显示当前编辑文件的文件类型):
1 | :set ft? |

下面的命令则是在 shell 里输入“which vim<CR>
”(用来检查 vim
命令的位置):
1 | $ which vim |

此外,当我用“:help
”描述帮助命令时,你不仅可以在 Vim 里输入这个命令来得到帮助,也可以点击这个帮助的链接,直接在线查看相应的中文帮助页面。

这节内容不需要死记。建议使用“收藏”功能,这样,你可以在以后碰到不认识的符号标记的时候,返回来查看这一节的内容。
Vim 的选项和配置
要想更好地使用 Vim,下一个关键点就是配置了,接下来我就带你看看 Vim 配置都有哪些需要注意的点。
作为一个可以越用越顺手的应用程序,Vim 是需要配置的。我们才刚开始学习,所以目前我们的配置文件是相当简单的,但随着课程的进展和你使用 Vim 越来越多,你的 Vim 配置文件必然会越变越复杂。我们今天就先来做一些初步的讨论,看看能实际使用的一个最基本 Vim 配置文件是什么样子。
我们上节课已经讨论过,根据 Unix 下的惯例,Vim 的配置文件放在用户的主目录下,文件名通常是 .vimrc
;而它在 Windows 下名字是 _vimrc
。我们前面给出最基本的配置文件是这个样子的:
1 | set enc=utf-8 |
如果你熟悉 shell 语法,你肯定能看到不少熟悉的影子在里面。这三行完成了下列功能:
设置编辑文件的内码是 UTF-8(非所有平台缺省,但为编辑多语言文件所必需)
设置 Vim 不需要和 vi 兼容(仅为万一起见,目前大部分情况下这是缺省情况)
导入 Vim 的示例配置(这会打开一些有用的选项,如语法加亮、搜索加亮、命令历史、记住上次的文件位置,等等)
如果有问题, 就删除掉
source $VIMRUNTIME/vimrc_example.vim
对于现代 Unix 系统上的 Vim 8,实际上只需要最后一句就足够了。对于现代 Windows 系统上的 Vim 8,中间的这句 set nocompatible
也可以删除。如果你在较老的 Vim 版本上进行配置,那么把这三行全放进去会比较安全。
备份和撤销文件
上面的基本设置会产生一个有人喜欢、但也有很多人感到困惑的结果:你修改文件时会出现结尾为“~
”的文件,有文件名后面直接加“~
”的,还有前面加“.
”后面加“.un~
”的。这是因为在示例配置里,Vim 自动设置了下面两个选项:
1 | set backup |
前一个选项使得我们每次编辑会保留上一次的备份文件,后一个选项使得 Vim 在重新打开一个文件时,仍然能够撤销之前的编辑(undo),这就会产生一个保留编辑历史的“撤销文件”(undofile)了。
我的通常做法是,不产生备份文件,但保留跨会话撤销编辑的能力;因为有了撤销文件,备份其实也就没有必要了。同时,把撤销文件放在用户个人的特定目录下,既保证了安全,又免去了其他目录下出现不必要文件的麻烦。
要达到这个目的,我在 Linux/macOS 下会这么写:
1 | set nobackup |
在 Windows 下这么写:
1 | set nobackup |
无论哪种环境,你都需要创建这个目录。我们可以用下面的命令来让 Vim 在启动时自动创建这个目录:
1 | if !isdirectory(&undodir) |
如果我告诉你, &undodir
代表 undodir
这个选项的值,那么其他代码的基本作用,相信你也一定能看出来了吧?我们暂时就不做进一步分析了。如果你好奇的话,可以提前看一下下面各项的 Vim 帮助文档:
这个跨会话撤销的能力,我还真不知道其他哪个编辑器也有。更妙的是,Vim 还有撤销树的概念,可以帮助你回到任一历史状态。
鼠标支持 (not recommend)
我不知道你会不会像某些资深 Vim 用户一样,只用键盘不用鼠标。我反正是做不到的,也没有动力去那样做——毕竟,浪费计算机界一项伟大的发明并不那么有必要😂。手一直在键盘上的本位排(home row)打字当然会更快,但一个程序员看代码的时间比写代码的时间要多得多,而在非线性的跳转任务上,鼠标比键盘更加快,也更加有效。
在 Vim 的终端使用场景下,鼠标的选择有一定的歧义:你希望是使用 Vim 的可视模式选择内容,并且只能在 Vim 里使用呢,还是产生 Vim 外的操作系统的文本选择,用于跟其他应用程序的交互呢?这是一个基本的使用问题,两种情况都可能发生,都需要照顾。
如果你使用 xterm 兼容终端的话,通常的建议是:
- 在不按下修饰键时,鼠标选择产生 Vim 内部的可视选择。
- 在按下 Shift 时,鼠标选择产生操作系统的文本选择。
对于不兼容 xterm、不支持对 Shift 键做这样特殊处理的终端,我们一般会采用一种“绕过”方式,让 Vim 在某种情况下暂时不接管鼠标事件。通常的选择是在命令行模式下不使用鼠标。下面,我们就分这两种情况来配置。
虽然最新的 Vim 缺省配置文件(示例配置文件会包含缺省配置),在大部分情况下已经可以自动设置合适的鼠标选项了,不过为照顾我们课程的三种不同平台,我们还是手工设置一下:
1 | if has('mouse') |
上面代码说的是,如果 Vim 有鼠标支持的话,那在以下任一条件满足时:
- 图形界面正在运行
- 终端是 xterm 兼容,并且不是 Mac(Mac 上的终端声称自己是 xterm,但行为并不完全相同)
我们将启用完全的鼠标支持(mouse=a)。特别是,此时鼠标拖拽就会在 Vim 里使用可视模式选择内容(只能在 Vim 里使用)。而当用户按下 Shift 键时,窗口系统接管鼠标事件,用户可以使用鼠标复制 Vim 窗口里的内容供其他应用程序使用。
否则(非图形界面的的终端,且终端类型不是 xterm),就只在正常模式(n)、可视模式(v)、插入模式(i)中使用鼠标。这意味着,当用户按下 :
键进入命令行模式时,Vim 将不对鼠标进行响应,这时,用户就可以使用鼠标复制 Vim 窗口里的内容到其他应用程序里去了。
非 xterm 的鼠标支持在 macOS 和 Windows 下都有效。但在 Windows 下需要注意的一点是,如果使用非图形界面的 Vim 的话,应当在命令提示符(Command Prompt)的属性里关闭“快速编辑模式”(QuickEdit Mode),否则 Vim 在运行时将无法对鼠标事件进行响应。
鉴于命令提示符的行为有很多怪异和不一致之处,强烈建议你在 Windows 下,要么使用图形界面的 Vim,要么使用 Cygwin/MSYS2 里、运行在 mintty 下的 Vim。
中文支持
接下来我和你讲讲中文支持的问题。如果你一直在 UTF-8 下使用中文的话,那这一小节的内容可以跳过。对于大部分在 Unix 下工作的人员,应该是这样的情况。而如果你在 Windows 上工作,或者有需要跟别人交换 GB2312、GBK、GB18030 编码的文本文件,那这部分的内容还是需要看一下的。
完整的 Unicode 历史和原理可以讲上整整一讲,但从实用的角度,我们就简化成下面几条吧:
- 整个世界基本上在向 UTF-8 编码靠拢。
- 微软由于历史原因,内部使用 UTF-16;UTF-16 可以跟 UTF-8 无损转换。
- GB2312、GBK、GB18030 是一系列向后兼容的中文标准编码方式,GB2312 编码的文件是合法的 GBK 文件,GBK 编码的文件是合法的 GB18030 文件。但除了 GB18030,都不能做到跟 UTF-8 无损转换;目前非 UTF-8 的简体中文文本基本上都用 GBK/GB18030 编码(繁体中文文本则以 Big5 居多)。鉴于 GB18030 是国家标准,其他两种编码也和 GB18030 兼容,我们就重点讲如何在 Vim 中支持 GB18030 了。
举一个具体的例子,“你好😄”这个字符串,在 UTF-8 编码下是下面 10 个字节(我按字符进行了分组):
1 | e4bda0 e5a5bd f09f9884 |
如果使用 GB18030 编码(GB2312/GBK 不能支持表情字符)的话,会编码成 8 个字节:
1 | c4e3 bac3 9439fd30 |
这么看起来,GB18030 处理中文在存储效率上是优势的。但它也有缺点:
- GBK 外的 Unicode 字符一般需要四字节编码(非中文情况会劣化)
- GBK 外的 Unicode 字符跟 Unicode 码点需要查表才能转换(UTF-8 则可以用非常简单的条件判断、移位、与、或操作来转换)
- 一旦出现文件中有单字节发生损毁,后续的所有中文字符都可能发生紊乱(而 UTF-8 可以在一个字符之后恢复)
因此,GB18030 在国际化的软件中不会作为内码来使用,只会是读取/写入文件时使用的转换编码。我们要让 Vim 支持 GB18030 也同样是如此。由于 UTF-8 编码是有明显规律的,并非任意文件都能成功地当成 UTF-8 来解码,我们一般使用的解码顺序是:
- 首先,检查文件是不是有 Unicode 的 BOM(字节顺序标记)字符,有的话按照 BOM 字符来转换文件内容。
- 其次,检查文件能不能当作 UTF-8 来解码;如果可以,就当作 UTF-8 来解释。
- 否则,尝试用 GB18030 来解码;如果能成功,就当作 GB18030 来转换文件内容。
- 最后,如果上面的解码都不成功,就按 Latin1 字符集来解码;由于这是单字节的编码,转换必定成功。
事实上,Vim 缺省差不多就是按这样的顺序,但第三步使用何种编码跟系统配置有关。如果你明确需要处理中文,那在配置文件里最好明确写下下面的选项设定:
1 | set fileencodings=ucs-bom,utf-8,gb18030,latin1 |
图形界面的字体配置
图形界面的 Vim 可以自行配置使用的字体,但在大部分环境里,这只是起到美化作用,而非必需项。不过,对于高分辨率屏幕的 Windows,这是一个必需项:Vim 在 Windows 下缺省使用的不是 TrueType 字体,不进行配置的话,字体会小得没法看。
在 Windows 的缺省字体里,一般而言,Consolas 和 Courier New 还比较合适。以 Courier New 为例,在 _vimrc
里可以这样配置(Windows 上的基本写法是字体名称加冒号、“h
”加字号;用“_
”取代空格,否则空格需要用“\”转义):
1 | if has('gui_running') |
字体名称如何写是件平台相关的事(可参见帮助文档“:help gui-font
”)。如果你不确定怎么写出你需要的字体配置,或者你怎么写都写不对的话,可以先使用图形界面的菜单来选择(通常是“编辑 > 选择字体”;在 MacVim 里是“Edit > Font > Show Fonts”),然后使用命令“:set guifont?
”来查看。
注意,Vim 在设置选项时,空格需要用“\
”进行转义。比如,如果我们要在 Ubuntu 下把字体设成 10 磅的 DejaVu Sans Mono,就需要写:
1 | " Linux 和 Windows 不同,不能用 '_' 取代空格 |
此外,宽字符字体(对我们来讲,就是中文字体了)是可以单独配置的。这可能就更是一件仁者见仁、智者见智的事了。对于纯中文的操作系统,这一般反而是不需要配置的;但如果你的语言设定里,中文不是第一选择的话,就有可能在显示中文时出现操作系统误用日文字体的情况。这时你会想要手工选择一个中文字体,比如在 Ubuntu 下,可以用:
1 | set guifontwide=Noto\ Sans\ Mono\ CJK\ SC\ 11 |
注意,在不同的中英文字体搭配时,并不需要字号相同。事实上,在 Windows 和 Linux 上我通常都是使用不同字号的中英文字体的。
在上面的动图中,你可以观察到设了中文字体之后,不仅中文字变大,更美观了,“将”、“适”、“关”、“复”、“启”等字的字形也同时发生了变化。
由于字体在各平台上差异较大,字体配置我就不写到 Vim 的参考配置中去了,只把如何选择和配置的方法写出来供你参考。
移动命令
移动计数
一个移动(motion)可以接受一个数字前缀作为参数,上面我提到的你可以通过12j
向下移动12行,其中12j
中的12
就是计数数字。
1 | [计数] + 移动 |
你可以把这个应用到所有移动上,如果你想向右移动9个字符,你可以使用9l
来代替按9次l
。 当你学到了更多的动作时,你都可以试试给定计数参数。
字符导航
命令 | 说明 |
---|---|
h | 左 |
j | 下 |
k | 上 |
l | 右 |
单词导航
我们现在移动一个更长的单元:单词(word)。 你可以通过w
移动到下一个单词的开始,通过e
移动到下一个单词的结尾,通过b
移动到上一个单词的开始,通过ge
移动到前一个单词的结尾。
另外,为了和上面说的单词(word)做个区分,还有一种移动的单元:词组(WORD)。 你可以通过W
移动到下一个词组的开始,通过E
移动到下一个词组的结尾,通过B
移动到前一个词组的开头,通过gE
移动到前一个词组的结尾。 为了方便记忆,所以我们选择了词组和单词这两个词,相似但有些区分。
命令 | 说明 |
---|---|
w | 移动到下一个单词的开头 |
W | 移动到下一个词组的开头 |
e | 移动到下一个单词的结尾 |
E | 移动到下一个词组的结尾 |
b | 移动到前一个单词的开头 |
B | 移动到前一个词组的开头 |
ge | 移动到前一个单词的结尾 |
gE | 移动到前一个词组的结尾 |
词组和单词到底有什么相同和不同呢?单词和词组都按照非空字符被分割,一个单词指的是一个只包含a-zA-Z0-9
字符串,一个词组指的是一个包含除了空字符(包括空格,tab,EOL)以外的字符的字符串。 你可以通过:h word
和:h WORD
了解更多。
当前行导航
当你在进行编辑的时候,你经常需要水平地在一行中移动,你可以通过0
跳到本行第一个字符,通过$
跳到本行最后一个字符。 另外,你可以使用^
跳到本行第一个非空字符,通过g_
跳到本行最后一个非空字符。 如果你想去当前行的第n列,你可以使用n|
。
命令 | 说明 |
---|---|
0 | 跳到本行第一个字符 |
^ | 跳到本行第一个非空字符 |
g_ | 跳到本行最后一个非空字符 |
$ | 跳到本行最后一个字符 |
n| | 跳到本行第n列 |
你也可以在本行通过f
和t
进行行内搜索,f
和t
的区别在于f
会停在第一个匹配的字母上,t
会停在第一个匹配的字母前。 因此如果你想要搜索并停留在”h”上,使用fh
。 如果你想搜索第一个”h”并停留在它的前一个字母上,可以使用th
。 如果你想去下一个行内匹配的位置,使用;
,如果你想去前一个行内匹配的位置,使用,
。
F
和T
是f
和t
对应的向后搜索版本。如果想向前搜索”h”,可以使用Fh
,使用;
,保持相同的搜索方向搜索下一个匹配的字母。 注意,;
不是总是向后搜索,;
表示的是上一次搜索的方向,因此如果你使用的F
,那么使用;
时将会向前搜索使用,
时向后搜索。
命令 | 说明 |
---|---|
f | 在同一行向后搜索第一个匹配 |
F | 在同一行向前搜索第一个匹配 |
t | 在同一行向后搜索第一个匹配,并停在匹配前 |
T | 在同一行向前搜索第一个匹配,并停在匹配前 |
; | 在同一行重复最近一次搜索 |
, | 在同一行向相反方向重复最近一次搜索 |
句子和段落导航
句子
一个句子的定义是以.!?
和跟着的一个换行符或空格,tab结尾的。 你可以通过)
和(
跳到下一个和上一个句子。
命令 | 说明 |
---|---|
( | 跳到前一个句子 |
) | 跳到下一个句子 |
如果你的Vim中遇到了无法将一个以.
结尾的字段并且后面跟着一个空行的这种情况判断为一个句子的问题,你可能处于compatible
的模式。 运行:set nocompatible
可以修复。 在Vi中,一个句子是以两个空格结尾的,你应该总是保持的nocompatible
的设置。
段落
一个段落可以从一个空行之后开始,也可以从段落选项(paragraphs
)中”字符对”所指定的段落宏的每个集合开始。
命令 | 说明 |
---|---|
{ | 跳转到上一个段落 |
} | 跳转到下一个段落 |
如果你不知道什么是段落宏,不用担心,重要的是一个段落总是以一个空行开始和结尾, 在大多数时候总是对的。
匹配导航
程序员经常编辑含有代码的文件,这种文件内容会包含大量的小括号,中括号和大括号,并且可能会把你搞迷糊你当前到底在哪对括号里。 许多编程语言都用到了小括号,中括号和大括号,你可能会迷失于其中。 如果你在它们中的某一对括号中,你可以通过%
跳到其中一个括号或另一个上(如果存在)。 你也可以通过这种方法弄清你是否各个括号都成对匹配了。
命令 | 说明 |
---|---|
% | Navigate to another match, usually works for (), [], {} |
行号导航
你可以通过nG
调到行号为n
的行,例如如果你想跳到第7行,你可以使用7G
,跳到第一行使用gg
或1G
,跳到最后一行使用G
。
有时你不知道你想去的位置的具体行号,但是知道它大概在整个文件的70%左右的位置,你可以使用70%
跳过去,可以使用50%
跳到文件的中间。
命令 | 说明 |
---|---|
gg | 跳转到第一行 |
G | 跳转到最后一行 |
nG | 跳转到第n行 |
n% | 跳到文件的n% eg: 70% - 跳转到文件的70%的位置 |
如果你想看文件总行数,可以用CTRL-g
查看。
窗格导航
为了移动到当前窗格的顶部,中间,底部,你可以使用H
(high),M
(middle)和L
(low)。
你也可以给H
和L
传一个数字前缀。 如果你输入10H
你会跳转到窗格顶部往下数10行的位置,如果你输入3L
,你会跳转到距离当前窗格的底部一行向上数3行的位置。
命令 | 说明 |
---|---|
H | 跳转到屏幕的顶部 |
M | 跳转到屏幕的中间 |
L | 跳转到屏幕的底部 |
nH | 跳转到距离顶部n行的位置 |
nL | 跳转到距离底部n行的位置 |
滚动
在文件中滚动,你有三种速度可以选择: 滚动一整页(CTRL-F
/CTRL-B
),滚动半页(CTRL-D
/CTRL-U
),滚动一行CTRL-E
/CTRL-Y
)。
命令 | 说明 |
---|---|
Ctrl-e | 向下滚动一行 |
Ctrl-d | 向下滚动半屏 |
Ctrl-f | 向下滚动一屏 |
Ctrl-y | 向上滚动一行 |
Ctrl-u | 向上滚动半屏 |
Ctrl-b | 向上滚动一屏 |
你也可以相对当前行进行滚动
命令 | 说明 |
---|---|
zt | 将当前行置于屏幕顶部附近 |
zz | 将当前行置于屏幕中央 |
zb | 将当前行置于屏幕底部 |
搜索导航
通常,你已经知道这个文件中有一个字段,你可以通过搜索导航非常快速的定位你的目标。 你可以通过/
向下搜索,也可以通过?
向上搜索一个字段。 你可以通过n
重复最近一次搜索,N
向反方向重复最近一次搜索。
命令 | 说明 |
---|---|
/ | 向后搜索一个匹配 |
? | 向前搜素一个匹配 |
n | 重复上一次搜索(和上一次方向相同) |
N | 重复上一次搜索(和上一次方向相反) |
你可以通过:set hlsearch
设置搜索高亮。 这样,当你搜索/let
,它将高亮文件中所有匹配的字段。 另外,如果你通过:set incsearch
设置了增量搜索,它将在你输入时不断匹配的输入的内容。 默认情况下,匹配的字段会一直高亮到你搜索另一个字段,这有时候很烦人,如果你希望取消高亮,可以使用:nohlsearch
。 因为我经常使用这个功能,所以我会设置一个映射:
1 | nnoremap <esc><esc> :noh<return><esc> |
你可以通过*
快速的向前搜索光标下的文本,通过#
快速向后搜索光标下的文本。 如果你的光标位于一个字符串”one”上,按下*
相当于/\<one\>
。 /\<one\>
中的\<
和\>
表示整词匹配,使得一个更长的包含”one”的单词不会被匹配上,也就是说它会匹配”one”,但不会匹配”onetwo”。 如果你的光标在”one”上并且你想向后搜索完全或部分匹配的单词,例如”one”和”onetwo”,你可以用g*
替代*
。
命令 | 说明 |
---|---|
* | 向后查找光标所在的完整单词 |
# | 向前查找光标所在的完整单词 |
g* | 向后搜索光标所在的单词 |
g# | 向前搜索光标所在的单词 |
位置标记
你可以通过标记保存当前位置并在之后回到这个位置,就像文本编辑中的书签。 你可以通过mx
设置一个标记,其中x
可以是a-zA-Z
。 有两种办法能回到标记的位置: 用 `x 精确回到(行和列),或者用 'x
回到行级位置。
命令 | 说明 |
---|---|
ma | 用a标签标记一个位置 |
`a | 精确回到a标签的位置(行和列) |
‘a | 跳转到a标签的行 |
a-z
的标签和A-Z
的标签存在一个区别,小写字母是局部标签,大写字母是全局标签(也称文件标记)。
我们首先说说局部标记。 每个buffer可以有自己的一套局部标记,如果打开了两个文件,我可以在第一个文件中设置标记”a”(ma
),然后在另一个文件中设置另一个标记”a”(ma
)。
不像你可以在每个buffer中设置一套局部标签,你只能设置一套全局标签。 如果你在myFile.txt
中设置了标签mA
,下一次你在另一个文件中设置mA
时,A标签的位置会被覆盖。 全局标签有一个好处就是,即使你在不同的项目中,你也可以跳转到任何一个全局标签上,全局标签可以帮助你在文件间切换。
使用:marks
查看所有标签,你也许会注意到除了a-zA-Z
以外还有别的标签,其中有一些例如:
命令 | 说明 |
---|---|
‘’ | 在当前buffer中跳转回到上一次跳转前的最后一行 |
`` | 在当前buffer中跳转回到上一次跳转前的最后一个位置 |
`[ | 跳转到上一次修改或拷贝的文本的开头 |
`] | 跳转到上一次修改或拷贝的文本的结尾 |
`< | 跳转到最近一次可视模式下选择的部分的开头 |
`> | 跳转到最近一次可视模式下选择的部分的结尾 |
`0 | 跳转到退出Vim前编辑的最后一个文件 |
除了上面列举的,还有更多标记,你可以通过: marks
查看。
跳转
最后,我们聊聊Vim中的跳转你通过任意的移动可以在不同文件中或者同一个的文件的不同部分间跳转。 然而并不是所有的移动都被认为是一个跳转。 使用j
向下移动一行就不被看做一个跳转,即使你使用10j
向下移动10行,也不是一个跳转。 但是你通过10G
去往第10行被算作一个跳转。
命令 | 说明 |
---|---|
‘ | 跳转到标记的行 |
` | 跳转到标记的位置(行和列) |
G | 跳转到行 |
/ | 向后搜索 |
? | 向前搜索 |
n | 重复上一次搜索,相同方向 |
N | 重复上一次搜索,相反方向 |
% | 查找匹配 |
( | 跳转上一个句子 |
) | 跳转下一个句子 |
{ | 跳转上一个段落 |
} | 跳转下一个段落 |
L | 跳转到当前屏幕的最后一行 |
M | 跳转到当前屏幕的中间 |
H | 跳转到当前屏幕的第一行 |
[[ | 跳转到上一个小节 |
]] | 跳转到下一个小节 |
:s | 替换 |
:tag | 跳转到tag定义 |
我不建议你把上面这个列表记下来,一个大致的规则是,任何大于一个单词或超过当前行导航的移动都可能是一个跳转。 Vim保留了你移动前位置的记录,你可以通过:jumps
查看这个列表,如果想了解更多,可以查看:h jump-motions
。
为什么跳转有用呢? 因为你可以在跳转列表中通过Ctrl-o
和Ctrl-i
在记录之间向上或向下跳转到对应位置。 你可以在不同文件中进行跳转.
文本操作
文本修改
小写字母命令 | 大写字母命令 |
---|---|
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 撤销当前行上的所有修改 |
文本选择
选择动作的基本附加键是 a
和 i
- ‘
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
前可以加上数字,对多个(层)文本对象进行操作。
点命令
用点命令来重放上一个修改操作。点命令是最简单的命令,然而又是减少重复操作最为有用的命令。
当你使用普通模式下的命令来更新(添加,修改或者删除)当前缓冲区中的内容时,你就是在执行一个修改操作了。其中的例外是使用命令行命令进行的修改(以:
开头的命令),这些命令不算作修改操作。
vim定制
目录结构
Vim 的工作环境是由运行支持文件来设定的。如果你想要定制 Vim,就要熟知 Vim 有哪些不同类型的运行支持文件,分别存放在哪里,怎样能快捷地找到它们。
Vim 比较有意思的一点的是,虽然运行支持文件是在 Vim 的安装目录下,但用户自己是可以“克隆”这个目录结构的。也就是说,你自己目录下的用户配置,到你深度定制的时候,也有相似的目录结构。
安装目录下的运行支持文件
Vim 的运行支持文件在不同的平台上有着相似的目录结构。以 Vim 8.2 为例,它们的标准安装位置分别在:
- 大部分 Unix 下面:
/usr/share/vim/vim82
- macOS Homebrew 下:
/usr/local/opt/macvim/MacVim.app/Contents/Resources/vim/runtime
- Windows 下:
C:\Program Files (x86)\Vim\vim82
在这个目录下面,你可以看到很多子目录,如 autoload、colors、doc、pack、plugin、syntax 等等。这些子目录下面就是分类放置的 Vim 支持文件。最常用的子目录应该是下面这几个:
- syntax:Vim 的语法加亮文件
- doc:Vim 的帮助文件
- colors:Vim 的配色方案
- plugin:Vim 的“插件”,即用来增强 Vim 功能的工具
以 syntax 目录为例,当前我在下面看到有 617 个文件,也就是说,Vim 对 617 种不同的文件类型提供了语法加亮支持!这里面的文件去掉“.vim”后缀后,就是文件类型的名字,你可以用类似 :setfiletype java
这样的命令来设置文件的类型,从而进行语法加亮。
在菜单中显示文件类型这个额外的步骤,可能是因为很久很久以前,加载所有文件类型的菜单是一个耗时的操作吧。在 menu.vim 里,目前有这样的代码:
1 | " Skip setting up the individual syntax selection menus unless |
不知道这段注释是什么年代加上的……但显然,我们的电脑已经不会再在乎加载几百个菜单项所占的时间了。即使我不怎么用菜单,我也找不出不直接展示这个菜单的理由;我可不想在需要使用的时候再多点一次鼠标。
所以,我会在我的 vimrc 文件里写上:
1 | let do_syntax_sel_menu = 1 |
同理,我会加载其他一些可能会被 Vim 延迟加载的菜单,减少需要在菜单上点击的次数:
1 | let do_no_lazyload_menus = 1 |
上面两个设置在我的机器上会让我打开 Vim 的速度下降大概 20 毫秒。我想我不在乎这点时间差异……
我们用“:help
”命令查看的帮助文件就放在 doc 目录下。我们可以用菜单“编辑 > 配色方案”(“Edit > Color Scheme”)浏览配色方案,相应的文件就在 colors 目录下。
在 plugin 目录下的系统内置插件不多,我们下面就快速讲解一下:
- getscriptPlugin:获得最新的 Vim 脚本的插件(在目前广泛使用 Git 的年代,这个插件过时了,我们不讲)
- gzip:编辑 .gz 压缩文件(能在编辑后缀为 .gz 的文件时自动解压和压缩,你会感觉不到这个文件是压缩的)
- logiPat:模式匹配的逻辑运算符(允许以逻辑运算、而非标准正则表达式的方式来写模式匹配表达式)
- manpager:使用 Vim 来查看 man 帮助(强烈建议试一下,记得使用 Vim 的跳转键
C-]
和C-T
) - matchparen:对括号进行高亮匹配(现代编辑器基本都有类似的功能)
- netrwPlugin:从网络上编辑文件和浏览(远程)目录(支持多种常见协议如 ftp 和 scp,可直接打开目录来选择文件)
- rrhelper:用于支持
--remote-wait
编辑(Vim 的多服务器会用到这一功能) - spellfile:在拼写文件缺失时自动下载(Vim 一般只安装了英文的拼写文件)
- tarPlugin:编辑(压缩的)tar 文件(注意,和 gzip 情况不同,这儿不支持写入)
- tohtml:把语法加亮的结果转成 HTML(自己打开个文件,输入命令“
:TOhtml
”就知道效果了) - vimballPlugin:创建和解开 .vba 文件(这个目前也略过时了,我们不讲)
- zipPlugin:编辑 zip 文件(和 tar 文件不同,zip 文件可支持写入)
除了 rrhelper 和 spellfile 属于功能支持插件,没有自己的帮助页面,其他功能都可以使用“:help
”命令来查看帮助。查看帮助时,插件名称中的“Plugin”后缀需要去掉:查看 zip 文件编辑的帮助时,应当使用“:help zip
”而不是“:help zipPlugin
”。
用户的 Vim 配置目录
Vim 的安装目录你是不应该去修改的。首先,你可能没有权限去修改这个目录;其次,即使你有修改权限,这个目录会在 Vim 升级时被覆盖,你做的修改也会丢失。用户自己的配置应当放在自己的目录下,这也就是用户自己的主目录下的 Vim 配置目录(Unix 下的 .vim,Windows 下的 vimfiles)。这个目录应和 Vim 安装目录下的运行支持文件目录有相同的结构,但下面的子目录在你需要修改 Vim 的相关行为时才有必要创建。**如果一个同名文件出现用户自己的 Vim 配置目录里和 Vim 的安装目录里,用户的文件优先。**
换句话说,修改 Vim 行为最简单的一种方式,就是把一个系统的运行支持文件复制到自己的 Vim 配置目录下的相同位置,然后修改其内容。我自己常常用这种方式来精调 Vim 的语法加亮。
显然,这种方式的缺点(在适当的时候也是优点)是,如果 Vim 的运行支持文件后来被修改/更新了,你也会继续使用你自己目录下的老版本修改版。如果你的修改不只是你自己的临时方案、同时也适合他人的话,最佳做法还是给 Vim 项目提交补丁,让其他所有人都能用上你的修改,这样才是开源的最佳使用方式。
关于 Vim 的公用脚本,这儿再多说几句。Vim 的网站过去是用来集中获取各种脚本——如插件和配色方案——的地方,而 getscriptPlugin 可以帮助简化这个过程。今天你仍然可以使用这个方法,但 Git 和 GitHub 的广泛使用已经改变了人们获取和更新脚本的方式。现在,最主流的分发 Vim 脚本的方式是利用 GitHub,而用户则使用包管理器来调用 Git 从 GitHub(或类似的 Git 库)获取和更新脚本,下面我们很快就会讲到。
Vim 8 新功能
站在我个人的角度看,从 Vim 7.4 到 Vim 8.2,最大的新功能是:
- Vim 软件包的支持(“
:help packages
”) - 异步任务支持(“
:help channel
”、“:help job
”和“:help timers
”) - 终端支持(“
:help terminal
”)
Vim 软件包
Vim 的目录结构有点传统 Unix 式:一个功能用到的文件可能会分散在多个目录下。就像传统 Unix 上 Vim 的文件可能分散在 /usr/bin、/usr/share/man、/usr/share/vim 等目录下一样,一个 Vim 的插件(严格来讲,应该叫包)通常也会分散在多个目录下:
- 插件的主体通常在 plugin 目录下
- 插件的帮助文件在 doc 目录下
- 有些插件只对某些文件类型有效,会有文件放在 ftplugin 目录下
- 有些插件有自己的文件类型检测规则,会有文件放在 ftdetect 目录下
- 有些插件有特殊的语法加亮,会有文件放在 syntax 目录下
- ……
以前我们安装插件,一般是一次性安装后就不管了。安装过程基本上就是到 .vim 目录(Windows 上是 vimfiles 目录)下,解出压缩包的内容,然后执行 vim -c 'helptags doc|q'
生成帮助文件的索引。到了“互联网式更新”的年代,这种方式就显得落伍了。尤其糟糕的地方在于,它是按文件类型来组织目录的,而不是按相关性,这就没法用 Git 来管理了。
Vim 上后来就出现了一些包管理器,它们的基本模式都是相通的:每个包有自己的目录,然后这些目录会被加到 Vim 的运行时路径(runtimepath
)选项里。最早的 runtimepath
较为简单,在 Unix 上缺省为:
$HOME/.vim,
$VIM/vimfiles,
$VIMRUNTIME,
$VIM/vimfiles/after,
$HOME/.vim/after
而在有了包管理器之后,runtimepath
就会非常复杂,每个包都会增加一个自己的目录进去。但是,好处也是非常明显的,包的管理变得非常方便。从 Vim 8 开始,Vim 官方也采用了类似的体系。Vim 会在用户的配置目录(Unix 下是 $HOME/.vim
,Windows 下是 $HOME/vimfiles
)下识别名字叫 pack 的目录,并在这个目录的子目录的 start 和 opt 目录下寻找包的目录。
一个实际的 Vim 配置目录的结构:
1 | . |
有了这样的目录结构,用户要自己安装、管理包就方便多了。不过,我们还是推荐使用一个包管理器。包管理器可以带来下面的好处:
- 根据文本的配置(一般写在 vimrc 配置文件里)决定要安装哪些包
- 自动化安装、升级和卸载,包括帮助文件的索引生成
折叠
Folds 折叠命令
命令 | 说明 |
---|---|
zo/zO |
Open 打开折叠 |
zc/zC |
Close 关闭折叠 |
za/zA |
Toggle 在打开折叠和关闭折叠之间进行切换 |
zv |
Open folds for this line 为当前行打开折叠 |
zM |
Close all 关闭所有折叠 |
zm |
Fold more (foldlevel += 1) 更多地折叠 |
zR |
Open all 打开所有折叠 |
zr |
Fold less (foldlevel -= 1) 更少地折叠 |
注:通过命令
:h fold-commands
查看更多关于折叠命令的帮助信息。
diff
vimdiff mode 常用命令速查表(cheat sheet)
命令 | 说明 |
---|---|
[c |
Jump to the previous diff 跳到前一个不同之处 |
]c |
Jump to the next diff 调到下一个不同之处 |
do /:diffget |
Pull the changes to the current file 将所有的不同之处拉到当前文件,使之与另一个文件内容相同 |
dp /:diffput |
Push the changes to the other file 将所有的不同之处推到另一个文件 |
:diffupdate |
rescan files for differences 重新扫描文件之间的不同之处 |
vimdiff合并git冲突
设置vimdiff
局部: 在git文件夹内运行
1
2
3git config merge.tool vimdiff
git config merge.conflictstyle diff3
git config mergetool.prompt false全局
1
2
3git config --global merge.tool vimdiff
git config --global merge.conflictstyle diff3
git config --global mergetool.prompt false修改配置文件
cat ~/.gitconfig
1
2
3
4
5
6
7[core]
editor = vim
[merge]
tool = vimdiff
conflictstyle = diff3
[difftool]
prompt = false
设置不生成backup文件
1 | #让git mergetool不再生成备份文件(*.orig) |
合并冲突
启动
1
$ git mergetool
对于每个需要merge的文件,会弹出
1
+——————————–+ | LOCAL | BASE | REMOTE | +——————————–+ | MERGED | +——————————–+
LOCAL
buffer: 当前分支BASE
buffer: 两个分支共同祖先,代表两个分支修改前REMOTE
buffer: 需要合并到当前分支的分支MERGED
buffer: 合并后的,即有冲突的
vimdiff使用
鼠标移动到
MERGED
窗口,1
2
3:diffget RE # 获取REMOTE的修改到MERGED文件, 忽略大小写
:diffg ba # get from base
:diffg lo # get from local注意:通过
diffget
只能选取local, base, remote三种的一种,要想都需要3种或者两种,只能通过修改MERGED
文件修改完成后, 保存
:wqa
冲突解决完,commit
1
$git commit -m "<your_commit_instructions>"
删除orig文件
1
find . -name "*.orig" | xargs rm
vim图解
经典版
一系列的入门教程键位图的组合结果。要查看不同编辑模式下的键位图, 可以再all下得原文地址中下载.
入门版
基本操作的入门版. 原版出处还有keynote版本可供DIY以及其他相关有用的cheatsheet, 原文地址.

进阶版

增强版
更新时间较新的现代版,含有的信息也更丰富。
