读 每日一 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: 等效于:tabngT: 等效于: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>