读 每日一 Vim 笔记
本笔记是在 VS Code 上装的 Vim 插件, 有些功能好像没用
每日一 Vim(0)入门操作
基本操作
vim helloworld.txt
(普通模式下打开 < 如果该文件不存在 vim 自动新建该文件并打开):w
或者:write
#保存正在工作状态的文件:up
或者:update
#保存正在工作状态的文件 up 在 windows 下面不生效:w newfile.txt
#另存为文件 newfile.txt:up newfile.txt
#另存为 newfile.txt:x
#保存当前文件再退出:wq
#同上:q!
#不保存文件直接退出
:x
和 :wq
区别:
:wq
强制性写入文件并退出(存盘并退出 write and quite)。即使文件没有被修改也强制写入,并更新文件的修改时间。:x
写入文件并退出。仅当文件被修改时才写入,并更新文件修改时间;否则不会更新文件修改时间。
光标移动
h
:向左移动j
:向下移动k
:向上移动l
:向右移动
每日一 Vim(1)基础进阶
翻一页 / 半页
ctrl + f
:向下翻一页 forward 前进ctrl + b
:向上翻一页 backward 后退ctrl + d
:向下翻半页 downctrl + u
:向上翻半页 up
光标一次移动一个单词的长度
w
:移动到下一个单词的起始处(既然是 w,代表的意思就是 word,好记吧)W
:移动到下一个单词的起始处
那么 w 和 W 它俩有什么区别呢,w 会把一个单词理解成由连续的字母或数字或特殊字符,而 W 却以空格来识别是否到了下一个单词
与之相反的两个操作是 b 和 B
b
:移动到前一个单词的起始处-
B
:移动到前一个单词的起始处(b 和 B 的区别与 w 和 W 是同理的) e
:移动到下一个单词的结尾处E
:移动到下一个单词的结尾处
光标在一行内的移动
0
(零):移动到行首$
:移动到行未^
:移动到当前行的第一个非空字符处(如果该行首没有空格,那么效果与 0 是一样的)g_
:移动到当前行的最后一个非空格字符处
插入,追加字符
i
:在当前光标位置插入字符I
: 在当前行行首插入o
:在当前行往下插入新的一空行O
:在当前行往上插入新的一空行a
:在当前光标后追加字符A
: 在当前行行尾插入r
: 单字符替换R
:替换当前光标的字符直到退出插入模式(按 ESC)
拷贝一个单词、行首、行尾、整行
y[n]w
:拷贝后面 n 个单词,yw
拷贝当前单词y0
:拷贝的范围是当前光标处到行首y$
:拷贝的范围是当前光标处到行尾y^
:拷贝的范围是当前光标处到本行第一个字符yg_
:拷贝的范围是当前光标处到本行最后一个字符yy/Y
:拷贝当前行nyy
:从当前行开始拷贝 n 行(这里的 n 是数字)
拷贝完后用 p
就可以粘贴了。
- 小
p
:粘贴到光标后 - 大
P
:粘贴到光标前
删除一个单词,行首、行尾、整行
x
:删除当前光标处字符(严格来说 x 不属于插入,因为你还要按 i 才能插入)d[n]w
:删除后面 n 个单词,dw
删除当前光标处单词d0
:删除光标处到行首的字符d$/D
:删除光标处到行尾的字符d^
:删除光标处到本行第一个字符dg_
:删除光标处到本行最后一个字符dd
:删除整行ndd
:删除 n 行(同样 n 代表数字)
每日一 Vim(2) 简单搜索
撤销恢复
u
: 撤销 (undo)ctrl + r
: 重做 (redo)
命令计数器
前面知道了翻页的操作,那么我想具体的往上或往下移动那个光标呢,那么你可以使用命令计数器来实现,如果我要向上移动 8 行,那么直接 8k
就 ok 了。
匹配括号
%
移动
G
: 移动到最后一行gg
: 移动到第一行nG
: 移动到第 n 行行首ngg
: 移动到第 n 行第一个非空字符处:n + enter
: 移动到第 n 行行首
简单搜索
/string
: 向下搜索 string。搜索出来后,如果有多个,回车后n
继续向下搜索,N
继续向上搜索?string
: 向上搜索 string。搜索出来后,如果有多个,回车后n
继续向上搜索,N
继续向下搜索
每日一 Vim(3)替换
-
:[addr]s / 源字符串 / 目的字符串 /[option]
: 我们可以看出 addr 和 option 是可以缺省不填的,他们各个字段的意思是:[addr]
代表检索范围,缺省表示当前行,1,10
表示 1 到 10 行,%
代表整个文件等价于1,$
,而.,$
代表当前行到文件末尾s
代表替换的意思option
代表操作类型,缺省只对第一个匹配的字符进行替换,g
代表全局替换,c
代表操作时确认,gc
可以组合使用
:s/aa/bb/g
: 将光标所在行出现的所有包含 aa 的字符串中的 aa 替换为 bb:%s/aa/bb/g
: 将文档中出现的所有包含 aa 的字符串中的 aa 替换为 bb:12,23s/aa/bb/g
: 将从 12 行到 23 行中出现的所有包含 aa 的字符串中的 aa 替换为 bb:%s/^/#
: 全文的行首加入 # 字符, 批量注释的时候非常有用:%s= *$==
: 将所有行尾多余的空格删除:g/^$/d
: 这里的g
表示对文章中所有符合要求字符串执行替换操作,^
表示行首,$
表示行尾,整个意思是:将所有的空行删除.
每日一 Vim(4)多文件编辑
每日一 Vim(5)c 命令
C or c$
: 表示修改当前行上光标后面的部分. 进入编辑状态.c0 or c^
: 表示从光标处到当前行行首的部分进行修改,^
代表首个非空格处。cc OR S
: 修改当前行. 进入编辑状态.cw
: 从光标所在的位置开始到该单词结束进行修改. 进入编辑状态cfx / cFx
: 这里的x
为一任意字符,cfx
表示修改从光标到下一个字符x
之间的文本;cFx
表示修改从光标到上一个字符x
之间的文本.cn|
: 修改从光标到当前行的第n
个字符 (不包括该字符) 间的所有字符,n
正整数.cnG / cG
: 这里的n
为一任意自然数,cnG
表示修改光标所在位置到第n
行 (不包括) 之间的所有行; cG 表示修改当前行直至末行.
c
命令所删除的数据都存在缓冲区, 可以结合 p/P
命令构成剪切粘贴操作, 方法是:
先进行 c
命令, 再按 Esc
键返回命令模式, 最后才进行 p/P
命令.
每日一 Vim(6)常用命令总结
搜索
/word
: 从顶部往底部搜索 word?word
: 从底部往顶部搜索 word-
/jo[ha]n
: 搜索 john 或 joan在 VS Code 中, 目前发现
\<
\>
无效 /\< the
: 搜索 the 或 theatre 或 then(只要是 the 开头就行)/the\>
: 搜索 the 或 breathe(只要是 the 结尾就行)/\<the\>
: 只搜索 the/\<....\>
: 搜索长度为 4 个字符的字符串/\<fred\>
: 搜索 fred,alfred 或者 frederick 都不能匹配/fred\|joe
: 搜 fred 或 joe/\<\d\d\d\d\>
: 搜索 4 位数字的字符串/^\n\{3}
: 查找 3 个空行的地方
替换
:%s/old/new/g
: 用 new 替换文件中出现的所有 old:%s/old/new/gc
: 与上面这条的作用一样,只不过每替换一个就要确认一次, 貌似 VS Code 没有:2,35s/old/new/g
: 用 new 替换 2 到 35 行的 new:5,$s/old/new/g
: 替换 4 行之后所有 old:%s/^/hello/g
: 用 hello 替换所有行首,相当于在行首插入 hello:%s/$/Harry/g
: 在所有行末加入 Harray:%s/onward/forward/gi
: 用 forward 替换 onward,忽略大小写:%s/ *$//g
: 删除所有行末的空格:%s/^ *//g
: 删除所有行首的空格:g/string/d
: 删除所有出现有 string 的行:v/string/d
: 删除所有不包含 string 的行:s/Bill/Steve/
: 用 Steve 替换当前行首次出现的 Bill:s/Bill/Steve/g
: 用 Steve 替换当前行出现的所有 Bill:%s#<[^>]\+>##g
: 删除所有 HTMl 标签,保留文本dit
: 保留当前行 html 标签,删除文本:%s/^\(.*\)\n\1$/\1/
: Delete lines which appears twiceCtrl+a
: 递增当前光标出的数字Ctrl+x
: 递减当前光标处的数字ggVGg?
: 将全文转换为 rot13 码,这是一种简单暗号语 Rot13,重复执行此命令回复原样
大小写
Vu
: 当前行转换为小写VU
: 当前行转换为大写,当然对中文无效g~~
: 大小写置换vEU
: 选择性的转换为大小,从光标起始处到vE~
: 也是将选中的大写转小写,小写转大写。ggguG
: 全文小写,其实我们可以拆分 3 个命令 gg/gu / 来记忆:set ignorecase
: 搜索时忽略大小写
每日一 Vim(7)自动补全
** 注:以下命令都是在插入模式下执行。**
单词自动补全:
ctrl+n
:当你输入第一个字母的时候,再 ctrl+n
,自动出现下拉菜单,单词默认选中第一个,继续 ctrl+n
,ctrl+p
可以上下切换,或者用方向键(太慢)
ctrl+p
:同上,只是默认的选中的是列表中最后一个单词
行自动补全:
ctrl+x ctrl+l
(l 指小写的 l):两个命令组合使用。在插入模式下输入已经存在行的第一个单词,再按这两个键,就会列出该整行出来
文件名自动补全:
ctrl+x ctrl+f
:插入模式下,按这两个组合键,可以插入当前目录下的文件名。处用在哪里呢,当然是有时候我们要指定默认执行文件的路径,这样就方便啦。
每日一 Vim(8)—Vim 寄存器
先抛出一个问题:每次打开 vim,想找一段文本来练练手,于是打开网页 copy 了一段,问题来了,怎样粘贴到 vim 的编辑器里头去呢?如果你还在 ctrl+v
的话,说明你还无法割舍 windows,这里暂且告诉你如何粘贴:shift+insert
两个键联合起来。再来看下面的原理
寄存器是 Vim 用来存储文件的临时空间,当使用命令 y
(yank)或 d
(delete)复制删除文本时,该文本就会被保存在寄存器中,通过 p
(put)命令插入刚删除或复制的内容。vim 的寄存器分为不同的种类:
数字寄存器:
在 normal 模式下输入 :reg
,您是否看到很多 "
(双引号)开头的数字了呢,这些都是寄存器,(如果暂时没看到,那么在对文本做几个操作,比如:dd
,yy
等),这些寄存器里保存了最近删除的和复制的文本。
数字寄存器有十个,分别是:"0
,"1
,"2
… "9
(注意:数字前有个双引号),寄存器 "0
保存上一次复制 (y) 操作的文本,"1
到 "9
寄存器保存最近 9 次删除的文本行(注意这个 “行” 字),"1
保存的内容是最最近一次删除的内容(也就是说最后一次执行删除命令保存的内容)"2
保存的是倒数第二次删除的内容,依此类推,直到 "9
,如果又有新的操作,那么 "9
的内容将会被 "8
的内容替换,先前 "9
的内容将被丢弃。
那么 p
(put)命令粘贴是哪个寄存器中的内容呢?有时候是粘贴的是 "1
寄存器的,有时粘贴的是 "0
寄存器中的,但是总的原则就是粘贴最近一次删除或者复制的内容,如果删除是最近的一次,就是粘贴 "1
的,也就是粘贴刚刚删除的文本,如果复制是最近的一次操作,那么粘贴的内容是 "0
中的,也就是粘贴刚刚复制的内容。
字母寄存器:
"a
,"b
,"c
… 都是字母寄存器,也许你执行 :reg
的时候看不到这些命令,不要紧,稍后就有了。之前粘贴我们用的都是 p
命令,如果我想粘贴其他寄存器里面的内容呢,你想到了吗?答案就是: 寄存器的名称 + p
。现在我们新建一个字母寄存器,把当前三行保存到 "a
寄存器中去,具体操作如下:在 normal 模式下输入 "a3yy
,这样当前三行就保存在 "a
中去了,粘贴同样在 normal 模式下,"3p
即可。如果是大写字母的寄存器,如执行:"Cdd
:他的作用是把当前行删除,再把内容追加到 "c
寄存器中,也就是说字母寄存器没有大写之分,只是功能上有区别,大写就是追加,小写是替换。
其他寄存器:
""
:无名寄存器,p 命令粘贴的内容,保存最近一次删除或复制的内容。
"-
:(-
是个减号)小删除寄存器(small delete register),前面说过要您注意这个” 行 “字,也就是说并不是所有删除的文本都会保存在数字寄存器中,如果你删除的只是一个单词或字母: dw
或者 x
,那么这个单词并不会保存在 "1
寄存器中,而是保存在 "-
寄存器里面。所有不包含换行符的删除都会保存在此寄存器中。
"*
:这个就是系统寄存器喽,最开始的问题的第二个答案知道了吧
当然还有一些寄存器,这里就不一一介绍了。
每日一 Vim(9)—- 缩进
normal 模式下:
>>
: 当前行增加缩进
<<
: 当前行减少缩进
每日一 Vim(10)—– 正则表达式
每日一 Vim(11)– 标记
文件保存高级篇
以下部分命令在之前的篇幅中有涉及过,有句话说的好:**vim 对新手最痛苦的是选择太多,不知所措,对老手来说最让人快乐的是一个问题总有不同的解决方法,而对寻找最优方法乐此不疲 **,细心的读者相信您都能从中总结出自己的规律以及经验来。
:w new_file
:将缓冲区内容保存为 new_file 文件,原文件内容不更改。:20,$w new_file
:将文件 20 行处到结尾保存为 new_file 文件:.,20w new_file
:将光标所在行到第 20 行保存为 new_file 文件:20,30w >> new_file
:追加 20 至 30 行内容到 new_file 文件中
一个文件 copy 到另一文件
:r filename
:把 filename 中的内容插入到光标所在行的下一行:100r filename
: 把 filename 中的内容插入到 100 行的后面:$r filename
:插入行尾:0r filename
: 插入行首:/parttern/r filename
:还可以使用正则表达式,插入到匹配出的后面一行,需要注意的是如果有多处匹配,它只插入到首个匹配的地方。
标记
标记又称为书签,在某个位置打上标记后,在别处编辑完,通过命令可以回到标记处(以下命令模式中执行)
mx
: 将当前位置标记成 x(此处的 x 可以是任意字母)'x
(单引号): 光标移到标记 x 处的行首- `x(反引号): 光标移到标记 x 处
- ``(双反引号): 当前光标位置与光标上次位置来回切换
''
(双引号): 当前光标位置与光标上次位置来回切换,光标定位在行首
每日一 Vim(12)ab 与 map 命令
每日一 Vim(13) 多窗口
默认情况下,Vim 只为一个 session 打开一个窗口,可以用参数 -o
来打开多个窗口,
如 :vim -o file1 fiel2
,默认这个 session 会水平分割两个窗口显示,
另外参数 o
后面还可以跟数字 :vim -o3 file1 file2
这样 Vim 会打开三个窗口,最后一个窗口会留空白.
打开窗口
如果 vim 已开启,那么在 normal 模式如下命令使用:
-
水平分割窗口
:split
: 当前窗口一分为二,两个窗口显示相同内容。:10split
: 新窗口的高度 10 行:split otherfile
: 新窗口中打开 otherfile:new
: 功能和 split 一样:sp
: split 的缩写形式ctrl+w+s
: 分割窗口的快捷方式:q
: 关闭当前窗口
-
垂直分割窗口
:vsplit
: 以上所有命令都适用于打开垂直分割窗口,只要在前面加 v(vetical)
窗口光标移动:
-
鼠标操作
gvim 默认支持鼠标移动光标操作。
vim 可以设置
:set mouse=a
, 我猜 a 就是 available 的意思。 -
键盘操作
ctrl+w+k
: 使用ctrl+w
(window) 结合hjkl
来移动。先按住CTRL+w
,再按k
,光标就移到上面窗口。hjkl
前面可加数字,移动多个窗口ctrl+w+T
: (大写 T)移动当前窗口至新的标签页(tab,下节专业讲讲标签页)ctrl+w+K
: (大写 K)HJKL
四个组合命令(移动并回流窗口命令,窗口和光标一起移动)
调整窗口尺寸
- gvim 鼠标支持拖拉动作来改变窗口大小。我想你不会这么做,命令行才是高效率工作。
ctrl+w
结合+-=
当然+-=
前面可以接数字,分表代表增大、减小、均分窗口。resize -4
明确指定窗口减少多少ctrl+w
结合<
>
增加窗口宽度
每日一 Vim(14)标签页(tab)
新建标签页
:tabe
: 新建未命名的标签页:tabe file
: 在新标签页中打开或新建文件file
:tabnew
: 和:tabe
命令功能一样:tab split
: 在新标签页中打开当前窗口(缓冲区)的文件:tabf *.txt
: 当前目录搜索匹配*.txt
的文件,在新标签页打开。该命令只能打开一个文件,如果该正则表达式匹配了多个文件,则提示 “文件名过多” 而无法打开。
列出标签页
:tabs
: 列出已打开的标签列表,>
表示当前标签页
切换标签页
:tabn
: 移动到下一个标签页(next):tabp
: 移动到上一个标签页(previous)gt
: 等效于:tabn
gT
: 等效于:tabp
:tabfirst
: 移到第一个标签页:tabr
: 等效于tabfirst
:tablast
: 移到最后一个标签页:tabm 0
: 移到第一个标签页:tabm
: 当前标签移到最后
标签移到两端时会循环移动
关闭标签页
:tabc
: 关闭当前标签页:tabo
: 关闭当前标签以外的标签页:set showtabline=0
: 关闭标签页菜单:set showtabline=1
: 显示标签页菜单:tabdo
: 多标签页命令,可以在多个标签页中执行命令,比如替换多个标签中的内容:tabdo %s/foo/bar/g
更多细节::help tab-page-intro
每日一 Vim(15)折叠 (fold)
Vim 用命令 foldmethod
实现折叠功能,一共有六种折叠方式,可以用 :set foldmethod
查看当前 session
用的是哪种折叠,默认 vim 使用 manual
(手动)方式。
manual
手工折叠是最基本的折叠方式,在处理小块文件的时候简单实用。
zf
: 创建折叠(fold creation)zo
: 打开折叠 (open)zc
: 再次折叠起来 (close)
举例说明:
v{motion}zf
: 折叠 V 模式下选中的文本。(这里的 v{motion} 指的是 Shift+v)。- zf\`a: 折叠当前光标处到标记 a 处的文本 (
ma
就表示在当前光标出做 a 标记) zf3j
: 折叠当前光标出下 3 行zf10G
: 从当前行折叠至第 20 行zfgg
: 折叠至行首zf%
: 光标移至’{‘时,vim 会去匹配’}’,这样’{}’之间的内容就可以折叠起来
indent
vim 自动根据缩进折叠,缩进量与折叠行的嵌套深度关系由 shiftwidth
控制,通过设置 :set foldlevel=num
,num
代表数字。foldlevel=0
时关闭所有折叠,等价于 zM
,zR
设置折行为最大值
每日一 Vim(16)Visual 模式(0)
Vim 的 Visual 模式(中文称之为可视化模式)可以对所选择的文本进行各种操作,Virsual 模式可以分为三种,分别是字符 (Characters)、行 (line)、矩形块 (rectangular block)
viwc
今天呢,就只讲一点点有关 V 模式的用途吧,在 windows 中替换一个单词惯用的手段就是先找到这个单词,鼠标双击该单词,选中之后直接输入新的单词就 Ok 了,但是使用 Vim,你就应该摒弃鼠标,甚至四个方向键也不要去碰。那么在 Vim 中,概括起来就是四个字 <E>f{char}viwc
(请看小标题,这里貌似有十多个字儿,且慢,一个个解析下:<E>
:Esc,进入 normal 模式,f
:查找字符串,当然还可以用 “;” 或者 “,” 继续往后或往前找,v
:visual 模式,iw
:选中整个单词,c
:删除单词,进入插入模式),这样整个单词就会删除,接着就可以插入你想替换的单词了。其次,在 Visual 模式下,hjkl
光标移动的键同样是可用的。对了,在 normal 模式下 “.” 可以重复执行上一次操作,有点象 Python 中的下划线 “_” 表示最后一个表达式的值一样。例如你最后执行的命令 dd
,那么按 “.” 就会继续删除当前行。
在 VS Code 中, f
无法查找字符串, 只能使用 /
查找
每日一 Vim(17)Visual 模式(1)
字符可视化模式可以对任何单个字符或字符串甚至是多行进行处理,通常适用于处理单词或者词组,如果是想处理整行,那么就可以使用(line)行可视化模式,块可视化 则可以对文档区域操作,支持列操作。normal 模式下,命令对应的 Visual 表如下:
v
: 基于字符的 Visual 模式V
: 基于行的 Visual 模式Ctrl+v
: 基于块的 Visual 模式gv
: 重新选取最后一次使用 Visual 模式选中的文本
Visual 模式之间的切换
如果当前是在字符 Visual 模式下,V
就能切换到基于行的 Visual 模式,Ctrl+v
就是切换到基于块的 Visual 模式下,来回的按 v
能在 normal 模式和字符 Visual 模式下切换。此规则同样适用与另外两种 Vrsual 模式。
每日一 Vim(18)Text-Object
前两节讲了 Visual mode 相关内容,这里提一个小问题,“如何选择一个单词?”3 秒后…,你可能会使用命令 vw
,很不幸的是它会把下一个单词的首字母也选中。如果你足够细心的话,你会发现答案在之前的章节中讲过,命令是:viw
。它的作用是选取一个单词(word),无论光标在这个单词的哪个位置都能选中整个单词,那么 i 到底有什么作用呢?这就是今天要讲解的内容。
-
Text-Object:
可以指一个单词,一整句文本,抑或一对括号内的文本,甚至是
html
或xml
标签内的文本,都可以抽象成 Text-Object。与 Text-Object 紧密相关的两个命令就是a
和i
,啊?这两个命令不是append
和insert
吗?其实,a
和i
操作在 Visual mode 或者某些操作(比如:d
,y
等)后面就是另外一种效果了。例如,删除一个单词可以用daw
或者diw
。那么a
与i
又有什么区别呢?
**a
会选择一个对象(an object)包括空格在内,而 i
只会选择一个对象的内部(an inner object)不包含空格 **
下面就是一些命令含义:
aw
: a wordiw
: inner wordaW
: a WORD 从当前单词向左右延伸一直到空格或换行, 包括空格iW
: inner WORD 同上, 但不包括空格as
: a sentenceis
: inner sentenceap
: a paragraphip
: inner paragraph-
a[|]
: a[] block(这里的’‘是或的意思,也就是说’a[‘和’a]’都表示一个 [] 块) at
: a tag (这里的 tag 可以是 html 或 xml 中任何标签对)it
: inner tag
比如在一个 html 文件中,当前光标在某个标签对的内容里头的时候,命令 dat
会把整个标签对包括内容都会删除,而 dit
只会删除标签对之间的内容,保留标签对。详细说明可以 :help text-objecgts
每日一 Vim(19)Visual-Block 模式
从这节开始做点小小变化,增加一些例子的成分,这些例子一般来自于实际编程情景中,算是理论与实践相结合。
Visual-Block 模式一个非常强大的功能就是它支持列操作,比如在某个代码块每行的行首插入注释符号。举例说明:假如有如下 Python 代码,我想把它全部注释
for e in exclude:
if e.endswith(".py"):
try:
os.remove("%sc" % e)
except:
pass
try:
with open(e, "r") as f:
exclude[e] = (f.read(), os.stat(e))
os.remove(e)
except:
pass
- 光标定位到代码块的行首,
Ctrl+v
进入 Visual-block 模式 - 光标向下移动,直到选择所有代码行的第 0 列
- 输入
I
(光标前插入字符),此时你会发现光标跳到了代码块的开头处,此时已经是 insert 模式了,现在就插入 python 的注释字符’#’ - 按
Esc
键,此时你会发现代码块所选区域都打上了注释符号,如下所示:
#for e in exclude:
#if e.endswith(".py"):
# try:
# os.remove("%sc" % e)
# except:
# pass
# try:
# with open(e, "r") as f:
# exclude[e] = (f.read(), os.stat(e))
# os.remove(e)
# except:
# pass
第二个例子:下面是一段 JavaScript 片断:
var foo = 'a'
var bar = 'bcd'
var fb = foo + bar
我们知道 js 中大部分浏览器都能忍受后面没有分号结尾的语句,但是并不推荐这样做,因为我们有必要给他们在行末都加上分号,我们知道 vim 吸引人的地方之一就是一个问题往往有不同的解决方案,这里我们至少有两种方法,1. 替换法::1,3s/$/;/g
(这里的 1,3 是第一到第三行)2. 在 Visual block 模式下 append(追加)。
我们观察上段代码发现每行的语句的长短不一,那有如何批量的加上 “;” 呢,这里关键的一个命令是 $
,美元符号定位了行未。操作步骤基本还是和第一个例子差不多。只需在选中代码块的时候要注意是:Ctrl+v jj$
,这样就能选中到每一行的行末。接着输入 A
命令表示在行末追加字符,输入 “;” 再按 Esc
大功告成了。最终的效果:
var foo = 'a'
var bar = 'bcd'
var fb = foo + bar
每日一 Vim(20)Vim 编码设置
每日一 Vim(21)又谈 abbreviation
每日一 Vim(23)宏 —Record、Play
今天要说的其实就和这个复读机相关,复读机在按下复读的按钮后,就开机录制需要复读的内容,再按一下录制完成,接下来就可以播放了。Vim 中也有与之惊人相似的操作,如果想重复某个操作,就可以用 ** 宏 ** 来完成,还记得以前讲过的一个命令吗:.
就是这个 ** 点 ** 可以重复执行最后一次操作,但是这个 .
的功能比较弱,没法组合使用,如下代码,想在每行末加上分号 “;”:
int a = 1
int b = 2
int c = a + b
print a
print b
print c
如果是用 .
来实现的话,首先在第一行执行 $a;
,然后重复 5 次执行 j$.
,这样算下来你要敲击的键总数在 15 次之多,但是我们用 Record/Play 的话,即使是 100 行代码,按键也不会超过 10 次。命令闪亮登场:q
,就是这个 q,它的威力很猛。接下来就详细介绍如何操作 q
来实现上述需求。
- normal 模式下输入
q
启动 recoding,q 后面跟任意 a-z 的小写字母比如m
,这个字母就是宏的名字,接下来你要执行的操作就会记录在这个宏中。 - 执行我们的任务:“行末加分号”,命令是:
$a;<Esc>j$
,这条命令意思就是:移动行尾插入分号,退到 normal 模式,光标移动到下一行的末尾。 - 再次输入
q
,表示录制结束 - 录制结束后我们就可以 play 了,输入
@m
就会执行宏中的操作,m
是第一步中使用的宏的名称,5@m
表示重复执行 5 次。这样,所有行都给加上分号了,真是好使。
再举一例:实现如下效果:从 1 到 100,每行 + 1。
1
2
3
...
100
命令:首先在第一行插入 1,然后光标定位了 “1” 处,进入 normal 模式,开始录制:qmyyp<Ctrl>aq
,(解释:yyp
:拷贝一行再粘贴在新的一行,<Ctrl>a
:数字 + 1)后然执行 98@m
,收工。
帮楼主补充几点:
-
楼主的宏中第 2 步用 A;
j 就行了。定义宏的一个惯用套路是: 行内跳转定位 + 真正操作 + 移动到下一目标行。 把行内跳转定位放在开头可以让你 replay 时不用事先把光标放在特定的列位置。而因此在宏末尾再做一次行内定位就多余了。 -
宏与 yank 是共享寄存器的,最好有某种策略保证不会冲突。我个人的习惯是 qwer 四个寄存器用来录制临时用完即弃的宏(靠近 q 和 @比较好按)。uiop 四个键预留给 yank (靠近 “ 和 y,p 键。也就是除了常用的 “和 0 号寄存器外,再预留四个寄存器来做复制粘贴,通常够用了),其他字母键用来记录固定宏(也就是关了 vim 下次打开还会接着用的常用宏)
-
可以用 :put 寄存器名称 命令把宏输出到编辑区进行编辑,改好后再 yank 回去。改动时在插入模式下可以用 ctrl+v 后跟组合键来输入组合键(例如你要在宏中回车,在修改宏时可以按 ctrl+v ctrl+m ),当然直接用尖括号括住的特殊键名称亦可。 (例如
表示回车)
具体可以参考 :h keycodes 。 利用这一点可以把一些常用的但又比较复杂的宏的导出到文件中,使用时再 yank 进去,突破 26 个字母寄存器的限制。
每日一 Vim(24)行复制与移动
每日一 Vim(25)filetype—- 文件类型检测
每日一 Vim(26)Normal 命令
每日一 Vim(27)高亮所有搜索模式匹配
*
向后搜索光标所在位置的单词
#
向前搜索光标所在位置的单词
n
和 N
可以继续向后或向前搜索匹配的字符串
:set hlsearch
高亮所有匹配字符串
:nohlsearch
临时关闭,他的缩写形式是::noh
:set nohlsearch
彻底关闭,只有重新 :set hlsearch
才可以高亮搜索
:nnormap <silent> <Space> :nohlsearch<Bar>:echo<CR>
按空格关闭高亮,清空所有已经显示的
如果你想在高亮与不高亮之间快速切换,可以做一个映射 : :noremap <F4> :set hlsearch! hlsearch?<CR>
按回车,临时返回高亮搜索
:nnoremap <CR> :nohlsearch<CR><CR>