回炉-vim实用技巧-vim模式

  |  

摘要: 本文是《vim实用技术》读书笔记的第 2 部分: vim 模式。

【对算法,数学,计算机感兴趣的同学,欢迎关注我哈,阅读更多原创文章】
我的网站:潮汐朝夕的生活实验室
我的公众号:算法题刷刷
我的知乎:潮汐朝夕
我的github:FennelDumplings
我的leetcode:FennelDumplings


vi-vim-cheat-sheet-sch.gif

《vim使用技巧》 【vim模式】部分,一共 4 个模式 31 个技巧

  • Chap2 普通模式
    • 技巧7 停顿时请移开画笔
    • 技巧8 把撤销单元切成块
    • 技巧9 构造可重复的修改
    • 技巧10 用次数做简单的算术运算
    • 技巧11 能够重复,就别用次数
    • 技巧12 双剑合璧,天下无敌
  • Chap3 插入模式
    • 技巧13 在插入模式中可即时更正错误
    • 技巧14 返回普通模式
    • 技巧15 不离开插入模式,粘贴寄存器中的文本
    • 技巧16 随时随地做运算
    • 技巧17 用字符编码插入非常用字符
    • 技巧18 用二合字母插入非常用字符
    • 技巧19 用替换模式替换已有的文本
  • Chap4 可视模式
    • 技巧20 深入理解可视模式
    • 技巧21 选择高亮选区
    • 技巧22 重复执行面向行的可视命令
    • 技巧23 只要可能,最好用操作符命令,而不是可视命令
    • 技巧24 用面向列块的可视模式编辑表格数据
    • 技巧25 修改列文本
    • 技巧26 在长短不一的高亮块后添加文本
  • Chap5 命令行模式
    • 技巧27 结识 Vim 的命令行模式
    • 技巧28 在一行或多个连续行上执行命令
    • 技巧29 使用:t:m命令复制和移动行
    • 技巧30 在指定范围上执行普通模式命令
    • 技巧31 重复上次的 Ex 命令
    • 技巧32 自动补全Ex命令
    • 技巧33 把当前单词插入到命令行
    • 技巧34 回溯历史命令
    • 技巧33 把当前单词插入到命令行
    • 技巧34 回溯历史命令
    • 技巧35 运行 Shell 命令

普通模式

技巧7 停顿时请移开画笔

就像画家只花一小部分时间涂色一样,程序员也只花一小部分时间编写代码。绝大多数时间用来思考、阅读,以及在代码中穿梭浏览。

技巧8 把撤销单元切成块

在 Vim 中,我们自己可以控制撤销的粒度。

从进入插入模式开始,直到返回普通模式为止,在此期间输入或删除的任何内容都被当成一次修改。因此,只要我们控制好对 <Esc> 键的使用,就可使撤销命令作用于单词、句子或段落。

当处于插入模式时,如果光标位于行尾的话,另起一行最快的方式是按 <CR> 。不过有时我更喜欢按 <Esc>o ,这是因为我有预感,也许在撤销时我想拥有更细的粒度。

在插入模式中移动光标会重置修改状态

当我提到撤销命令会回退从进入插入模式到退出此模式期间输入(或删除)的全部字符时,我略过了一个小细节。如果在插入模式中使用了 <Up><Down><Left><Right> 这些光标键,将会产生一个新的撤销块。你可以把这想象为先切换回普通模式,然后用 h 、 j 、 k 或 l 命令对光标进行了移动,唯一区别是我们并没有退出插入模式。这也会对 . 命令的操作产生影响。

技巧9 构造可重复的修改

在 Vim 中,要完成一件事,总是有不止一种方式。在评估哪种方式最好时,最显而易见的指标是效率,即哪种手段需要的按键次数最少 — 又名 vimgolf(http://vimgolf.com/)

技巧10 用次数做简单的算术运算

很多普通模式命令都可以带一个次数前缀

<C-a><C-x> 命令分别对数字执行加和减操作。在不带次数执行时,它们会逐个加减,但如果带一个次数前缀,那么就可以用它们加减任意整数。

数字的格式

那么当你尝试对任意以 0 开头的数字使用 <C-a> 命令时, 也许会感到诧异。像在某些编程语言中的约定一样,Vim 把以 0 开头的数字解释为八进制值,而不是十进制。

Vim 的缺省行为或许会适合你。如果不是这样,那么你可能想把下面这行加入你的 vimrc 里:

1
set nrformats=

技巧11 能够重复,就别用次数

次数风格( d5w ) vs. 重复风格( dw.... )

现在假设我们想删除 7 个单词,我们可以运行 d7w ,或是 dw...... (即 dw 后面跟 6 次 . 命令)。计算一下按键的次数,哪个命令胜出是很显而易见的。不过你真地确信自己数对了次数吗?

计算次数很是讨厌,因此我宁愿按 6 次 . 命令,也不愿意只为减少按键的次数,而浪费同样的时间去统计次数。如果我多按了一次 . 命令怎么办?没关系,只要按一次 u 键就可以回退回来。

只在必要时使用次数。

技巧12 双剑合璧,天下无敌

操作符 + 动作命令 = 操作

d{motion} 命令可以对一个字符( 1dl )、一个完整单词( daw )或一整个段落( dap )进行操作,它作用的范围由动作命令决定。 c{motion}y{motion} 以及其他一些命令也类似,它们被统称为操作符(operator)。可以用 :h operator 查阅

g~gugU 命令要用两次按键来调用,我们可以把上述命令中的 g 当做一个前缀字符,用以改变其后面的按键行为,进一步的讨论请参见本技巧最后的“结识操作符待决模式”部分

学习新的动作命令及操作符,就像是在学习 Vim 的词汇一样。如果掌握了这一简单的语法规则,在词汇量增长时,就能表达更多的想法。

假如我们已经知道如何用 daw 删除一个单词,然后又学到 gU 命令(参见 :h gU )。它也是个操作符,所以我们可以用 gUaw 把当前单词转换成大写形式。

Vim 的语法只有一条额外规则,即当一个操作符命令被连续调用两次时,它会作用于当前行。所以 dd 删除当前行,而 >> 缩进当前行。 gU 命令是一种特殊情况,我们既可以用 gUgU ,也可以用简化版的 gUU 来使它作用于当前行。

自定义操作符与已有动作命令协同工作

如何创建自定义操作符 :h map-operator

操作符待决模式

普通、插入及可视模式很容易辨识,但是 Vim 还有另外一些很容易被忽视的模式,操作符待决模式(Operator-Pending mode)就是一个例子。在我们执行命令 dw 时,就会激活该模式。这一模式只在按 dw 键之间的短暂时间间隔内存在,一眨眼工夫就不见了。

如果我们把 Vim 想象成有限状态机,那么操作符待决模式就是一个只接受动作命令的状态。这个状态在我们调用操作符时被激活,然后什么也不做,直到我们提供了一个动作命令,完成整个操作。当操作符待决模式被激活时,我们可以像平常一样按 <Esc> 中止该操作,返回到普通模式。

很多命令都由两个或更多的按键来调用, 但在多数情况下,头一个按键只是第二个按键的前缀。这些命令不会激活操作符待决模式,相反,可以把它们当成命名空间(namespace),用来扩充可用命令的数目。只有操作符才会激活操作符待决模式。

插入模式

尽管删除、复制以及粘贴命令都是在普通模式中执行的,不过我们将会看到一种方便快捷的方式,让我们无需离开插入模式就能粘贴寄存器中的文本。另外我们也会学习 Vim 所提供的两种简单方式,用来插入键盘上不存在的非常用字符。

技巧13 在插入模式中可即时更正错误

在插入模式下,退格键的作用如你所愿,它删除光标前的字符。另外,我们还可以用下面这些组合键:

技巧14 返回普通模式

Vim 区分模式的特点在下面这种特定场景中却显得有点烦琐: 当我们处于插入模式时,想运行一个普通模式命令,然后马上回到原来的位置继续输入。Vim 为此提供了一种巧妙的方法,以减少模式切换所带来的不畅, 这就是插入-普通模式。

<C-o> 进入

在当前行正好处于窗口顶部或底部时,有时我会滚动一下屏幕,以便看到更多的上下文。用 zz 命令可以重绘屏幕,并把当前行显示在窗口正中,这样就能够阅读当前行之上及之下的半屏内容。我常常会键入 <C-o>zz ,在插入-普通模式中触发这条命令。此操作完成后就会直接回到插入模式,因此我可以不受中断地继续打字。

技巧15 不离开插入模式,粘贴寄存器中的文本

注意大小写转换键的威胁

yt 命令把“Practical Vim”复制到复制专用寄存器中(我们将在技巧 49 中结识t{char} 动作命令),然后我们在插入模式中,按 <C-r>0 把刚才复制的文本粘贴到光标所在位置

这个命令一般的格式是 <C-r>{register} ,其中 {register} 是我们想要插入的寄存器的名字

在插入模式中,<C-r>{register} 命令如果寄存器中包含了大量的文本,你也许会发现屏幕的更新有些轻微的延时。这是因为 Vim在插入寄存器内的文本时,其插入方式就如同这些文本是由键盘上一个个输进来的。因此,如果 ‘ textwidth ’ 或者‘ autoindent ’ 选项被激活了的话,那么最终就可能会出现不必要的换行或额外的缩进。

<C-r><C-p>{register} 命令则会更智能一些,它会按原义插入寄存器内的文本, 并修正任何不必要的缩进。

不过这个命令有点不太好输入!因此,如果我想从一个寄存器里粘贴很多行文本的话,我更喜欢切换到普通模式,然后使用某个粘贴命令(参见技巧 62)。

技巧16 随时随地做运算

表达式寄存器则是个另类,它可以用来执行一段 Vim 脚本,并返回其结果。在本节,我们将把它当成计算器来用。

我们可以用 = 符号指明使用表达式寄存器。在插入模式中,输入 <C-r>= 就可以访问这一寄存器。

表达式寄存器远不止能做简单算术运算。我们将在技巧 70 中看到一些更高级的应用。

技巧17 用字符编码插入非常用字符

只要知道某个字符的编码,就可以让 Vim 插入该字符,我们可以用这种方式插入任意字符。要根据字符编码插入字符,只需在插入模式中输入 <C-v>{code} 即可,其中 {code} 是要插入字符的编码。

Vim 所接受的字符编码共包含 3 位数字。例如,假设我们想插入大写字母“A”,它的字符编码是 65,因此我们需要输入 <C-v>065

然而,如果我们想插入一个编码超过 3 位数的字符该怎么办?比方说,Unicode基本多文种平面(Unicode Basic Multilingual Plane)的地址空间最大会有 65535 个字符。解决方法是可以用 4 位十六进制编码来输入这些字符,即输入 <C-v>u{1234} (注意数字前的 u )。假设我们想插入字符编码为 00bf 的反转问号(“¿”),只需在插入模式中输入 <C-v>u00bf 即可。

如果你想知道文档中任意字符的编码,只需把光标移到它上面并按 ga 命令,然后屏幕下方就会显示出一条消息,分别以十进制和十六进制的形式显示出其字符编码

另外,如果 <C-v> 命令后面跟一个非数字键,它会插入这个按键本身所代表的字符。例如,如果启用了 ‘expandtab’ 选项,那么按 <Tab> 键将会插入空格而不是制表符。然而,按 <C-v><Tab> 则会一直插入制表符,不管 ‘expandtab’ 选项激活与否。

技巧18 用二合字母插入非常用字符

<C-k>{char1}{char2}

Vim 在选择组成二合字母的两个字符时,尽量使之具有描述性,这样就更容易记住它们,甚至也能猜出其含义。例如,左右书名号«和»分别以二合字母<<及>>表示, 普通分数(或常用分数)1⁄2、1⁄4和3⁄4则分别以二合字母 12、14 和 34 来表示。

Vim 的缺省二合字母集依从一定的惯例, :h digraphs-default 文档对此进行了总结。

用命令 :digraphs 可以查看可用的二合字母列表,不过该命令的输出不太好阅读。你也可以用 :h digraph-table 查看另一个更为有用的列表。

技巧19 用替换模式替换已有的文本

在替换模式中输入会替换文档中的已有文本,除此之外,该模式与插入模式完全相同。

R 命令可以由普通模式进入替换模式

如果你的键盘上有 <Insert> 键,那么你也可以用该键在插入模式和替换模式间切换

用虚拟替换模式替换制表符

某些字符会使替换模式变得复杂化。以制表符为例,在文件中它以单个字符表示, 但在屏幕上它却会占据若干列的宽度,此宽度由 ‘tabstop’ 设置决定

如果把光标移到制表符上,然后进入替换模式,那么我们所输入的下一个字符将会替换制表符。假设 ‘tabstop’ 选项设置为 8(这是缺省值),那么该操作的结果就是把 8 个字符替换成了一个字符,这将大幅缩短当前行的长度。

虚拟替换模式(Virtual Replace mode)。该模式可由 gR令触发,它会把制表符当成一组空格进行处理。假设我们把光标移到一个占屏幕 8 列宽的制表符上,然后切换到虚拟替换模式,在输入前 7 个字符时,每个字符都会被插入到制表符之前;最后,当输入了第 8 个字符时,该字符将会替换制表符。

在虚拟替换模式中,我们是按屏幕上实际显示的宽度来替换字符的,而不是按文件中所保存的字符进行替换。这会减少意外情况的发生,因此我建议在可能的情况下尽量使用虚拟替换模式。

Vim 也提供了单次版本的替换模式及虚拟替换模式。 r{char}gr{char} 命令允许我们覆盖一个字符,之后马上又回到普通模式

可视模式

Vim 具有 3 种不同的可视模式,分别用于操作字符文本、行文本或块文本。

技巧20 深入理解可视模式

选择模式

在一个典型的文本编辑器环境中,当选中一段文本后,再输入任意可见字符时,这些选中的文本将会被删除。虽然 Vim 的可视模式未遵从此惯例,但是其选择模式( Select Mode )却按此方式工作。根据 Vim 的内置文档所述,选择模式“类似于 MicrosoftWindows 的选择模式”(参见 :h Select-mode )。在此模式下,输入的可见字符会使所选中的文本被删除,同时 Vim 会进入插入模式,并插入这个可见字符。

<C-g> 可以在可视模式及选择模式间切换。切换后看到的唯一不同是屏幕下方的提示信息会在 “— 可视 —”( — VISUAL — )及“—选择—”( —SELECT— )间转换。但是,如果在选择模式中输入任意可见字符的话,此字符会替换所选内容并切换到插入模式。当然,如果是在可视模式中,你仍可以像往常一样用 c 键来修改所选内容。

这一模式的存在,只是为了迎合那些想让 Vim 更像其他文本编辑器的用户。我只知道有一处地方会用到选择模式。

技巧21 选择高亮选区

可视模式的 3 个子模式用于处理不同类型的文本。我们将在本节看到如何激活每种子模式,以及如何在它们之间切换。

在可视模式间切换

切换选区的活动端

高亮选区的范围由其两个端点界定。其中一端固定,而另一端可以随光标自由移动,我们可以用 o 键来切换其活动的端点。

技巧22 重复执行面向行的可视命令

高亮选区,用 >, < 控制缩进

Vj + > 执行多行缩进

技巧23 只要可能,最好用操作符命令,而不是可视命令

可视模式可能比 Vim 的普通模式操作起来更自然一些,但是它有一个缺点:在这个模式下 . 命令有时会有一些异常的表现。

例子:想把下面列表中的链接文字转换为大写格式:

可以用 vit 来选择标签里的内容。 vit 可被解读为高亮选中标签内部的内容(visually select inside the tag),其中, it 命令是一种被称为文本对象(text object)的特殊动作命令,参见技巧51

当一条可视模式命令被重复执行时,它会影响相同数量的文本(参见 :h visual-repeat )。在本例中,最初的命令影响了一个由 3 个字母组成的单词。在第二行它依旧工作得很好,因为该行恰好也包含一个由 3 个字母组成的单词。但是,当我们想对一个由 5 个字母组成的单词重复此命令时,它只成功转换了其中的前 3 个字母,留下 2 个字母未被转换。

可视模式下的 U 命令有一个等效的普通模式命令 :gU{motion}

这两种方式都只需要 4 次按键操作 : vitUgUit ,但其背后的含义却大相径庭。在可视模式所采用的方式里,这 4 次按键可以被当做两个独立的命令。 vit 用来选中选区,而 U 用来对选区进行转换。与之相反的是, gUit 命令可以被当成一个单独的命令,它由一个操作符( gU )和一个动作命令( it )组成。

技巧24 用面向列块的可视模式编辑表格数据

想画一条横线来分隔表头及其下的内容。我们先快速地复制顶行并粘贴一份副本( yyp ),然后再用连字符替换该行内的所有字符( Vr- )。

技巧25 修改列文本

<Ctrl-c> 选中后,c, 所有被选中的文本都消失了,同时我们进入了插入模式。

技巧26 在长短不一的高亮块后添加文本

在进入列块可视模式后,我们按 $ 键把选区扩大到每行的行尾。

确定好选区后,用 A 命令就可以在每行的结尾添加内容

Vim 对“i”及“a”键的约定Vim 对于从普通模式切换到插入模式的

Vim 对于从普通模式切换到插入模式的命令有几个约定, i 命令和 a 命令都完成此切换,并分别把光标置于当前字符之前或之后, I 命令和 A 命令的表现类似,只是它们分别把光标置于当前行的开头和结尾。Vim 对于从列块可视模式切换到插入模式的命令也遵从类似的约定。 I 命令和 A命令都完成此切换,并分别把光标置于选区的开头和结尾。那 i 和 a 命令呢,它们在可视模式里干什么?

在可视模式及操作符待决模式中, i 和 a 键沿用一个不同的约定。它们会被当作一个文本对象的组成部分,我们将在技巧 51 中深入探讨文本对象。如果你在列块可视模式里选中了一块区域,并且很奇怪为什么按 i 键没进入插入模式,那么换用 I 键试一下。

命令行模式

技巧27 结识 Vim 的命令行模式

在按下 : 键时,Vim 会切换到命令行模式。

出于历史原因,在命令行模式中执行的命令又被称做 Ex 命令

在我们按 / 调出查找提示符或用 <C-r>= 访问表达式寄存器(参见技巧 16)时,命令行模式也会被激活。

我们可以用 Ex 命令读写文件( :edit:write ),创建新标签页( :tabnew )及分割窗口( :split ),或是操作参数列表( :prev / :next )及缓冲区列表( :bprev / :bnext )。事实上,Vim 为几乎所有功能都提供了相应的 Ex 命令(参见 :h ex-cmd-index 可获得完整列表)。

本节中,我们主要关注那些用来编辑文本的 Ex 命令

Vim 命令行模式中的特殊按键

在这两种模式中都可以用组合键触发命令。有些命令在插入模式和命令行模式中可以通用。例如,可以用 <C-w><C-u>分别删除至上个单词的开头及行首,也可以用 <C-v><C-k> 来插入键盘上找不到的字符,还可以用 <C-r>{register} 命令把任意寄存器的内容插入到命令行

然而,有些命令行模式中的组合键在插入模式中不存在, 参考技巧33

在命令行提示符下,可以使用的动作命令数量很有限。 <left><right> 光标键可以一次把光标向左或右移动一个字符,与我们已经习以为常的普通模式下的大量动作命令相比,这让人感觉极度受限。然而,正如我们即将在技巧 34 中看到的那样, Vim 的命令行窗口提供了构造复杂命令所需的完整编辑能力。

有时使用 Ex 命令,能比用普通模式命令更快地完成同样的工作。

例子:普通模式命令一般操作当前字符或当前行,而 Ex 命令却可以在任意位置执行,这意味着我们无需移动光标就可以使用 Ex 命令做出修改。

但使 Ex 命令脱颖而出的最让人赞叹的功能,是它们拥有能够在多行上同时执行的能力。

Vim(及其家族)的词源

ed -> em, en, ex -> vi -> vim

技巧28 在一行或多个连续行上执行命令

很多 Ex 命令可以用 [range] 指定要操作的范围。我们可以用行号、位置标记或是查找模式来指定范围的开始位置及结束位置。

用行号作为地址

:3p(等于先 :3, 再:p)

用地址指定一个范围

:2,5p

符号 . 代表当前行的地址。因此,我们可以很容易地写出一个范围,用以代表从当前位置到文件末尾间的所有行:

:.,$p
符号 % 也有特殊含义,它代表当前文件中的所有行
:%p

用高亮选区指定范围

选定高亮选区后再:, 会预先填充成 :'<,'>(可以理解为代表高亮选区的范围)

如果只是想对文件的部分内容执行 :substitute 命令,用这种方式定义范围会很方便。

符号 '< 是代表高亮选区首行的位置标记,而 '> 则代表高亮选区的最后一行(关于位置标记,参考技巧53)

这些位置标记即使在退出可视模式后仍然存在。如果你尝试在普通模式下直接运行 :'<,'>p ,它会始终回显上一次高亮选区所选中的内容。

用模式指定范围

:/<html>/,/<\/html>/p

符合范围的一般形式 :{start},{end} 。在本例中, {start} 地址是模式 /<html>/ ,而 {end} 地址是 /<\/html>/ 。换句话说, 这个范围由 <html> 开标签所在的行开始,到对应闭标签所在的行结束。

用偏移对地址进行修正

假设我们想对位于 <html></html> 之间的每一行都运行一条 Ex 命令,但是不想包括 <html></html> 标签所在的行,那么可以为之加上偏移:

:/<html>/+1,/<\/html>/-1p
:.,.+3p

技巧29 使用‘:t’和‘:m’命令复制和移动行

:copy 命令(及其简写形式 :t )让我们可以把一行或多行从文档的一部分复制到另一部分,而 :move 命令则可以让我们把一行或多行移到文档的其他地方。

copy 命令格式

:[range]copy {address}

copy命令的一些例子

move命令格式, 简写为一个字母 :m

:[range]move {address}

技巧30 在指定范围上执行普通模式命令必知必会

如果想在一系列连续行上执行一条普通模式命令,我们可以用 :normal 命令。此命令在与 . 命令或宏结合使用时,我们只需花费很少的努力就能完成大量重复性任务。

把整个文件注释掉:
:%normal i//

既可以用 :normal . 应对简单的重复性工作, 也可以用 :normal @q 应对较复杂的任务。

技巧31 重复上次的 Ex 命令

. 命令可以重复上次的普通模式命令。然而,如果想重复上次的 Ex 命令的话, 我们得使用 @: 才行。

: 寄存器总是保存着最后执行的命令行命令
在运行过一次 @: 后,后面就可以用 @@ 命令来重复它。

技巧32 自动补全Ex命令

技巧33 把当前单词插入到命令行

技巧34 回溯历史命令

<C-d> 命令会让 Vim 显示可用的补全列表

另外还要<Tab><S-Tab>也可用

如果我们输入了一个以文件路径作为参数的命令(如 :edit:write ),那么 <Tab> 会用当前工作目录中的目录或文件名进行补全。在 :tag 命令中,它会自动补全标签名;而在 :set:help命令中,它可以对 Vim 的每一个设置选项进行补全。

甚至在我们创建自定义 Ex 命令时,也能够定义该命令的 Tab 键补全行为。参考 :h command-complete

调整 ‘wildmode’ 选项可以自定义补全行为

当 ‘wildmenu’ 选项被启用时,Vim 会提供一个补全导航列表。我们可以按<Tab><C-n><Right> 正向遍历其列表项, 也可以用 <S-Tab><C-p><Left> 对其进行反向遍历。

技巧33 把当前单词插入到命令行

Vim 也始终知道光标位于何处以及哪个分割窗口处于活动状态。

在 Vim 的命令行下, <C-r><C-w> 映射项会复制光标下的单词并把它插入到命令行中。

例子:

* 命令就可以查找它出现的每处地方( * 命令等效于输入 /\<<C-r><C-w>\><CR> 序列(关于 \<\> 在模式中的作用,参见技巧76)

当按下 * 键时,光标会正向跳到下一处匹配项,不过光标始终停留在相同的单词上。接下来,我们就可以输入 cwcounter<Esc> 对其进行修改。然后 , 我们将用 :substitute 命令完成其余的修改 。 由于光标已经在单词“counter”上了,因此我们无需再次输入它,而是直接用 <C-r><C-w> 映射项把它插入到替换域:

:%s//<C-r><C-w>/g

此处也用不着输入查找模式,而这要感谢 * 命令。要知道为什么可以像上面这样将查找域留空,请参考技巧 90。

技巧34 回溯历史命令

我们先按 : 键切换到命令行模式,在保持提示符为空的情况下按 <Up> 键(<Down>反向)

Vim 缺省会记录最后 20 条命令,对内存越发便宜的现代计算机来说,保存更多历史命令只是小菜一碟,因此我们可以修改 ‘history’ 选项,以提高其保存的上限。

set history=200

重启vim后,这些命令历史仍然存在

/ 查找时, 同样可用<Down>,<Up>,从本质上讲,查找提示符只是命令行模式的另一种形式。

结识命令行窗口

使用 q: 调出

命令行窗口就像是一个常规的 Vim 缓冲区,只不过它的每行内容都对应着命令历史中的一个条目。我们可以用 k 及 j 键在历史中向前或向后移动,也可以用 Vim 的查找功能查找某一行。在按下 <CR> 键时,将会把当前行的内容当成 Ex 命令加以执行。

我们可以用任何习以为常的动作命令进行移动,也可以在高亮选区上操作,或是切换到插入模式中。我们甚至还能对命令行窗口中的内容执行 Ex 命令。

当命令行窗口处于打开状态时,它会始终拥有焦点。这意味着,除非关闭命令行窗口,否则我们无法切换到其他窗口。要想关闭命令行窗口,我们可以执行 :q 命令

当我们在命令行窗口内按 <CR> 时,该命令在活动窗口的上下文中执行。活动窗口指的是在调出命令窗口前,处于活动状态的那个窗口。当命令行窗口处于打开状态时,Vim 并不会提示哪个窗口是活动窗口,因此如果你用了分割窗口的话,需要特别留意。

假设我们正在命令行上构建一条 Ex 命令,做到一半时,才意识到需要更强大的编辑能力,这时该怎么办呢?当处于命令行模式下时,我们可以用 <C-f> 映射项切换到命令行窗口中,此前已经输入到命令行上的内容仍然会得以保留。

打开命令行窗口的几种方式

技巧35 运行 Shell 命令

我们不用离开 Vim 就能方便地调用外部程序。更棒的是,我们还可以把缓冲区的内容作为标准输入发送给一个外部命令,或是把外部命令的标准输出导入到缓冲区里。

在 Vim 的命令行模式中, :! 可以调用外部程序

在 Vim 的命令行中,符号 % 代表当前文件名, 在运行那些操作当前文件的外部命令时,我们可以使用它。

Vim 也提供了一组文件名修饰符,让我们可以从当前文件名中提取出诸如文件路径或扩展名之类的信息,参考:h filename-modifiers

如果想在 shell 中执行几条命令,Vim 的 :shell 命令来启动一个交互的 shell 会话

:shell 命令是 Vim 提供的一个功能,它可以让我们切换到一个交互 shell 中。但是,如果 Vim 自身是在终端中运行的话,那么我们也能直接访问终端内置的 shell 命令。例如,bash shell 支持作业控制,让我们可以暂停一个作业,把它放到后台,然后在稍后某个时间再把它调回前台继续运行。

假设我们正在 bash shell 中运行 Vim,然后需要执行一些 shell 命令。我们可以先按 Ctrl-z 挂起 Vim 所属的进程,并把控制权交还给 bash。此时 Vim 进程在后台处于挂起状态,让我们可以像往常一样与 bash 会话进行交互。运行下面这条命令可以查看当前的作业列表:

在 bash 中,我们可以用 fg 命令唤醒一个被挂起的作业,把它移到前台。这会让 Vim恢复成挂起前的状态。 Ctrl-zfg 命令比 Vim 所提供的 :shellexit 命令更加方便快捷。

:read !{cmd}{cmd} 命令的输出读入当前缓冲区中
:write !{cmd} 做相反的事。它把缓冲区内容作为指定 {cmd} 的标准输入

注意!的位置

:write !sh 命令的作用是在shell中执行当前缓冲区中的每行内容, 查阅 :h rename-files

可看到该命令的一个绝佳示例。

上面注意第三行的技巧,\(\), &, \1 的用法

使用外部命令过滤缓冲区内容

当给定一个范围时, :!{cmd} 命令就具有了不同的含义。由 [range ]所指定的行会传给{cmd} 作为标准输入,然后又会用 {cmd} 的输出覆盖 [range] 内原本的内容。换一种说法。就是 [range] 内的文本会被指定的 {cmd} 进行过滤

Vim把过滤器器定义为“一个由标准输入读取文本,并对其进行某种形式的修改后输出到标准输出的程序”。

例子

用外部的 sort 命令对下列 CSV 文件中的记录进行排序

:2,$!sort -t',' -k2

Vim 提供了一种方便的快捷方式来设置 :[range]!{filter} 命令中的范围。我们可以用 !{motion} 操作符切换到命令行模式,并把指定 {motion} 所涵盖的范围预置在命令行上(参见 :h ! )。

如果我们把光标移到第 2 行,然后执行 !G ,Vim 就会打开命令行并把范围 :.,$! 预置在命令行上。虽然此后我们仍需输入剩下的 {filter} 命令

最有用的一些调用外部命令的方式:

Vim 对某些外部命令会另眼相待。例如, make 及 grep 在 Vim 中都有包装命令,这些命令不仅执行起来更方便,而且 Vim 还会将它们的输出解析、导入到 quickfix 列表中。参考 chap17, chap18


Share