Vim 8文本处理实战

Hands-on Text Processing with Vim 8.

Posted by xxxbrian on May 19, 2021

本文介绍了各种常用的文本编辑方法和程序设计中的实用操作,深入Vim内部的数据结构和VimScript脚本编程,内容详实。本文基于Vim 8平台,介绍了前沿分支Neovim,还推荐了更先进的Oni编辑器,兼容并包,集Vim社区典型使用经验和发展趋势于一体。

本文面向的读者群体是所有使用Vim的程序员,书中的示例文本为Python代码,并详细介绍了Git和正则表达式。读者需要对操作系统和程序设计有基本的了解,特别是需要了解Linux操作系统的基本使用。虽然本文尝试兼顾三大操作系统,但毫无疑问书中内容以Linux为主。本文可以帮助读者完善Vim技能,增加程序设计的知识储备。

关于作者

Ruslan Osipov 是 Google 公司的软件工程师,也是一名旅游爱好者和业余博主。他自学成才,2012 年开始发布个人的 Vim 笔记。从那时开始,Ruslan 就越来越关注这款强大的编辑器,以及那些可优化工作流程的应用。

本文的读者

本文适用于初级、中级和高级程序员。本文将介绍如何高效地将 Vim 应用于日常工作流程的方方面面。虽然书中涉及了 Python,但 Python 或 Vim 的经验并不是阅读本文所必需的

本文的内容提要

  • 第 1 章,开始 Vim 之旅。介绍了 Vim 的基本概念。
  • 第 2 章,高级编辑和文本浏览。介绍了光标移动方法和更复杂的编辑操作,另外,还介绍了几种插件。
  • 第 3 章,使用先导键——插件管理。介绍了模式、键盘映射和插件管理。
  • 第 4 章,理解文本。介绍如何基于语义地使用代码库,并在代码库中浏览文件。
  • 第 5 章,构建、测试和执行。介绍如何在编辑器内外运行代码。
  • 第 6 章,用正则表达式和宏来重构代码。深入介绍代码重构操作。
  • 第 7 章,定制自己的 Vim。讨论了如何进一步定制个人的 Vim 工作流程。
  • 第 8 章,卓尔不凡的 Vimscript。深入介绍了 Vim 提供的强大脚本语言。
  • 第 9 章,Neovim。推介了一种新的 Vim 变体。
  • 第 10 章,延伸阅读。本章为读者提供了一些建议以供参考,并推荐了一些读者可能会感兴趣的资源站点。

配套资源

本文源代码: B11044_Code.zip

第 1 章 开始 Vim 之旅

本文将向读者介绍如何更好地使用 Vim 和 Vim 插件,以及一些与 Vim 理念一脉相承的工具。

每个工具背后都有它的独特理念,Vim 也不例外。Vim 引入了一种不同的文本处理方式,这种方式是现如今大部分人并不熟悉的。

本章的内容是为使用 Vim 作铺垫,重点介绍这种理念的与众不同之处,并向读者推荐一些良好的编辑习惯,帮助读者体验一个操作更友好的 Vim,并确保读者能够在工作中找到适合自己的工具。为了让示例更加具体,本章会使用 Vim 来创建一个短小的 Python 程序。

本章会涉及如下主题。

  • 模式界面和无模式界面的对比,为什么 Vim 与众不同。
  • Vim 的安装和基本编辑功能。
  • Vim 的图形用户界面 gVim。
  • 通过配置 Vim 来编写 Python,修改配置文件.vimrc
  • 常用文件操作,包括打开、修改、保存和关闭文件。
  • 光标移动操作,包括通过箭头键移动、hjkl键、逐个单词移动、逐段落移动等。
  • 文件的简单编辑,将编辑命令与光标移动命令结合起来。
  • 持久化的撤销历史。
  • 浏览 Vim 的内置手册。

1.1  技术性要求

本章示例是一些基本的 Python 程序,读者没必要专门去下载与本章相关的任何代码,因为这些代码都可以从头开始编写。如果读者没有跟上节奏而需要更多指引,可以在异步社区中找到示例代码。

本文用 Vim 编写 Python 代码,并且假定读者对该语言比较熟悉,版本为 Python 3。

如果读者习惯 Python 2 的语法,则只需要修改print()命令,就可以将 Python 3 示例转换为 Python 2 了。比如,将所有的print('Woof!')换成print 'Woof!',代码就可以作为 Python 2 版本正常运行了。

本章还会介绍如何创建和修改 Vim 配置文件,即.vimrc文件。最终的.vimrc文件可以在异步社区中找到。

1.2  开始对话(关于模式界面)

如果读者曾经编辑过文本,很可能已经非常熟悉无模式(modeless)界面了,因为这是现代主流文本编辑器的默认选项,大多数人也是通过它来学习文本处理的。“无模式”指的是每个界面元素都只有一个功能,每个按钮都对应于屏幕上的一个字母或某种其他操作,每个按键(或组合键)总是做同样的事:此应用程序总是以单一模式来执行操作。

但这并不是文本处理的唯一方式。那么现在,欢迎来到模式界面的世界。在这里,根据上下文的不同,每个行为可能对应于不同的操作。现在常见的模式界面应用设备为智能手机,每当打开一个不同的应用或菜单时,在屏幕上单击一下就会执行不同的功能。

对于文本编辑器,情况类似。Vim 就是一款模式编辑器,即在不同的上下文,单击一个按钮会产生不同的行为结果。当 Vim 处于插入模式(用于文本输入的模式)时,单击 o 键会在屏幕上得到 o 。但当切换到不同的模式时,按 o 键的行为会发生变化,比如在光标下面添加新行。

使用 Vim 就像是与编辑器进行对话。通过命令 d3w\[ 刚好是删除(delete)3 个单词(word)的英文缩写, ] 可以删除后面 3 个词;通过命令 ci"[ 改变(change)引号里面(inside)的英文缩写]则可以改变引号里面的文本。

编辑速度快并不是 Vim 的卖点。Vim 让用户置身于文本处理的流程中,不需要因为找鼠标而打乱节奏;也不需要按 17 次方向键到达页面中的某个位置;更不需要在复制粘贴时通过鼠标操作来小心翼翼地选择文本。

当使用无模式编辑器时,工作流程总是会被打断。而对于模式编辑器,特别是 Vim,文本处理就像是与编辑器进行了一次亲密交谈,而且是用一种一致的语言与编辑器进行交流,比如删除 3 个单词(命令为 d3w )、改变引号内文本(命令为 ci" )。通过 Vim,文本编辑变成一种更从容的操作。

1.3  安装

Vim 可在各种操作系统中安装,而且在 Linux 和 macOS 中是自带的(不过,读者可能需要将其升级到更新的版本)。在接下来的章节中,请读者确认自己的操作系统,并根据指令设置好 Vim。

1.3.1  在 Linux 系统中设置 Vim

Linux 操作系统自带 Vim,但是其版本可能比较旧了,而本文使用的 Vim 8 引入了一些急需的优化。首先,读者需要进入命令行界面,然后执行如下命令。

1
2
3
4
$ git clone https://github.com/vim/vim.git
$ cd vim/src
$ make
$ sudo make install

如果读者在安装 Vim 时遇到问题,原因可能是系统中缺少一些依赖库。如果读者使用的是基于 Debian 的 Linux 发行版,下列命令可以用于安装常用的缺失依赖库。

1
2
3
$ sudo apt-get install make build-essential libncurses5-dev

  libncursesw5-dev --fix-missing

注意,这里的 $ 仅仅用来标识这是一个 Shell 命令,并不属于命令行的一部分。按照上述方法,可以成功将 Vim 更新到最新版本。当然,如果读者不在乎是否最新,仍然可以使用系统的包管理器来更新 Vim。不同的 Linux 发行版本使用不同的包管理器,如下表所示。

发 行 版 安装最新 Vim 的命令
基于 Debian(Debian、Ubuntu、Mint) $ sudo apt-get update
  $ sudo apt-get install vim-gtk
CentOS(以及 Fedora 22 之前的版本) $ sudo yum check-update
  $ sudo yum install vim-enhanced
Fedora 22+ $ sudo dnf check-update
  $ sudo dnf install vim-enhanced
Arch $ sudo pacman -Syu
  $ sudo pacman -S gvim
FreeBSD $ sudo pkg update
  $ sudo pkg install vim

在上表中可以发现,Vim 在不同的软件库中使用不同的名称。基于 Debian 的发行版中的 vim-gtk ,或 CentOS 上的 vim-enhanced 提供了更多的功能(如图形用户界面支持)。

有一点需要注意的是,包管理器软件仓库中的 Vim 版本一般会有所滞后,少则几个月,多则几年。

现在已经准备好进入 Vim 世界了!可以通过如下命令打开一个 Vim 编辑器。

1
$ vim

在现代的操作系统上,读者可以通过命令 vi 打开 Vim,但这不是绝对的。在旧版本的系统上,两者是不同的程序。Vim 是 Vi 的继承者(Vim 是 Vi improved 的缩写),只不过,现如今 Vi 仅仅是指向 Vim 的一个别名。而且,我们没有理由使用 Vi 而不使用 Vim,除非由于某种原因无法安装 Vim。

1.3.2  在 macOS 系统中设置 Vim

macOS 系统中已经安装好了 Vim,但是版本较旧。安装更新版本的 Vim 有很多种方法,这里介绍两种。第一种方法是使用 Homebrew 安装,这是 macOS 上的一种包管理器。不过,读者需要首先安装 Homebrew。第二种方法是下载 MacVim 的.dmg安装包,对于习惯了图形界面的 Mac 用户而言,这种安装体验会更熟悉一些。

因为本文使用命令行进行交互,所以推荐使用 Homebrew 安装 Vim。但是如果读者对命令行实在不感兴趣,则可以使用.dmg安装包完成 Vim 的安装。

1.使用 Homebrew

Homebrew 是 macOS 上的一种第三方包管理器,它可以使用户方便地安装或更新到最新的软件。关于如何安装 Homebrew,读者可以在 Homebrew 官网中找到相关指令。编写本文的时候,Homebrew 的安装命令已经简化为一条命令行。

1
2
$ /usr/bin/ruby -e "$(curl –fsSL
https://raw.githubusercontent.com/Homebrew/install/master/install)"

下图为该命令执行 Homebrew 安装过程所需要经历的一系列操作。执行操作后按Enter键。

如果读者没有安装 Xcode(Xcode 通常是在 macOS 上进行与开发相关的行为的必备条件),则会得到一个 Xcode 的安装提示框。这里不会直接使用 Xcode,因而按照默认设置安装好就可以了。

这个过程可能会有点长,但如果一切顺利,最终会安装好 Homebrew。Homebrew 是一个神奇的工具,它的功能不仅仅是安装 Vim!安装完成时,会看到粗体字显示的安装成功!提示。

用下面的命令安装新版本的 Vim。

1
$ brew install vim

Homebrew 会安装好所有必要的依赖项,正常情况下,读者会看到如下图所示的结果。

如果读者已经安装了 Homebrew,而且曾经安装过 Vim,则前面的命令将会产生一个错误。如果读者只是想更新到最新版本的 Vim,这时应该执行下列命令。

1
$ brew upgrade vim

现在,已经准备好使用 Vim 了,那么用下面的命令开启 Vim 之旅吧。

1
$ vim

下图所示为 Vim 的启动界面。

2.下载.dmg 安装包

首先,下载MacVim.dmg。然后双击打开MacVim.dmg,再将 Vim 图标拖曳到Applications目录中,如下图所示。

由于 Mac 的安全设置,因此当读者进入Applications目录并尝试打开MacVim应用时,系统可能会弹出下图中的错误提示。

为解决这个问题,可以打开Applications目录,找到MacVim,右键单击图标,选择Open选项,系统会弹出如下图所示的对话框。

单击Open按钮,MacVim会正常启动,而且以后都不会再弹出这样的对话框。下图所示为 Vim 的启动界面。

1.3.3  在 Windows 系统中设置 Vim

在 Windows 操作系统下有两种安装 Vim 的方式:第一种是在 Cygwin 中安装命令行版本的 Vim,并在命令行中使用 Vim;第二种是安装 Vim 的图形界面版本 gVim(它也有在cmd.exe上运行的终端版本)。建议读者尝试两种安装方式并从中选择喜欢的一种:gVim 更像 Windows 系统中的其他应用程序(也更容易安装),而 Cygwin 可能对于习惯了 UNIX Shell 命令行的人来说更亲切一些。

在 Cygwin 中感受类 UNIX 操作体验

Cygwin 是 Windows 的类 UNIX 环境,它提供了一种命令行界面,致力于将强大的 UNIX Shell 命令行以及相关的支撑工具带到 Windows 操作系统中。

(1)安装 Cygwin

在开始安装之前,需要先浏览 Cygwin 官网 ,然后下载setup-x86_64.exesetup-x86.exe,它们分别对应于 64 位和 32 位的版本。

如果不确定操作系统是 32 位还是 64 位,可以打开“控制面板->系统和安全->系统”,找到“系统类型”。比如,很多 64 位的 Windows 机器上会显示系统类型:64 位操作系统,基于 x64 的处理器

双击下载的可执行文件,会弹出如下图所示的 Cygwin 安装窗口。

在接下来的安装工程中,单击Next按钮数次,即以此选择如下默认设置。

  • 下载源(Download source):从互联网地址下载,而不是本地缓存。
  • 根目录(Root directory):C:\cygwin 64(或其他推荐的默认设置)。
  • 为哪些用户安装(Install for):所有用户。
  • 本地软件包目录(Local package directory):C:\Downloads(或其他推荐默认设置)。
  • 网络连接(Internet connection):使用系统代理设置。
  • 下载站点(Download site):http://cygwin.mirror.constant.com (或任意其他可用选项)。
在完成这些步骤之后,会看到选择软件包的界面。这里,本文将选择vimgvimvim-doc软件包。较容易的方法是在搜索框中输入vim,展开**All Editors**类别,然后单击相应的软件包旁边的图标,如下图所示。

上图显示 Vim 版本为 8.0.1567-1。编写本文时,也就是 2018 年 11 月,这是 Cygwin 中唯一可用的版本。与 8.1 版本相比,8.0 版本主要缺少了:terminal命令(见第 5 章)。

读者可能还需要安装 Net 类别中的curl,以及 Devel 类别中的git,因为在第 3 章中会用到这两个工具。另外,安装 Utils 类别中的dos2unix也大有好处,此工具可将文本中 Windows 样式的换行符转换成 Linux 样式的换行符(使用 Vim 通常会遇到这个问题)。

然后,单击两次Next按钮,正式开始这些软件包的安装过程。安装过程会持续一段时间。

有时候,安装过程中会产生一些 post-install 脚本错误,大部分情况下可以安全地忽略(除非其中包含 Vim 相关的错误—— 这时可能就需要参考 Google 的意见:搜索错误消息中的文本,然后尝试找到解决方案)。

再接着单击Next按钮数次,即默认选择如下选项。

  • 在桌面上创建图标。
  • 在开始菜单中添加图标。

现在已经成功安装了 Cygwin 和 Cygwin 中的 Vim。

如果读者还需要在 Cygwin 中安装其他软件包,则只需要再次打开安装包可执行文件,然后选择需要的软件包。

(2)使用 Cygwin

Cygwin 的应用程序可能叫作Cygwin64 TerminalCygwin Termianl,这取决于操作系统的类型。找到其图标,如下图所示。

打开它,可以看到如下图所示的命令行提示界面,Linux 用户应该相当熟悉了。

Cygwin 支持本文中用到的所有 UNIX 样式的 Shell 命令行。如果部分命令行需要修改才能用于 Cygwin,本文也会特别说明。但是目前,只需要简单地打开 Vim 使用即可,直到第 2 章都不会有任何问题。在命令行提示符中输入vim,按Enter键启动 Vim,界面如下图所示。

Cygwin 是在 Windows 环境下体验 Linux 系统 Shell 命令的一种方式,这意味着,一旦在阅读本文时选择使用 Cygwin,就需要遵循 Linux 系统中的指令和约定。同时,还需要注意 Windows 样式的换行符和 Linux 样式的换行符,因为 Windows 和 Linux 处理换行的方式不同。如果在 Vim 中遇到^M字符无法识别,则对相应的文件执行dos2unix命令就可以解决。

1.3.4  可视化的 Vim:gVim

通过对比命令行 Vim 和 gVim,本节将详细介绍 Vim 的图形化版本 gVim。

与 Windows 系统中其他程序的安装过程相比,gVim 的安装过程要更图形化一些。在浏览器中打开Vim网站,下载一个可执行的安装包。编写本文时(2018 年 11 月),这个二进制文件名为gvim81.exe,其中的81代表版本 8.1。打开这个可执行文件,会弹出如下图所示的提示框。

单击Yes按钮,然后单击I Agree按钮,直到出现Installation Options界面。大部分默认设置是满足本文需求的,如果需要在命令行中使用 Vim,可以通过启用Create .bat files for command line use选项来实现。这个选项让读者可以在 Windows 命令提示符中使用vim。本文中的一些例子需要用到命令提示符,因此启用这个选项对于接下来的阅读是有帮助的。

下图所示为Installation Options界面的截屏,注意,图中已经启用了所有选项。

单击Next按钮,设置如下选项。

  • 选择安装类型(Select the type of install):典型(Typical),(启用Create .bat files for command line use选项之后,安装类型会自动变成Custom)。
  • 不针对 Windows 行为重新映射按键(Do not remap keys for Windows behavior)
  • 右键打开菜单,左键开始可视模式(Right button has a popup menu, left button starts visual mode)
  • 安装路径(Destination Folder)C:\Program Files (x86)\Vim(或其他推荐的默认值)。

完成这些选项的设置之后,单击Install按钮,然后单击Close按钮,如下图所示。

安装结束时系统会询问是否查看 README 文件,单击No按钮即可(谁会现在就看手册呢?),如下图所示。

安装完成后,桌面上会出现一些新的图标,如下图所示。

双击此图标,Vim 就打开了!

1.3.5  安装结果的验证和故障排除

不管在哪个平台上安装 Vim,最好先确认一下 Vim 的相关功能是否都已经启用。在命令行中,执行如下命令。

1
$ vim --version

可以看到如下图所示的输出结果,它列出了一系列功能,每项功能前面都有加号(+)或减号(-)。

这里,加号(+)表示功能启用,减号(-)表示功能未启用。上图中的 Vim 支持 Python 2(+python),而不支持 Python 3(-python3)。要想解决这个问题,可以重新编译 Vim 并启用+python3,或者寻找一个支持 Python 3 的 Vim 发布版本。

Vim 可以支持的所有功能列表参见:help feature-list

在 Linux 系统中重新编译一个支持 Python 3 的 Vim 8.1,可以执行如下命令。

1
2
3
4
5
$ git clone https://github.com/vim/vim.git
$ cd vim/src
$ ./configure --with-features=huge --enable-python3interp
$ make
$ sudo make install

传入--with-features=huge编译选项,是为了启用 Vim 的大部分功能。不过,--with-features=huge并不涉及语言的绑定,因此需要显式地启用 Python 3。

一般而言,如果读者感觉自己的 Vim 不像其他 Vim 那样运行(包括本文中描述的行为),那么有可能是因为缺失了某个 Vim 功能。这和读者的计算机操作系统以及特定的功能有关,因而安装过程可能或多或少会有不同。通过在网上搜索 Install Vim <version> with + <feature> on <operating system>可能会有所帮助。

1.4  命令行 Vim 和 gVim

通过前面介绍的指令,读者应该已经安装了两种 Vim——命令行 Vim 和 gVim。Windows 系统下的 gVim 如下图所示。

gVim 实际上是为 Vim 绑定了一个图形用户界面(GUI),它具有更好的鼠标支持,还有更多上下文菜单。与终端模拟器相比,它还支持更多的配色,并具备一些现代图形用户界面应有的优质功能。在 Windows 系统中,读者可以通过打开桌面图标gVim 8.1来启动 gVim,而在 Linux 和 macOS 系统中,可通过如下命令行启动。

1
$ gvim

Windows 用户可能会更青睐于 gVim。不过,由于本文更关注于文本编辑技巧中的效率方面,因此会避免涉及 gVim 菜单,虽然它们也很直观,但会影响用户专注于自己的工作流程。本文会更关注 Vim 的非图形界面版本,但这些内容同样适用于 gVim。这两个版本的 Vim 共享配置文件,相互之间切换使用完全没有问题。

总体来说,gVim 对新手更友好一些。

1.5  通过.vimrc文件来配置 Vim

Vim 从一个名为.vimrc的文件中读取配置信息。Vim 安装好后就可以使用,但是有些选项会使程序编码更容易。

在类 UNIX 系统中,以句点.开头的文件为隐藏文件。为了看到这些文件,可以运行ls -a命令行。

在 Linux 和 macOS 系统中,.vimrc位于用户根目录中(完整路径为/home/<用户名>/.vimrc)。读者也可以打开一个命令行终端,并通过如下命令进入终端。

1
$ echo $HOME

Windows 系统不允许文件名中出现句点,因此配置文件的名称为_vimrc,其路径通常为C:\Users\<用户名>_vimrc。读者也可以通过命令提示符中的如下命令找到其所在的目录。

1
$ echo %USERPROFILE%

如果遇到了问题,可以打开 Vim,输入:echo $MYVIMRC,然后按Enter键。Vim 会显示它正在使用的.vimrc的路径。

找到操作系统存储 Vim 配置文件的目录,然后将准备好的配置文件放入其中。读者也可以从本文的官方 GitHub 仓库中找到本章涉及的.vimrc。下列代码为本章中使用的.vimrc文件的内容。

1
2
3
4
5
6
7
8
9
10
11
syntax on                 " 支持语法高亮显示
filetype plugin indent on " 启用根据文件类型自动缩进

set autoindent            " 开始新行时处理缩进
set expandtab             " 将制表符Tab展开为空格,这对于Python尤其有用
set tabstop=4             " 要计算的空格数
set shiftwidth=4          " 用于自动缩进的空格数

set backspace=2           " 在多数终端上修正退格键Backspace的行为

colorscheme murphy        " 修改配色

上面的代码中,双引号开头的内容为注释,会被 Vim 忽略。这些设置还是比较合理的,比如语法高亮和一致的缩进。它同时还解决了不同环境中退格键可能出现不同行为的问题。

当编写 Vim 配置文件时,可以先尝试相应的设置,然后再写到.vimrc文件中去。操作过程为先输入冒号,然后输入相应的命令,再按Enter键即可。比如:set autoindent(按Enter键执行)。如果想知道某种设置当前的值,可以在命令后面加上问号,比如执行:set tabstop?命令会显示出当前的tabstop的值。

此例中还修改了配色,让屏幕显示效果更好一些,但这并不是必需的。

Vim 8 自带如下主题配色。

blue、darkblue、default、delek、desert、elflord、evening、industry、koehler、morning、murhpy、pablo、peachpuff、ron、shine、slate、torte、zellner。读者可以尝试其中一种配色主题,方法是输入:colorscheme<name>,然后按Enter键;也可以在所有可用的配色主题之间循环切换,方法是输入:colorscheme,然后输入一个空格,并多次按 Tab 键。第 7 章中有更多关于 Vim 的配置和配色的介绍,届时读者可以拥有完全属于自己的 Vim。

1.6  常用操作(特别是如何退出 Vim)

下图所示为一位 Vim 用户在 Twitter 上发布的帖子:我已经使用 Vim 两年了,主要原因是我不知道怎么退出来。

现在,本文将介绍如何在不使用鼠标或菜单的情况下与 Vim 进行交互。编程本身是一种要求精力高度集中的任务,没有人会愿意一直单击菜单,让双手一直保持在键盘中心位置也有助于避免在鼠标和键盘之间频繁切换。

1.6.1  打开文件

首先,请读者打开自己最喜欢的命令行终端(Linux 和 macOS 系统中是终端,Windows 系统中为 Cygwin),跟随下面的步骤来编写一个非常基础的 Python 程序。

先从一个简单的开平方根计算器开始,运行如下命令。

1
$ vim animal_farm.py

如果读者使用 gVim,那么可以在File菜单中单击Open选项,然后打开一个文件。有时候,读者可能确实需要一个图形界面。

这会打开一个名为animal_farm.py的文件。如果此文件存在,则读者会看到它的内容;如果文件不存在,则得到一个空白界面,如下图所示。

在上图中,Vim 的底部状态中显示了文件名,旁边还有[New File]字样,表示这是一个新文件。现在读者已经用 Vim 打开了第一个文件。

Vim 的状态栏通常会包含很多有用的信息,它是 Vim 与用户交流的主要途径,因此需要保持对状态栏中的消息的关注。

如果之前已经打开过 Vim,则可以用如下命令加载一个文件(别忘了命令后面要按Enter键)。

1
:e animal_farm.py

这有可能是读者在 Vim 中运行的第一条命令。输入冒号字符:表示进入命令行模式,在此模式下输入的文字会被 Vim 解析为命令。按Enter键可以结束命令,通过 Vim 命令可以执行很多复杂的操作,包括访问系统的命令行。命令:e表示编辑(edit)。

Vim 的帮助文档中通常将Enter键记为回车(carriage return)的意思。

1.6.2  修改文字

默认情况下,Vim 处于正常模式(normal mode),即每个键都对应于某个命令。输入命令i将使 Vim 进入插入模式(insert mode)。它会在底部的状态栏中显示– INSERT –字样(如果读者使用的是 gVim,则光标由块状变为竖线状),如下图所示。

插入模式下的行为和在其他无模式编辑器中相似。正常情况下,除添加新文本之外,本文不会花太多篇幅介绍插入模式。

本文中已经涉及了 3 种 Vim 模式:命令行模式、正常模式和插入模式。本文还会介绍很多模式,详情参见第 3 章。

现在输入如下图所示的代码,这就是之前提到的 Python 程序。本章将反复使用这几行代码。

按下 Esc 键可以返回到 Vim 的正常模式。这时,状态栏上的-- INSERT --字样消失,可以继续在 Vim 中输入命令。

上述代码并不是 Python 编程的最佳实践,这里只是用它来展示 Vim 的一些功能。

1.6.3  保存和关闭文件

保存文件可执行:w命令。

注意,在输入命令后按下Enter键。

:w表示写(write)的意思。

:w命令后面也可以接一个文件名,并另存为新文件。修改后的内容会保存到这个新文件中,当前文件也变成了这个新文件。尝试执行命令:w animal_farm2.py

退出 Vim,并检查一下文件是否已经生成。命令:q表示退出(quit)的意思。也可以将写和退出这两个命令组合为:wq,表示先保存后退出。

如果修改了文件,但是不想保存而直接退出 Vim,可以用命令:q!强制退出 Vim。命令后面的感叹号表示强制执行。

Vim 的许多命令都有长短两个版本。比如:e:w:q分别是:edit:write:quit的短版本。在 Vim 手册中,命令的可选部分通常置于一对中括号中,比如:w[rite]:e[dit]

退出 Vim 之后又回到了系统的命令行,可以检查一下当前目录中的内容是否发生了变化,如下列命令所示。

1
2
3
$ ls
$ python3 animal_farm.py
$ python3 animal_farm.py cat dog sheep

在 UNIX 中,ls 表示列出当前目录的内容。python3 animal_farm.py表示用 Python 3 解释器来执行这个脚本。python3 animal_farm.py cat dog sheep表示执行此脚本,并传入(cat, dog, sheep)这 3 个参数。

下图中显示了这 3 条命令的输出结果。

1.6.4  关于交换文件

默认情况下,Vim 用交换文件跟踪文件的变化情况。当用户编辑文件的时候,Vim 会自动产生交换文件。交换文件的作用是恢复文件内容,以防止用户的 Vim、SSH 会话或系统崩溃。一旦出现上述问题,或者由于其他失误意外地退出 Vim,再次用 Vim 打开同一个文件时,就会看到如下图所示的画面。

这时,可以输入r从交换文件中恢复文件,或者输入d直接忽略交换文件。如果读者决定从交换文件中恢复,为了避免下次打开此文件时再次出现这个提示,可以输入d删除交换文件。

默认情况下,Vim 会在原始文件所在的目录下生成类似于<filename>.swp.<filename>.swp的文件。为避免这些交换文件污染文件系统,可以修改这个默认行为,使 Vim 将所有交换文件都统一存放在同一个目录中。要实现这个设置,可以在.vimrc文件中加入如下内容。

1
set directory=$HOME/.vim/swap//

如果使用 Windows 系统,设置命令为set directory= %USERDATA%.vim\swap//(注意最后两个斜线的方向)。

或者,也可以选择完全禁止交换文件,在.vimrc中加入set noswapfile即可。

1.6.5  随意移动:与编辑器对话

Vim 中的光标移动方式比大部分传统编辑器都要更便捷高效一些。本节只介绍基本的操作。

在 Vim 中可以用方向键或字母hjkl来逐个字符地移动光标,这是效率最低,但也是最精确的移动方式,如下表所示。

按键 替代键 行为
h 向左箭头键 向左移动光标
j 向下箭头键 向下移动光标
k 向上箭头键 向上移动光标
l 向右箭头键 向右移动光标

这几个字母不是随意选的,从下图中可以发现它们在方位上的对应关系。

Vi(Vim 的前身)是从 ADM-3A 终端机上创造出来的,如下图所示,这台机器并没有方向键,因而hjkl被选择用来表示方向。

习惯用hjkl来移动光标有很多好处:双手就可以集中于键盘中央,从而使用户更专注于工作流程。此外,许多应用也将hjkl用作方向键,也许数目多到让人惊讶。

现在,读者可能已经倾向于多次敲击这些方向键到达目标位置了,但是还有更好的方式。在每一个命令之前可以加一个数字,表示重复这条命令的次数。比如,敲击5j会让光标下移 5 次,而14l会让光标右移 14 个字符。这条规则适用于本文提到的大多数命令。

但是,精确计算到底要移动多少次往往是比较麻烦的(没人会愿意这么做),因此,还有一种方式是逐个词语移动光标。可以用w移动到下一个单词开头,用e移动到最近的单词的结尾。如果想反向移动到单词的开头,可以按b键。

在 Vim 中还可以使用这些命令的大写版本,表示将除空格外的所有字符视为单词的一部分!这两套命令可让读者以两种不同的方式浏览文本。

Vim 中有两种单词对象:狭义单词(word)和广义单词(WORD)。在 Vim 的世界里,狭义单词指的是由空白字符(比如空格、制表符或换行符)分隔的字母、数字和下划线组成的序列,广义单词则是由空格分隔的任何非空字符组成的序列。

比如前面的示例中的某一行代码,如下图所示。

注意光标位置,它覆盖了add_animal的首字符。

输入w,光标会停在add_animal的首字符上,而W则会跳到animal的首字符上。大写的WEB将以空格分隔的非空字符序列视为单词,如下表所示。

按键 行为
w 逐个狭义单词移动
e 向前移动直到最近狭义单词的结尾
W 逐个广义单词移动
E 向前移动直到最近广义单词的结尾
b 向后移动到狭义单词开头
B 向后移动到广义单词开头

下表则为每个命令的具体表现。

按键 初始光标位置 光标最终位置
w
e
b
W
E
B

将这些命令与之前的方向命令结合起来,可以用更少的输入实现更快的移动。

另外,按照段落移动也是很有用的。任意两个空行之间的文字被视为段落,这也意味着每个代码块可视为一个段落,如下图中所示。

函数add_animalmain为两个不同的段落。在段落间向前移动的命令是结束大括号},向后移动的命令是开始大括号{,如下表所示。

命令 行为
{ 向后移动一个段落
} 向前移动一个段落

在这些命令前面也可以加数字,这样,即使需要跳过多个段落,也可以一步到位。

移动光标还有其他方式,上述只是一些重要的基础知识。第 2 章中会介绍更复杂的浏览方式。

1.6.6  插入模式下的简单编辑

使用 Vim 的时候,通常希望在插入模式下花费尽可能少的时间(除非只负责写而不编辑)。因为大部分文本操作涉及编辑,所以本节将关注于这一部分。

前面已经提到过,进入插入模式的命令为i。除此之外,还有其他方式可以进入插入模式。很多时候,需要对一部分文字进行替换,实现这个功能的方式是修改命令c。通过修改命令读者可以在删除一部分文字后立刻进入插入模式。修改命令是一个复合命令,即它后面必须指定其他命令,用于告诉 Vim 修改哪一部分。读者可以将修改命令与前面介绍过的任何移动命令组合起来使用,可参考下表中的示例。

命令 执行前 执行后
cw
c3e(逗号视为一个词)
cb
c4l
cW

其中有一个奇怪的例外,cwce的行为类似,这是 Vim 的前身 Vi 的历史遗留问题。

在掌握了更复杂的移动命令之后,也可以将它们与修改命令组合起来,实现快速的无缝编辑。本文后续还会介绍一些 Vim 插件,它们会重新实现修改命令,从而支持更强大的编辑功能,比如修改括号里的文字或直接替换引号类型。

所有这些例子都遵循<命令> <数字> <移动或一个文本对象>这样的语法结构,可以将数字放在命令之前或之后。

若想将farm = add_animal(farm, animal)修改为farm = add_animal (farm, creature),可以依次执行下表中列出的命令。

代码行 行为
![(/img/in-post/2021-05-12-vim/d7cc0c65d023b315.png) 将光标置于行首
3W让光标跳过广义单词到达animal的首字母
cw删除单词animal,然后立刻进入插入模式
输入creature
按 Esc 键回到正常模式

不过,有时候用户可能只想删除文字,而不想插入任何东西,命令d可以实现这个功能。它表示删除(delete)的意思,其行为类似于c,只不过这时候的we的行为会标准得多,如下表所示。

命令 执行之前 执行之后
dw
d3e(逗号算一个单词)
db
d4l
dW

还有两个更好的快捷命令用于修改或删除一整行,如下表所示。

命令 行为
cc 清除整行,然后进入插入模式。保持当前的缩进水平,这在编程时很有用
dd 删除整行

比如,对于下1图中的代码片断,通过dd命令,可以移除整行,并得到下2图中的结果。

但如果使用cc命令删除该行,则会保留原来的缩进并进入插入模式,如下图所示。

如果读者在选择正确的光标移动命令时存在困难,也可以用可视(visual)模式来选择待修改的文本。按v键可进入可视模式,然后通过常用的光标移动命令调整选择的文本。一旦选择完毕,就可以运行相应的命令(如用c键来修改或用d键来删除)。

1.6.7  持久性的撤销和重复

和任何其他编辑器一样,Vim 也记录了每一步操作。按u键可以撤销最后一次操作,而Ctrl + r组合键则可以重做此操作。

欲了解关于 Vim 撤销树的更多内容(Vim 的撤销历史记录不是线性的!),以及如何浏览这些历史记录,请参考第 4 章。

Vim 还支持在不同会话之间持久保存撤销历史,从而允许撤销几天前的操作。

可以通过在.vimrc中进行如下设置来启用持久性撤销。

1
set undofile

不过,这会在系统中为每个被编辑过的文件保留一个撤销历史记录文件,显得有些混乱。也可以将这些文件保存在同一个目录中,配置如下所示。

1
2
3
4
5
6
" 为所有文件设置持久性撤销
set undofile
if !isdirectory("$HOME/.vim/undodir")
  call mkdir("$HOME/.vim/undodir", "p")
endif
set undodir="$HOME/.vim/undodir"

对于 Windows 操作系统,将上述设置中的目录换成%USERPROFILE%_vim。需要注意,Windows 下的配置文件是_vimrc,而不是.vimrc

1.6.8  通过:help阅读 Vim 手册

Vim 提供了一个学习工具:help命令,其界面如下图所示。

Vim 手册中附带了大量的资源和教程。通过翻页键(PageUp 和 PageDown)可以浏览手册的内容(注意,Ctrl + b组合键和Ctrl + f组合键也能起到翻页的效果),信息极其丰富。

如果读者使用 Vim 时遇到问题,或者希望深入了解某个命令,可尝试使用:help(其缩略版为:h)来搜索这个命令。比如,读者可以搜索一下cc

1
:h cc

下图中的帮助信息显示了这条命令的运行方式,以及不同选项和设置是如何影响它的(如 autoindent 设置可保持缩进)。

:help命令可用于浏览所有这些帮助文件。在阅读帮助文件时会发现,某些词是高亮显示的。它们是标签,即可用于:help命令的关键字。不过,不是每个标签名都很直观。如果想知道如何在 Vim 中搜索一个字符串,用户可能会尝试使用如下命令。

1
:h search

然而,输入这条命令后进入了表达式评估(expression evaluation)的页面,这并不是读者想要的,如下图所示。

为找到正确的词条,输入:h search(先不要按Enter键),然后按Ctrl + D组合键。这时会得到一个包含字符search的标签列表。其中一项为search-commands,这正是读者需要的。接下来继续补充命令行。

1
:h search-commands

得到如下图所示的帮助页面,这正是预期的结果。

关于搜索功能,读者可以在帮助页面(或在 Vim 中打开的任何文件)中输入“/关键字”进行正向搜索,或输入“?关键字”进行反向搜索。欲了解更多关于搜索操作的内容,请参考第 2 章。

任何时候都不要忘记使用 Vim 的帮助系统,特别是有疑问或希望更好地理解 Vim 的行为时。

1.7  小结

原来的 Vi 版本是针对远程终端开发出来的,那时的带宽和网速都有限。但正是这些限制使 Vi 的文本编辑流程变得高效而专业,从而演变为如今的 Vim(改进版 Vi,Vi Improved)的核心。

本章介绍了如何在主流平台上安装和更新 Vim,以及它的图形界面版本 gVim(介绍了太多方法,有些可能根本就不需要)。

然后介绍了如何通过修改.vimrc文件来配置 Vim,这个过程在今后可能会反复进行,因为读者需要根据自己的需求定制这个编辑器。

另外,还介绍了处理文件、在 Vim 中移动光标和修改内容等基本操作。Vim 中的文本对象的概念(字母、单词和段落)和复合命令(如d2w会删除两个单词)可以帮助读者做出精确的文本操作。

如果读者能从本章中学会一件事,那一定是:help。Vim 内置的帮助系统极其详细,它几乎可以回答所有关于 Vim 的问题。