通过阅读本章,读者将能更加得心应手地在日常任务中使用Vim。本章使用一个Python工程作为示例,模拟了一系列日常编码的场景。当然,读者完全可以拿自己手头的项目练手;只不过,本章中的使用场景不一定都适用于读者自己的代码。
本章包括如下主题。
grep
和ack
实现跨文件的搜索。本章将介绍如何用Vim在一个Python工程上作业。读者可以在异步社区中找到本章用到的代码。
本章会介绍几个Vim插件,但暂时不会涉及较为复杂的插件管理,相关的内容参见第3章。
首先,读者必须要做好准备工作。
1.创建一个存储插件的目录,执行下列命令。
$ mkdir -p ~/.vim/pack/plugins/start
如果在Windows系统中使用gVim,则需要在用户目录(通常是
C:\Users\
<用户名>
)下创建vimfiles
目录,然后在其中创建子目录pack\ plugins\ start
。
2.使Vim能够自动加载每个插件的文档(Vim默认不会这么做)。在~/.vimrc
文件(在Windows系统中为用户目录下的_vimrc
文件)中添加下列代码。
packloadall " 加载所有插件
silent! helptags ALL " 为所有插件加载帮助文档
然后,每次安装插件都可按照下列步骤进行。
1.在 GitHub 上找到想要安装的插件。比如,读者想安装scrooloose/ nerdtree
(注意,这里的scrooloose/nerdtree
为该GitHub仓库的唯一标识,实际地址为https://github.com/scrooloose/nerdtree.git
)。假设读者已经安装了Git,则可以找到此Git仓库的克隆地址,然后运行如下命令。
$ git clone https://github.com/scrooloose/nerdtree.git
~/.vim/pack/plugins/start/nerdtree
如果读者没有安装Git,或者在Windows系统中使用gVim,则可以在GitHub页面上找到克隆或下载(Clone or download)按钮,下载ZIP压缩包,然后将其解压到相应的插件目录中,比如在Linux系统中为目录
~/.vim/pack/ plugins/start/nerdtree
,而在Windows系统中为用户目录下的子目录vimfiles/pack/plugins/start/nerdtree
。
2.重启Vim之后,即可使用插件进行相关操作。
到目前为止,本书还只是用Vim处理单个文件。但是在编写程序时,经常需要同时处理多个文件,涉及来回切换、跨文件编辑或到其他界面查询资料等操作。幸运的是,Vim提供了一个能够处理多个文件的插件。
图1中展示了上述要点,解释如下。
图1
farm.py
、animal/cat.py
和animal_farm.py
)。3 farm.py
和a/dog.py
)。+--
开头的行表示折叠,它隐藏了文件的部分内容。本节将详细介绍窗口、标签页和折叠,通过这些功能,读者可以在工作中同时处理任意多个文件。
缓冲区是文件的内部表示,每个打开的文件都有一个缓冲区。比如,通过命令行vim animal_farm.py
打开一个文件,然后可以用:ls
命令看到现有的缓冲区列表。
很多命令都有别名或等价命令,
:ls
也不例外,它和:buffers
及:files
实现的是同样的功能,读者可以从中选择一个最容易记的命令。
图2所示为ls
命令的执行结果(最下面的那3行)。
图2
图2中的状态栏显示了已经打开的缓冲区(这里只有一个)的相关信息,这些信息的含义如下。
1
为缓冲区编号,在整个Vim会话中,它的值保持不变。%
表示该缓冲区位于当前窗口中。a
表示该缓冲区处于活动状态,即它已被加载并可见。animal_farm.py
"为文件名。line 30
表示当前光标位置。现在,用下列命令打开另一个文件。
:e animals/cat.py
然后,可以看到之前打开的文件已经被当前文件所取代。不过,animal_farm.py
仍然存储在某个缓冲区中,读者可以再次用:ls
命令将其显示出来。
现在,可以看到两个文件名都被列出来了,如图3所示。
图3
那么怎样才能跳转到之前的文件呢?
Vim通过数字和名称来标识每个缓冲区,在同一个Vim会话中,它们都是唯一的(除非退出Vim)。为了在不同的缓冲区之间切换,可使用:b
命令,其参数为缓冲区的编号数字。
:b 1
:b 1
命令中的空格可以省略,得到简化版的命令:b1
。
通过一条很简单的命令就可以回到原来的文件。由于缓冲区还可以用文件名来标识,因此读者可以用文件名的一部分来切换缓冲区。下列命令将打开animals/cat.py
的缓冲区。
:b cat
不过,如果名称匹配了多个缓冲区,则Vim会报错。比如,用下面的命令查找所有文件名包含py
的缓冲区。
:b py
Vim的状态栏中会显示错误,如图4所示。
图4
为解决这个问题,可以使用Tab键补全文件名,从而实现在不同缓冲区之间循环切换。输入:b py
(先不要按Enter
键),然后按Tab键,在所有匹配的结果之间循环遍历。
读者也可以使用:bn
(:bnext
)和:bp
(:bprevious
)命令循环遍历缓冲区。
当不再需要某缓冲区的时候(如不再需要编辑该文件),可以将其删除。通过如下命令可以将一个缓冲区从打开的缓冲区列表中删除,而无须退出Vim。
:bd
但如果没有保存当前缓冲区,则Vim会报错。因此,在不小心删除缓冲区之前,读者还有一次保存文件的机会。
Tim Pope的vim-unimpaired是一个Vim插件,它为很多内置命令(以及一些新的命令)添加映射。本书作者每天都会使用这个插件,因为它提供了更为直观的映射,比如]b
和[b
用于循环遍历缓冲区,]f
和[f
用于遍历目录中的文件。该插件可以在GitHub仓库tpope/vim-unimpaired
中找到(安装方法参见本章2.2节)。
下面是vim-unimpaired提供的部分映射。
]b
和[b
循环遍历缓冲区。]f
和[f
循环遍历同一目录中的文件,并打开为当前缓冲区。]l
和[l
遍历位置列表(参见第5章)。]q
和[q
遍历快速修复列表(参见第5章)。]t
和[t
遍历标签列表(参见第4章)。此插件还支持用少数几次按键来切换某些选项,比如yos
切换拼写检查,或yoc
切换光标行高亮显示。更多功能参见:help unimpaired
中vim-unimpaired所提供的完整映射和功能清单。
Vim将缓冲区加载到窗口中。一个屏幕上可以同时显示多个窗口,它们将屏幕分割成几块。
1.窗口的创建、删除和跳转
本节将介绍Vim窗口的使用方式。首先,打开animal_farm.py
文件(在命令行中执行$ vim animal_farm.py
或从Vim中执行:e animal_farm.py
)。
然后,使用如下命令将窗口分割成两个,其中一个显示新的文件。
:split animals/cat.py
:split
命令可以简化为:sp
。
可以看到animals/cat.py
被打开,显示在原文件上方的窗口中,而且光标也出现在里面,如图5所示。
图5
也可以使用下面的命令按水平方向分割窗口。
:vsplit farm.py
如图6所示,当前窗口又水平分隔出一个新的窗口(光标也随之移动到左边的新窗口中)。
图6
:vs
是:vsplit
的简化版。
通过组合:split
和:vsplit
,可以生成任意多个窗口。
目前本书提到的所有命令都适用于窗口,包括切换缓冲区。为了使光标能在不同窗口间移动,先按Ctrl + w
组合键,然后输入一个方向键:h、j、k、l
中的一个或键盘方向键。
按Ctrl + h
组合键,之后再按Ctrl + j
组合键(Ctrl
键可以不松开,记为Ctrl + w,j
组合键),光标会进入下面的窗口,而使用Ctrl + w,k
组合键则进入上面的窗口。
如果经常使用窗口,读者可以按照如下配置绑定快捷键。
" 使用
+ hjkl快速在窗口间跳转 noremap noremap noremap noremap
然后,就可以用Ctrl + h
组合键跳到左边的窗口,用Ctrl + j
组合键跳到底部的窗口,依此类推。
读者可以用下列方式来关闭窗口。
Ctrl + w,q
组合键关闭当前窗口。:q
命令关闭窗口并卸载缓冲区;不过,当只有一个窗口打开的时候,这会导致退出Vim。:bd
命令删除当前缓冲区,并关闭当前窗口。Ctrl + w,o
组合键(或:only
,或:on
命令)关闭除当前窗口之外的所有窗口。当打开了多个窗口时,可通过
:qa
命令关闭所有窗口并退出。也可以结合:w
命令,即:wqa
,它会先保存所有打开的文件,再退出Vim。
如果只想关闭缓冲区,而保留它所在的窗口,则可以在.vimrc
文件中加入如下配置。
" 关闭缓冲区而不关闭窗口
command! Bd :bp | :sp | :bn | :bd
然后,读者就可以使用:Bd
来关闭缓冲区,而保留分割窗口。
2.窗口的移动
窗口也可以移动、交换或改变大小。因为Vim中没有鼠标拖曳的功能,所以只能记住一些命令了。
读者并不需要记住所有这些命令,只要知道Vim支持哪些窗口操作,剩下的操作可以通过查看文档。使用
:help window-moving
和:help window- resize
打开Vim手册中相应的条目,即可找到所有相关的快捷键。
窗口命令的快捷键都要先按Ctrl + w
组合键,后面跟一个大写的方向键(H、J、K
和L
中的一个),当前窗口会被移动到相应的位置。
Ctrl + w,H
组合键将当前窗口移动到屏幕的最左边。Ctrl + w,J
组合键将当前窗口移动到屏幕的底部。Ctrl + w,K
组合键将当前窗口移动到屏幕的顶部。Ctrl + w,L
组合键将当前窗口移动到屏幕的最右边。比如图 7 所示的窗口布局(先打开animal_farm.py
,然后再依次运行:sp animals/cat.py
和:vs farm.py
,可得到这个布局)。
图7
注意,图7中光标位于animals/cat.py
文件所在的窗口中。通过前面介绍的几个快捷键,可以让这个窗口朝不同的方向移动。
Ctrl + w,H
组合键将animals/cat.py
移动到最左边,如图8(a)所示。Ctrl + w,J
组合键将animals/cat.py
移动到底部,而且左右分割变成了上下分割,如图8(b)所示。Ctrl + w,K
组合键将animals/cat.py
移动到顶部,如图8(c)所示。Ctrl + w,L
组合键将animals/cat.py
移动到最右边,如图8(d)所示。
(a)
(b)
(c)
(d)
图8
若想修改一个窗口的内容,则只需要跳转到这个窗口,然后用:b
命令来选择所需的缓冲区。不过,也有一些快捷键可以用于交换两个窗口的内容。
Ctrl + w,r
组合键将当前行或当前列(行优先于列)中的每个窗口的内容向右或向下移动。使用Ctrl + w,R
组合键则以相反的方向执行类似的操作。Ctrl + w,x
组合键将当前窗口与下一个窗口的内容交换(如果当前窗口是最后一个,则与前一个交换)。 Vim内部用数字来标识窗口。不过,与缓冲区不同,窗口的编号是随着布局变化而改变的,而且并没有直接的方法来修改窗口编号。有些窗口管理命令以窗口编号为参数,但本书不会涉及这部分内容。有一条原则仅供参考,窗口编号顺序为由上至下、由左至右递增。
3.改变窗口的大小
Vim窗口默认的宽高比为50/50,这可能并不满足读者的需求,因此窗口的大小可以通过一些方法来改变。
快捷键Ctrl + w,=
(按Ctrl+w
后再按=
键)能够将所有打开窗口的宽和高调整为一致。如果不恰当地调整了窗口大小,这个命令将非常有用。
:resize
命令会增加或减少当前窗口的高度,而:vertical resize
将调整窗口的宽度。读者还可以使用如下命令。
:resize +N
用于将当前窗口的高度增加N
行。:resize -N
用于将当前窗口的高度减少N
行。:vertical resize +N
用于将当前窗口的宽度增加N
列。:vertical resize -N
用于将当前窗口的宽度减少N
列。
:resize
和:vertical resize
可分别简写为:res
和:vert res
。另外,还有将窗口高度和宽度改变一行/列的快捷键:Ctrl + w,-
和Ctrl + w,+
用于调整高度,而Ctrl+w,>
和Ctrl + w,<
用于调整宽度。
两种命令都可以将宽度/高度设置为具体的行数/列数。
:resize N
用于将窗口高度设置为N
。:vertical resize N
用于将窗口宽度设置为N
。在很多现代编辑器中,标签页(Tabs)用于表示不同的文件。在Vim中自然也是如此,但读者需要考虑其原始目的。
Vim用标签页来组织一个窗口的集合,进而支持在不同的窗口集合之间切换,这让用户方便地拥有了多个工作区。标签页通常用来在同一个Vim会话中区分不同的问题或者文件集合。标签页功能不一定是一个频繁使用的功能,但如果希望在不同项目或同一项目的不同上下文之间切换,那么标签页将是一个不错的选择。
用户愿意使用标签页的另一个原因可能与Vim的diff功能有关,因为diff作用于一个标签页内。更多详情请参考第5章中关于vimdiff的介绍。
在一个新标签页中打开一个空缓冲区的命令如下。
:tabnew
在新标签页中打开一个已有文件的命令为
:tabnew <文件名>
。
本文截选自《Vim 8文本处理实战》
作为全面介绍Vim使用方法的教程,本书介绍了各种常用的文本编辑方法和程序设计中的实用操作,深入Vim内部的数据结构和VimScript脚本编程,内容详实。本书基于Vim 8平台,介绍了前沿分支Neovim,还推荐了更先进的Oni编辑器,兼容并包,集Vim社区典型使用经验和发展趋势于一体。
本书面向的读者群体是所有使用Vim的程序员,书中的示例文本为Python代码,并详细介绍了Git和正则表达式。读者需要对操作系统和程序设计有基本的了解,特别是需要了解Linux操作系统的基本使用。虽然本书尝试兼顾三大操作系统,但毫无疑问书中内容以Linux为主。本书可以帮助读者完善Vim技能,增加程序设计的知识储备。