《Vim使用技巧》笔记
个人笔记
zc
折叠代码,zv
展开代码
结识.命令
. 命令可以让我们重复上次的修改,它是Vim 中最为强大的多面手。
在普通模式下,x命令会删除当前字符,.命令会重复上次命令,比如上次命令是x,那么.和x的效果是一样的。使用u命令来撤销上次修改,可以多次使用u命令。
>G
命令会给当前行后的每行增加一个TAB缩进,在这之后使用.
命令会进行重复>G
,这样增加了很大的便利性。比如>Gj.j.j.
会给每行多加一个缩进,j
命令是移到下一行。
.号命令记录的是上次修改的命令。比如j
只是移动光标到下一行,不涉及修改,所以不会被记录。
但是注意.
号不会记录u
命令。
不要自我重复
行尾添加分号,
$
到行尾,然后a
;
a命令是在当前光标之后添加内容,而A命令则是在当前结尾添加内容,其实就是$a
的合体。a和A都会导致进入insert模式。
那么如果想要对每行添加;
,可以通过A;
来添加第一行的分号,然后使用j
,再使用.
之后就是j.j.j.
以退为进
var tmp = a+b+c+d
要给上述代码中每个+前后添加一个空格,操作方式为首先执行f+
,查找当前光标后的第一个+,然后s +
,s是删除当前光标下元素并到insert模式,然后+
则是自动输入空格+空格,接着使用f+.
来重复上述步骤。
可见先删一个元素并不是坏事,而是可以达到重复的效果。
f+
是查找命令,使用;
会重复上一次查找,所以以上命令又可进一步优化为;.
执行重复,回退
对于修改,可以通过u
来进行撤销,而对于f+
这种查找,可以使用,
,该命令是反向查找上一次f+
的字符。
如下表是可重复操作和响应的撤销命令:
命令 | 操作 | 重复 | 回退 |
---|---|---|---|
作出修改 | {edit} | . |
u |
在行内查找下一行指定字符 | f{char}/t{char} |
; |
, |
在行内查找上一指定字符 | F{char}/T{char} |
; |
, |
在文档中查找下一个处匹配项 | /pattern |
n |
N |
在文档中查找上一个匹配项目 | ?pattern |
n |
N |
执行替换 | :%s/target/replacement/g |
& |
u |
执行一系列修改 | qx{change}q |
@x |
u |
查找并手动替换
*
号可以查找当前光标出的字符串。在查找到后按下n
就可以跳到下一个查找项。注意n
是文档查找的重复,;
是每行查找的重复,.
是修改的重复。
cw
会删除当前光标指向的单词
那么手动查找替换的命令就是先找到第一个预期的单词,然后*cwn.n.n.n.
,在每次n.
的时候都可以判断,当前是否要进行替换,如果不需要就可以nn.
。
.
范式
一键查找,一键修改。这就叫装逼的.
范式。
撤销单元切成块
u
命令是撤销一次修改,比如i<修改>
就算是一次修改。
好的方式是,在某一段时间调用一次
或者回车命令换成
等。这样就将撤销变成了块状。
构造可重复的修改
如果当前光标指向某个单词的末尾,那么删除整个单词怎么做呢。
第一种方式是db
删除光标前的单词,但不会删除当前光标的字符,然后x
来删除最后的那个字符
第二种方式是b
移动到单词头,然后dw
删除整个单词。
第三种方式是daw
直接删除,可以将daw
理解为delete a word
最好的方式是第三个,因为他是一个命令,可以发挥.
号的优势。
用次数做简单的算数运算
yyp
用来复制一行
数字
会将当前光标处的数字减去该数字,数字
则是加上某数字。
能够重复,就别用次数
删除两个单词d2w
理解为delete 2 word.还可以是2dw
。还有一种是dw.
虽说推荐使用dw.
但我觉得可以按照自己意愿来。
到这就应该明白,次数可以用于命令前,表示后边的命令连续执行多次。
天下无敌。。
Vim的操作方式是操作方式
+ 动作命令
比如dl
中d
就是操作方式,表示删除,l
表示动作命令,这个地方为一个字符。同样的还有daw
删除一个单词,dap
一个段落等。
那么比如现在有一个操作方式的命令gU
表示转换为大写,那么gUaw
就是将一个单词转换为大写。
注意操作方式只是操作,动作命令才会指定范围。
Vim有一个规则是,当一个操作符命令连续敲击两次的时候,就会作用于当前行,所以dd
就是删除当前行。>>
就是缩进当前行,gUgU
/gUU
大写当前行。
Vim中表示操作的命令
命令 | 用途 |
---|---|
c | 修改 |
d | 删除 |
y | 复制到寄存器 |
g~ | 反转大小写 |
gu | 转换为小写 |
gU | 转换为大写 |
> | 增加缩进 |
< | 减小缩进 |
= | 自动缩进 |
! | 使用外部程序过滤{motion}所跨越的行 |
在插入模式中可随时更换错误
插入模式下:
删除前一个字符,
删除前一个单词,Ctrl+u
删除到行首
替换模式
R
进入替换模式
可视模式
v
进入可视模式,通过iw
选取当前单词,c
删除当前选取的字符,并进入插入模式。
可视模式有三种
-
v
是进入面向字符的可视模式 -
Ctrl-v
是面向列块的可视模式 -
V(shift-v)
是面向行的可视模式
o
原先高亮不变,该命令会进行就行选区
vit
可以方便的选择标签内的内容
U
将字母转换为大写
ctrl-v
面向列可视模式,然后使用3j
连续选择3列,之后使用x...
连续给3列绘制空格,之后gv
重新上次高亮区域,再之后输入r|
可以给3行都添加|
符号
Vr-
面向行的可视化,并用-
替换所有的字符。
ctrl-v
面向列可视,然后jje
可以下移两个行,e
会选择单词尾部,之后通过c
删除当前高亮,并进入插入模式,添加字符后,按esc才能看到所有行都被替换了。
Ctrl-v
-> jjjj$
-> A;
给每行添加;
符号,$
是将选择区域跳到行尾。
a``i
,A``I
都是将普通模式切换到插入模式,但是a
,i
是将光标切换到当前字符后或尾,A
,I
是将光标切换到行尾或行开头。
命令模式
命令 | 用途 |
---|---|
:[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} |
如果不注明范围,即ragne的值,则默认是当前行。
p是print的简写,所以:4p
和:4print
命令是一样的,都是打印第4行的内容
range是可以通过行号来指定,如4
就表示第四行,而4,6
表示4到6行,所以:4,6p
就会打印第4行到第6行的内容。为了方便起见{start},{end}
表示范围
而.
代表当前地址$
代表文件末尾,所以:.,$p
就表示打印当前行到文件末尾的内容。
%
代表当前文件中的所有行,所以%p
表示打印当前文件中的所有内容,所以到这就可以知道::%s/source/target/g
为什么可以进行全局替换,原因就是%
表示当前文件的所有行。
同样和p
一样的还有d
表示delete
2G
表示跳到第2行,这个时候运行VG
就会选取到文件末尾,然后按:
进入命令行模式就会出现代表当前内容的字符'<,'>
,输入p就会打印出来。其中'<
表示高亮区的首行的位置标记,'>
代表高亮区的最后一行。
://,/<\/html>/p
表示从标签到结束的内容。
在范围中也可以指定+-操作,比如//+1,/<\/html>/-1p
,而通用格式就是{start}+n,{end}-m[action]
那么对当前行后的n行操作,就可以这么写:.,.+np
范围操作表如下:
符号 | 地址 |
---|---|
1 | 文件的第一行 |
$ | 文件的最后一行 |
0 | 虚拟行,位于文件第一行上方 |
. | 光标所在行 |
'm | 包含位置标记m 的行 |
'< | 高亮选区的起始行 |
'> | 高亮选区的结束行 |
% | 整个文件(:1,$ 的简写形式) |
:t
是:copy
的简写模式,:m
是:move
的简写模式
除了。:{start},{end}t.
就表示把范围内的内容复制到当前行的后边。注意是复制到当前行的后边。
:normal
是对范围内所有的行进行某一操作,比如想在文件中的每一行的末尾添加一个;
号,可以执行%normal A;
而相对的命令,也可以使用.
来表示。
那么对每行输入注释的话就可以用%normal i//
命令。
当使用:n
来进行快速跳转后,可以使用ctrl+o
来快速返回原先的行。
重复命令
@:
重复上次命令行中的命令。
.
重复上次正常状态的命令
命令模式自动补全
按tab会进行命令自动补全,但是如果没有相应的命令就会显示一个特殊符号,而使用ctrl+d
会将所有的能够补全的命令显示出来。
光标移动到某个单词上,使用*
命令就会高亮所有的当前单词,再次按*
会跳转到下一个单词处。
在命令模式下,使用ctrl+r``ctrl+w
会把当前单词直接复制到命令行上。
q:
进入命令行窗口,命令行窗口也是可以编辑的,比如在某行输入A
就会跳到当前行的最后并进入编辑模式,使用J
就会把下一行的内容移到上一行。
想要退出命令行窗口可以按回车执行某命令,或者使用:q
来退出。
在命令行模式下,可以使用ctrl+f
切换到命令行窗口。
q/
是进入搜索内容的缓冲窗口。
执行shell
在命令模式中也可以执行shell命令,如:!ls
执行ls
命令,显示当前目录中的文件。注意:ls
调用的是vim中的ls命令。
%
表示当前文件,比如当前文件为test.py
,想要在编辑后执行py程序,就可以直接在命令行中调用:! python %
但是:!
这种方式只能执行shell的一次性命令,如果想要执行多次命令,可以使用:shell
来启动一个交互的窗口,执行后看起来像是退出,其实只是开启了一个shell,再执行exit
就会回到当前编辑的文件中。
ctrl+z
可以挂起当前的进程,所以在vim中执行该命令就可退出,执行jobs
可以查看当前被挂起的进程,执行fg
可以恢复进程。
命令 | 用途 |
---|---|
:shell |
启动一个shell |
:!{cmd} |
在shell中执行cmd |
:read !{cmd} |
将shell执行的结果输出到当前文件的光标处 |
:[range]write !{cmd} |
将range处的内容作为cmd的输入 |
:[range]!{filter}
使用外部程序过滤range
最后一行如:79,84!sort
就会对79~84行进行排序,其实79,84sort
也可以实现这样的功能,只不过是!
的包装而已,加个!
可以使用外部程序。
文件
vim可以打开多个文件,但是当前编辑的只有一个文件,比如vim *.txt
可以打开所有txt文件,这些文件都处于内存中,使用:ls
可以显示当前打开的所有文件,然后使用:bnext
可以跳到下一个文件中,使用ctrl+^
可以切换文件。
:bnext
到下一个文件中,:bprev
到上一个文件中,:bfirst
,:blast
分别跳到文件列表的开头或结尾。
:buffer {num}
可以跳转到数字表示的文件中,buffer {bufname}
可以跳转到对应的文件名中。
使用bdelete
可以删除当前打开的文件缓冲区。
:args
可查看传递给vim的参数列表。其中[]指明了哪个是活动文件(即当前被打开的文件)
窗口
水平切割窗口(竖向排列)
垂直切割窗口(横向排列)
在窗口间循环切换
切换到左边的窗口
切换到下边的窗口
切换到上边的窗口
切换到右边的窗口
使所有窗口等高等宽
最大化窗口高度
最大化窗口宽度
标签页
:tabe[dit] {path}
创建一个标签页,如果有path则打开对应的文件作为新的标签
:lcd {path}
设置当前窗口的本地工作目录
:close
关闭当前标签页中的窗口
:tabc[lose]
关闭当前标签页,不论有多少个窗口
:tabo[nly]
关闭其余所有标签页
:tabN[ext] {N}
跳到下一个标签页或第N个标签,没有gt
命令好用
:tabp
跳到上一个标签页
{N}gt
跳转到第N个标签页,不带N则跳到下一个
gT
跳到上一个标签页
:tabmove {N}
移动当前标签页到第N个位置,从0开始,省略N则排到末尾。
打开文件
:pwd
和pwd一样
:edit {path}
打开路径对应的文件,支持绝对路径和相对路径
:find {file}
find只需要文件名,不需要填写路径即可打开对应的文件,其默认搜索方式和环境变量一个道理,可以使用:set path+={path}
来设置搜索路径。
使用:edit
打开一个不存在的文件的时候,与vim一个道理,但是如果打开一个目录不存在的时候,就不好保存了,但是这个时候可以在vim中调用shell来创建一个目录:!mkdir -p %:h
其中%
表示当前文件的路径,:h
来去除文件名
查看文件目录
:edit .
或:e.
注意edit后边有个.,该命令打开一个新的窗口(之前的窗口退出),显示当前目录。
:E
查看目录,并可查看隐藏文件
:Vex
水平方向打开一个窗口,显示目录
:Sex
垂直方向打开一个窗口,显示目录
可查看当前文件的一些信息
文件内移动
hjkl
这些字母是在屏幕中上下移动的,但是有的时候会遇见一行占据多行的现象,而hjkl
只能一行一行移动,对于跨行的行是无所适从的,在vim的那本书里面,将其区分为实际行和屏幕行,hjkl
就是针对实际行进行的操作。而针对屏幕行的操作为在hjkl
前加上g
即可,如gj
就是在当前屏幕行下移一行。
0
移动到实际行的行首,g0
移动到屏幕行的行首,^
移动到实际行第一个非空白字符处,g^
移动到屏幕行的第一个非空白字符处。$
移动到实际行的行尾g$
移动到屏幕行的行尾。
其实如果平常使用屏幕行多的话,可以通过nnoremap k gk
来将对应的命令映射到屏幕行的命令中,这样以后只需要使用hjkl
来移动即可。
基于单词的移动
w
正向移动到下一个单词的开头
b
反向移动到上一单词的开头
e
正向移动到下一个单词的结尾
ge
反向移动到上一个单词的结尾
基于字符串的移动
字符串和单词有很大区别,字符串之间的间隔为空格,而单词可以用其他特殊符号进行间隔,对于字符串的移动和基于单词移动类似,不过将对应的命令变为大写,W
,B
,E
,gE
查找
f{char}
正向移动到下一个char所在处
F{char}
反向
t{char}
正向移动到下一个char的前一个字符上
T{char}
反向
;
重复上一次操作,,
反转方向并重复上一次操作
可视模式下的操作
使用前先进入v模式
如果不想在可视模式下操作,还有以下操作方式
c/d/y + 范围
如di"
表示删除"范围中的内容,ci"
表示删除"范围内容并进入插入模式。
范围文本对象
这里的命令表示范围,可以结合d
这个命令进行操作,所以显而易见的daw
就表示删除当前单词和单词前的一个空格(如果有空格的时候删除空格),而diw
则表示删除单词,不删除任何空格。
d
命令和aw``as
等命令配合会比较好,c
命令和iw
等命令配合比较好。
位置标记
使用m{a~Z}
可以给当前位置打个标记,标记名就是a~Z中任意指定字符,而跳转到指定字符指定的标记则使用`{a\~Z}
其中大写字母是全局标记,在第一个文件中打标记,第二个文件中可以感知到该标记,而小写字母则是局部标记。
如mm
给当前位置打标记,后续使用`m
来回退到该标记
vim会自动进行标记,使用以下命令来进行跳转:
括号间跳转
在()``{}``[]
括号间跳转,使用%
即可跳转。
使用r
可进行对字符进行替换,但是如果想要把[]
替换为{}
是不好进行操作的,但是也有方便的方法,可以先通过%
来跳转,这样vim会自动给上一个位置打上标记,然后使用r{
来进行替换,完成后使用``
来跳会另一个括号处,再使用r}
来替换即可。
默认的%
只能在这几个括号间跳转,但是vim自带一个插件,该插件功能是在代码间的if /else
或者其他相关语句跳转,开启的方式为在vimrc中添加以下命令,懒得折腾了,没有进行尝试。
set nocompatible
filetype plugin on
runtime macros/matchit.vim
文件内跳转
使用
可以回跳,而
则相反。
使用:jumps
可以查看历史记录的跳转的记录,这些内容都可以通过
来进行跳转,即使之前关闭了,如:e.
命令打开一个目录,之后还可以通过
来跳转回来之前的文件中。
使用{count}G
也是一个跳转,比:{count}
方便一点,但是jk这种上移,下移则不是。
遍历改变列表
当对文件修改的后,vim会自动记录当前光标所在位置。
使用:changes
来查看修改列表,使用g;
跳转到上一次完成编辑时光标所在行处。
跳转到光标下的文件
gf
可以跳转到光标下的文件,如果配置正确的话。比如使用:e.
来打开一个目录后,就可以通过gf
来跳转到该文件中去,当然使用回车也可以。
复制与粘贴
x
命令将某个字符删除并放入一个寄存器中,之后使用p
将寄存器中的字符取出放入当前光标的尾部。而P
则将字符放入当前光标前
dd
命令不仅仅删除一行,还将当前行保存到寄存器中,之后使用p
来复制。使用ddp
则可以调换当前行和下一行,为什么就不解释了吧。
使用yiw
可以复制一个单词,注意是y
和iw
的结合
寄存器
vim默认使用一个无名寄存器,所以在进行复制剪切等操作都会覆盖之前复制或剪切的内容,如果不想这种效果,则可以指定寄存器。
在使用的时候,所有标记的寄存器前边都有一个引号,切记。
如果真正的想删除某个字符或某个字符串,而不保存到寄存器中,类比linux中的/dev/null
,vim中可以指定"_
寄存器,这个就表示真正的删除,如"_d{motion}
其他的寄存器以字母开头,如"ayiw
表示把一个单词复制到"a
寄存器中,使用"ap
则将"a
寄存器中的内容粘贴。
这些寄存器被称为有名寄存器,以为"a~z
26个字母进行标记。
而使用命令行模式可以通过:delete c
将删除内容放入c
寄存器中,:put c
则粘贴"c
中的内容.
使用y
进行复制的时候,其又一个专用的寄存器,称为复制寄存器,与d``x
命令的寄存器丝毫不相互影响,但是粘贴的时候,如果使用p
或P
粘贴则实际上粘贴的是无名寄存器中的内容,若要粘贴复制寄存器中的内容,需要使用"0
前缀,注意不是0,0前边有个引号,即"0P
或"0p
进行粘贴复制寄存器中的内容。
使用:reg {mark}
来查看某个寄存器中的内容,如:reg "0
查看"0
复制专用寄存器中的内容。
当然使用:reg
可查看所有的寄存器的内容。
以上都是在vim中进行操作的,但是如果想要与外部程序进行互通,则需要使用"+
,
宏
q
键是录制按钮,也是停止按钮,一开始需要按q{reg}
指定一个保存宏的寄存器,此时状态显示recording
则表示在录制中,之后执行一系列命令,再按q
则将命令保存在寄存器中。此时可以通过:reg
命令查看对应寄存器中的内容。
而执行方式则通过@{reg}
来进行执行。通过@@
来执行最近的宏。
使用{count}@{reg}
则执行对应的宏count次。
给宏追加命令,则使用大写的方式,如qa
来对a寄存器进行录制,而qA
则向a寄存器进行中追加命令。
模式
忽略大小写: :set ignorecase
,不忽略大小写::set smartcase
正则表达式,通常使用/
来进行搜索的时候,如果遇到{
这种符号,都需要加上转义字符\
,这样非常不方便,为了和python的那种正则表达式类似,可以在搜索的时候加上\v
命令,这样后边的字符都有特殊含义,不需要加转义字符,如搜索css中的color的值,vim中一般的搜索方式为/#\([0-9a-fA-F]\{6}\|[0-9a-fA-F]\{3}\)
,但是如果加上了\v
命令,则为:/\v#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})
,可以看到少了很多转义符号。同样\v
模式下的\x
表示16进制字符,那么上述又可以表示为/\v#(\x{6}|\x{3})
如果想要按照原义来进行查找,则可以加上\V
字符,表示全匹配,并不会被当作正则来看待。但是\V
模式下的\
和?
还是特殊字符。?
表示前向匹配,/
则是正向匹配。
有时候会有这种问题,想要匹配一全匹配的单词,比如the
,但是匹配的时候there
也被匹配,那么这种方式的匹配规则则为/\v
,即加上<>
符号。
使用\zs命令可以进行特殊匹配,如/i love you
则匹配i love you
,而/i love \zsyou
则只有i love you
中的you
高亮,而其他单独出现的you
不会被匹配。\zs
是排除之前的字符,而\ze
是匹配之后的字符,比如\i \zslove \zeyou
则只匹配love
。
查找
使用:set incsearch
则在输入查找字符的时候实时进行查找。
查看匹配的次数:%s///gn
注意该命令不会进行替换,因为最后的字符n抑制了替换操作。
在匹配到某个单词的时候,可以按下e
自动将光标移动到单词的结尾处,但是也可以直接在查找的命令中写下\e
则在查找的时候不用按任何键,则会自动的将光标移动到对应的结尾处,如\love\e
*
命令可进行查找当前光标处的单词。
替换
:s/[old]/[new]/g
:%s/[old]/[new]/gc
每次替换都会进行提示
使用
可以将寄存器中的内容取出。
global
跳到文件的第一行或最后一行
-
:$
跳到文件最后一行 -
:0
或:1
跳到文件第一行 -
:8
跳到文件第8行
或 另外一组命令: -
gg
跳到文件第一行 -
Shift + g
跳到文件最后一行
复制粘贴
- 选定文本块。使用v进入可视模式,移动光标键选定内容。
2.复制的命令是y,即yank(提起) ,常用的命令如下:
y 在使用v模式选定了某一块的时候,复制选定块到缓冲区用;
yy 复制整行(nyy或者yny ,复制n行,n为数字);
y^ 复制当前到行头的内容;
y$ 复制当前到行尾的内容;
yw 复制一个word (nyw或者ynw,复制n个word,n为数字);
yG 复制至档尾(nyG或者ynG,复制到第n行,例如1yG或者y1G,复制到档尾)
剪切的命令是d,即delete,d与y命令基本类似,所以两个命令用法一样,包括含有数字的用法.
d 剪切选定块到缓冲区;
dd 剪切整行
d^ 剪切至行首
d$ 剪切至行尾
dw 剪切一个word
dG 剪切至档尾粘贴的命令式p,即put(放下)
p 小写p代表贴至游标后(下),因为游标是在具体字符的位置上,所以实际是在该字符的后面
P 大写P代表贴至游标前(上)
显示隐藏行号
set nu
显示行号
set nonu
隐藏行号