目录
5.1.2 Git 与 Vim 的整合(vim-fugitive)
5.3 其他终端工具(Tmux、Screen 和 Vim 的终端模式)
第一章 开始Vim 之旅
1.1 模式界面与无模式界面对比
“无模式”指的是每个界面的元素都只有一个功能,每个按钮都对应于屏幕上的一个字母或某种其他操作,每个按键(或组合键)总是做同样的事:此应用程序总是以单一模式来执行操作。如:Windows下的文本文档、word等
”模式“ 根据上下文的不同,每个行为可能对应不同的操作。Vim就是一款模式编辑器,即在不同的上下文,单击一个按钮会产生不同的行为结果。
编辑速度快并不是Vim的卖点。Vim让用户置身于文本处理的流程中,不需要因为找鼠标而打乱节奏;也不需要按17次放方向键到达页面中的某个位置;更不需要在复制粘贴时通过鼠标操作来小心翼翼地选择文本。
当使用无模式编辑器时,工作流程总是会被打断。而对于模式编辑器,特别是Vim,文本处理就像是与编辑器进行了一次亲密交谈,而且是用一种一致的语言与编辑器进行交流,比如删除3个单词(命令为d3w)、改变引号内文本(命令为ci“)。通过Vim,文本编辑变成一种更从容的操作。
1.2 通过.vimrc文件来配置Vim
Vim会从一个名为.vimrc的文件中读取配置信息。Vim安装好了后就可以使用,但是通过对.vimrc的配置会让Vim更好使用。
.vimrc一般位于home目录中用户目录下,如果没有可自行创建。
配置示例:
syntax on "支持语法高亮显示
filetype plugin indent on "启动根据文件类型自动缩进
set autoindent "开始新行时处理缩进
set expandtab "将制表符Tab展开为空格,这对于Python尤其有用
set tabstop=4 "要计算的空格数
set backspace "在多数终端上修正退格键Backspace的行为"
colorscheme murphy "修改配色
Vim 配置 Tip:
当编写Vim配置文件时,可以先在Vim编辑界面中尝试相应的设置,然后再写到.vimrc文件中去。
操作过程为先输入冒号,然后执行相应的命令,再按Enter键即可。比如:set autoindent(按 Enter 键执行)。如果想知道某种设置 当前的值,可以在命令后面加上问号,比如执行:set tabstop?命令会 显示出当前的 tabstop 的值。
Vim 自带如下主题配色
blue、darkblue、default、delek、desert、elflord、evening、 industry、koehler、morning、murhpy、pablo、peachpuff、ron、 shine、slate、torte、zellner。读者可以尝试其中一种配色主题, 方法是输入:colorscheme,然后按 Enter 键;也可以在所有可 用的配色主题之间循环切换,方法是输入:colorscheme,然后输入一个 空格,并多次按 Tab 键。第 7 章中有更多关于 Vim 的配置和配色的介绍, 届时读者可以拥有完全属于自己的 Vim
1.3 Vim 交换文件
默认情况下,Vim用交换文件跟踪文件的变化情况。当用户编辑文件的时候,Vim会自动产生交换文件。交换文件的作用时恢复文件内容,以防用户的VIM、SSH会话或系统崩溃。一旦出现上述问题,或者由于其他失误意外地退出Vim,再次用Vim打开同一个文件时,就会出现恢复界面。
这时可以输入r从交换文件中恢复文件,或者输入d直接忽略交换文件。
默认情况下,Vim会在原始文件所在目录下生成类似于filename.swp
或.filename.swp 的文件。为避免这些交换文件污染文件系统,可以修改这个默认 行为,使 Vim 将所有交换文件都统一存放在同一个目录中。要实现这个设置,可以 在.vimrc 文件中加入如下内容。
set directory=$HOME/.vim/swap//
或者,也可以选择完全禁止交换文件,在.vimrc 中加入 set noswapfile 即可。
-
Vim 中有两种单词对象:狭义单词(word)和广义单词(WORD)。在 Vim的世界里,狭义单词指的是由空白字符(比如空格、制表符或换行符)分隔的字母、数字和下划线组成的序列,广义单词则是由空格分隔的任何非 空字符组成的序列。
1.4 通过:help阅读Vim手册
Vim 提供了一个学习工具:help 命令。
Vim 手册中附带了大量的资源和教程。通过翻页键(PageUp 和 PageDown)可以浏 览手册的内容(注意,Ctrl + b 组合键和 Ctrl + f 组合键也能起到翻页的效果), 信息极其丰富。 如果读者使用 Vim 时遇到问题,或者希望深入了解某个命令,可尝试使用:help(其 缩略版为:h)来搜索这个命令。比如,读者可以搜索一下 cc。
h cc
:help 命令可用于浏览所有这些帮助文件。在阅读帮助文件时会发现,某些词是高 亮显示的。它们是标签,即可用于:help 命令的关键字。不过,不是每个标签名都很直 观。如果想知道如何在 Vim 中搜索一个字符串,用户可能会尝试使用如下命令。
:h search
然而,输入这条命令后进入了表达式评估(expression evaluation)的页面,这并不 是读者想要的
为找到正确的词条,输入:h search(先不要按 Enter 键),然后按 Ctrl + D 组合键。这时会得到一个包含字符search 的标签列表。其中一项为search-commands,这正是读者需要的。接下来继续补充命令行。
:h search-commands
本章小结
原来的 Vi 版本是针对远程终端开发出来的,那时的带宽和网速都有限。但正是这些 限制使 Vi 的文本编辑流程变得高效而专业,从而演变为如今的 Vim(改进版 Vi,Vi Improved)的核心。
本章介绍了如何在主流平台上安装和更新 Vim,以及它的图形界面版本 gVim(介绍 了太多方法,有些可能根本就不需要)。
然后介绍了如何通过修改.vimrc 文件来配置 Vim,这个过程在今后可能会反复进 行,因为读者需要根据自己的需求定制这个编辑器。
另外,还介绍了处理文件、在 Vim 中移动光标和修改内容等基本操作。Vim 中的文 本对象的概念(字母、单词和段落)和复合命令(如 d2w 会删除两个单词)可以帮助读 者做出精确的文本操作。
如果读者能从本章中学会一件事,那一定是:help。Vim 内置的帮助系统极其详细, 它几乎可以回答所有关于 Vim 的问题。
第二章 高级编辑和文本浏览
主要内容:
-
一种粗暴但快捷地Vim插件安装方式
-
介绍如何使用缓冲区、窗口、标签页和折叠来处理多个文件或长文件,从而使工作区更为整洁
-
介绍插件Netrw、NERDTree、Vinegar 和 CtrlP,通过这些插件,读者可以在不退 出 Vim 的情况下浏览复杂的文件树。
-
介绍文件中的高级文本浏览方式、极其高效的光标移动插件EasyMotion 以及多 种文本对象,介绍通过 grep 和 ack 实现跨文件的搜索
-
介绍如何利用寄存器来复制和粘贴
2.1 安装插件
-
创建一个存储插件的目录,执行下列命令
mkdir -p ~/.vim/pack/plugins/start
-
使Vim能够自动加载每个插件的文档(Vim默认不会这么做)。在~/.vimrc文件中添加下列代码
packloadall " 加载所有插件 silent! helptags ALL " 为所有插件加载帮助文档
然后,每次安装插件都可按照下列步骤进行。
-
在GitHub上找到想要安装的插件。比如,读者想安装scrooloose/ nerdtree (注意,这里的 scrooloose/nerdtree 为该 GitHub 仓库的唯一标识,实际地址为 GitHub - preservim/nerdtree: A tree explorer plugin for vim.)。假设读者已经安装了 Git, 则可以找到此 Git 仓库的克隆地址,然后运行如下命令。
$ git clone https://github.com/scrooloose/nerdtree.git ~/.vim/pack/plugins/start/nerdtree
-
重启Vim之后,即可使用插件进行相关操作
2.2 组织工作区
到目前为止,还只是用Vim处理单个文件。但是在编写程序时,经常需要同时处理多个文件,涉及到来回切换、跨文件编辑或到其他界面查询资料等操作。幸运的是,Vim提供了一个能够处理多个文件的插件。
-
Vim内部用缓冲区来表示文件;通过缓冲区,用户可以在不同文件之间快速切换
-
Vim用多个窗口在同一屏幕中显示多个文件
-
Vim用标签页对窗口进行分组
-
Vim用折叠效果来隐藏或展开一个文件的部分内容,从而让读者可以更容易地浏览文件的内容
2.2.1 缓冲区
缓冲区是文件的内部表示,每个打开的文件都有一个缓冲区。比如,通过命令行vim main.c 打开一个文件,然后可以用:ls命令看到现有的缓冲区列表。
缓冲区信息含义
-
1为缓冲区编号,在整个Vim会话中,它的值保持不变
-
%表示该缓冲区位于当前窗口中
-
a 表示该缓冲区处于活动状态,即它已被加载并可见
-
“main.c” 为文件铭
-
line 30 表示当前光标位置
Vim 通过数字和名称来标识每个缓冲区,在同一个 Vim 会话中,它们都是唯一的(除 非退出 Vim)。为了在不同的缓冲区之间切换,可使用:b 命令,其参数为缓冲区的编号 数字。
:b1
2.2.2 插件——unimpaired
Tim Pope的vim-unimpaired是一个Vim插件,它为很多内置命令(以及一些新的命令) 添加映射。本书作者每天都会使用这个插件,因为它提供了更为直观的映射,比如]b 和 [b 用于循环遍历缓冲区,]f 和[f 用于遍历目录中的文件。该插件可以在 GitHub 仓库 tpope/vim-unimpaired 中找到(安装方法参见本章 2.1节)。
下面是 vim-unimpaired 提供的部分映射。
-
]b 和[b 循环遍历缓冲区
-
]f 和[f 循环遍历同一目录中的文件,并打开为当前缓冲区
-
]l 和[l 遍历位置列表(参见第 5 章)
-
]q 和[q 遍历快速修复列表(参见第 5 章)
-
]t 和[t 遍历标签列表(参见第 4 章)
此插件还支持用少数几次按键来切换某些选项,比如 yos 切换拼写检查,或 yoc 切换光标行高亮显示。更多功能参见:help unimpaired 中 vim-unimpaired 所提供的 完整映射和功能清单。
$ git clone https://github.com/tpope/vim-unimpaired.git ~/.vim/pack/plugins/start/nerdtree
2.2.3 窗口
Vim将缓冲区加载到窗口中。一个屏幕上可以同时显示多个窗口,它们将屏幕分割成几块。
-
窗口的创建、删除和跳转
-
窗口的创建 首先,打开 main.c 文件 然后,使用如下命令将窗口垂直分割成两个,其中一个显示新的文件。
:split test.c
也可以使用下面的命令按水平方向分割窗口
:vsplit farm.py
这两个命令都可以简化成sp、vs
-
窗口的跳转 为了使光标能在不同窗口间 移动,先按 Ctrl + w 组合键,然后输入一个方向键:h、j、k、l 中的一个或键盘方向键。
如果经常使用窗口,读者可以按照如下配置绑定快捷键。
" 使用<Ctrl> + hjkl 快速在窗口间跳转 noremap <c-h> <c-w><c-h> noremap <c-j> <c-w><c-j> noremap <c-k> <c-w><c-k> noremap <c-l> <c-w><c-l>
然后,就可以用 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 来关闭缓冲区,而保留分割窗口。
-
-
窗口的移动
窗口也可以移动、交换或改变大小。因为 Vim 中没有鼠标拖曳的功能,所以只能记 住一些命令了。
并不需要记住所有这些命令,只要知道 Vim 支持哪些窗口操作,剩下的 操作可以通过查看文档。使用:help window-moving 和:help windowresize 打开 Vim 手册中相应的条目,即可找到所有相关的快捷键
窗口命令的快捷键都要先按 Ctrl + w 组合键,后面跟一个大写的方向键(H、J、 K 和 L 中的一个),当前窗口会被移动到相应的位置
使用 Ctrl + w,H 组合键将当前窗口移动到屏幕的最左边。 使用 Ctrl + w,J 组合键将当前窗口移动到屏幕的底部。 使用 Ctrl + w,K 组合键将当前窗口移动到屏幕的顶部。 使用 Ctrl + w,L 组合键将当前窗口移动到屏幕的最右边。
Vim 内部用数字来标识窗口。不过,与缓冲区不同,窗口的编号是随着布 局变化而改变的,而且并没有直接的方法来修改窗口编号。有些窗口管理 命令以窗口编号为参数,但本书不会涉及这部分内容。有一条原则仅供参 考,窗口编号顺序为由上至下、由左至右递增。
-
改变窗口的大小 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。
-
2.2.4 标签页
在很多现代编辑器中,标签页(Tabs)用于表示不同的文件。在 Vim 中自然也是如 此,但用户需要考虑其原始目的。
Vim 用标签页来组织一个窗口的集合,进而支持在不同的窗口集合之间切换,这让 用户方便地拥有了多个工作区。标签页通常用来在同一个 Vim 会话中区分不同的问题或 者文件集合。标签页功能不一定是一个频繁使用的功能,但如果希望在不同项目或同一 项目的不同上下文之间切换,那么标签页将是一个不错的选择。
用户愿意使用标签页的另一个原因可能与 Vim 的 diff 功能有关,因为 diff 作用于一个标签页内。更多详情请参考第 5 章中关于 vimdiff 的介绍。
在一个新标签页中打开一个空缓冲区的命令如下。
:tabnew
在新标签页中打开一个已有文件的命令为:tabnew <文件名>。
标签页显示在屏幕的顶部。在标记为 3 main.c 的标签页中打 开了三个窗口及一个活动缓冲区main.c。[No Name]标签页则是刚才打开过的空缓冲区。
在一个标签页中,可以通过常用的方式(:e <文件名>)来加载文件,也可以用:b 命令在不同缓冲区之间切换。 为了在不同标签页之间跳转,可以使用如下命令。
快捷键 gt 或:tabnext 命令用于切换到下一个标签页。 快捷键 gT 或:tabprevious 命令用于切换到上一个标签页。
标签页可通过:tabclose 命令来关闭,标签页关闭也会导致其中的窗口关闭(如 果只剩一个标签页,则需要用:q 来关闭)。 :tabmove N 命令将当前标签页移动到第 N 个标签页之后(如果 N 为 0,则变成第 一个标签页)。
2.2.5 折叠
-
开启折叠
Vim 为浏览大型文件提供的一个强大工具是折叠。折叠功能支持文件部分内容的隐 藏,隐藏的依据既可以是预定义的规则,也可以是手动添加的折叠标记。 设置折叠方式的方法为在.vimrc 文件中加入 set foldmethod=<折叠 方法>
set foldmethod=indent
设置 foldmethod 为 indent,使 Vim 基于缩进来折叠代码。
命令 | 作用 |
---|---|
zo | 【将光标移动到其中一个折叠行上】打开当前折叠 |
zc | 【只要光标在一个潜在的折叠文本中】将此折叠关闭 |
za | 切换折叠状态(打开关闭的折叠或关闭打开的折叠) |
zR | 同时打开所有折叠 |
zM | 同时关闭所有折叠 |
将 foldmethod 设置为自动类型(如 indent)会默认将所有文件折叠。 这只是一种偏好,读者也可能会选择在打开新文件时打开折叠。在.vimrc 文件中添加 autocmd BufRead * normal zR 会在打开新文件时令折叠 处于打开状态,即 Vim 在读取新的缓冲区时执行 zR 命令(打开所有折叠)。
-
折叠的类型
从某种意义上来说,Vim 在折叠代码方面是比较智能的,而且支持多种折叠方式。 折叠的方法由.vimrc 文件中的 foldmethod 选项来指定。Vim 支持如下折叠方式。
-
manual:手动折叠,这种方法对于长文本而言并不适用。
-
indent:基于缩进的折叠,这对于依赖缩进的编程语言非常合适(不管哪种语 言,标准的编码风格中总是会采用某种一致性的缩进。因此,当读者想要快速隐 藏不关心的代码时,indent 折叠方式不失为一种高效率的选择)。
-
expr:基于正则表达式的折叠。如果读者想要用复杂的规则来定义折叠,那么 可以选择这种方式。
-
marker:使用文本中特殊的标记来定义折叠,比如{{{和}}}。这种方法对于 管理很长的.vimrc 文件非常有效,但是在 Vim 之外不常用,因为这种方式需 要修改文件内容。
-
syntax 提供了可识别语法的折叠,但它并非对所有语言都开箱即用(不支持 Python)
-
diff:当 Vim 处于 diff 模式时会自动采用这种折叠方式,diff 模式下需要展示 两个文件的不同之处,而相同之处往往需要隐藏起来(参见第 5 章)。
2.3 文件树浏览
软件项目往往包含大量的文件和目录,能够利用 Vim 快速浏览和展示这些文件和目 录将是一件很方便的事。本节介绍 5 种不同的文件浏览方式,它们分别是内置的 Netrw文件管理器、启用了 wildmenu 的:e 命令、NERDTree、Vinegar 和 CtrlP 插件。这些方 式都可用于处理文件,并可按需求组合使用。
2.3.1 目录浏览器Netrw
Netrw 是 Vim 的内置文件管理器(用技术语言来说,它是 Vim 自带的一个插件)。 Netrw 支持对目录和文件的浏览,这和操作系统下的文件管理器类似。
使用方法为执行命令:Ex(完整命令为:Explore),它会打开文件浏览窗口
-
因为 Netrw 与 Vim 集成在一起,所以编辑一个目录时(如用:e .命令打开 当前目录),实际上打开的是 Netrw
Enter 键用于打开文件和目录 -键进入上一层目录 D 键删除一个文件或目录 R 重命名一个文件或目录 Netrw 的窗口也可以在分割窗口或标签页中打开。 :Vex 以左右分割方式打开 Netrw :Sex 以上下分割方式打开 Netrw :Lex 以左右分割方式打开 Netrw,当前 Netrw 窗口位于最左边,且高度占满整 个屏幕
Netrw 非常强大,它还支持远程编辑。比如,通过下列命令可以列出 SFTP 下远程目 录的内容
:Ex sftp://<domain>/<directory>/
2.3.2 支持文件菜单的:e 命令
另一种浏览文件树的方式为在.vimrc 文件中设置 set wildmenu。此选项将在增 强模式下产生一个自动补全的文件名菜单(wildmenu),并在状态栏中快速按 Enter 键 呈现所有可能的自动补全选项。启用 wildmenu 之后,输入:e 命令(不按 Enter 键, 输入一个空格),然后按 Tab 键。这时,状态栏中会显示一个文件列表,读者可以用 Tab 键遍历选择这些文件,或者用 Shift + Tab 组合键反向遍历(左方向键和右方向键可 以起到同样的作用)
选择完成后再按 Enter 键,就打开相应的文件或目录了。按向下方向键将进入光标 选中的目录,而向上方向键则进入上一级目录。
wildmenu 也支持部分路径,输入:e <文件名开始的字符>,然后按 Tab 键,会触 发 wildmenu。 .vimrc 中常用的 wildmenu 设置如下所示。
set wildmenu " 启用增强的 Tab 自动补全
set wildmode=list:longest,full " 补全为允许的最长字符串,然后打开 wildmenu
上述设置允许读者在第一次按 Tab 键时将部分路径补全为最长的匹配字符串(并且 还会展示所有的可能项);第二次按 Tab 键时遍历 wildmenu 中的文件。
2.3.3 插件—— NERDTree
NERDTree 是一种模拟现代 IDE 行为的优秀插件,它在屏幕边缘用一个分割的缓冲 区来展示文件树。NERDTree 可从 GitHub 仓库 scrooloose/nerdtree 中找到.
安装 NERDTree 之后可通过:NERDTree 命令启动 NERDTree。将在左 边窗口中列出了一个目录以及其中的文件。
使用 h、j、k 和 l 键或方向键可以浏览文件树结构,按 Enter 键或 o 键可打开选 中的文件。还有一些其他有用的快捷键,可以用 Shift + ?组合键查看。
NERDTree 有一个不得不提的功能:支持书签。读者可通过:Bookmark 命令来收藏 当前光标在 NERDTree 中选择的目录。在 NERDTree 窗口中,按 B 键可以在窗口顶部列出 所有书签。
读者可以在 NERDTree 窗口中使书签保持显示,方法是在.vimrc 文件中设置 NERDTreeShowBookmarks 选项,如下所示。
let NERDTreeShowBookmarks = 1 " 启动 NERDTree 时显示书签
隐藏 NERDTree 窗口的命令是:NERDTreeToggle。如果读者希望在编辑时令 NERDTree 窗口保持打开,则可以在.vimrc 中加入如下设置。
autocmd VimEnter * NERDTree " Vim 启动时打开 NERDTree
当 NERDTree 窗口变成最后一个窗口时并不会自动关闭,读者可以通过.vimrc 文 件中的如下设置来改变这种行为。
" 当 NERDTree 窗口是最后一个窗口时自动关闭
autocmd bufenter * if (winnr("$") == 1 && exists("b:NERDTree") &&
\ b:NERDTree.isTabTree()) | q | endif
NERDTree 的优点是可以在工作区中显示一个项目文件的概览,很多人习惯使用图 形化用户界面,因此会喜欢 NERDTree。但是,当用户的编辑习惯被 Vim 改变时,可能 会觉得文件列表容易让人分心,转而又会返回到更简洁的 Netrw。
2.3.4 插件——Vinegar
Tim Pope 的 vinegar.vim 是一个小插件,用于解决项目侧边栏与分割窗口无法 同时工作的问题。当打开了多个分割窗口时,诸如 NERDTree 这样的插件会让人更加 分心。
假设已经打开了 3 个窗口(第四个 NERDTree 窗口在最左边)。如果在 NERDTree 窗口中按 Enter 键,则光标选中的文件将在右边哪个窗口中打开呢?
这个文件将在左下方打开,但用户无法预知。NERDTree 总是在最后一个 创建的窗口中打开文件
Tim Pope 用一个称为 Vinegar 的小插件解决了这个问题,使 Netrw 拥有无缝集成的 用户体验。此插件可在 GitHub 仓库 tpope/vim-vinegar 中找到
如果读者同时安装了 NERDTree 和 Vinegar,则 Vinegar 会使用 NERDTree 窗 口,而不是 Netrw。为了避免 NERDTree 取代 Netrw(而且使-键之类的命令 保持可用),读者需要在.vimrc 文件中设置 let NERDTreeHijackNetrw = 0。
Vinegar 提供了一种新的快捷键映射:-键(短横线)用于在当前目录中打开 Netrw
此插件隐藏了 Netrw 顶部的帮助栏,这可能会让读者有些迷惑。按 I 键(大写的 i), 帮助栏又会重新出现。另一个快捷键是 Shift + ~组合键,它将打开用户主目录,很 多人习惯在主目录中保存项目。
2.3.5 插件——CtrlP
CtrlP 是一个模糊补全插件,可帮助读者在只知道部分关键字时快速打开所需文 件。CtrlP 可在 GitHub 仓库 ctrlpvim/ctrlp.vim 中找到
安装此插件,然后在 Vim 中按下 Ctrl + p 组合键。屏幕下方会 出现 CtrlP 窗口,其中列出了项目目录中的文件列表。然后,输入文件名或目录中的关 键字,列表中将只剩下匹配项。读者可以用 Ctrl + j 组合键和 Ctrl + k 组合键来 上下遍历列表,并用 Enter 键来打开选中的文件。按 Esc 键退出 CtrlP 窗口
除当前目录下的文件之外,CtrlP 还支持在缓冲区或最近使用的文件之间切换。在打 开 CtrlP 窗口的情况下,使用 Ctrl + f 组合键和 Ctrl + b 组合键可以在 3 种不同的 搜索模式之间的循环切换。
读者可以用命令来选择一种搜索模式,:CtrlPBuffer 命令会列出缓冲区供读者选 择,:CtrlPMRU 命令会列出最近使用的文件,而:CtrlPMixed 命令则同时显示文件、 缓冲区和最近使用的文件。
读者也可以在.vimrc 文件中绑定其他快捷键。比如,将:CtrlPBuffer 命令绑定 到 Ctrl + b 组合键,可以使用如下设置。
nnoremap <C-b> :CtrlPBuffer<cr> " 将 CtrlP 缓冲区模式绑定到 Ctrl + b 组合键
2.4 文本的浏览
2.4.1 切换到插入模式
前面已经介绍过,在 Vim 中使用 i 键进入插入模式,而插入文本的位置为光标的 位置。
除此之外,还有其他进入插入模式的便捷方法。
-
a键用于在光标后面进入插入模式
-
A 键用于在当前行行尾进入插入模式(等价于$a)
-
I 键用于在当前行行首(在缩进之后)进入插入模式(等价于_i)
-
o 键用于在光标下面新增一行,在新的一行里进入插入模式
-
O 键用于在光标上面新增一行,在新的一行里进入插入模式
-
gi 用于在最后退出的位置进入插入模式
第 1 章已经介绍了如何通过修改命令 c 来删除文本,然后进入插入模式。还有一些 其他的先修改再插入的组合命令,介绍如下
-
C 用于删除光标右边的文字(直到行尾),然后进入插入模式
-
cc 或 S 用于删除当前行的内容,然后进入插入模式,但会保留缩进
-
s 用于删除单个字符(如果前面加了数字,则会删除多个字符),然后进入插入 模式
2.4.2 用/和?搜索
大多数情况下,Vim 中最快的文本浏览方式是搜索指定的字符串,搜索方法是按/ 键(从正常模式进入命令模式),然后输入待搜索的字符串。按 Enter 键之后,光标将 移动到第一个匹配的地方。
按 n 键可以在同一个缓冲区中循环遍历所有匹配的位置,而按 N 键则可以开始反向 遍历
搜索过程中常用到的一个选项是 set hlsearch(可以考虑添加到.vimrc 文件中), 因为这个选项会在屏幕上高亮显示每个匹配项。
使用 set incsearch。这个选项会在读者还未完整输入 搜索命令时,就将光标动态跳转到第一个匹配处。
如果想要反向搜索,则将/换成?即可,这时 n(跳转到下一个匹配)和 N(跳转到 上一个匹配)的行为也会发生变化。
-
跨文件搜索
Vim 提供了两个命令来实现跨文件搜索,分别是:grep 和:vimgrep。
-
:grep 调用的是系统命令 grep,这是一个非常强大的工具,特别是对于熟悉 grep 用法的人而言
-
:vimgrep 则属于 Vim 的一部分,如果读者还不是太熟悉 grep,则:vimgrep 命令会更容易掌握
:vimgrep 的语法为:vimgrep <模式> <路径>。其中<模式>既可以是一个字符 串,也可以是 Vim 风格的正则表达式。<路径>通常为一个通配符,当<路径>为**
时, 表示对目录递归搜索(或者使用**/*.py
搜索具体的文件类型)。
比如,使用下面的命令在本书的 Python 工程中搜索 calc 字符串。
:vimgrep animal **/*.py
然后,Vim 会跳转到第一个匹配处,并在屏幕底部显示匹配的个数
然后可以用:cn 或:cp 来逐个浏览各匹配项。读者也可以执行:copen 命令,这时 会在底部出现一个新窗口,其中有可视化显示的快速恢复(quickfix)列表
在快速恢复列表中,可以用 j 和 k 来上下移动光标,然后按 Enter 键跳转到相应的匹配处。这个快速恢复窗口和其他窗口一样,也可以用:q 命令或 Ctrl + w,q 组合 键退出。
-
ack
在 Linux 操作系统中,Vim 可以结合 ack 工具来搜索代码库。ack 继承了 grep 的 思想,它更关注于搜索代码。读者可以用自己喜欢的包管理器来安装 ack,下面是使用 apt-get 的安装示例。
sudo apt-get install ack-grep
比如,读者可以在命令行中用 ack 来递归搜索所有包含单词 Animal 的 Python 文 件,命令如下。
ack --python Animal
Vim 中包含一个集成 ack 的插件,可以将 ack 的结果显示在快速恢复窗口中(参考 5.5.1 节关于快速列表的介绍)。这个插件的地址为 GitHub 仓库 mileszs/ack.vim。安装此插件之后,可以在 Vim 中执行如下:ack 命令。
:ack --python Animal
此命令会运行 ack,然后显示快速恢复窗口(参考 5.5.1 节中关于快速恢复窗口的 详细介绍)
2.4.3 利用文本对象
文本对象是 Vim 中额外增加的对象类型,比如括号内或引号内的文本都可以称作文 本对象。通过文本对象,读者可以更方便地处理代码。文本对象只能与其他操作符组合 起来使用,比如修改命令、删除命令或可视模式。
可以尝试使用文本对象,如下,将光标置于括号内
def print_contents(self): print("We've got some animals on the farm:", ', '.join(animal.kind for animal in self.animals) + '.')
然后输入di)
(删除括号内的文本),括号内的文本就会被删除
def print_contents(self): print("We've got some animals on the farm:", ', '.join() + '.')
上面的删除命令和修改命令类似。用 u 来撤销上面的修改
执行 c2aw(修改两个单词)会删除光标后的两个单词(包括周围的空格),然后进 入插入模式
def print_contents(self): print("We've got some animals on the farm:", ', '.join(animal.kind in self.animals) + '.')
从上面的两个例子中可以看到,文本对象有两种风格:内对象(以 i 开头)和外对 象(以 a 开头)。内对象不包含空白字符(或周围其他字符),而外对象是包含的。
文本对象的完整列表可通过:help text-objects 命令来查看,这里列出一些有 趣的文本对象。
-
w 和 W 分别表示狭义单词 word 和广义单词 WORD。
-
s 表示句子。
-
p 表示段落。
-
t 表示 HTML/XML 标签。
编程语言中常用的成对的字符全部可以表示为文本对象,包括`、''、""、()、[]、<> 和{},因而读者可以选择这些字符之间的文本。
读者可以将文本对象的使用方式理解为句子的构造
2.4.4 插件——EasyMotion
EasyMotion 一直是作者工具箱中的核心组成部分。它简化了文本浏览过程,可以准 确且快速地跳转到指定位置。插件的网址为 GitHub 仓库 easymotion/vimeasymotion
启动方式:安装完成之后,连续按两次先导键\,然后按某个移动键,可以启动此插件。
Vim 插件常用先导键来实现额外的快捷键映射。默认情况下,Vim 的先导 键为\。关于先导键的更多介绍请参考第 3 章
\\w
命令(按两次反斜划线,然后按 w 键)将触发逐个单词的移动方式
屏幕上每个单词的开头都被替换为一个字母(或两个字母, EasyMotion 命令用完了所有英文字母之后就会使用两个字母)。按一个字母(或依次按 两个字母),光标将瞬间跳转到屏幕上的指定位置.
EasyMotion 默认支持下列移动命令(所有命令都要加上两个先导符)
-
f 用于向右查找一个字符,F 则用于向左查找字符
-
t 用于向右移动直到找到该字符,T 则用于向左移动直到查找该字符
-
w 用于向后跳过一个狭义单词(W 向后跳过一个广义单词)
-
b 用于向前跳过一个狭义单词(B 向前跳过一个广义单词)
-
e 用于向前跳到狭义单词末尾(E 向前跳到广义单词末尾)
-
ge 用于向后跳到狭义单词的末尾(gE 向后跳到广义单词的末尾)
-
k 和 j 分别用于跳到上一行或下一行的开关
-
n 和 N 分别用于跳到上一个或下一个的搜索结果(在用/或?搜索之后)
EasyMotion 还保留了很多快捷键没有使用,因此读者可以构建自己的快捷键映 射。:help easymotion 命令可查看 EasyMotion 的所有功能
2.5 使用寄存器进行复制和粘贴
读者可以用 y 命令(yank)来复制文本,后面接一个移动命令或一个文本对象。选 择一些文本后也可以在可视模式下使用 y 来复制。
这里的复制和粘贴只限于 Vim 内部,复制是将文本存入相应的 Vim 寄存器中,而粘贴是 从某个 Vim 寄存器中取出文字并插入当前光标位置。如果想要和系统的粘贴板进行交互,需要使用特 殊的寄存器。
-
ye 命令(复制文本直到下一个单词结尾)
-
删除和修改操作同时也复制了相关的文本,这些文本可以用于后续的粘贴操作中。 另外,粘贴操作 p 的前面可以加数字,从而实现多次粘贴。
2.5.1 寄存器
Vim 中复制和粘贴文本时,文本是储存在 Vim 寄存器里面的。Vim 支持多种寄存 器,每个寄存器用字母、数字或特殊符号来标识。
寄存器的访问方式是引号键",后面接寄存器的标识符,然后是针对指定寄存器的 操作。
a~z 所标识的寄存器用于手动复制数据。比如,将一个单词复制到 a 寄存器,可以 使用"ayw 命令,而粘贴命令为"ap
前面介绍的复制和粘贴操作使用的都是默认的无名寄存器。这个无名寄存器用双引 号"来标识,读者可以用这个标识符来显式访问寄存器。比如,""p 用于从无名寄存中 粘贴文本,等同于 p。
用数字编号的寄存器存储的是最后 10 次删除操作的历史记录。0 寄存器存储的是最 后一次删除的文本,1 寄存器则为上上次删除的文本,依此类推。假设读者记忆力超群, 想起了 7 次粘贴操作之前的粘贴操作,"7p 命令会将那次操作的文本再次粘贴出来。
还有一些很有用的只读寄存器:%存储了当前文件名,#存储了上次打开的 文件名,.中为最后插入的文本,:为最后执行的命令。
读者也可以在正常模式之外与缓冲区进行交互。Ctrl + r 组合键允许读者在插入 模式或命令行模式下粘贴某个寄存器的内容。比如,在插入模式下,按 Ctrl + r 组合 键,"会在光标处粘贴无名寄存器中的内容。
读者可以在任何时候通过:reg <寄存器标识符>命令来访问某个寄存器的内容。比 如,:reg a b 命令可同时得到 a 和 b 寄存器中的内容。
还可以用:reg 命令列出所有寄存器的内容
y 命令会重写寄存器内的内容,而字母命令的寄存器(a~z)是可以附加内容的, 方法是使用大写的寄存器标识符。比如,若想附加一个单词到寄存器 a 中,可以先将光 标置于此单词开头,然后执行"Ayw 命令。
2.5.2 从外部复制文本到Vim中
Vim 中有如下两种内置的寄存器用于和外部世界交互。
-
*寄存器表示系统的主粘贴板(macOS 和 Windows 系统中的默认粘贴板,在 Linux 系统中为终端的鼠标选择内容)
-
+寄存器(只针对 Linux)用于 Windows 风格的 Ctrl + c 组合键和 Ctrl + v 组合键操作[称为粘贴板选择器(Clipboard selection)]
这两个寄存器的使用方式与其他寄存器相同。比如,"*p 命令用于从系统主粘贴板 中将文本粘贴进来,"+yy 命令则将一行文本复制到 Linux 的粘贴板选择器中。
如果读者希望默认使用这些寄存器,可以在.vimrc 文件中设置 clipboard 变量, 将其设置为 unamed 时,表示默认使用*寄存器进行复制和粘贴。
set clipboard=unamed " 复制到系统寄存器(*)
将 clipboard 设置为 unnamedplus,将默认使用+寄存器
set clipboard=unnamedplus " 复制到系统寄存器(+)
利用如下命令还可以同时使用这两个寄存器
set clipboard=unamed,unnamedplus " 复制到系统寄存器(*, +)
在.vimrc 文件中完成设置之后,y 和 p 命令将分别从指定的默认寄存器中复制和 粘贴。
有时,读者希望在插入模式下从系统粘贴板中将文字粘贴到缓冲区中。在 老版本的 Vim 或某些终端模拟器中,这样粘贴会出现问题,因为 Vim 会在 粘贴过程中自动缩进代码或添加注释。为避免这种情况,在粘贴代码之前 先禁用缩进和自动注释,方法是运行:set paste 命令,粘贴完成之后, 恢复的命令为:set nopaste。从 8.0 版本开始,Vim 默认启用括号化粘 贴模式(bracketed paste mode),从而基本解决了这些问题。
本章小结
本章介绍了 Vim 中的一些核心概念,以及如何利用这些概念进行文本浏览,具体包 括使用缓冲区表示文件、分割窗口和用标签页组织多个窗口。另外还介绍了如何通过折 叠来更有条理地浏览大文件的内容。
经过本章的学习,读者应该可以更自信地用 Vim 来处理大型代码库,包括用插件(如 Netrw、NERDTree、Vinegar 和 CtrlP)来浏览文件。本章还介绍了一种安装这些插件的 快速方式(虽然不够自动化)。
本章介绍了几种新的光标移动操作、文本对象、快速切换到插入模式的方法以及如 何用 EasyMotion 插件在文件中快速跳转。
本章还介绍了搜索功能,包括文件内搜索和整 个代码库内文件之间的搜索。如果读者能够尝试本章介绍的 ack 插件,收获会更大。 最后,本章还介绍了寄存器的概念,以及如何用寄存器来复制和粘贴文本。
第三章 使用先导键——插件管理
主要内容
-
使用手动方法或 vim-plug、Vundle、Pathogen 等管理多个插件
-
介绍配置慢速插件的方法
-
深入介绍 Vim 中的主要模式
-
理解命令重映射的复杂性
-
介绍先导键及其在定制快捷键时的用处
-
配置和定制插件
3.1 插件管理
到目前为止,读者应该已经安装了一些插件,而且今后安装的插件会越来越多,特别是其中可能还包含一些用于解决疑难杂症的专用插件。手动让这些插件保持更新还是 比较麻烦的,幸运的是,已经有一些现成的插件管理方案了。 当读者需要在多台机器之间切换,并希望 Vim 插件保持更新时,插件管理就显得非 常重要了。
在多台机器之间同步 Vim 配置的方法,请参见第 7 章。
3.1.1 插件管理——vim-plug
vim-plug 是很有前景的插件管理器。这个插件管理器是轻量级的,它易用且兼容大 量的插件。其 GitHub 仓库地址为 junegunn/vim-plug(它的帮助文件 README 非常 友好,还想进一步偷懒的读者可以直接查看本节中的摘要)。
插件 vim-plug 有如下优点。
-
轻量级、单个文件且支持一些直观的安装选项
-
支持并行插件加载(要求 Vim 编译带有 Python 或 Ruby 支持,这几乎已经是现 代 Vim 的标配)
-
支持大多数插件的延迟加载,即只为特定命令或文件类型触发必要的插件
Linux 系统中的删除 命令为 rm -rf $HOME/.vim/pack
安装 vim-plug :
-
下载插件文件
-
保存为$HOME/.vim/autoload/plug.vim
-
为了从 GitHub 上下载文件,在 Linux 或 macOS 系统中可以使用 curl 或 wget 命令,或者直接在浏览器中打开链接,然后“右键->另存为”。比如,UNIX 用户可以用 下列命令下载文件。
$ curl -fLo ~/.vim/autoload/plug.vim --create-dirs https://raw.github.com/junegunn/vim-plug/master/plug.vim
-
修改.vimrc 文件,加入 vim-plug 初始化的代码,如下所示。
" 使用 vim-plug 管理插件 call plug#begin() call plug#end()
-
在这两行之间加入一些插件,其中的地址格式为 GitHub 地址的最后两部分 (<用户名>/<仓库>,比如 GitHub - preservim/nerdtree: A tree explorer plugin for vim. 记为 scrooloose/nerdtree),用于唯一标识插件,如下所示。
" 使用 vim-plug 管理插件 call plug#begin() Plug 'scrooloose/nerdtree' Plug 'tpope/vim-vinegar' Plug 'ctrlpvim/ctrlp.vim' Plug 'mileszs/ack.vim' Plug 'easymotion/vim-easymotion' call plug#end()
-
保存.vimrc 文件,然后重载(命令为:w | source $MYVIMRC)或重启 Vim, 以使这些修改生效。执行:PlugInstall 来安装这些插件。然后上面提到的插件将会自 动从 GitHub 上下载下来
vim-plug 有两个主要的命令。
-
:PlugUpdate 用于更新所有已安装的插件。
-
:PlugClean 用于删除.vimrc 中已经移除的插件。如果不执行:PlugClean, 则没有激活的插件(.vimrc 中删除或注释掉的那些 Plug...行)将仍然保存 在文件系统中
运行:PlugUpdate 将更新 vim-plug 所管理的插件,但不包括它自己。如 果想要更新 vim-plug,需要运行:PlugUpgrade 命令,然后重载.vimrc 文件(执行:source $MYVIMRC 或重启 Vim)
延迟加载是一种避免插件拖延 Vim 运行速度的有效技术,这一点可通过 Plug 指令 的可选参数来实现。比如,如果想要在:NERDTreeToggle 命令执行时再加载 NERDTree,可以使用 on 参数。
Plug 'scrooloose/nerdtree', { 'on': 'NERDTreeToggle' }
如果只想对特定文件类型加载某个插件,可以使用 for 参数,如下所示。
Plug 'junegunn/goyo.vim', { 'for': 'markdown' }
由于 vim-plug 采用单文件安装方式,因此它的帮助文档并未安装到 Vim 中。 如果想要用:help vim-plug 来查看文档,则需要将 Plug 'junegunn/ vim-plug'添加到插件安装列表中,然后运行:PlugInstall 命令。
在 vim-plug 的 GitHub 仓库 junegunn/vim-plug 中,读者可以在它的 README 文 件中找到 vim-plug 支持的所有参数列表。
对于 Linux 或 macOS 系统用户(以及 Cygwin 用户),可以将下列代码添加到.vimrc 文件中,当该.vimrc 被移植到新机器上时,它会自动安装 vim-plug。
" 如果没安装过 vim-plug,则下载安装 if empty(glob('~/.vim/autoload/plug.vim')) silent !curl -fLo ~/.vim/autoload/plug.vim --create-dirs \https://raw.GitHub.com/junegunn/vim-plug/master/plug.vim autocmd VimEnter * PlugInstall --sync | source $MYVIMRC endif
再次打开 Vim 时,vim-plug(以及所有用 Plug 指令列出的插件)就安装好了。
3.1.2 其他推荐
除了 vim-plug,还有很多其他的插件管理方案。本节的介绍并不全面,而是侧重展 示不同的插件管理风格。读者可以选择一款适合自己的,或者从网上搜索其他方案。
-
Vundle Vundle 是 vim-plug 的前身(也许只是提供了灵感),它们有着相似的工作方式。比 如,插件安装是同步的(不是后台运行),只不过 Vundle 的插件打包方式更重量级一些。 另一个不同之处在于插件的搜索方式,Vundle 支持直接从 Vim 中搜索插件。此外,Vundle 还支持用户在安装插件之前先进行测试。Vundle 及其安装指令可以在它的 GitHub 仓库 VundleVim/Vundle.vim 中找到。
Vundle 和 vim-plug 的工作方式类似, :PluginInstall 、 :PluginUpdate 和:PluginClean 这几个命令的作用相同。
-
手动方式 由于大部分插件都可以在 GitHub 上找到,因此使插件保持更新的主要方法是将它们 安装成 Git 的子模块。如果读者熟悉 Git,可以在.vim 目录中初始化一个 Git 仓库,然 后在此仓库中安装插件,作为 Git 仓库的子模块。
Vim8 提供了一种原生的插件加载方式,即在.vim/pack 目录中搜索插件目录树。 Vim8 支持如下目录结构。
-
.vim/pack/<目录名>/opt/中保存的插件用于手动加载
-
.vim/pack/<目录名>/start/中保存的插件用于始终加载
如果读者想要深入了解每个插件目录的组织方式,请参考第 8 章。
首先,需要选择一个好记的名字,作为.vim/pack/的子目录。比如,plugins 就 是一个不错的选择。
然后,<目录名>/start/目录用于存储那些总是需要加载的插件。
opt/目录中的插件只会在执行:packadd <目录名>命令之后再加载,因此可以 在.vimrc 中用 packadd 命令有选择性地加载插件。opt/目录和 packadd 命令可以 实现插件的延迟加载(与 vim-plug 相同)。
" 通过:Ack 命令来加载和运行 ack.vim 插件 command ! -nargs=* Ack :packadd ack.vim | Ack <f-args> " 当打开 Markdown 文件时加载并运行 Goyo 插件 autcmd! filetype markdown packadd goyo.vim | Goyo
此外,在.vimrc 中加入如下代码,可以加载所有插件的文档。
packloadall " 加载所有插件 silent! helptags ALL " 为所有插件加载帮助文档
执行 packloadall 命令使 Vim 加载 start/目录中的所有插件(Vim 会在加 载.vimrc 之后自动执行这个步骤,这里是提前执行)。helptags ALL 加载所有插件的 帮助文档,而 silent!前缀则是为了隐藏加载帮助文档过程中的所有输出和错误信息。
读者可以通过 Git 子模块来自行管理插件(稍微有点麻烦),即用 Git 下载插件并保 持更新
首先,在.vim 目录中初始化一个 Git 仓库(只需要操作一次)
$ cd ~/.vim $ git init
然后,添加一个插件,比如 nerdtree,作为子模块。
$ git submodule add https://github.com/scrooloose/nerdtree.git pack/plugins/start/nerdtree $ git commit -am "Add NERDTree plugin"
每次更新插件时,执行下列命令。
$ git submodule update --recursive $ git commit -am "Update plugins"
若要删除插件及相应的子模块,可执行下列命令。
$ git submodule deinit -f -- pack/plugins/start/nerdtree $ rm -rf .git/modules/pack/plugins/start/nerdtree $ git rm -f pack/plugins/start/nerdtree
-
Pathogen
本节可能更像是对 Pathogen 光荣历史的回顾
从定义看,Pathogen 更像是一种 runtimepath 管理器,而非插件管理器。但在 实践中,runtimepath 管理可以相当好地过渡为插件管理。在 Vim 8 之后,已经不再 需要通过操作 runtimepath 来安装插件。不过,如果读者还在使用 Vim 8 之前的版 本 Vim(或者不愿意使用重量级的包管理器),则 Pathogen 可以作为简便的插件管理器 来使用。
Pathogen 是插件管理的先行者之一,并在很大程度影响了后来者。许多 Vim 用户至 今仍在使用 Pathogen。
Pathogen 可以在它的 GitHub 仓库 tpope/vim-pathogen 中找到
3.1.3 分析运行慢的插件
Vim 使用得越久,安装的插件可能也会越多。有时候,这些插件会导致 Vim 运行速 度减慢。Vim 运行速度慢的根源通常是某个未优化的插件,原因可能是插件的缺陷或插 件与系统之间独特的交互方式。为此,本节将介绍 Vim 内置的插件分析功能,它可以用 于检测这些问题。
-
启动时间分析
Vim 启动时,若加上--startuptime <文件名>选项,则 Vim 会将启动时的每个行 为记录到一个文件中。比如,下列命令将启动日志记录到文件 startuptime.log 中。
$ vim --startuptime startuptime.log
-
特定行为的分析
有时候,读者会发现 Vim 中的某个行为比较慢,这时可以对特定几个行为进行分析。
这里设计了一种典型的场景。从 GitHub 下载 Python 和 Vim 仓库,然后尝试运行 CtrlP 插件提供的:CtrlP 命令(参见第 2 章)。:CtrlP 命令将试图从当前目录开始递归为所有文件建立索引,对于文件数众多的这两个仓库而言,速度显然是非常慢的。
为了分析这个行为,在启动 Vim 后,执行如下几条命令。
:profile start profile.log :profile func * :profile file *
Vim 将分析这里执行的每个行为。当一个命令运行速度较慢时,比如这里的:CtrlP 命令(或按 Ctrl + P 组合键)。等待这个操作完成之后,退出 Vim(:q)。 用 Vim 打开 profile.log 文件
3.2 模式详解
Vim 有 7 种主模式,理解每一种模式的用途非常重要
3.2.1 正常模式
用户使用较多的 Vim 模式是正常模式(normal mode)。打开 Vim 时默认为正常模式, 在其他模式中按一次 Esc 键(有时候需要按两次),也会返回正常模式。
3.2.2 命令行模式和 ex 模式
命令行模式(command-line mode)的进入方式是输入冒号(:)(或者用/或?进行 搜索),进入命令行模式之后,读者可以输入一条命令,然后按 Enter 键执行命令。命 令行模式提供了以下几个常用的快捷键。
-
上下箭头键(或 Ctrl + p 组合键和 Ctrl + n 组合键)可以逐个命令地浏览 历史记录。
-
Ctrl + b 组合键和 Ctrl + e 组合键可以跳转到命令的开头(beginning)和 结尾(ending)。
-
Shift 键和 Ctrl 键结合左右箭头键可以逐个单词移动光标。
-
Ctrl + f 也是一个非常有用的快捷键,它可以打开一个可编辑的命令行窗口,其 中显示的是之前运行过的命令的历史记录
命令历史记录窗口只是普通的缓冲区,读者可以在其中找到曾经执行过的命令,并 进一步编辑(使用 Vim 中正常的文本编辑方式),然后再次执行。按 Enter 键可以执行 光标所在的命令行,按 Ctrl + c 组合键可以编辑此缓冲区。
查看帮助文档:help cmdline-editing 可以了解到更多命令行模式的使用方法。
Vim 还有一个命令行模式变体,称为 ex 模式,进入方式是按 Q 键。ex 模式是为了兼容 Vim 的前身 Ex。ex 模式支持执行多个命令而无须退出,但这个模式现在已经很少使用。
3.2.3 插入模式
插入模式(insert mode)用于输入文本,除此之外没有其他功能。按 Esc 键可返 回到正常模式,大部分工作其实是在正常模式下完成的。在插入模式下,也可以使用 Ctrl + o 组合键来执行正常模式下的命令,然后再回到插入模式。
在状态栏上,插入模式的标识文本为--INSERT--。
3.2.4 可视模式和选择模式
Vim 的可视模式(visual mode)支持文本的任意选择(通常用于执行某些操作)。如 果需要选择的文本不属于已定义的文本对象(单词、句子和段落等),则这个模式非常有 用。进入可视模式有以下几种方式。
-
v 进入字符可视模式(状态栏标文本--VISUAL--)
-
V 进入行可视模式(状态栏标识文本--VISUAL LINE--)
-
Ctrl + v 组合键进入块可视模式(状态栏标识文本--VISUAL BLOCK--)
一旦进入可视模式,读者可以通过常用的移动命令来移动光标,从而扩展选择范围。
Vim 还有一个选择模式(select mode),它模拟的是其他编辑器中的选择模式:输 入任意可打印字符可立即删除选中文本,然后进入插入模式(所以这时常用的移动命令 已经失去作用)。这个模式和 ex 模式相同,只应用于特定和受限的场合。事实上,本书 的作者也从未使用过这个模式,这里只是为了内容的完整性才进行介绍。
读者可以在正常模式下按 gh 键进入选择模式,也可以在可视模式下按 Ctrl + g 组合键,退出方式为按 Esc 键。
3.2.5 替换模式和虚拟替换模式
在其他编辑器里,按 Insert 键进入替换模式,其效果是擦除其他文本。在 Vim 下, 替换模式也类似,输入的文本会覆盖已有的文本(而不像插入模式下,输入文本会移动 已有文本)。当读者不想改变原始文件中的字符数时,这种模式非常有用。
替换模式的进入方式是按 R 键
替换模式在状态栏上的标识文本为--REPLACE--。在替换模式下,读者可以体验 替换文本的效果
按 Esc 键可退出替换模式,并返回到正常模式。
读者可按 r 键进入单字符替换模式,在此模式下,替换单个字符后会马上切换回正 常模式。
Vim 还提供了虚拟替换模式,它和替换模式类似,只不过操作的对象是屏幕上的显 示,而非直接针对文件中的字符。主要的区别包括 Tab 键会替换多个字符(而替换模式 下只会替换单个字符);按 Enter 键不会新增一行,但会移动到下一行。虚拟替换模式 的进入方式是输入 gR,详情参见帮助文档:help vreplace-mode
3.2.6 终端模式
终端模式(terminal mode)出现在 Vim 8.1 版本中,此模式支持在一个分割窗口中运 行一个终端环境。进入终端模式的命令如下。
:terminal
-
:terminal 命令可简化为:term
:terminal 命令会在水平分割窗口中打开系统的命令行系统(Linux 系统中为默认 的 Shell)
终端模式中封装了系统的终端,读者可以像往常一样使用命令行。这个终端窗口与 其他窗口类似(可以用 Ctrl + w 命令进行切换),只不过此窗口中只有插入模式。读 者可以考虑使用 Linux 或 macOS 系统下的 tmux 命令或 screen 命令,与 Vim 的终端模式 配合使用。
3.3 命令的重映射
只要是愿意使用插件的读者,都会希望对 Vim 中的命令进行重映射,以满足自己进 一步的需求。那些插件往往是由不同的人编写的,而每个人的工作流程往往也不同。Vim 本身则是无穷可扩展的,几乎支持每一个操作的重映射,读者可以任意改变默认行为, 从而让 Vim 彻底为己所用。本节介绍的就是命令的重映射。
Vim 支持将某些键映射为其他键,:map 和:noremap 提供了这样的功能
-
:map 用于递归映射
-
:noremap 用于非递归映射
这意味着经:map 重映射的命令可以识别自定义映射,而:noremap 则针对系统默 认映射
当读者决定创建一个新映射时,最好先确认一下此键或按键序列是否已经 被映射为其他用途了。内置的按键绑定列表可通过:help index 命令查 看。而:map 命令则可以查看插件和读者自定义的映射。比如,:map g 将 显示所有以 g 键开头的映射
比如,在.vimrc 文件中将按如下方式自定义映射
noremap ; : " 用分号取代默认的冒号,用于输入命令
模式感知的重映射
:map 命令和:noremap 命令都可用于正常模式、可视模式、选择模式和操作待决 模式(operator pending mode)。不过,Vim 还支持更细粒度的映射控制方式,读者可针 对每一种模式分别定义映射。
-
:nmap 和:nnoremap 用于正常模式
-
:vmap 和:vnoremap 用于可视和选择模式
-
:xmap 和:xnoremap 用于可视模式
-
:smap 和:snoremap 用于选择模式
-
:omap 和:onoremap 用于操作待决模式
-
:map!和:noremap!用于插入和命令行模式
-
:imap 和:inoremap 用于插入模式
-
:cmap 和:cnoremap 用于命令行模式
3.4 先导键
本书前面已经提到过先导键(leader key),它本质上是读者或插件定义的快捷方式 的命名空间。先按先导键,然后按下的任何键都来自于该命名空间。
默认的先导键为反斜线\,但这个键使用起来不太方便。在 Vim 社区中有几个替代的方 案,其中逗号是较流行的。为重新绑定先导键,需要在.vimrc 文件中加入如下设置。
" 将先导键重新映射为逗号 "let mapleader = ','
先导键的设置应该放在.vimrc 的顶部,因为新定义的先导键只会在定义之后 生效。
本书推荐的先导键是空格键。因为这个键足够大,而且在正常模式下并没有什么实 际的用途(只不过是在功能上模拟了右箭头键)。
" 将先导键映射为空格键 "let mapleader = "\<space>"
这里之前的转义符\是必要的,因为 mapleader 变量中不含特殊 字符(如空格符)。对于这个转义来说,只能用双引号,而不能是单引号, 因为单引号中只能存字面量字符串,而不含转义字符。
然后,读者就可以在.vimrc 中使用先导键了,比如下列代码
" 用 leader-w 保存文件 "noremap <leader>w :w<cr>
3.5 插件的配置
Vim 插件通常会提供一些命令来绑定快捷键,或提供一些变量用于控制插件的行为。 因此,在使用一个插件时,查看它提供了哪些命令和选项是一个好习惯。读者可以将命 令绑定到方便记忆的快捷键上,这会有助于记住插件的用法。
Vim 支持全局变量,其主要用途是配置插件。全局变量通常以 g:为前缀。通过:help <插件名>命令查看插件文档,可以找到它提供了哪些配置选项。
本章小结
本章介绍了管理插件的几种不同方式,其中 vim-plug 是一种轻量级的插件管理器, 支持插件的异步安装和更新。vim-plug 的前身 Vundle 也支持新插件的搜索和临时安装。
本章还介绍了一种手动的插件安装方式,因为 Vim 8 引入了一种插件加载方式,从而无 须手动修改每个插件的 runtimepath。对于低于 Vim 8 版本,读者仍然可以使用 Pathogen,它提供了一种自动执行部分 runtimepath 操作的方法。
本章介绍了两种分析 Vim 性能的方法:--startuptime 选项和:profile 命令。
本章介绍了 Vim 的主要模式:正常模式、命令行模式和 ex 模式、插入模式、可视 模式和选择模式、替换模式和虚拟替换模式,以及终端模式。 本章还介绍了如何通过重新映射命令来定制 Vim。不同的用户习惯使用不同的快捷 键组合。Vim 支持根据不同的模式映射不同的快捷键,即同一个按键在不同的模式下可 以有不同的意义。先导键支持创建一个全新的命名空间,可以用于插件和用户自定义的 命令。
本章还介绍了如何通过定制插件的配置选项来充分使用插件,以及通过为插件添加 快捷键来改进工作流程。
第四章 理解文本
当代码库越来越庞大时,代码文件之间的跳转也会变得更加困难。幸运的是,Vim 拥有一些浏览复杂代码结构的功能。
主要内容:
-
利用 Vim 内置的自动补全功能和相关插件对代码自动补全。
-
使用 Exuberant Ctags 浏览大型代码库。
-
使用 Gundo 浏览 Vim 复杂的撤销树。
4.1 代码补全功能
代码自动补全是现代集成开发环境(IDE)的一项极其吸引人的功能。通过自动补 全,读者可以在 IDE 中避免拼写错误,而且无须反复输入和记忆冗长复杂的变量名。
Vim 已经内置了自动补全功能,还有一些插件进一步扩展了这个功能。
4.1.1 内置自动补全
Vim 支持在打开的缓冲区中对单词进行简单的自动补全,这个功能从 Vim 7 开始默 认启用。输入一个函数名的开始几个字符,然后按 Ctrl + n 组合键,Vim 会弹出一 个自动补全列表。然后用 Ctrl + n 和 Ctrl + p 组合键可以在这个列表中上下移动, 以选择合适的备选项。比如,打开 animal_farm.py 文件,进入插入模式,输入 make_animal 的前两个字符 an,然后按 Ctrl + n 组合键,自动补全列表中会出现
如果继续输入,列表则会消失。
本节中仅列出了部分常用命令,其他关于自动补全的完整命令列表请参见 帮助文档:help ins-completion。每个人的工作流程都是独一无二的, 除非亲自操作,否则无法预知哪些命令对自己是最有用的。读者还可以查 看:help 'complete', 'complete'选项用于控制 Vim 补全建议的来 源(默认为缓冲区、标签文件和头文件)。
4.1.2 YouCompleteMe 插件
YouCompleteMe 插件扩展了 Vim 内置的自动补全引擎,而且还增添了大量新功能, 下面是 YouCompleteMe 优于内置自动补全的几个重要功能。
-
支持程序语言感知的自动语义补全;YouCompleteMe 更能理解代码的语义
-
补全建议的智能排序和过滤
-
能够显示代码文档、重命名变量、自动格式化代码以及修正某些类别的输入 错误(这个功能与具体的语言有关,参见官方 GitHub 仓库 Valloric/ YouCompleteMe)
-
安装 首先,确保安装了 cmake 和 llvm,因为 YouCompleteMe 需要编译代码
sudo apt-get install cmake llvm
如果使用 vim-plug 插件管理器,则可在.vimrc 中加入如下设置
let g:plug_timeout = 300 " 为 YouCompleteMe 增加 vim-plug 的超时时间 Plug 'Valloric/YouCompleteMe', { 'do': './install.py' }
保存.vimrc,然后执行如下命令
:source $MYVIMRC | PlugInstall
-
使用 YouCompleteMe YouCompleteMe 并没有新增太多快捷键,因此读者比较容易适应。(进入插入模式, 开始编辑。),自动补全列表会自动弹出来。按 Tab 键会循环遍历所有建议。此外, 如果 YouCompleteMe 能够查找函数定义,并且找到的函数支持文档字符串,则会在窗口 顶部显示一个预览窗口.
预览窗口只在 YouCompleteMe 使用语义自动补全引擎时显示。语义自动补 全引擎可通过在插入模式下输入句点.来启动,或者通过 Ctrl +空格组合 键来手动启动
4.2 撤销树和Gundo
大部分现代编辑器都支持撤销栈,其中保存了撤销和重做操作的历史记录。Vim 则 更进一步,采用了撤销树。如果读者执行修改操作 X,然后撤销并执行另一修改操作 Y, X 却仍然被保存起来了。Vim 支持手动浏览撤销树的叶子结点,但还有更好的方式。
Gundo 是一种对撤销树进行可视化的插件,读者可以在 GitHub 上找到。
如果使用 vim-plug 管理插件,请在.vimrc 中添加 Plug 'sjl/gundo.vim'。执行:w | so $MYVIMRC | PlugInstall,即 可成功安装 Gundo。
本章小结
本章介绍了 Vim 中的一些高级工作流程。首先,本章介绍了如何利用 Vim 的内置自 动补全功能来进行代码自动补全。然后,本章推荐了插件 YouCompleteMe,它能够通过 识别语法来辅助自动补全。此外,对于更复杂的代码库,可以使用 Exuberant Ctags 工具。 最后,本章介绍了撤销树和 Gundo 插件,可以让读者更直观地浏览撤销树。
第五章 构建、测试和执行
主要内容
本章重点介绍版本控制及相关流程和代码的构建及测试,具体包括如下几个方面
-
介绍版本控制的相关知识(主要是 Git)
-
介绍如何高效地将 Git 和 Vim 结合起来
-
用 vimdiff 来比较和合并文件,以及处理 Git 冲突
-
用 Tmux、Screen 或 Vim 终端模式来执行多任务和 Shell 命令
-
用快速提示列表和位置列表捕获警告和错误
-
用内置的:make 命令或插件构建和测试代码
-
手动或用插件来运行语法检查器
5.1 版本控制
5.1.1 git基本操作
-
安装
$ sudo apt-get install git
-
配置用户名和邮件地址
$ git config --global user.name 'Your Name' $ git config --global user.email 'your@email'
-
Git 文档查看
$ git help
-
初始化仓库
$ cd animal_farm/ $ git init
-
将文件添加到暂存区
$ git add
-
创建初始提交
$ git commit -m "初始提交"
-
添加远程仓库
$ git remote add origin <url>
-
将本地仓库推送(push)到远程仓库
$ git push -u origin master
-
克隆已有仓库
$ git clone <url>
-
查看状态
$ git status
-
创建分支
$ git checkout -b <branch-name>
-
查看分支
$ git branch -a
-
切换分支
$ git checkout <branch-name>
-
合并分支
# 切换回主分支 $ git checkout master # 合并分支 $ git merge <branch-name>
5.1.2 Git 与 Vim 的整合(vim-fugitive)
Tim Pope 的 vim-fugitive 插件可以使用户在不离开 Vim 的情况下进行 Git 操作。读 者在使用 Vim 编辑文件时,也可以同时利用版本管理系统记录编辑的位置
如果使用 vim-plug 安装插件,则可以在.vimrc 中添加 Plug 'tpope/vim-fugitive',并执行命令:w | source $MYVIMRC | PlugInstall。
5.2 用vimdiff解决冲突
在开发过程中,经常需要比较不同文件之间的差异,比如比较不同的输出,或者比 较一个文件的不同版本,或者处理合并时的冲突。Vim 提供了一个独立的可执行程序 vimdiff,非常适用于对比文件差异。
5.2.1 比较两个文件
用 vimdiff 比较两个文件是非常简单的。以 animal_farm 目录中的 animals/ cat.py 和 animals/dog.py 为例,下面用 vimdiff 比较它们之间的差异。
用 vimdiff 打开多个文件的命令行,如下所示
$ vimdiff animals/cat.py animals/dog.py
-
可以用]c 和[c 分别在多个修改处之间向前和向后跳转
-
可以在不同文件之间推送修改。 do 或:diffget(do 表示 diff obtain,即获得差异的意思)将文件修改应用于当 前窗口中的文件。 dp 或:diffput(dp 表示 diff put,即推送差异的意思)将当前窗口中的文件修 改推送给另一个文件。
5.2.2 vimdiff和Git组合
个人感觉不适用,不记录
5.3 其他终端工具(Tmux、Screen 和 Vim 的终端模式)
-
推荐使用Tmux
-
Screen 是 Tmux 的思想先驱,但它现在仍然有很多用户。Screen 的可扩展性不如 Tmux, 事实上,若不经过一番配置,Vim 和 Screen 是不能和谐共处的。不过,如果已经习惯使用 Screen,又不想改变现有的工作流程,那么本节的一些技巧可让两者更融洽地相处。
-
在 8.1 版本中,Vim 中有了终端模式。终端模式是 Vim 会话中运行的一个终端模拟 器。和 Tmux 不同,终端模式是 Vim 自带的。当一个程序需要运行很长时间时,终端模 式是很有帮助的,因为用户可以同时使用 Vim 进行其他操作。 终端模式可以用命令:term 启动。它会打开一个上下分割的窗口,然后在其中运行 默认的 Shell 解释器
本章小结
本章介绍了(或回顾了)Git 的使用方法,包括 Git 的核心要领、如何新建/克隆工 程以及几个常用的命令。同时还介绍了 vim-fugitive 插件,这个工具让用户在 Vim 中以 一种更具有交互性的方式使用 Git。
本章介绍了 vimdiff,它是 Vim 自带的工具,用于比较多个文件的差异或在文件之间 消除差异。此外,本章中还展示了如何解决 Git 分支合并时的冲突,优化了用户体验。
本章介绍了在 Vim 中运行 Shell 命令的几种不同方式,包括 Tmux、Screen 和 Vim 终端模式。
本章还介绍了(全局的)快速恢复列表和(局部的)位置列表,它们都用于保存文 件中某些行的引用。将它们与:grep 和:make 命令的输出结合起来,可以方便用户浏览。 然后,本章解析了:make 命令是如何调用外部编译器的、使用 vim-dispatch 插件来扩 展:make 命令功能的方法,以及利用 vim-test 来更流畅地运行测试的技巧
最后,本章还推荐了几种在 Vim 中检查语法的方案,包括为 Pylint 定制自己的检查 方案。另外还有两个插件,异步语法检查器 ALE 和流行的 Syntastic。
第六章 用正则表达式和宏来重构代码
主要内容
本章重点关注 Vim 提供的一些代码重构功能,包括如下几个方面。
-
使用:substitute 进行搜索或替换
-
使用正则表达式进行更智能化的搜索和替换
-
使用参数列表(arglist)对多个文件进行操作
-
提供代码重构操作的示例,比如方法的重命名和参数的重排序
-
介绍宏的用法,宏可用于录制键盘动作,并回放
6.1 用正则表达式来搜索和替换
61.1 搜索和替换
Vim 通过:substitute 命令实现搜索和替换功能,大部分时候都会将其简写为:s。 默认情况下,:s 命令将当前行中的一个子字符串替换为其他字符串,其命令形式如下。
:s/<find-this>/<replace-with-this>/<flags>
<选项>参数是可选的。打开 animal_farm.py 文件,体验此命令。跳转到包含 cat 的行(如用搜索命令/cat),然后执行:s/cat/dog 命令。
:substitute 的一些选项。
-
g 表示全局替换,即将匹配到的所有项都替换掉,而不仅仅是第一个
-
c 表示每次替换前需要确认,即弹出一个界面供用户确认是否替换。
-
e 表示没有匹配项时不显示错误。
-
i 表示忽略大小写,即搜索时不关心大小写。
-
I 表示区分大小写
这些选项可以根据需求结合起来使用(除了 i 和 I 之外)。比如,命令:s/cat/dog/gi 会将字符串 cat.Cat()替换为 dog.dog()
:substitute 命令可以作用于一个区间范围,即哪些内容中的匹配项会被替换掉。 常用的范围是%,它使:s 命令作用于整个文件。 如果要将一个文件中的所有 animal 替换成 creature,则只需要执行:%s/ animal/creature/g 命令。
:substitute 还支持其他区间范围,常用的有以下几种。
-
数字,表示行号
-
$表示最后一行
-
%表示整个文件(最常用的一种)
-
/search-pattern/,即在下一个搜索结果所在的行操作
-
?backwards-search-pattern?,与/search-pattern/功能类似,只不 过是反向搜索
6.2 宏的录制和回放
宏是一种非常强大的工具,它支持录制一系列动作,然后用于回放。
使用方法:
用命令 q 进入宏录制模式,后面是任意寄存器,即 qa 命令(这里用的是寄存器 a)。然后,我们可以在状态栏中看到 recording @a 的字样,表示宏已经开始录制。
之后的每一个移动操作或编辑操作都会在宏模式下被记录下来,在回放时被重复。 这也是需要录制宏的原因,在宏模式下的每一个移动或编辑操作都需要考虑到后续的 回放。
录制过程完成。按 q 键退出宏录制过程,可以看到状态栏中的 recording @a 字样 已经消失了。
我们可以用@a 命令回放这个宏
@@是一个不错的快捷方式,它可以回放最后一次运行的宏
6.2.1 宏的编辑
宏被保存在寄存器中,与复制和粘贴操作使用的寄存器基本没有区别。可以 用:reg 命令来查看每个寄存器中的内容。
我们可以在列表的中间位置看到"a,即保存宏的寄存器。查看这个寄存器内容的命 令为:echo @a
事实上,宏和寄存器没有区别,只不过,读者可以用 q 命令往寄存器中附加按键, 而@命令则重复执行寄存器中的按键序列。
既然宏也相当于一个寄存器,读者可以用 p 命令来将其粘贴出来。用:new 命令打 开一个新的缓冲区,并用"ap 命令将寄存器中的宏粘贴出来
用户就可以自由编辑宏的内容,而无须将整个过程重新操作一遍
编辑完成之后,可以将其复制回原来的寄存器,命令为"ay$。表示回到行首, "a 表示使用寄存器 a 来复制,而 y$表示复制整行,直到行尾为止。
总之,我们用"ap 将寄存器 a 中的内容粘贴出来,编辑完成后再用_"ay$将修改后 的内容重新放回这个寄存器。
6.3 用插件来实现代码重构
本章小结
本章主要介绍了:substitute 命令和宏,这是代码重构中会用到的两种强大的 工具。
首先,本章中介绍了:substitute 命令及其选项。同时还介绍了参数列表,它可 以用于在多个文件中执行一条命令。
:substitute 命令还支持正则表达式,这是一种比简单字符串匹配更强大的工具, 能够使用户获得更轻松的使用体验。
本章中介绍了正则表达式的基础知识和 Vim 的魔法 模式(解析含正则表达式字符串的 3 种不同方式)。
然后,本章中还介绍了宏,宏用于录制用户的键盘操作,读者可以在必要时回放一 个宏。宏和寄存器的编辑方式一样,还可以递归调用,实现任意次数的重复执行。
第七章 定制自己的Vim
主要内容
本章介绍 Vim 定制,以及提高 Vim 易用性的方法。每个人的需求是不同的,本章的 目标就是帮助读者拥有自己的风格
-
Vim 的配色和界面美化
-
定制 Vim 的状态栏,以显示更多信息
-
针对 gVim 的图形用户界面的配置
-
定制工作流程时的健康习惯
-
组织.vimrc 的方法学
7.1 Vim用户界面
Vim 用户界面是可扩展的,读者可以改变 Vim 的主题,修改某些界面元素的显示方 式,并且增强状态栏中的信息显示。此外,gVim 还有更多其他可定制选项。
7.1.1 配色
Vim 中可以使用多种配色,一部分是 Vim 自带的,一部分则由社区成员提供
读者可以通过在.vimrc 中设置 colorscheme 来设置配色,如下所示
:colorscheme elflord
通过执行:colorscheme Ctrl + d 命令,可以看到当前安装的配色列表(这里 的 Ctrl + d 表示快捷键)
上面的例子中,使用的是:colorscheme PaperColor,它来自于 GitHub 仓库 NLKNguyen/papercolor-theme。
读者可以进一步定制配色,修改其背景色,即将 background 选项设置为 light 或 dark(必须在设置 colorscheme 之前完成)。
7.1.2 常见问题
有时候,读者会发现自己正在试用的配色并没有示例图片看起来那么漂亮,而且颜 色数目好像也不够多。
最可能的原因是终端模拟器错误地告诉 Vim 它只支持 8 种颜色,而现代终端模拟器 普遍支持 256 种颜色。为解决这个问题,读者需要正确地设置$TERM 环境变量。
这种情况极有可能发生在 Tmux 和 GNU Screen 中,因为它们错误地汇报了颜色数目。
为查看环境变量$TERM 当前的值,可运行如下命令。
$ echo $TERM
如果使用 Tmux,则在.tmux.conf 中添加如下设置。
set -g default-terminal "xterm-256color"
如果使用 GNU Screen,则在.screenrc 中添加如下设置。
term "xterm-256color"
如果上述方法还不奏效,则在.bashrc 中添加如下设置。
TERM=xterm-256color
不过在.bashrc 中修改$TERM 绝不是什么好主意。读者可以自行研究擅自修改 $TERM 会有什么后果
7.2 状态栏
状态栏是屏幕底部用于显示信息的一个区域。通过下列简单的设置,可以使状态栏 更加符合用户要求。
" 总显示状态栏(默认情况下,有时会隐藏) set laststatus=2 " 在状态栏中显示最后执行的命令 set showcmd
如果读者想深度定制状态栏,则可以使用插件。这里介绍两款插件(Powerline 和 Airline),其中 Powerline 是强大的“全家桶”,而 Airline 则更为轻量级。
7.2.1 Powerline
powerline 为 Vim 提供了增强版的状态栏,而且还有其他功能,比如扩展 Shell 命令 提示符或 Tmux 状态栏。此插件的 GitHub 仓库为 powerline/powerline
Powerline 提供的状态栏中包含了大量的信息,包括当前模式、Git 分支、 当前文件状态、文件类型、编码,以及光标所在的位置。这个状态栏是可定制的,需要 显示多少信息可由读者自行决定。
不过,这个插件的安装有些麻烦,因为它不仅仅是一个 Vim 插件。首先,需要通过 pip 安装 Python 包 powerline-status。
$ python3 -m pip install powerline-status
然后,还需要确保$HOME/.local/bin 目录在系统 PATH 路径列表中,即 在.bashrc 中添加以下代码。
最后,将 laststatus 设置为 2(确保状态栏不会隐藏),并在~/.vimrc 中加载 Powerline。
" 总显示状态栏(默认情况下,有时会隐藏) set laststatus=2 " 加载 Powerline python3 from powerline.vim import setup as powerline_setup python3 powerline_setup() python3 del powerline_setup
7.2.2 Airline
如果读者不需要过多的功能,也不希望 Python 程序一直在后台运行,那么 Airline 是更好的选择
Airline 的 GitHub 仓库为 vim-airline/vim-airline,它不需要任何依赖项。
7.3 配置文件的同步
正常情况下,我们不会在十年后使用同一台计算机,每个人也有可能同时使用多台 计算机。因此,有必要在多个环境之间同步 Vim 的配置文件。
一般而言,文件的同步方式有很多,人们通常会将文件存储在一个 Git 仓库中[这 些配置文件常常称为点文件(dotfiles),这是因为 Linux 系统中的配置文件常常是主目录 下以句点开头的隐藏文件],并在主目录中用符号链接文件指向点文件目录中的相应文 件。读者只需要正常地执行 Git 操作(如 commit/push/pull),就可以使不同机器上的配 置文件保持同步。
比如,下面是一种常用的修改配置文件的流程(Linux 和 macOS 系统中的点文件存储 在$HOME/.dotfiles 中,Windows 系统中则存储在%USERPROFILE%_dotfiles 中)。
$ cd ~/.dotfiles $ git pull --rebase # 执行修改操作,比如编辑.vimrc $ git commit -am "某个重要更新" $ git push
比如,~/dotfiles 中有一个配置文件的仓库,其中包含.vimrc 文件和.gVimrc 文件,还有一个.vim 目录。然后,读者可以手动创建符号链接,命令为 ln -s ~/dotfiles/.vimrc .vimrc。也可以用如下 Python 脚本实现。
import os dotfiles_dir = os.path.join(os.environ['HOME'], 'dotfiles') for filename in os.listdir(dotfiles_dir): os.symlink( os.path.join(dotfiles_dir, filename), os.path.join(os.environ['HOME'], filename))
7.4 健康的Vim定制习惯
使用 Vim 的时间越长,就会发现配置文件的改动也越来越频繁。以至于.vimrc 文 件最后变成了也许用不到的别名、函数和插件,用户再也无法思考真正的需求。
因此,定期查看.vimrc,并清理掉多余的函数、插件以及快捷键绑定是一件有必 要的事。如果不清楚一个配置项的目的,最好将它删除
每个人的工作流程都是独一无二的,没有两个人能同时走出一条完全相同的 Vim 轨 迹。可以想办法填补读者的 Vim 使用风格的缺陷,并改善自己使用 Vim 的工作方式
第八章 卓尔不凡的Vimscript
Vimscript,这是 Vim 内置的一种强大的脚本语言
第九章 Neovim
Neovim 是 Vim 的一个分支,它的目标是使 Vim 的核心开发者更便捷地维护 Vim,同 时使插件更易于开发和集成。本章主要包括以下内容。
-
Neovim 的重要性
-
Neovim 如何安装和配置
-
Neovim 和 Vim 配置文件的同步
-
Neovim 独有的插件
9.1 为什么需要另外一种VIM
-
Vim 的代码库已经有多年的历史,维持向后兼容是非常困难的。
-
编写某些 Vim 插件比较困难,特别是异步操作,这是 Vim 长期以来的痛点(从 Vim 8 开始,Vim 开始支持异步操作,但这已经是 Neovim 出现之后的事了)。
-
事实上,不仅是异步操作,编写 Vim 插件也不太容易,而且要求开发者熟悉 Vimscript
-
在现代操作系统中,如果没有一个编写好的.vimrc,那么 Vim 使用起来会比较 困难
Neovim 从如下几个方面来解决这些问题。
-
大刀阔斧重构 Vim 的代码库,包括使用单一的编码风格和增加测试的覆盖率。
-
放弃对旧系统的支持
-
使用适应于现代系统的默认设置
-
提供丰富的插件开发 API,支持与外部程序的通信,包括对 Python 和 Lua 脚本 的支持
Vim 被安装到了大量各式各样的系统中,因此向后兼容且适应各种特殊情况需要重 点考虑。而在新的分支上,Neovim 就没有这个负担,可以不断进行各种尝试和改进,而 且能够促使 Vim 变得更好。
Neovim 的重要性体现在它可以更容易地增加新功能,插件的开发也更方便,因此 有希望吸引更多的开发者,并吸收更多新的思考和想法,从而让这个编辑器有更好的 发展
9.2 Neovim的安装和配置
Neovim 及其安装方法可以在其 GitHub 仓库 neovim/neovim 中找到。读 者既可以下载二进制安装包,也可以通过包管理器安装。由于网上的安装 过程已经非常详尽,而且更新非常快,因此建议读者安装之前先浏览该仓 库中的 wiki/Installing-Neovim 文件。 对于 Debian 系列的 Linux 发行版,可以通过$ sudo apt-get install neovim 安装 Neovim,并用 Python3 -m pip install neovim 来实 现 Neovim 对 Python 3 的支持。
安装好 Neovim 之后,启动 Neovim 的命令为$ nvim。我们可以看到 Vim 界面,看起来与 Vim 并没有太大区别。
所有 Vim 命令都可以在 Neovim 中使用,Neovim 的配置文件格式也与 Vim 相同。不过,.vimrc 在 Neovim 中不会自动加载。
Neovim 的配置文件遵守 XDG 基本目录结构,即所有的配置文件都放在~/.config 目录中。Neovim 的配置文件被保存在~/.config/nvim 中。
~/.config/nvim/init.vim 对应于~/.vimrc。 ~/.config/nvim/对应于~/.vim/。
读者可以直接将 Neovim 的配置文件链接到 Vim 的配置文件。
$ mkdir -p $HOME/.config $ ln -s $HOME/.vim $HOME/.config/nvim $ ln -s $HOME/.vimrc $HOME/.config/nvim/init.vim
做好上述软连接之后,Neovim 就可以加载原来的.vimrc 文件了
9.2.1 检查健康状态
Neovim 欢迎界面中,Neovim 提示用户运行:checkhealth 命令.Neovim 的健康检查会汇报当前 Neovim 设置中的所有错误,并给出修复的建议。读 者应该查看检查结果,并修复相关的错误。
读者可通过查看:help nvim-defaults 了解 Neovim 的默认选项。
9.2.2 合理的默认选项
Neovim 的默认选项与 Vim 有很大的不同。在现代的计算机世界里,文本编辑器的 默认值需要对用户比较友好。默认情况下 Vim 的.vimrc 文件并不包含任何默认设置, 而 Neovim 默认已经设置好语法高亮、合理的缩进设置、wildmenu、高亮显示搜索结果 和增量搜索(incsearch)等
如果读者想要同步 Vim 和 Neovim 的配置文件,则最好是在~/.vimrc 中加入如下 设置(然后再将其链接为~/.config/nvim/init.vim)。
if !has('nvim')
set nocompatible " 与 Vi 不兼容
filetype plugin indent on " 对现在的插件是必须的
syntax on " 语法高亮
set autoindent " 沿用上一行缩进
set autoread " 从磁盘自动重载文件
set backspace=indent,eol,start " 现代编辑器的退格键行为
set belloff=all " 禁用错误报警声
set cscopeverbose " 详细输出 cscope 结果
set complete-=i " 补全时,不要对当前被包含的文件进行扫描
set display=lastline,msgsep " 显示更多消息文本
set encoding=utf-8 " 设置默认编码
set fillchars=vert:|,fold: " 分隔字符
set formatoptions=tcqj " 更直观的自动格式化
set fsync " 调用 fsync()实现更健壮的文件保存
set history=10000 " 最大的历史记录数
set hlsearch " 搜索结果高亮显示
set incsearch " 搜索时边输入边搜索、并移动光标
set langnoremap " 避免出现映射崩溃的情况
set laststatus=2 " 总是显示状态栏
set listchars=tab:>\ ,trail:-,nbsp:+ " :list 时一些特殊字符的显示
set nrformats=bin,hex " 对<c-a>和<c-x>的支持
set ruler " 在状态栏角落里显示当前行位置信息
set sessionoptions-=options " 不同会话不共享选项
set shortmess=F " 文件信息少显示一些
set showcmd " 在状态栏中显示最后一条命令
set sidescroll=1 " 更平滑的侧边滚动条
set smarttab " 更智能的<Tab>键响应方式
set tabpagemax=50 " -p 选项能够打开的最大数目的标签页
set tags=./tags;,tags " 用于搜索标签的那些文件名
set ttimeoutlen=50 " 按键序列中等待下一个的时间,单位为毫秒
set ttyfast " 要求实现快速的终端连接
set viminfo+=! " 为多个会话保存全局变量
set wildmenu " 增强命令行补全功能
endif
9.3 Oni
Oni 是基于 Neovim 实现的跨平台图形用户界面编辑器, GitHub 仓库为 onivim/oni。该编辑器为 Neovim 增加了集成开发环境(IDE)的功能,包括一个内置 的浏览器、原生支持的自动补全和模糊搜索、一个命令菜单以及多种教程,还有明显提 升用户体验的其他功能,而且它还沿用了 Neovim 的配置文件和键盘绑定。
第十章 延伸阅读
本章作为总结,旨在为读者提供一些思考,主要包括以下内容
-
健康的文本编辑习惯(来自于 Bram Moolenaar 的讲稿)
-
在 Vim 之外使用基于模式的界面,包括集成开发环境(IDE)、浏览器,等等
-
推荐几个 Vim 社区和一些参考资料
10.1 高效文本编辑的7个习惯
本节为 Bram Moolenaar 在 2000 年发表的文章及讲稿的摘要,介绍了高效编辑的 7 个习惯。
-
快速移动光标
-
避免重复输入
-
发现错误马上修改
-
学会同时处理多个文件
-
学会组合使用多种工具
-
用结构化思想去理解文本
-
坚持好的做法并养成习惯
因为开发者需要花大量时间阅读和编辑代码,所以 Bram 的 7 个习惯实际上可以进 一步总结为改进文本编辑能力的三步法。
1.发现低效
2.提高效率
3.形成习惯
1.发现低效:移动光标需要花费很多时间。
2.提高效率:通常,用户移动光标是为了找到某些已经存在的文本。读者可以通过 搜索文本来移动光标,或者进一步采用如下策略。
用*来搜索光标下的单词
用:set incsearch 实现输入即搜索
用:set hlsearch 高亮显示每个匹配项
3.形成习惯:练习学到的技能,在.vimrc 设置 incsearch 和 hlsearch。需要 用/搜索光标附近的单词时,改用*