vim-basic
基本概念
进入 Vim
在终端使用 vim 的话,相当于是在当前目录打开 vim 编辑器
vin <path>
在指定的 path 打开 vim
vim ~/.vimrc
模式
caret 模式 光标模式,移动光标
visual 模式,可视模式,移动框选
search 模式,搜索
insert 模式,i 和 a
命令行模式
基本命令
Vim 拥有大量的动作命令,我们无法在本章里涵盖所有的命令,因此我推荐你自行查阅 Vim 文档中的 :h motion.txt
,以获得一个完整的动作命令列表.
操作 | 快捷键 |
---|---|
进入 Vim 编辑器 (从命令行提示符) | vim 文件名 <回车> |
退出 Vim 编辑器,保存改动 | <ESC> :wq <回车> |
按下 <ESC> 键会带您回到正常模式或者撤消一个不想输入或部分完整的命令 |
命令语法
重复命令
在正常模式下修改命令的格式是:operator [number] motion
其中:
- operator - 操作符,代表要做的事情,比如 d 代表删除
- [number] - 可以附加的数字,代表动作重复的次数
- motion - 动作,代表在所操作的文本上的移动,例如
- w 代表单词 (word)
- $ 代表行末等等。
.
→ (小数点) 可以重复上一次的命令
100idesu [ESC]
写 insert 100 个 desu
此时 . 会重复 100 desu 3. 会重复 三次 desu
100dw 和 d100w 有什么不同?乍看之下主要是重复时会有区别,但实测了一下,好像没有区别
指定命令的范围
你一定要记住光标的移动,因为很多命令都可以和这些移动光标的命令连动。很多命令都可以如下来干:
<start position><command><end position>
例如 0y$
命令意味着:
0
→ 先到行头y
→ 从这里开始拷贝$
→ 拷贝到本行最后一个字符
一个命令连续调用两次:作用于当前行
Vim 的语法只有一条额外规则,即当一个操作符命令被连续调用两次时,它会作用于当前行。所以 dd 删除当前行,而 >> 缩进当前行。gU 命令是一种特殊情况,我们既可以用 gUgU ,也可以用简化版的 gUU 来使它作用于当前行。
Vim Cheat Sheet 小抄
:h *
移动
基础移动类命令
操作 | 快捷键 |
---|---|
h (左移) j (下行) k (上行) l (右移) | |
至下一个单词 | w = word |
至当前单词的末尾 | e = end |
反向移动至当前单词的末尾 | ge |
配对括号 | % |
当前行末尾 | $ = line end |
到本行第一个不是 blank 字符的位置 | ^ |
到本行最后一个不是 blank 字符的位置 | g_ |
移动光标到行首 | 数字 0 键:0 |
所谓 blank 字符就是空格,tab,换行,回车等
单词跳转
w
→ 到下一个单词的开头。e
→ 到下一个单词的结尾。
如果你认为单词是由默认方式,那么就用小写的 e 和 w。默认上来说,一个单词由字母,数字和下划线组成(陈皓注:程序变量)
如果你认为单词是由 blank 字符分隔符,那么你需要使用大写的 E 和 W。可以跳过单引号及双引号等, 在 html attributes 跳转中特别有用
匹配括号
如果光标当前位置是括号 (、)、[、]、{、},按 % 会将光标移动到配对的括号上
提示:在程序调试时,这个功能用来查找不配对的括号是很有用的。
匹配单词
*
和 #
: 匹配光标当前所在的单词,移动光标到下一个(或上一个)匹配单词(* 是下一个,#是上一个)
方便查找变量
Ea
把 ea
命令连在一起可被解读为“在当前单词结尾后添加”。我经常会用到 ea
,就好像它是一条单独的命令似的。另外,也可以把 gea
命令当成“在上一单词结尾后添加”的命令,我们偶尔也会用到它。
Find 命令 (f/f/t/t)
f+
查找这一行里的 + 加号,通过 ;
移动到下一个匹配项
在使用字符查找命令时,最好是选择 出现频率比较低 的字母作目标字符。多练习一下,你就能学会发现这些字符。
;
和 ,
命令
使得移动可以重复
;
会重复上次 f/F/t/T 命令所查找的字符
,
则是反向
在当前行上移动光标
0
→ 到行头^
→ 到本行的第一个非 blank 字符$
→ 到行尾g_
→ 到本行最后一个不是 blank 字符的位置。fa
→ 到下一个为 a 的字符处,你也可以 fs 到下一个为 s 的字符。t,
→ 到逗号前的第一个字符。逗号可以变成其它字符。3fa
→ 在当前行查找第三个出现的 a。F
和T
→ 和f
和t
一样,只不过是相反方向。
屏幕行和实际行
为了让一行完整显示,所以 vim 做了区分
j
和 k
命令会根据实际行向下及向上移动,而 gj
和 gk
则是按屏幕行向下及向上移动。
其他常见的行移动命令加上 g 即可移动到屏幕行的相应位置,如:g0
、g^
、g$
理解单词与字串
Vim 对此有两种不同的定义,并且分别用“单词”(word)和“字串”(WORD)对其进行区分。我们之前遇到过的每个面向单词的动作命令,都有一个面向字串的命令与其对应,这当中包括 W、B、E 和 gE。
一个单词由字母、数字、下划线,或其他非空白字符的序列组成,单词间以空白字符分隔(参见:h word)。而字串的定义则更简单,它由 非空白字符序列 组成,字串间以空白字符分隔(参见:h WORD)。
e.g. we're going too slow
上例中包含了 5 个字串及 10 个单词,句号及单引号都被当成了单词
如果你想更快地移动的话,可以用面向字串的动作命令;
而如果你想以更细的粒度移动的话,则可以用面向单词的动作命令。
对于中文而言,所有的字符都被当成串,上面一行使用 E 可以直接跳到末尾。使用 w 则可以以标点为节点做跳转
e.g. D{motion} 与 查找动作
刚开始,我们先把光标直接移到逗号上,因此使用了 f, 命令。接下来,我们想删除从此处到句尾的所有文本,但又不想删除句号,此时可以用 dt. 命令完成这项工作。
删除句子的后半句话则是经常会做的操作。因此我们可以把 f,dt.
训练成手指的下意识动作。
通常,当我想在当前行内快速移动光标时,我倾向于在普通模式中使用 f{char}
和 F{char}
命令;当与 d{motion}
或 c{motion}
一起使用时,我会更倾向于使用 t{char}
及 T{char}
命令。
换句话说,我在普通模式中会用 f 和 F,而在 操作符待决模式 中则使用 t 和 T。
折行
基本命令
折行的组合快捷键都是以字母 z 开头 (字形是不是像被折过的直线?) 的,常用的有
zf
创建折行,f
表示 foldzo
打开折行,o
表示 openzc
关闭折行,c
表示 closezd
删除折行,d
表示 delete
更多折行内容请移步
:h folding
Markdown
也可以折叠
屏幕
zz 将当前行置于屏幕的中间
zt 将当前行置于屏幕的顶部
zb 将当前行置于屏幕的底部
<c-d>
<c-u>
<c-f>
<c-b>
跳转
行定位
操作 | 快捷键 |
---|---|
显示当前光标所在位置和文件状态信息 | ctrl + G |
跳转至文件第一行 | gg |
用于将光标跳转至文件最后一行 | G |
移动至该行号代表的行 | [number] + G /[number] + gg /:n |
标记
设置位置标记,以便快速跳回
m{a-zA-Z}
命令会用选定的字母标记当前光标所在位置(参见:h m)。小写位置标记只在每个缓冲区里局部可见,而大写位置标记则全局可见。我们将在技巧 58 中学到更多关于位置标记的内容。
设置一个位置标记时,Vim 不会用可见的标识表明它已被设置。不过如果你已经正确地设置好了,那么只用两个键你就能从文件的任何地方直接跳到该位置标记所在之处。
Vim 提供了两条普通模式命令,可以用它们跳转到一个位置标记上(注意,这两条命令看起来很像):
'{mark}
命令跳到位置标记所在行,并把光标置于该行第一个非空白字符上- `{mark} 命令则把光标移动到设置此位置标记时光标所在之处,也就是说,它同时恢复行、列的位置(参见
:h mark-motions
)。
如果你只想记一条命令,那就记住 `{mark} 好了。不论你是想恢复到准确的光标位置,还是只想回到正确的行,这条命令都能做到。
只有在 Ex 命令的上下文中,你才需要用 '{mark}
这种形式(参见技巧 28)。
mm
和 `m 命令是一对便于使用的命令,它们分别设置位置标记 m,以及跳转到该标记。在 交换两个词 一例中展示了一则小技巧,它用这两条命令先标定一个位置,而后再快速跳回来。
自动位置标记
我们可以为每个缓冲区设置最多 26 个小写位置标记。字母表中的每个字母都对应着一个位置标记,这可能远比你实际需要的数目要多。
之所以会这样,是因为在 Vim 的前身 vi 里,并没有诸如现在的可视模式这样的功能。在那个时候,位置标记是一个比现在重要得多的功能。
但现在,很多在 vi 里需要用位置标记完成的工作,都可以在 Vim 里用可视模式来做,因此对位置标记的需求也就相应减少了。但是位置标记在 Vim 里并没有过时,它们仍然有用处。
Vim 会自动帮我们设置一些位置标记,这些标记用起来非常方便
高亮选区的起始和结束位置都会被自动记录成位置标记,因此我们甚至可以把可视模式当成位置标记功能的一个图形化界面。
在匹配括号间跳转
概述
Vim 提供了一个动作命令,让我们可以在开、闭括号间跳转。在激活了 matchit.vim 插件后,此命令也可以用于成对的 XML 标签,以及某些编程语言中的关键字上。
%
命令允许我们在一组开、闭括号间跳转(参见:h %),它可作用于 ()
、{}
以及 []
修改匹配符号
假设我们想把 %w{London Berlin New\ York}
改成普通的列表定义 ["London","Berlin", "New York"]
,因此要把大括号改成方括号。你或许会想这是用 %
动作的完美场合,你说对了,但这里有个陷阱!
假设我们先把光标移到开括号上,然后按 r[
把它改成了方括号。现在我们得到一个怪模怪样的结构 [London Berlin New\ York}
。由于 %
命令只能用在配对的括号上,所以现在我们无法用它跳到闭括号字符 }
上。
此处的窍门是在做修改之前,要先执行一次 %
命令。在执行 %
命令时,Vim 会自动为发生跳转的地方设置一个位置标记,而后我们就可以按 `` 跳回那里
注意:在本例中 <C-o>
命令也能完成 `` 动作命令所做的工作(参见技巧 55)。另外,也可以用 surround.vim 插件提供的一些命令,更容易地完成上面的工作,更多内容请见 Surround.vim。
Surround.vim
S"
命令是 surround.vim 提供的一个命令,可以把它解读为“用一对双引号把选中的文本括起来”(Surround the selection with a pair of double quote marks)。如果想把选中的文本用圆括号或花括号括起来,只需简单地用 S) 或 S} 即可。
我们也可以用 surround.vim 修改已有的分隔符。例如,我们可以用 cs}]
命令把 {London} 改成 [London]
,可以把它解读为“把周边的花括号 {} 改成方括号 []”(Change surrounding {} braces to [] brackets)。另外,我们也可以用 cs]} 实现相反的修改。
不知道是为什么反正 vscodevim 里可以直接使用了,不用下载,但是原生的 vim 不行
句子与段落
(
begin sentence
)
end sentence
{
prev paragraph
}
next paragraph
[( N [( 向后至第 N 个未闭合的 '('
[{ N [{ 向后至第 N 个未闭合的 '{'
]) N ]) 向前至第 N 个未闭合的 ')'
]} N ]} 向前至第 N 个未闭合的 '}'
跳转到光标下的文件
先把光标放在字符串 'practical_vim/core' 的某个位置上(例如,按 fp 快速移到该字符串上),尝试执行 gf 命令。
指定文件的扩展名
指定要搜寻的目录
跳转到函数定义处
<C-]>
查看有哪些地方引用、调用了该函数
<C-]>
和跳转到函数定义的命令时同一个,在函数定义处使用即可查看函数引用,在引用列表内可以使用常规移动
遍历改变列表
在大多数场景下,跳转到`. 的效果与使用 g;
命令相同。不过位置标记只指向最后修改的位置,而改变列表中则保存了多组位置。
我们可以多次按 g;
命令,每次它都会把我们带到改变列表中较早的一个位置,而 `. 则总是把我们带到改变列表的最后一项。
`^ 标记指向上次插入的位置,它比上次修改的位置更具体一点。如果我们先退出插入模式,接着又在文档中四处移动,然后,当我们又想快速回到退出的地方继续编辑时,用 gi 命令就行了(:h gi)。此命令会用 `^ 标记恢复光标位置,并切换到插入模式,这真是省时省力的好办法!
遍历跳转列表
<C-o>
命令像后退按钮一样,而与之互补的 <C-i>
命令则像是前进按钮。这两条命令允许我们对 Vim 的跳转列表进行遍历
任何改变当前窗口中活动文件的命令,都可以被称为跳转命令。Vim 会把执行跳转命令之前和之后的光标位置,记录到跳转列表中。例如,如果我们运行 :edit 命令打开了一个新文件(参见技巧 41),那么就可以用 <C-o>
和 <C-i>
命令在这个新文件以及原本的文件之间来回跳转。
用 vscode 命令打开的文件也同样可以切换
用 [count]G
命令直接跳到指定的行号也会被当成一次跳转,但每次向上或向下移动一行则不算。面向句子的动作及面向段落的动作都算跳转,但面向字符及面向单词的动作则不算。用一句话来概括,我们可以说大范围的动作命令可能会被当成跳转,但小范围的动作命令则只能算移动。
下表节选了一些跳转动作:
Vim 会为编辑会话中的每个单独缓冲区维护一个改变列表,而与之不同的是,每个窗口都会创建一个单独的跳转列表。
与 vscode 配合,可以轻松的跨文件跳转回之前的地方
修改命令
对应插入模式,同样可以对文本做修改,但是因为是命令形式,所以不用进入插入模式,代表着在 normal 模式下的修改类命令
X
删除光标下的字符
~
切换大小写
Replace 命令
要替换光标所在位置的字符,请输入小写的 r 和要替换掉原位置字符的新字符即可。
大写的 R 可以进入替换模式,逐个替换
gR 虚拟替换模式
替换命令 :substitute
删除类命令 Delete
操作符 d + motion
操作 | 快捷键 |
---|---|
在正常模式下删除光标所在位置的字符 | x = dl |
从当前光标删除至下一个单词 | dw |
删除当前单词 | de |
删除一个完整的单词 | daw |
删除一个完整的段落 | dap |
从当前光标删除至当前行末尾 | d$ |
欲删除整行(用的太多了,语法糖) | dd |
复制、黏贴、剪切
复制
- 接着使用 v 进入可视模式,移动光标到 "first" 的前面。
- 现在输入 y 以抽出 (复制) 高亮的文本。
- 接着输入 p 以放置 (粘贴) 复制了的文本。然后输入:a second
<ESC>
。
提示:您还可以把 y 当作操作符来使用;例如 yw 可以用来复制一个单词。
复制类命令
操作 | 快捷键 |
---|---|
复制当前行 | yy 相当于 ddp |
从当前位置拷贝到本单词的最后一个字符 | ye |
拷贝 1 个 “foo” 之间的字符串 | y2/foo |
剪切
删除类命令删除的内容会被放到 vim 寄存器当中
要重新置入已经删除的文本内容,请按小写字母 p 键。该操作可以将已删除的文本内容置于光标之后。
如果最后一次删除的是一个整行,那么该行将置于当前光标所在行的下一行。
选中文本并替换
操作步骤如下:
- 使用
yiw
yank(复制的意思)要复制的文本 - 移动到要替换的文本
viwp
使用 yank 的文本替换选中的文本- 移动到下一个需要替换的文本
viw"0p
使用步骤 1yank 的文本再次替换
次数做简单的算术运算
<C-a>
和 <C-x>
命令分别对数字执行加和减操作。在不带次数执行时,它们会逐个加减,但如果带一个次数前缀,那么就可以用它们加减任意整数。例如,如果我们把光标移到字符 4 上,执行 10<C-a>
就会把它变成 15。但是如果光标不在数字上会发生什么?文档里说,<C-a>
命令会“把当前光标之上或之后的数值加上 [count]”(参见:h ctrl-a)。因此,如果光标不在数字上,那么 <C-a>
命令将在当前行正向查找一个数字,如果找到了,它就径直跳到那里。我们可以利用这一点简化操作。
在本例中,我们只复制了一行并做出改动。但是,假设你要复制 9 份,并对后续数字依次减 180。如果要切换到插入模式去修改每个数字,我们每次都得输入不同的内容(-180,然后 -360,以此类推)。但是如果用 180<C-x>
命令的话,对后续行也可以采用相同的操作过程。我们甚至还可以把这组按键操作录制成一个宏(参见第 11 章),然后根据需要执行多次。
文本排版类命令
motion 类型
/> G 从当前行到文档末尾处的缩进层级
插入模式
进入 Insert 模式
操作 | 快捷键 |
---|---|
删除当前光标所在的字符,并进入 insert 模式 | s = cl |
在光标前面插入文本 | i |
I = ^i | |
在光标后插入文本 | a |
在光标所在行的行末之后插入文本 | A = $a |
在光标下方打开新的一行并进入插入模式 | o = A<CR> |
在光标上方打开新的一行并进入插入模式 | O = ko |
更改类命令 Correct
更改类命令允许您改变从当前光标所在位置直到动作指示的位置中间的文本。
比如输入 ce 可以替换当前光标到单词的末尾的内容;输入 c$ 可以替换当前光标到行末的内容。
C = c$
s = cl
S =
返回普通模式
用途 | 按键操作 |
---|---|
切换到普通模式 | <Esc> |
切换到普通模式 | <C-[> |
切换到插入 - 普通模式 | <C-o> |
插入普通模式
插入 - 普通模式是普通模式的一个特例,它能让我们执行一次普遍模式命令。
在此模式中,我们可以执行一个普通模式命令,执行完后,马上就又返回到插入模式。
要从插入模式切换到插入 - 普通模式,可以按 <C-o>
(参见:h i_CTRL-O)
在当前行正好处于窗口顶部或底部时,有时我会滚动一下屏幕,以便看到更多的上下文。用 zz 命令可以重绘屏幕,并把当前行显示在窗口正中,这样就能够阅读当前行之上及之下的半屏内容。
我常常会键入 <C-o>zz
,在插入 - 普通模式中触发这条命令。此操作完成后就会直接回到插入模式,因此我可以不受中断地继续打字。
插入模式下快速移动
使用 <C-o>
进入插入 - 普通模式,然后通过 f 或者 / 一步到位的移动
在插入模式中可即时更正错误
专业打字员会建议先删除整个单词,然后再重新输入一遍。如果你能以每分钟超过 60 个单词的速度输入,那么重新输入一个词只需要 1 秒钟的时间。
即便你打不了这么快,最好也采用这种方式。我以前总是输错某些特定的词,但自从采纳这一建议后,我就更清楚地意识到哪些词会让我犯错,因此现在犯的错也少了很多。
另外,你也可以切换到普通模式,然后跳到这个词的开头并更正错误,再按 A 返回刚才的位置。
不过完成这一套动作要花的时间可能不止 1 秒钟,并且它也无助于提高你的盲打技巧。虽然说我们可以切换模式,不过这并不意味着一定就得切换。
用途 | 按键操作 |
---|---|
删除前一个字符(同退格键) | <C-h> |
删除前一个单词 | <C-w> |
删除至首行 | <C-u> |
这些命令不是插入模式所独有的,甚至也不是 Vim 所独有的,在 Vim 的命令行模式中,以及在 bash shell 中,也可以使用它们。
不离开插入模式,粘贴寄存器中的文本
yt, 命令把“Practical Vim”复制到复制专用寄存器中,然后我们在插入模式中,按 <C-r>0
把刚才复制的文本粘贴到光标所在位置。
这个命令一般的格式是 <C-r>{register}
,其中 {register}
是我们想要插入的寄存器的名字
在插入模式中,可以用 <C-r>{register}
命令很方便地粘贴几个单词。可是如果寄存器中包含了大量的文本,你也许会发现屏幕的更新有些轻微的延时。这是因为 Vim 在插入寄存器内的文本时,其插入方式就如同这些文本是由键盘上一个个输进来的。因此,如果‘textwidth’ 或者‘autoindent’ 选项被激活了的话,那么最终就可能会出现不必要的换行或额外的缩进。
<C-r><C-p>{register}
命令则会更智能一些,它会按原义插入寄存器内的文本,并修正任何不必要的缩进(参见:h i_CTRL-R_CTRL-P),不过这个命令有点不太好输入!因此,如果我想从一个寄存器里粘贴很多行文本的话,我更喜欢切换到普通模式,然后使用某个粘贴命令(参见技巧 62)。
表达式寄存器:随时随地做运算
大部分的 Vim 寄存器中保存的都是文本,要么是一个字符串,要么是若干行的文本。
删除及复制命令允许我们把文本保存到寄存器中,而粘贴命令则允许我们把寄存器中的内容插入到文档里。
不过表达式寄存器则是个另类,它可以用来执行一段 Vim 脚本,并返回其结果。
在本节,我们将把它当成计算器来用。传给它一个简单的算术表达式,比方说 1 + 1,那它就会给出结果 2。
对表达式寄存器所返回的文本,我们可以像用普通寄存器中的文本那样使用它
插入非常用字符
用二合字母插入非常用字符
二合字母用起来很方便。在插入模式中,只需输入 <C-k>
即可。因此,如果想输入以二合字母 ?I 表示的“¿”字符,我们可以简单地输入 <C-k>?I
。
:h digraphs-default
文档对此进行了总结。
你也可以用 :h digraph-table
查看另一个更为有用的列表。
可视模式
概念
你已经熟识的很多普通模式命令,它们在可视模式中也完成相同的功能。
我们仍可以把 h、j、k 及 l 当成光标键使用;
也可以用 f{char} 跳到当前行的某个字符上,然后用 ; 和 , 命令相应地正向或反向重复此跳转;
甚至还可以用查找命令(以及 n /N 命令)跳转到匹配指定模式的地方。
选择模式 *
激活可视模式
v 键是通往可视模式的大门。在普通模式下,按 v 可激活面向字符的可视模式,按 V(v 和 Shift 键一起按)可激活面向行的可视模式,而按 <C-v>
(v 和 Ctrl 键一起按)则可激活面向列块的可视模式,请参见下表中的汇总:
用途 | 命令 |
---|---|
打开可视模式 | v |
激活面向行的可视模式 | V |
激活面向 列块 的可视模式 | <C-v> |
重选上次的高亮选区 | gv |
切换选区的活动端
高亮选区的范围由其两个端点界定。其中一端固定,而另一端可以随光标自由移动,我们可以用 o 键来切换其活动的端点。
在可视模式执行完一条命令后,就会返回普通模式
重复执行面向行的可视命令
当使用 .
命令重复对高亮选区所做的修改时,此修改会重复作用于相同范围的文本。
只要可能,最好用操作符命令,而不是可视命令
可视模式可能比 Vim 的普通模式操作起来更自然一些,但是它有一个缺点:在这个模式下 . 命令有时会有一些异常的表现。我们可以用普通模式下的操作符命令来规避此缺点。
当一条可视模式命令被重复执行时,它会影响相同数量的文本(参见:h visual-repeat)。
在本例中,最初的命令影响了一个由 3 个字母组成的单词。在第二行它依旧工作得很好,因为该行恰好也包含一个由 3 个字母组成的单词。但是,当我们想对一个由 5 个字母组成的单词重复此命令时,它只成功转换了其中的前 3 个字母,留下 2 个字母未被转换。
可视模式下的 U 命令有一个等效的普通模式命令:gU{motion}(参见:h gU)。如果我们用此命令做第一处修改,就可以用点范式完成后续的修改,如表 4-2 所示。
这两种方式都只需要 4 次按键操作:vitU 及 gUit,但其背后的含义却大相径庭。
在可视模式所采用的方式里,这 4 次按键可以被当做两个独立的命令。vit 用来选中选区,而 U 用来对选区进行转换。
与之相反的是,gUit 命令可以被当成一个单独的命令,它由一个操作符(gU)和一个动作命令(it)组成。如果我们想使点命令能够重复某些有用的工作,那么最好要远离可视模式。作为一般的原则,在做一系列可重复的修改时,最好首选操作符命令,而不是其对应的可视模式命令。
用面向列块的可视模式编辑表格数据
一开始,我们先使用 <C-v>
进入列块可视模式,然后向下移动几行光标,选中一列文本。
接下来,按 x 键删除此列,并用 .
命令重复删除相同范围的文本,多重复几次直到距右边差不多有两列的距离。
我们也可以不用 .
命令,而是把光标向右移动两三次,把列选区扩展为块选区,而后只需删除一次即可。不过,我更喜欢在删除时看到即时的视觉反馈,然后再多次重复此操作。
现在,我们已经把所需的两列文本排列到了合适的位置,接下来就可以在这两列文本间画一条竖线了。我们先用 gv
命令重选上次的高亮选区,然后输入 r|
,用管道符替换此选区内的字符。
到了这一步,我们或许也想画一条横线来分隔表头及其下的内容。我们先快速地复制顶行并粘贴一份副本(yyp),然后再用连字符替换该行内的所有字符(Vr-)。
修改列文本
用列块可视模式可以同时往若干行中插入文本。列块可视模式不仅仅对表格数据有用,在编程时我们也时常受惠于此功能。
整个过程看起来非常熟悉。先指定想要操作的选区,本例中的高亮选区恰好为方形。
当我们按 c 键时,所有被选中的文本都消失了,同时我们进入了插入模式。当我们在插入模式中输入单词“components”时,此单词只出现在顶行,下面的两行没什么变化。
只有在按了 <Esc>
返回到普通模式后,我们才看到刚才输入的文本出现在下面这两行里。在 Vim 列块可视模式中,修改命令的表现或许有点怪,它看上去有点不一致。删除操作会同时影响所有被选中的行,但插入操作只影响顶行(至少在处于插入模式的期间)。
其他文本编辑器也提供了类似的功能,但是它们会同时更新所有被选中的行,如果你已经习惯了这样的表现(就像我以前一样),那么你会发现 Vim 的实现不太完美。不过在实践中,最终的结果没什么区别。因为你处于插入模式的时间很短,所以没必要太过惊讶。
在长短不一的高亮块后添加文本
列块可视模式在操作由行列组成的方形代码块时表现得很好,然而,它并不仅限于操作方形的文本区域。
在进入列块可视模式后,我们按 $
键把选区扩大到每行的行尾。Vim 知道我们是想把选区扩大到所选中的这些行的结尾,它会让我们打破方形的限制,创建出一个右边界长短不一的文本选区。
确定好选区后,用 A
命令就可以在每行的结尾添加内容(参见 Vim 对“i”及“a”键的约定)。此命令让我们进入插入模式,且使光标停留在顶行。处于插入模式期间,任何输入的内容只出现在顶行,然而一旦返回到普通模式,这些修改就会被扩散到其余选中的行上。
文本对象
用文本对象执行操作
可视模式适用于介绍文本对象,因为可以很容易看到发生的变化。然而,在 操作符待决模式 中使用文本对象,才能真正展现出它们的强大能力。
文本对象自身并不是动作命令,我们不能用它们在文档中移动。但是我们却可以在可视模式及操作符待决模式中使用文本对象。
记住:每当在命令语法里看到 {motion}
时,你也可以在这个地方使用文本对象,常见的例子包括 d{motion}
、c{motion
} 和 y{motion}
我们可以把 ci"
命令解读为“修改双引号内部的内容”,把 cit
命令解读为“修改标签内部的内容”。另外,我们也可以很容易地用 yit
命令拷贝标签内的文本,或者是用 dit
删除这些文本。
用精确的文本对象选择选区
文本对象允许我们操作括号、被引用的文本、XML 标签以及其他文本中的常见结构。
每个开括号字符 {
都对应一个闭括号字符 }
,[
和 ]
、<
和 >
,以及 HTML 标签 <a>
和 </a>
也是一样。这段代码中也包含单引号及双引号,它们也是成对出现的。
这些配对符号具有规整的格式,而 Vim 能够理解其结构,并允许对它们所分隔的区域进行操作。文本对象就是基于结构定义的文本区域(参见:h text-objects)。通过使用文本对象,我们只需几个键就可以选择或操作一大段文本。
Vim 的文本对象由两个字符组成,第一个字符永远是 i 或是 a。我们一般说,以 i 开头的文本对象会选择分隔符内部的文本,而以 a 开头的文本对象则会选择包括分隔符在内的整个文本。为了便于记忆,可以把 i 想成“inside”,而把 a 想成“around”或“all”。
表 8-1 总结了部分 Vim 内置的文本对象。出于整洁起见,表中省略了一些重复的文本对象。例如,i( 和 i) 等同,a[ 和 a] 也相同,你可以使用最适合自己的那种风格。
删除周边,修改内部
文本对象通常是成对出现的,一个用于操作对象内部的文本,而另一个则操作对象周围的文本。在本节中,我们将剖析每类文本对象的典型用法。Vim 的文本对象分为两类:一类是操作分隔符的文本对象,如 i)、i" 和 it;另一类用于操作文本块,如单词、句子和段落。
我把第一类标注为“分隔符文本对象”,因为它们以配对的符号作为开始和结束。单词、句子以及段落则以文本结构的范围进行界定,因此我把这一类称为“范围文本对象”。
Vim 的文档把它们称为“块对象”(block object)和“非块对象”(non-block object),但我发现这种区分方式无助于理解。
一般来说,d{motion} 命令和 aw、as 和 ap 配合起来使用比较好,而 c{motion} 命令和 iw 及类似的文本对象一起用效果会更好。
折行与 text-object
配合工作
zfa{
折叠成对大括号之间的内容,包括大括号所在行,一般用于折叠函数定义、 循环、只有一个分支的条件判断。
zfi{
折叠成对大括号之间的内容,不包括大括号所在行,一般用于折叠条件判断的多个分支、try-cache 的各部分内容。
不管代码有多长,一个 zfo{
或者 zfi{
立马折叠。
Plugin Text Object
function text object