Vim/Gvim 基础
文本编辑
基础编辑
Normal 模式下,使用如下命令进行基本的插入、删除等操作:
命令 | 作用 |
---|---|
i | insert,光标所在位置之前插入文本 |
a | append,光标所在位置的后面插入内容 |
I | 将光标置于当前行的第一个非空白字符,并进入 Insert 模式(行首插入内容) |
A | 将光标置于当前行的行尾并进入 insert 模式 |
O | 光标所在行之后另起一行,并进入 insert 模式 |
x | 删除光标选中的内容 |
dd | 删除整行内容 |
J | 删除光标所在行的换行符(相当于是合并两行的内容) |
u | 撤销上一次的操作 |
U | 撤销对一行的(连续)所有操作 |
Ctrl+R | 重做(反转撤销) |
ZZ 或 :wq | 保存并退出 |
示例1:删除换行符
示例2:撤销
操作符命令和位移
x
命令可以删除一个字符。使用一个命令记数 4x
可以删除 4 个字符。
dw
命令可以删除一个 word,你可以把其中的 w
看作是向右移一个 word 的命令。
其实,d
命令后面可以跟任何一个位移命令,它将删除从当前光标起到位移的终点处的文本内容。【delete】
例如,4w
命令是向前移动 4 个 word. 所以 d4w
命令就是删除 4 个 word。
Vim 只删除到位移命令之后光标的前一个位置。这是因为 Vim 知道你并不是要删除下一个 word 的第一个字符。
但是,如果你用e
命令来移动到 word 的末尾,Vim 也会假设你是要包括那最后一个字符。
# Example 1
To err is human. To really foul up you need a computer.
------------------>
d4w
To err is human. you need a computer.
# Example 2
To err is human. You need a computer.
------->
d2e
To err is human. a computer.
删除的内容是否包括光标所移动到的那个字符上取决于你的位移命令。在这种不包括该位置的操作叫做"排外的"(exclusive), 把包括该位置的操作叫"内含的"(inclusive)。
例如,\$
命令是移动光标到行尾。所以d$
命令就是删除自当前光标到行尾的内容。这是一个"内含的"位移,所以该行最后一个字符也被删除。
此类命令有一个固定的模式:操作符命令 + 位移命令。首先键入一个操作符命令。比如 d
是一个删除操作符。接下来是一个位移命令,如 4l
或 w
,这样任何移动光标命令所及之处,都是命令的作用范围。
改变文本
操作符命令 c
(change)的行为和 d
命令类似,不过在命令执行之后,会进入 insert 模式。
比如,cw
的意思是改变一个 word,或者说,它可以删除一个 word 并让 vim 处于 Insert 模式。如下示例所示:
这里的 c2wbe<Esc>
包含了如下内容:
这里其实有一个细节,为什么 "human"之前的空格并没有被删除?
【对每一个问题,都会有一个简单而清晰的答案,而那个答案总是错的】
cw
命令正式如此,c
操作符与 d
操作符一样,只是有一个例外:cw
,它就象 ce
一样,改变到一直到 word 结尾的内容。而 word 之后的空格被留下了。
【很人性化,因为改变单词的时候,本身也不想删除那个空格】
就像 dd
命令可以删除整行一样,cc
命令可以改变整行。不过仍保持原来的缩进(每行开头的空白)。
也正如 d$
删除到行尾为止的内容,c$
改变当前光标到行尾的内容。就好象是用 d$
删除然后又以a
进入 Insert 模式追加新的文本一样。
快捷命令
有一些操作符+位移命令使用率是如此之高以至于它们以一个单独的字符作为其快捷方式:
快捷方式 | 作用 |
---|---|
x | dl,删除当前光标下的字符 |
X | dh,删除当前光标左边的字符 |
D | d$,删除当前光标到行尾的内容 |
C | c$,修改到行尾的内容 |
s | cl,修改一个字符 |
S | cc,修改一整行 |
此外,r
命令可以在 Normal 模式下完成字符的替换。也可以用"cl"或"s"完成同样的事情,但用"r"的话就不需要再用键回到 Normal 模式。
重复改动
.
命令是 Vim 中一个简单而强大的命令。它会重复上一次做出的改动。
如下示例,假设你在编辑一个 HTML 文件,想删除其中所有的 <B> 标签。你把光标置于<B>的 < 字符上然后命令df>
。然后到\ </B> 的<上用 .
命令做同样的事。.
命令会执行上一次所执行的更改命令( 此例中是df>
)。 要删除另一个标签,同样把光标置于 < 字符上然后执行.
命令即可。
.
命令会重复你做出的所有修改,除了 u
命令 CTRL-R 和以冒号开头的命令。
示例2:你想把"four"改为"five". 它在你的文件里多次出现。你可以用以下命令来做出修改:
【重复的是命令,而不是改动的内容】
如下两行文本,
将光标置于第一行的 1 上时执行 cwxyz
,然后退回到 normal 模式,这个时候第一行变为
然后将光标置于第二行的 1 上,执行 .
命令,则第二行将会变为
而不是
Visual 模式
通常很难说用什么位移命令可以把光标刚好移动到你想删除的文本范围,这时你可以用 Visual 模式。
按v
可以进入 Visual 模式,移动光标以覆盖你想操纵的文本范围,同时被选中的文本会以高亮显示。选中完成之后,键入操作符命令。
在发出实际的更改命令之前,任何时间你都可以决定放弃,用 <Esc> 命令退出 Visual 模式。
下图的的高亮块就是在 visual 模式下选中的。光标的初始位置在 b,然后先 l 向右移,在 j 向下移,然后就变成了下图的样子。
这个时候,使用 d 命令,删除的也只是选中的内容,并不会完整的删除两行。
选择多行
如果想整行整行地操纵文本,使用V
进入 Visual Line 模式。你会看到被选中的文本是一整行为最小选择单位。此时左右移动命令毫无意义。而上下位移命令则会整行整行地选择文本。
如下所示,光标 e 处的时候,使用 V
,就直接选中整行,然后在使用上下方向键的时候,选中的也是整行。
【这个时候使用左右方向键,只会移动光标的位置,选中的内容还是完整的一行】
选择文本块
如果你想以一个矩形的文本块为对象进行操作,你需要用 CTRL+V
进入 Visual block 模式。在编辑表格时这可就派上用场了。
要删除其中的"Q2"列,把光标置于"Q2"的"Q"上。
按下CTRL-V
进入 Visual block 模式,然后用"3j"向下移动 3 行,用"w"选择直到下一个word 的区域。
你可以看到被选中的文本中包含了下一列的第一个字符。使用"h"排除这一列。现在按下"d",中间的这一列就被删除了。
到另一端
如果你已经在 Visual 模式下选中了一些文本,但此时发现还要改变另一头的被选择区域。如果直接移动光标,之前选中的内容会被取消。
此时,可以使用 o
命令(o
代表 other end,另一头)会让光标置于被选中文本的另一头,这样你就可以通过控制光标移动来决定被选文本将从何处开始。再按o
又会让光标置于被选文本的末端。
当你进行矩形文本块内容的选择时,你有 4 个角都可以改变。o
只会把你带到对角的位置去,使用O
命令可以让你在同一行的左右两个角之间移动。
o
和O
在 Visual 模式与 Normal 模式下行为迥异,在 Normal 模式下它们是在当前行的下面或上面插入一个新行。
多行插入
在使用vim编辑器时,有时候需要对多行代码进行加注释或去注释,该操作就可以在 visual 模式下完成,具体步骤如下:
(1)首先按键盘上的 ESC 进入命令行模式;
(2)再按Ctrl+V
进入 VISUAL BLOCK 模式;
(3)利用上下左右(或 h j k l
)键调整需要注释多少行以及行的宽度;【宽度其实无所谓】
(4)再按I
进入插入模式;【行首插入内容】
(5)输入代表注释的符号,比如#;
(6)再次按ESC键,这时就可完成多行注释(可能需要等上一会,不要着急)
删除注释的方法和前面描述的删除 Q2 列的方法是一样的,在 VISUAL BLOCK 模式下,选中后使用 d
删除。
如果想要在多行的行尾插入相同的内容,其步骤如下:
(1)按Ctrl+v
进入可视块模式
(2)通过上下按键选中多行
(3)按$
定位到行尾
(4)按A
进行行尾插入
(5)添加插入内容
(6)按 Esc 退出插入模式
移动文本(复制、粘贴)
粘贴(p)
使用 d
或 x
这样的命令删除文本时,被删除的内容其实是被保存了起来。此时,可以用 p
命令把它取回来(在 Vim 中这叫 put)。
如果删除的是整行的内容,p
命令会把整个文本行都放到光标下面作为单独一行。如果删除的是一行的部分内容(比如说一个 word),p
命令会把这部分文本放到当前光标后面。
P
命令也是取回被删除的内容,不过它把被取回的内容置于光标之前。对于以 dd
删除的整行内容,P
会把它置于当前行的上一行。对于以 dw
删除的部分内容,P
会把它放回到光标之前(光标左边)。
复制文本(y)
y
(yanking)操作符命令会把文本复制到一个寄存器中。然后可以用 p
命令把它取回。
Yanking 只是 Vim 对复制的另一种说法,c
字母已经用来表示更改操作符了, y
还没人占用。把这个操作符叫做 “yank” 也会时时提醒你记得用y
操作符。
因为 y
是一个操作符命令,所以可以用 yw
来复制一个 word,同样可以使用命令记数。例如,用 y2w
命令可以复制两个 word。
yw
复制的内容中包括了 word 之后的空白字符。如果你不想要它们,那就用 ye
yy
命令复制一整行,就象 dd
是删除一整行一样。不过并不像 D
删除当前光标至行尾的内容那样,Y
也是复制整行的内容。注意这种规律中的例外!复制当前光标至行尾的命令是 y$
。【 操作符 + 位移命令 】
文本对象
如果光标位于一个单词的中间而你要删除这个单词,通常你需要把光标移到该单词的开头然后用 dw
命令。不过有一个更简单的办法:daw
。
daw
中的d
还是操作符命令,aw
是一个文本对象。 (“aw"意为"A Word”. 这样"daw"的完整意思是"Delete A Word")更准确地说,该 Word 之后的空白字符也被删除了。
【正常情况下,删除一个 word 的时候,自然是想把其后面空格删除,这样保留下的 word 之间的间隔还是一个空格】
这里其实是对文本使用 " 操作符命令+文本对象 " 的方式进行修改。它很像操作符+位移命令,但是它的起始点不像前者一样始于当前光标,终于位移命令。它不管当前光标所在的位置而把整个文本对象作为操作对象。
例如,如果要删除一个句子,可以使用 das
(delete a sentence);如果想以新的文本替代它,空白就可以留下来,可以使用 cis
(Inner Sentence)。
替换模式
R
命令会让 Vim 进入 replace 模式。在此模式下,每个键入的字符都会替换掉当前光标下的字符。
replace 模式下的例外是按下回车键并不会把当前字符替换为回车,而是插入一个回车。
使用键盘上的 <Insert> 键来可以在 Insert 模式和 Replace 模式之间来回切换。
在 Replace 模式下,使用 <BS> 键做出修改的时候,你会发现原来的字符又回来了。所以它对于最后键入的字符来说实际上等价于一个撤销操作。
光标移动
在插入或删除文本之前,光标当然要先移动到正确的位置上,Vim 有众多的命令来移动光标。
以 word 为单位移动
命令 | 作用 |
---|---|
w | word,光标向后移动到下一个 word 的首字符 |
b | backward,光标移动到前一个 word 的首字符 |
e | end of word,光标向后移动到下一个 word 的最后一个字符 |
ge | 光标移动到前一个 word 的最后一个字符 |
这些命令可以自动换行,例如,移动到当前行的最后一个 word 的时候,再次使用 w
,光标会移动到下一行的第一个 word。
如果当前光标在当前 word 上的位置不是最后一个字符,则 e
命令会把光标移动到当前 word 的最后一个字符上;
ge
其实也不是e
行为的完全反向版,不管当前光标在当前 word 中的位置,它都会移动到前一个 word 的最后一个字符上。
【其实无所谓这些细节,实际使用的时候不过是多按一次和少按一次的区别。】
上述命令会把特殊字符(如 . , _ /
)当作 word 的边界,如下图所示:
如果从光标一开始在 g,使用 w
的时候,光标会一次跳转到 h / j / d / t k
,这些特殊符号也相当于是一个 word。
如果想要从第一个 g 到 h 再到 k,可以使用 W
。
上述表格中的四个操作命令的大写形式就是以空白为分界进行 WORDs 之间的移动。【这里大写就是表示它不是常规意义的 word】
行首和行尾
命令 | 作用 |
---|---|
$ 或 End | 光标移动到当前行的行尾 |
^ | 光标移动到当前行的第一个非空白字符上 |
0 或者 Home | 光标移动到当前行的第一个字符上(行首) |
具体示例如下所示:
^
<----------
This is a line with example text.
<-------------- ----------------->
O $
数字 + 命令可以实现多次的移动。但是在这里多次移动到行尾并没有什么意义,所以他被赋予了新的意义。 1$
的意思是移动到当前行的行尾,2$
的意思是移动的下一行的行尾,一次类推。
^
和 0
不能和数字组合使用。
行内指定单字符
单字符搜索命令 fx
是从光标所在位置开始,向右查找第一个 x 字符,并将光标停留在该字符上。
3fx
就是向右跳转到第 3 个 x 字符。
Fx
是从光标所在位置开始,向左查找并跳转。
tx
和 Tx
的命令可以实现该功能,只不过光标会停留在 x 字符的前一个字符上。
Notes:
- 这四个命令都不会自动换行,只在行内搜索。
- vim 中使用
;
可以重复上一次执行的命令,上面给出的命令是可以使用;
来重复的。使用,
可以反向重复。例如,Fx
本身是向左搜索,用,
重复时因为反转了命令的方向,所以又变为向右搜索。
移动到匹配的括号
%
:跳转到与当前光标下的括号相匹配的那一个括号上去
如果当前光标在 “(” 上,它就向前跳转到与它匹配的 “)” 上,如果当前在 “)” 上,它就向后自动跳转到匹配的 “(” 上去。
该跳转对 []、{}
等同样适用,具体可以通过 matchpairs
选项来指定。
如果当前光标并没有停留在一个可用的括号字符上,%
也会向前找到一个括号,并将光标跳转到与之匹配的括号上。例如,对于下述示例,如果光标一开始行首的 i 上,使用 %
之后,光标会跳转到 d 之后的 “)” 上。
if (a == (b*c)/d)
---+------------>
%
光标移动到指定行
命令 | 作用 |
---|---|
G | Go,把光标定位到最后一行的第一个行首 |
33G | 光标定位到第 33 行的行首 |
gg | 光标定位到第一行的行首 |
滚屏
命令 | 作用 |
---|---|
Ctrl+U | 文本向下滚动半屏,up,文本向下滚动,相对来说就是光标向上,向上翻页 |
Crtl+D | 文本向上滚动半屏,down,“光标向下移动”,向下翻页 |
Ctrl+F | forward,= page down,向下一整页 |
Crtl+B | backward,= page up,向上一整页 |
zz | 将光标所在行置于屏幕正中央 |
简单查找 /string
最基本的查找方法:/string
或 ?string
(?
是向上查找,就是使用 n 的时候会向上查找)
如果需要查找的字符串中有 .*[]^%/?~$
这些特殊字符,需要使用 \
进行转义。
查找时忽略大小写:set ignorecase
/ set noignorecase
/o
+ ↑
会显示命令历史以 o 开头的需要查找的字符串。【长字符串不用每次都打字】
可以使用正则表达式,比如表示行首的 ^
行尾的 $
假设你在当前文件中有一个 word 是"TheLongFunctionName", 你想查找它的下一次出现在哪。当然可以用 “/TheLongFunctionName”, 但这要敲太多次键盘。万一哪个字符敲错了 Vim 就找不到你真正想要的东西。
有一个便捷的方法:把光标定位于这个 word 上,然后按下 *
键。Vim将会取当前光标所在的 word 并以它为目标字符串进行搜索。
这个时候,vim 的底部会显示如下内容。
这里其实是精确查找的语法。例如,/\<the\>
就是精确查找 the 这个单词,而 /the
查找的是三个连续的字母。
【这里只是一个小细节,精确查找应该用的不多】
标记
使用 G
命令从一个地方跳转到另一个地方时,Vim 会记得你起跳的位置。这个位置在 Vim 中是一个标记,使用 `` 命令可以跳回到标记的出发点。
因为 `` 本身也是一个跳转命令,所以再次使用该命令的时候会跳转回来。【a→b→a这样的跳转】
一般地说,只要你执行一个命令使光标定位于当前行之外的某行上去,这都叫一个跳转。例如,/
和 n
这些搜索命令也可以用于跳转。
但是字符搜索命令 fx
和 tx
,或者是以 word 为单位的光标移动命令 w
和 e
则不叫跳转。使用 hjkl
的移动也不叫跳转。
`` 相当于是一个两点之间跳转的命令,而 Ctrl+O(older)可以使光标跳转到更之前的位置。与之相反的命令是 Ctrl+I (因为键盘上 I 和 O 相邻)或者 Tab。
具名标记
就是给光标的位置起一个名称,然后后续可以使用名称将光标跳转到相应的位置。
命令 ma
将当前光标下的位置名之为标记 a, 从 a 到 z 一共可以使用 26 个自定义的标记。定义后的标记在屏幕上也看不出来。不过 Vim 在内部记录了它们所代表的位置。
使用命令 `{mark} 就可以跳转到所标记的光标的位置,`a 就是跳转到之前标记为 a 的位置。
使用 :marks
可以查看已经标记的位置的列表,该列表中会有一些特殊的标记,其含义如下所示:
分屏
vim 可以在启动的时候分屏,也可以在使用阶段分屏,具体方法如下所述。
启动时分屏
左右分屏:vim -On file1 file2 ... filen
上下分屏:vim -on file1 file2 ... filen
其中,-on
中的 n 表示的是分几个屏,可以缺省不写,vim 会按照文件数量进行分屏。
编辑中分屏
上下分割当前文件:crtl+w s
上下分割,并打开新的文件:sp filename
【sp 和 s 就是 split,vim 默认是上下分屏】
左右分割当前打开的文件:ctrl+w v
左右分割,并打开一个新的文件:vsp filename
【v 指的是vertical,垂直分割】
【先按 crtl+w
,松开后再按 s
或者 v
】
切换窗口
针对所有窗口的操作命令
qall、wall、wqall、qall!
这些命令会作用于所有的窗口。【本质上,这些命令只会作用于修改过的窗口】
vimdiff
vimdiff 命令可以分屏打开两个文件,并高亮显示两个文件的不同之处。