Vim实用技巧
基本操作
模式
普通模式(normal mode)
使用 <Esc>
回到普通模式
插入模式(insert mode)
使用i
, a
等命令可以从普通模式进入到插入模式
替换模式(replace mode)
插入模式的一种特例,在替换模式中输入会替换文档中的已有文本,除此之外,该模式与插入模式完全相同.
R
命令会进入该模式
插入-普通模式
是插入模式的一个子模式,可以让我们执行一个普通模式命令,之后马上又回到插入模式.
<C-o>
会进入该模式
可视模式(visual mode)
v
或 <C-v>
(有些插件是 <C-q>
) 进入该模式
常用操作符列表
d
deletec
changey
yank(复制操作)~
大小写切换g~
大小写切换gu
转成小写gU
转成大写>
右缩进<
左缩进=
自动缩进!
使用外部程序过滤 {motion} 所跨越的行
使用介绍: 操作符简介,或者查看帮助: :h operator
.
动作命令(motion)
j
下移一行k
上移一行h
左移一个字符l
右移一个字符w
后移到下一个单词词首e
后移到下一个单词词尾
上述位移操作可以前面加上数字, 表示移动多次. 比如 5k
表示上移5行.
^
移到行首(不包含空格)$
移到行尾gg
回到文档第一个字符G
回到文档最后一个字符0
移到行首%
在()
和{}
括弧之间来回跳转
文本对象(text object)
aw
光标所在的整个单词(简记 a word)ap
光标所在的整个段落(简记 a paragraph)it
标签内(简记 inside the tag)
修改
a
在光标后进入Insert模式,i
当前光标处进入Insert模式A
在行尾进入Insert模式,I
在行首进入Insert模式dd
删除当前行D
删除当前光标后面所有字符cc
删除当前行并进入insert模式C
删除当前光标后的所有字符并进入insert模式x
删除当前字符X
删除当前光标前一个字符u
撤销操作,参考把撤销单元切成块s
删除当前光标所在字符,并进入insert模式,相当于xi
S
等于cc
以退为进
将以下代码
var foo = "method("+argument1+","+argument2+")";
的+
前后加上空格, 转成以下格式
var foo = "method(" + argument1 + "," + argument2 + ")";
0
移到行首f+
查找第一个+
s + <Esc>
将第一个+
变成+
, 并进入normal模式;
移动到下一个+
.
重复第3步的操作;.
继续重复操作;.
继续重复操作
执行、重复、回退
.
命令是一个微型的宏, 用于重复上次修改.@:
可以用来重复任意 Ex 命令&
来重复上次的:substitute
命令(它本身也是一条 Ex 命令)
目的 | 操作 | 重复 | 回退 |
---|---|---|---|
做出一个修改 | {edit} | . | u |
在行内查找下一指定字符 | f{char} /t{char} | ; | , |
在行内查找上一指定字符 | F{char} /T{char} | ; | , |
在文档中查找下一处匹配项 | /pattern<CR> | n | N |
在文档中查找上一处匹配项 | ?pattern<CR> | n | N |
执行替换 | :%s/target/replacement | & | u |
执行一系列修改 | qx{changes}q | @x | u |
查找并手动替换
:%s/content/copy/g
会将所有的content
替换成copy
, 可组合使用以下几个命令做到手动确认后再替换:
*
: 在当前文档查找当前光标所在的单词 (#
是*
命令的反向操作)cw
: 删除当前单词并进入insert模式(这个时候输入想要替换的单词)n
: 查找下一个*
匹配的单词.
: 重复执行第二步
普通模式
把撤销单元切成块
在 Vim 中,u
键会触发撤销命令,它会撤销最新的修改. 我们自己可以控制撤销命令的粒度. 从进入插入模式开始,直到返回普通模式为止,在此期间输入或删除的任何内容都被当成一次修改. 因此,只要我们控制好对 <Esc>
键的使用,就可使撤销命令作用于单词、句子或段落.
当我提到撤销命令会回退从进入插入模式到退出此模式期间输入(或删除)的全 部字符时,我略过了一个小细节. 如果在插入模式中使用了 <Up>
、 <Down>
、 <Left>
或 <Right>
这些光标键,将会产生一个新的撤销块. 你可以把这想象为先切换回普通模式,然后用 h
、 j
、 k
或 l
命令对光标进行了移动,唯一区别是我们并没有退 出插入模式. 这也会对 .
命令的操作产生影响.
构造可重复的修改
假设光标位于行尾处的字符“h”上,而我们想要删除单词“nigh”:
The end is nigh
方式1: 反向删除
db
反向删除字母nigx
删除剩下的字母h
方式2: 正向删除
b
先将光标移到单词开头dw
删除整个单词
方式3: 删除整个单词
我们可以使用更为精准的 aw
文本对象(text object), 而不是动作命令:
daw
直接删除光标所在的整个单词(可以简记为 delete a word)
哪种方式最具重复性?
上述的三种删除单词的方式: dbx
、 bdw
以及 daw
,只有daw
最具有可重复性(利用.
命令重复删除单词):
dbx
是两个命令:db
和x
,所以最后.
命令相当于x
bdw
由一个位移操作b
和一个修改命令dw
组合而成,所以最后.
命令相当于dw
用次数做简单的算术运算
<C-a>
和 <C-x>
命令分别对光标所在的整个数字执行加和减操作.
如果执行时光标不在数字上,命令会把当前光标移到之上或之后的数值,再进行加减.
和很多其他普通模式命令一样,<C-a>
和<C-x>
可以带一个次数前缀,这样 Vim 就会尝试把该命令执行指定的次数,而不是只执行一次,比如要把 .blog { background-position: 0px 0px }
变成 .blog { background-position: -180px 0px }
,只需要执行180<C-x>
即可.
Vim 默认把以 0 开头的数字解释为八进制值,而不是十进制,因此对文本007
执行<C-a>
,会变成010
. 如果想禁用Vim默认行为, 可以在vimrc里增加配置set nrformats=
,这回让Vim把所有数字当成十进制处理.
操作符简介
Vim 的强大很大程度上源自操作符与动作命令相结合:
操作符 + 动作命令 = 操作 简写 {operator}{motion}
操作符的作用范围由动作命令决定,比如:
dl
删除一个字符daw
删除一个完整单词dap
删除一整个段落
c{motion}
、y{motion}
也类似,它们被统称为操作符.
其他操作符 g~
、 gu
和 gU
命令要用两次按键来调用,我们可以把上述命令中的 g
当做一个前缀字符,用以改变其后面的按键行为(这种行为被称为 结识操作符待决模式 ). daw
是删除当前单词,同理gUaw
就是把当前单词转成大写形式.
Vim 的语法有一条额外规则,即当一个操作符命令被连续调用两次时,它会作用于当前行:
dd
删除当前行>>
缩进当前行gU
命令是一种特殊情况,可以用gUgU
或gUU
来使它作用于当前行(把当前行全部转成大写)- 其他操作符使用类似
cc
删除当前行并进入插入模式yy
复制当前行
随同 Vim 发布的标准操作符集合相对比较少,但我们可以定义新的操作符. Tim Pope 的 commentary.vim 插件提供了一个很好的例子, 此插件为 Vim 所支持的编程语言增添了注释及取消注释的命令.
如果你对如何创建自定义操作符感到好奇,可以先阅读一下文档 :h :map-operator
.
Vim 缺省的动作命令集已经相当全面了,但是我们还是可以定义新的动作命令及文本对象来进一步增强它.
Kana Natsuno 的 textobj-entire 插件是一个很好的例子,它为 Vim 增加了两种新的文本对象 ie
和 ae
,它们作用于整个文件.
如果想用 =
命令自动缩进整个文件,我们可以执行 gg=G
(就是说,先用 gg
跳到文件开头,然后用 =G
自动缩进从光标位置到文件结尾的所有内容). 但是如果我们安装了 textobj-entire 插件的话,简单地执行 =ae
就可以了. 运行这条命令时光标在哪儿并不重要,因为它总是作用于整个文件.
如果你对如何创建自定义动作命令感到好奇,可以由阅读 :h omap-info
结识操作符待决模式
普通、插入及可视模式很容易辨识,但是 Vim 还有另外一些很容易被忽视的模式,操作符待决模式(Operator-Pending mode)就是一个例子. 每天我们无数次地使用它,但通常它只持续不到一秒时间. 举个例子,在我们执行命令 dw
时,就会激活该模式. 这一模式只在按 d
及 w
键之间的短暂时间间隔内存在,一眨眼工夫就不见了.
如果我们把 Vim 想象成有限状态机,那么操作符待决模式就是一个只接受动作命令的状态. 这个状态在我们调用操作符时被激活,然后什么也不做,直到我们提供了一个动作命令,完成整个操作. 当操作符待决模式被激活时,我们可以像平常一样按 <Esc>
中止该操作,返回到普通模式.
很多命令都由两个或更多的按键来调用(查阅 :h g
、 :h z
、 :h ctrl-w
,或者 :h [
, 可以看到一些例子) ,但在多数情况下,头一个按键只是第二个按键的前缀. 这些命令不会激活操作符待决模式,相反,可以把它们当成命名空间(namespace), 用来扩充可用命令的数目. 只有操作符才会激活操作符待决模式.
你也许想知道,为什么要有一个完整的模式,专门用于操作符和动作命令之间的短暂瞬间,而命名空间命令则仅仅是普通模式的一个扩充?好问题!这是因为我们能够创建自定义映射项来激活或终结操作符待决模式. 换句话说,它允许我们创建自定义的操作符及动作命令,从而让我们可以扩充 Vim 的词汇.
插入模式
在插入模式中可即时更正错误
以下按键操作在插入模式下使用:
按键操作 | 用途 |
---|---|
<C-h> | 删除前一个字符(同退格键) |
<C-w> | 删除前一个单词 |
<C-u> | 删至行首 |
返回普通模式
按键操作 | 用途 |
---|---|
<Esc> | 切换到普通模式 |
<C-[> | 切换到普通模式 |
<C-o> | 切换到插入-普通模式 |
结识插入-普通模式
插入-普通模式是普通模式的一个特例,在此模式中,我们可以执行一个普通模式命令,执行完后,马上就又返回到插入模式. 要从插入模式切换到插入-普通模式,可以按 <C-o>
(参见 :h i_CTRL-O
).
zz
命令可以重绘屏幕,并把当前行显示在窗口正中,这样就能够阅读当前行之上及之下的半屏内容. 我常常会键入 <C-o>zz
,在插入-普通模式中触发这条命令. 此操作完成后就会直接回到插入模式,因此我可以不受中断地继续打字.
插入模式粘贴寄存器中的文本
插入模式, <C-r>{register}
会把复制的文本粘贴到光标所在位置, 其中 {register}
是我们想要插入的寄存器的名字(参见 :h i_CTRL-R
).
假设光标位于行首,针对文本 hello world. 执行以下操作:
yaw
将 hello 复制到复制专用寄存器中A
行尾进入插入模式<C-r>0
行尾粘贴 hello 字符- 操作完成之后仍是插入模式,文本内容变成 hello world.hello
对面向字符的寄存器使用 <C-r>{register}
命令
Vim插入寄存器内的文本时,其插入方式就如同这些文本是由键盘上一个个输进来的. 因此,如果 textwidth
或者 autoindent
选项被激活了的话,可能会出现不必要的换行或额外的缩进,粘贴大量文本会有轻微延时.
<C-r><C-p>{register}
命令则会更智能一些,它会按原义插入寄存器内的文本,并修正任何不必要的缩进(参见 :h i_CTRL-R_CTRL-P
),不过这个命令有点不太好输入!因此,如果我想从一个寄存器里粘贴很多行文本的话,我更喜欢切换到普通模式,然后使用某个粘贴命令.
表达式寄存器做运算
插入模式执行<C-r>=
,然后输入表达式按下回车键<CR>
,Vim就会把表达式执行结果插入到光标所在位置.
比如对文本 6 chairs, each costing $35, totals $ 执行以下操作:
A
在行尾进入插入模式<C-r>=6*35<CR>
执行表达式- 操作完成后仍是插入模式,文本内容变成 6 chairs, each costing $35, totals $210
用字符编码插入非常用字符
插入模式执行<C-v>{code}
可以插入任意字符,比如:
<C-v>065
会插入A
(八进制)<C-v>00bf
会插入¿
(hex十六进制)- 普通模式下,
ga
可以在状态栏显示当前光标下的字符的编码
用二合字母插入非常用字符
插入模式执行<C-k>{char1}{char2}
可以插入以二合字母{char1}{char2}
表示的字符, 比如:
<C-k>?I
=>¿
<C-k>12
=>½
<C-k>14
=>¼
用命令 :digraphs
或者 :h digraph-table
可以查看可用的二合字母列表
用替换模式替换已有文本
R
会进入替换模式,输入字符即可完成替换.
gR
会进入虚拟替换模式. 该模式会把制表符当成一组空格处理,而R
会把制表符当成一个字符处理.
r{char}
和 gr{char}
是单次替换,替换完成后又回到普通模式
可视模式
某些可视模式命令执行的基本功能与普通模式相同,但操作上有些细微的变化. 例如,在这两种模式中, c
命令的功能是一样的,都是删除指定的文本并切换到插入模式. 不过,要指定其所操作的范围,二者的方式却不甚相同. 在普通模式中,我们先触发修改命令,然后使用动作命令指定其作用范围. 然而在可视模式中,我们先选中选区,然后再触发修改命令. 这种次序颠倒的方式对所有的操作符命令都适用.
结识选择模式
在一个典型的文本编辑器环境中,当选中一段文本后,再输入任意可见字符时,这些选中的文本将会被删除. 虽然 Vim 的可视模式未遵从此惯例,但是其选择模式( Select Mode )却按此方式工作.
在进入可视模式后,按 <C-g>
可以在可视模式及选择模式间切换. 切换后看到的唯一不同是屏幕下方的提示信息会在 “-- 可视 --” ( -- VISUAL -- )及“--选择--” ( --SELECT-- )间转换. 如果在选择模式中输入任意可见字符的话,此字符会替换所选内容并切换到插入模式.
按键操作 | 用途 |
---|---|
v | 激活/退出 面向字符的可视模式 |
V | 激活/退出 面向行的可视模式 |
<C-v> | 激活/退出 面向列块的可视模式 |
gv | 重选上次的高亮选区 |
o | 切换高亮选区的活动端 |
切换选区的活动端
如果选取定义到一半发现开始位置不对,可以按下o
,将光标移动到选区的开端.
列块可视模式下批量插入文本
<C-v>
进入可视模式- 利用动作命令创建选好范围(比如
$
选到行尾,即便行的长度不一样) - 使用
A
、I
进入插入模式然后输入文本(也可直接使用r
执行替换,~
大小写转换) - 然后按下
<Esc>
进入到普通模式
示例, 对以下文本的行尾添加;
:
var foo = 1
var bar = 'a'
var foobar = foo + bar
执行<C-v>jj$A;<Esc>
即可.
Vim 对于从普通模式切换到插入模式的命令有几个约定, i
命令和 a
命令都完成此切换,并分别把光标置于当前字符之前或之后, I
命令和 A
命令的表现类似,只是它们分别把光标置于当前行的开头和结尾.
Vim 对于从列块可视模式切换到插入模式的命令也遵从类似的约定. I
命令和 A
命令都完成此切换,并分别把光标置于选区的开头和结尾. 那 i
和 a
命令呢,它们在可视模式里干什么?
在可视模式及操作符待决模式中, i
和 a
键沿用一个不同的约定. 它们会被当作一个文本对象的组成部分,我们将在技巧 51 中深入探讨文本对象. 如果你在列块可视模式里选中了一块区域,并且很奇怪为什么按 i
键没进入插入模式,那么换用 I
键试一下.
命令行模式
Vim 的先祖是 vi,正是 vi 开创了区分模式编辑的范例. 相应的,vi 奉一个名为 ex 的行编辑器为先祖,这就是为什么会有 Ex 命令.
在按下 :
键时,Vim 会切换到命令行模式. 输入一条命令,然后按 <CR>
执行它. 在任意时刻,我们都可以按 <Esc>
键从命令行模式切换回普通模式.
在我们按 · 调出查找提示符或用 <C-r>=
访问表达式寄存器时,命令行模式也会被激活. 本节介绍的一些技巧在这些不同的提示符下都适用.
几乎所有功能都有相应的 Ex 命令(参见 :h ex-cmd-index
),Ex 命令影响范围广且距离远,因此普通模式命令适合在本地进行操作,而 Ex 命令则可以远距离操作.
结识Vim的命令行模式
- 读写文件
:edit
和:write
- 创建新标签页
:tabnew
- 分割窗口
:split
- 操作参数列表
:prev
/:next
- 缓冲区列表
:bprev
/:bnext
- 重复上次的 Ex 命令
@:
操作缓冲区文本的Ex命令
命令 | 用途 |
---|---|
:[range]delete [x] | 删除指定范围内的行[到寄存器 x 中] |
:[range]yank [x] | 复制指定范围的行[到寄存器 x 中] |
:[line]put [x] | 在指定行后粘贴寄存器 x 中的内容 |
:[range]copy {address} | 把指定范围内的行拷贝到 {address} 所指定的行之下 |
:[range]move {address} | 把指定范围内的行移动到 {address} 所指定的行之下 |
:[range]join | 连接指定范围内的行 |
:[range]normal {commands} | 对指定范围内的每一行执行普通模式命令 {commands} |
:[range]substitute/{pattern}/{string}/[flags] | 把指定范围内出现{pattern} 的地方替换为{string} |
:[range]global/{pattern}/[cmd] | 对指定范围内匹配{pattern} 的所有行,在其上执行 Ex 命令{cmd} |
Vim命令行模式中的特殊按键
有些命令在插入模式和命令行模式中可以通用. 例如:
- 可以用
<C-w>
和<C-u>
分别删除至上个单词的开头及行首 - 可以用
<C-v>
或<C-k>
来插入键盘上找不到的字符 - 可以用
<C-r>{register}
命令把任意寄存器的内容插入到命令行
在一行或多个连续行上执行命令
:[range]print
回显指定范围的内容,它不产生什么实际影响:[range]delete
删除指定范围的内容:[range]join
指定范围的内容连接起来
如果不指定范围(没有[range]
),默认是当前行.
用行号作为地址
如果输入一条只包含数字的 Ex 命令,那么 Vim 会把这个数字解析成一个地址,并把光标移动到该数字所指定的行上:
:1
光标移到第一行:$
光标移到最后一行:5p
光标移到第5行,并回显当前行内容(p
是print
的简写)
用地址指定一个范围
:{start},{end}
可以用来指定一个范围:
:2,5p
回显第2到5行内容:.,$p
回显当前行到文件末尾所有行,.
表示当前行:%p
回显当前文档所有内容,%
表示当前稳当的所有行,等价于:1,$p
:%s/Hello/World/
对当前文档所有行进行替换,把 Hello 替换成 World:78,86s/,/;/
把78到86行中的逗号换成分号
用高亮选区指定范围
使用选区命令创建好选区之后,按下:
就会进入Ex模式,并且会预先填充一个范围 :'<,'>
,接下来我们就可以输入一条 Ex 命令,使它在每个被选中的行上执行:
:'<,'>p
回显选区内容:'<,'>s/'/"/g
把选区内的单引号变成双引号
用模式指定范围
Vim 也接受以模式作为一条 Ex 命令的地址,比如 :/<html>/,/<\/html>/p
,实际上也符合范围的一般形式 :{start},{end}
,{start}
地址是模式 /<html>/
,而 {end}
地址是 /<\/html>/
. 换句话说, 这个范围由 <html>
开标签所在的行开始,到对应闭标签所在的行结束.
用偏移对地址进行修正
偏移的一般形式是 :{address}+n
,如果 n
被省略,那么缺省偏移量为 1. {address}
可以是一个行号、一个位置标记,或是一个查找模式.
:/<html>/+1,/<\/html>/-1p
回显<html></html>
之间的内容,但是不包括<html>
及</html>
标签所在的行:.,.+3p
回显当前行(.
)及当前行下三行(.+3
)的内容,如果当前行是第2行,就相当于:2,5p
Ex命令地址及范围符号总结
符号 | 地址 |
---|---|
1 | 文件的第一行 |
$ | 文件的最后一行 |
0 | 虚拟行,位于文件第一行上方 |
. | 当前行 |
'm | 包含位置标记 m 的行 |
'< | 高亮选区的起始行 |
'> | 高亮选区的结束行 |
% | 整个文件(:1,$ 的简写形式) |
第 0 行在文件中并不真实存在,但它作为一个地址,在某些特定场景下会很有用处. 特别是,在把指定范围内的行复制或移动到文件开头时,可以用它做 :copy {address}
及 :move {address}
命令的最后一个参数.
使用:t和:m命令复制和移动行
:[range]copy {address}
命令(copy
可以简写成co
或者t
)可以把一行或多行从文档的一部分复制到另一部分
:[range]move {address}
命令则可以让我们把一行或多行移到文档的其他地方(move
可以简写成m
)
比如(可以把下面例子中的t
换成m
即可实现移动):
:.t.
等同于:t.
, 复制并粘贴当前行,相当于执行Yp
或yyp
命令(不同点是yy
或者Y
会腐败默认寄存器中的内容,而:t.
不会):5t.
把第5行复制到当前行下面:3,5t$
把第3到5行复制到文档底部:.+3t0
把当前行上方的第三行复制到文档顶部:
把当前行上方的第三行复制到文档顶部:6t.
把第 6 行复制到当前行下方:t6
把当前行复制到第 6 行下方:t$
把当前行复制到文本结尾:'<,'>t0
把选中的行复制到文件开头
在指定范围上执行普通模式命令
如果想在一系列连续行上执行一条普通模式命令,我们可以用 :normal
命令:
:3,5normal gUU
第3到5行转成大写:.,.+3normal i//
将当前行及后面三行的行首添加//
:'<,'>normal .
对高亮选区中的每一行, 对其执行普通模式下的.
命令(即对选区内文本重复执行上次执行的普通模式命令)%normal A;
文件每行的结尾都添加一个分号(修改完后 Vim 会自动返回到普通模式. )
重复上次的Ex命令
.
可以重复上次的普通模式命令,而@:
可以重复上次的Ex命令.<C-o>
命令会回到跳转列表的上条记录
自动补全Ex命令
<Tab>
自动补全命令<S-Tab>
反向遍历补全列表<C-d>
显示可用的补全列表
在多个补全项间选择
调整 wildmode
选项可以自定义补全行为(参见 :h 'wildmode'
习惯用 bash shell 的方式工作,那么下面的设置会满足你的需要:
set wildmode=longest,list
如果你习惯于 zsh 提供的自动补全菜单,或许会想试试这个:
set wildmenu
set wildmode=full
当 wildmenu
选项被启用时,Vim 会提供一个补全导航列表. 我们可以按 <Tab>
、 <C-n>
或 <Right>
正向遍历其列表项, 也可以用 <S-Tab>
、 <C-p>
或 <Left>
把当前单词插入到命令行
在 Vim 的命令行下, <C-r><C-w>
映射项会复制光标下的单词并把它插入到命令行中:
/\<<C-r><C-w>\><CR>
等效于*
命令,即查找当前光标下的单词:%s/hello/<C-r><C-w>/g
把hello替换成当前光标下的单词- 把光标移到中文句号, 然后执行
:%s/<C-r><C-w>/. /g
即可把中文句号替换成.
其他快捷键(:h c_CTRL-R_CTRL-W
):
<C-r><C-a>
插入当前光标下的字符串
回溯历史命令
在进入Ex命令行模式(:
)、查找模式(/
)后可以按以下按键填充之前执行过的命令:
<Up>
、向上箭头、<C-p>
反向遍历历史命令<Down>
、向下箭头、<C-n>
正向遍历历史命令
也可以输入 :help
然后在遍历历史命令, 这样只展示包含help
的命令.
模式Vim会记录最后20条命令,可以修改vimrc配置,提高上限:
set histroy=200
结识命令行窗口
可以将两个命令使用 |
连接合成一条使用, 比如:
:write # 保存文件内容
:!node % # 使用node执行当前文件
合并后变成:
:write | !node %
在普通模式下使用q:
命令可以打开命令行窗口(参见 :h cmdwin
), 命令行窗口中的每行内容都对应着命令历史中的一个条目. 在命令行窗口中可以使用Vim全部功能来查找编辑修改命令, 然后使用回车键<CR>
时, 将会把当前行的内容当成 Ex 命令加以执行.
当命令行窗口处于打开状态时,它会始终拥有焦点. 这意味着,除非关闭命令行窗口,否则我们无法切换到其他窗口. 要想关闭命令行窗口,我们可以执行 :q
命令(就像关闭普通 Vim 窗口那样),或是按 <CR>
.
当我们在命令行窗口内按 <CR>
时,该命令在活动窗口的上下文中执行. 活动窗口指的是在调出命令窗口前,处于活动状态的那个窗口. 当命令行窗口处于打开状态时,Vim 并不会提示哪个窗口是活动窗口,因此如果你用了分割窗口的话,需要特别留意.
运行Shell命令
不用离开Vim, 我们还可以把缓冲区的内容作为标准输入发送给一个外部命令,或是把外部命令的标准输出导入到缓冲区里.
执行Shell中的程序
在命令行模式中, 给命令加一个叹号前缀(参见 :h :!
)就可以调用外部程序 :!{cmd}
:
:!ls -al
查看当前目录下的所有文件
在命令行中,符号 %
代表当前文件名(参见 :h cmdline-special
). 在运行那些操作当前文件的外部命令时,我们可以使用它:
:!ruby %
使用Ruby执行当前文件
:!{cmd}
适用于执行一次性命令, 如果想在 shell 中执行多条命令, :shell
命令来启动一个交互的 shell 会话(参见 :h :shell
), 执行完shell后使用exit
退出shell回话并返回Vim.
:shell
命令是 Vim 提供的一个功能,它可以让我们切换到一个交互 shell 中。但是,如果 Vim 自身是在终端中运行的话, 可以利用 bash shell 的作业控制, 暂停一个作业,把它放到后台,然后在稍后某个时间再把它调回前台继续运行.
假设我们正在 bash shell 中运行 Vim,然后需要执行一些 shell 命令。我们可以先按 Ctrl-z
挂起 Vim 所属的进程,并把控制权交还给 bash。此时 Vim 进程在后台处于挂起状态,让我们可以像往常一样与 bash 会话进行交互。
在 bash 中,我们可以用 fg
命令唤醒一个被挂起的作业,把它移到前台。这会让 Vim 恢复成挂起前的状态。 Ctrl-z
和 fg
命令比 Vim 所提供的 :shell
和 exit
命令更加方便快捷。
把缓冲区内容作为标准输入或输出
:read !{cmd}
命令把{cmd}
命令的输出读入当前缓冲区中.:write !{cmd}
命令把缓冲区内容作为指定{cmd}
的标准输入.
下面展示一个重命名文件的例子(例子来自:h rename-files
), 把当前目录下的.js扩展名改成.ts:
- 打开bash shell, 执行vim进入Vim环境
:r !ls *.js
会把当前目录下的所有.js文件读到当前缓冲区, 其中:r
是:read
的简写:%s/\(.*\).js/mv & \1.ts
把每行文本替换成shell脚本:w !sh
把缓冲区内容作为标准输入传递给sh
执行.:q!
退出Vim
使用外部命令过滤缓冲区内容
[range]!{cmd}
当给定一个范围时, [range]
所指定的行会传给 {cmd}
作为标准输入,然后又会用 {cmd}
的输出覆盖 [range]
内原本的内容, 也就是说 [range]
内的文本会被指定的 {cmd}
进行过滤. Vim 把过滤器定义为“一个由标准输入读取文本,并对其进行某种形式的修改后输出到标准输出的程序”.
利用把以下文本中的姓氏按照第二个字段重排:
first name,last name,email
john,smith,john@example.com
drew,neil,drew@vimcasts.org
jane,doe,jane@example.com
执行命令:2,$!sort -t',' -k2
替换即可.
Tricks
普通模式
按键操作 | 用途 | 备注 |
---|---|---|
zz | 把当前行显示在窗口正中 | |
zt | 把当前行显示在窗口顶部 | top |
zb | 把当前行显示在窗口底部 | bottom |
K | 查看处于光标之下的那个单词的手册页 | |
J | 把当前行和下一行连接在一起 | |
ga | 在状态栏显示当前光标下的字符的编码 | |
Vr- | 当前行字符全部替换成- | |
<C-o> | 跳回上一个位置 | |
* | 查找当前单词 |
Percent
- 在普通模式中
%
用来在()
和{}
之间来回跳转,可以搭配操作符操作. - 在Ex命令模式中,
%
表示整个文档.
大小写切换
~
对当前字符进行大小写切换, 无需结合动作命令(motion).
g~
(大小写切换)、gu
(变成小写) 和 gU
(变成大写) 需要结合动作命令:
gUaw
当前单词转成大写gUit
当前标签内文本变成大写
或者调用两次时作用于当前行:
gUgU
或者gUU
当前行全部变成大写
(g~
和gu
使用方式一样)
缩进
>
用于缩进, >
可以配合其他位移操作使用
>>
缩进当前行>G
缩进当前行及后所有行
字符查找
f{char}
在行内查找下一个定字符(光标会移动到字符)F{char}
在行内查找上一个定字符(光标会移动到字符)t{char}
在行内查找下一个定字符(光标停留在字符前)T{char}
在行内查找上一个定字符(光标停留在字符前);
命令会重复查找上次f
命令所查找的字符, 是移动可重复执行,
与;
相反,回到上一个查找的字符*
查找当前光标下的单词