第一章 Vim解决问题的方式
-
.
命令会重复上次的修改- 从进入插入模式到返回普通模式,其间的操作被认为是一次可重复的修改
-
f{char}
:查找下一处指定字符出现的位置并跳转;
:向后重复查找,
:向前重复查找
-
*
:查找当前光标所在的单词并跳转n
正向重复查找N
反向重复查找
-
如何替换文档中某一单词?
① 可以使用
%s/old/new/g
,回车即可② 光标移到一个old上按
*
,再按cw
进行单词修改,之后按n.n.
即可(相较于①,可以应对一些可能不需修改的位置)
第一部分 模式
第二章 普通模式
-
u
命令会撤销最新的修改- 进入插入模式到返回普通模式被认为是一次修改,因此可以通过控制<Esc>的使用来控制撤销的粒度。
- 另起一行最好使用
<Esc>o
以便更好地控制撤销粒度 - 如果在插入时按了方向键,会产生一个新的撤销块!
- ⭐️
<C-r>
重做
-
n<C-a>
将下一个数字增加n;n<C-x>
将下一个数字减少n- Vim把以0开头的数字解释为8进制,如007 + 001 = 010
- 可以通过设置
set nrformats=
让Vim把所有数字都当成十进制
-
zz
命令重绘屏幕 ,将当前行显示在屏幕中央 -
ga
在屏幕下方显示当前字符的字符编码(十进制,十六进制和八进制)
-
操作符(operator) + 动作命令(motion) = 操作
-
gg=G
可以自动缩进对应语言的文件 -
操作符待决模式:调用操作符和输入动作命令之间的状态,按<Esc>可以返回普通模式
-
R
由普通模式进入替换模式- 制表符在文件中以单个字符表示,但屏幕上会占据若干列的宽度,此宽度由
tabstop
设置决定 - 替换模式下将制表符当单个字符处理(Vscode的Vim不会),应对这个情况可以使用
gR
命令进入虚拟替换模式 r
和gr
命令允许替换一个字符后马上回到普通模式
- 制表符在文件中以单个字符表示,但屏幕上会占据若干列的宽度,此宽度由
第三章 插入模式
-
⭐️ 插入模式下的快捷删除方式(在bash shell中也可以用)
<C-h> or Backspace
:删除前一个字符<C-w>
删除前一个单词<C-u>
删除至行首
-
插入-普通模式
- 插入模式下按
<C-o>
进入,在此模式下,可以执行一个普通模式命令,执行完后,马上就返回到插入模式 - ⭐️
<C-o>zz
可以在插入模式下,将当前行显示在窗口正中间
- 插入模式下按
-
插入模式下,
<C-r>{register}
可以方便的粘贴几个单词,而不用返回普通模式按p- 多行文本的时候可能会有不必要的换行/缩进,此时可以使用
<C-r><C-p>{register}
,或者返回普通模式按p - 寄存器的部分参看第四部分
- 多行文本的时候可能会有不必要的换行/缩进,此时可以使用
-
表达式寄存器:允许我们做一些运算,并将运算结果直接插入文档中
- 用
=
指明使用表达式寄存器 - 例如,
<C-r>=1+1<CR>
,在光标位置显示2
- 用
-
<C-v>{code}
用字符编码(3位)插入任意字符- 例如
<C-v>065
会输入A - 普通模式下使用
ga
命令可以查询字符编码 - 十六进制和二合字母如果用到了可以再查询
- 例如
第四章 可视模式
- 3种不同的可视模式
- 操作字符文本
v
- 行文本
V
- 块文本
C-v
- ⭐️
gv
可以重复上次的高亮选区
- 操作字符文本
- 不同模式之间可以通过上面的触发键进行切换,可以达到很特别的效果,比如只选每一行的前半行
- 可视模式下按
o
可以切换高亮选区的活动端 - 选区可以配合操作符使用,如选中后按
c
就剪切选区并进入插入模式 - 可以利用
.
命令重复执行可视模式中的命令,但只在行文本时比较有用- 例如增加某两句代码的缩进两次,可以先
V
选中这两行,然后使用>
,再按.
重复
- 例如增加某两句代码的缩进两次,可以先
- 可视模式下怎么快捷选择区域:
- 使用移动光标的各个命令来改变选区,如
e
,G
等 f{char}
以及/
和?
查询及对应的重复操作也可以使用- 可以跟一个文本对象来快捷选中,如
vaw
- 使用移动光标的各个命令来改变选区,如
- ⭐️ 可视模式的巧用
- 可视模式下按
r
进行替换有奇效!可以快速进行横向和纵向的替换 - 同时修改位于同一列的单词,只需要选中后按
c
,修改时只有第一行会实时更新,返回普通模式后其他行才会显示修改后的结果 - 在选定行的行首或行尾加上一样的文本,只需要使用
I
或A
命令- ⚠️ 可视模式下的
i
和a
不再是普通模式下的作用,而会被当作文本对象的组成部分
- ⚠️ 可视模式下的
- 可视模式下按
- 选择模式(有些画蛇添足,基本不用)
- 使用<C-g>切换,将可视模式下选择的文本删除并替换成输入的文本,同时切换到插入模式,相当于按了个
c
(那我为什么不直接按c呢?)
- 使用<C-g>切换,将可视模式下选择的文本删除并替换成输入的文本,同时切换到插入模式,相当于按了个
第五章 命令行模式
-
编辑器家族史:ed -> ex ->vi ->vim,Ex命令(命令行模式下执行的命令)继承自ex行编辑器,可以方便地处理行编辑任务,
:h ex-cmd-index
查看完整Ex命令列表 -
:
进入命令行模式 -
Ex命令的优势:普通模式命令一般操作当前字符或当前行,而Ex命令可以在任意位置执行,并且可以在多行同时执行的能力(影响范围广且距离远)
-
命令行模式下可以使用
<C-h> <C-w> <C-u>
进行快捷删除,也可以使用<C-v> <C-k>
插入不常见字符,还可以使用<C-r>{register}
粘贴一些文本 -
⭐️
[range]
指定范围,可以用行号、位置标记或是查找模式来指定范围的开始位置及结束位置range缺省为本行
- 行号作为地址:
:index
- 如
:1
会跳转到第一行,:3d
会跳到并删除第3行 = 3Gdd
- 如
- 用地址作为一个范围:
:{start},{end}
- 地址可以是行号,位置标记或是查找模式
- 如
:2,5p
打印第2到第5行
- 用高亮选区指定范围
- 在可视模式下按
:
,命令行会填充:'<,'>
,其中'<
表示高亮选区首行,'>
表示最后一行 - 可视模式以外输入
:'<,'>p
,也会回显上次选中的内容
- 在可视模式下按
- 用模式指定范围
- 如
:/<html>/,/</html>/p
- 如
- 用偏移对地址进行修正
:{address}+n
n
可以省略,缺省为1- 如
:/<html>/+1,/</html>/-1p
会剔除html首位标签所在的行 - 又如
:.,.+3
表示当前行以及下面3行
- 行号作为地址:
命令 | 简写 | 用途 |
---|---|---|
:[range]delete [x] | d | 删除指定范围内的行[到寄存器x中] |
:[range]yank [x] | y | 复制指定范围内的行[到寄存器x中] |
:[range]put [x] | 在指定行后粘贴寄存器x中的内容 | |
:[range]copy {address} | t | 把指定范围内的行拷贝到{address}所指定的行之下 |
:[range]move {address} | m | 把指定范围内的行移动到{address}所指定的行之下 |
:[range]join | 连接指定范围内的行 | |
:[range]normal {commands} | 对指定范围内的每一行执行普通模式命令{commands} | |
:[range]substitute/{pattern}/{string}/{flags} | s | 把指定范围内出现{pattern}的地方替换成{string} |
:[range]global/{pattern}/[cmd] | 对指定范围内匹配{pattern}的所有行,在其上执行Ex命令 |
- 一些常用符号:
符号 | 地址 |
---|---|
1 | 文件的第一行 |
$ | 文件的最后一行 |
0 | 虚拟行,位于文件第一行上方 |
. | 光标所在行 |
’m | 包含位置标记m的行 |
’< | 高亮选区的起始行 |
'> | 高亮选区的结束行 |
% | 整个文件(:1,$ 的简写形式) |
-
:t
和yyp
的区别,:t
不使用寄存器,不会覆盖默认寄存器中的内容! -
@:
重复上次的Ex命令 -
⭐️ 怎么为大量行同时执行一个操作?(和无数次的.说byebye)
例如在每行末尾增加一个分号
- 可以先在第一行执行后,可视模式下选中同样需要加分号的行,按
:
后输入:'<,'>normal .
即可实现大量的重复 - 也可以直接执行
:%normal A;
再比如将整个文件注释掉
:%normal i//
- 可以先在第一行执行后,可视模式下选中同样需要加分号的行,按
-
Ex命令可以用
Tab
自动补全,可以用<C-d>
显示可用的补全列表,每次按Tab都会替换成列表中的下一项,按<Shift-Tab>
则会反向替换 (这条试了一下不太好用,windows下的vim按Tab相当于这里<C-d>的效果)- 还有个妙用,按<C-d>还可以对参数列表也展示,不过和命令之间要打一个空格
-
⭐️
<C-r><C-w>
会复制光标下的单词并插入到命令行中- 例如:全局替换时,使用查找找到old,然后修改一个old为new,在new上调用
:%s//<C-r><C-w>/g
即可全局替换 - 要插入字串的话,使用
<C-r><C-a>
- 例如:全局替换时,使用查找找到old,然后修改一个old为new,在new上调用
-
⭐️ 回溯历史命令
- 按<Up><Down>可以查看历史命令,同时支持根据当前输入进行过滤,同样适用于查找模式
/
哦! - 也可以使用<C-p><C-n>替换上下键,避免把手移到小键盘区,但是不支持过滤,可以自定义映射项将<C-p>完全替换成<Up>
cnoremap <C-p><Up>
set history=
可以设定保存的历史记录数
- 按<Up><Down>可以查看历史命令,同时支持根据当前输入进行过滤,同样适用于查找模式
-
使用
|
将Ex命令组合::write|!ruby %
,之后就可以通过历史找到这条组合命令 -
⭐️ 命令行窗口
- 进入
- 普通模式下:输入
q:
进入(经常输错进入,以前都不知道是什么…) - 命令行模式下:
<C-f>
切换进入,当前输到一半的命令会保留 q/
打开查找模式命令历史的命令行窗口,查找提示符只是命令行模式的另一种形式
- 普通模式下:输入
- 使用hjkl移动,回车代表着执行该条历史Ex命令
- 可以对命令行窗口中的内容进行vim的几乎所有操作,包括Ex命令本身哦
:q
退出
- 进入
-
⭐️ 运行Shell命令:命令行模式下加一个
!
前缀:!{cmd}
-
例如
:!ls
-
%
代表当前文件名,例如:!ruby %
-
可以使用vim的
:shell
启动一个交互的shell会话,然后就可以自由使用这个shell,直到输入exit返回Vim- 更便捷的方式是,按
<C-z>
先挂起vim,之后可以通过jobs
查看,并用fg
命令恢复前台作业
- 更便捷的方式是,按
-
:read !{cmd}
会把cmd的输出重定向到缓冲区(就是当前编辑的区域啦):[range]write !{cmd}
会把range指定的内容作为cmd的标准输入,缺省是整个文件-
如:
:write !sh
命令的作用是在shell中执行当前缓存区中的每行命令 -
注意
!
的位置:write ! {cmd}
=:write !{cmd}
,但是⚠️:write! sh
会把缓冲区的内容强制覆盖到sh文件中!
-
-
-
过滤器:
:[range]!{cmd}
是将range的内容作为cmd的标准输入,再用cmd的输出替换range指定的范围 —— 即range指定的文本会被cmd过滤- 我们可以用
!{motion}
操作符切换到命令行模式,并把指定{motion}所涵盖的范围预置在命令行上- 例如按
!G
,Vim就会打开命令行并填充:.,$!
,就不用自己费事整范围了
- 例如按
- 我们可以用