vim 入门笔记——3. 进阶使用
寄存器
Vim 提供了许多寄存器⽤于存放内容,可以理解为剪贴板,
⼀个字符对应⼀个寄存器(例如a-z
,0-9
),不同的寄存器有对应的功能,具体细节非常复杂,下表只列举常用的寄存器。
名称 | 标识 | 内容或功能 |
---|---|---|
无名寄存器 | " |
默认寄存器(上一次复制或删除的内容) |
删除寄存器 | 0-9 |
文本复制和删除历史 |
小写寄存器 | a-z |
手动指定用于保存文本 |
大写寄存器 | A-Z |
用于追加内容到同名的小写寄存器 |
剪切板寄存器 | + / * |
系统剪贴板(需要 Vim 支持) |
空寄存器 | _ |
删除但不存储(黑洞) |
此外,还有一些存放特殊信息的只读寄存器:
%
:当前文件名.
:上一次插入的内容:
:上一次执行的命令
通过 :reg {register}
可以查看对应寄存器的内容,使用
:reg
则会查看所有寄存器。
在复制/删除操作前加上"{register}
就可以指定本次操作所使用的寄存器,例如:
"ayy
:复制当前行内容,保存到a
寄存器中;"bdiw
:删除单词,保存到b
寄存器中;"_dd
:删除当前行,保存到空寄存器(也就是直接丢弃,不污染剪贴板)
在粘贴时可以指定使用的寄存器,例如:
"cp
:粘贴,使用c
寄存器的当前内容。
注:即使退出 vim,寄存器中的内容通常也不会丢失,而是会存储在
.viminfo
文件中。
宏
宏指的是录制⼀系列键盘操作,并允许我们重放这些操作,常用于批量化操作文本。
基本用法:
q{register}
:开始录制一段宏,将动作记录在寄存器register
中;- 执行希望记录的动作,按
q
退出录制; @{registetr}
:重放寄存器register
中的动作;
在使用一次 @{registetr}
之后,直接使用 @@
就可以自动重放上一次宏操作,使用 [count]@{register}
可以自动重放 count
次。
注意:
.
命令对宏不⽣效,.
命令只记录上⼀次修改,⽽宏可能包含多次修改。- 由于宏的目标是重复操作,在动作序列中需要在开头或结尾跳转到需要编辑的位置,否则重放是错误的。
Command 模式
Ex Command 格式
Ex Command 的完整格式如下: 1
:[range] {excommand} [args]
其中:
[range]
:指定操作的行范围,缺省时默认为当前行;{excommand}
:具体操作命令;[args]
:命令附带的参数。
range 与 address 表示
Command 模式下的命令都可以加上对应的行范围
range
,range
由一到两个 address
组成(两个之间用,
分隔)。
下面是一些 address
的例子:
{lineno}
:具体行号,例如3
代表第3行,0
代表首行之上的虚拟行$
:最后一行.
:光标所在行/{patttern}/
:下一个pattern
所在行
还支持简单的加减运算,例如:
.+3
:当前行加上3行$-3
:倒数第4行
address
可以组合得到 ranges
,例如:
1, 3
:1行到3行., .+4
:当前行到后续4行(共5行)$-3, $
:倒数第3行到末尾行
除此之外,还有一些特殊范围:
%
:整个文件的所有行'<,'>
:Visual 模式下选中范围的开头和结尾(如果在 Visual 模式下选中范围并输入:
,会自动补充为:'<,'>
)
常见的 Ex Command
:[range] yank [x]
:复制指定行(保存到寄存器x
中)(yank
可以缩写为y
):delete [x]
:删除指定行(保存到寄存器x
中)(delete
可以缩写为d
):print
:打印指定行(print
可以缩写为p
),注意这只是在底部展示一下对应内容,并不是粘贴到文本中。:[range] copy {address}
:把指定行插入到address
:[range] move {address}
:把指定行复制到address
:[address] put [x]
:把寄存器x
的内容插入到address
后面(可以插入第0行后面)
例如
:yank a
:复制当前行,保存到寄存器a
中;:1, 3 delete a
:删除1行到3行,保存到寄存器a
中;:$-3, $ print
:打印倒数第3行到末尾行
Command 批量操作
normal 命令
normal 命令可以对 range
中的所有⾏执⾏ Normal
模式下的命令 commands
。
1 | :[range] normal {commands} |
例如:
:[range] normal .
:⽤ normal 命令在指定的⾏上重复.
记录的操作(先进行一次修改以记录到.
):[range] normal @{register}
:⽤ normal 命令在指定的⾏上重放宏register
global 命令
global 命令可以对 range
中的所有包含
pattern
的⾏执⾏ Command 模式下的 Ex 命令
commands
。
1 | :[range] global/{pattern}/[cmd] |
其中 cmd
缺省时是打印print
。
例如:
:% global /TODO/delete
:删除文件中所有包含TODO的行
替换命令
替换命令可以对 range
中的所有包含 pattern
的⾏操作,将 pattern
替换为 string
。
1 | :[range]s/{pattern}/{string}/[flags] |
其中的 flags
是可选的,用于调整匹配替换行为的细节:
g
:替换所有匹配项(默认仅替换第一个匹配项)i
:忽视大小写(默认区分大小写)c
:每次替换时都要求确认,可以执行、跳过或退出n
:计数匹配项,不进行替换
一些例子:
:s/abc/xyz
:替换当前行的abc
字符串为xyz
:s/abc/xyz/g
:替换当前行的abc
字符串为xyz
(替换所有匹配项):%s/abc/xyz/g
:替换所有行的abc
字符串为xyz
:10,20s/abc//gn
:计数指定范围内的abc
字符串
补充
从外部的粘贴
现在考虑在 windows 系统下基于 terminal+ssh 远程操作中的复制粘贴,此时显然无法使用 vim 内部的复制粘贴机制。
对于文本文件的大段粘贴,如果直接ctrl+v
会出现很多异常:
- 例如如果当前不是 Insert
模式,在开头的部分字符可能会被直接丢弃,直到出现
i
或a
等字符才会进入。 - 例如可能产生异常的缩进,还可能将某些行自动注释掉。
这是因为vim将字符流视为用户从键盘进行的输入行为,并且视作命令进行处理。
可以通过下面的选项将 vim 设置为粘贴模式,此时就可以保持原样进行粘贴
1
:set paste
在执行ctrl+v
之前,最好让 vim 保持在如下模式
1
-- INSERT (paste) --
在粘贴完成后关闭选项即可 1
:set nopaste
复制粘贴的过程实际上非常复杂,vim 和 nvim 的表现并不一致,使用各种 terminal,使用 tmux 都可能带来额外的麻烦,字符流在这些环节中传递,稍不注意就会出错,就像 windows 中的中文乱码一样麻烦。nvim 在这方面比 vim 更加友好,但是也有很多坑。
字母与常见含义关联
字母 | 常见含义 |
---|---|
a | append:追加 |
around:包含边界(文本对象) | |
b | back:返回 |
block:括号内容 | |
c | change:修改 |
d | delete:删除 |
e | end:结尾 |
f | find:行内搜索 |
g | goto:跳转(不能单独使用) |
h | 左移 |
help:帮助 | |
i | insert:插入 |
inner:内部(文本对象) | |
j | 下移 |
join:合并行(J ) |
|
k | 上移 |
l | 右移 |
m | mark:标记 |
n | next:下一个 |
o | open:打开新行 |
p | paste:粘贴 |
paragraph:段落(文本对象) | |
q | quit:退出(还有录制宏等功能) |
r | replace:替换(单个字符) |
s | substitute:替换 |
sentence:句子(文本对象) | |
t | till:行内搜索(跳转到目标前) |
u | undo:撤销 |
v | visual:可视化 |
w | write:保存 |
word:单词 | |
x | 删除单个字符 |
y | yank:复制 |
z | 滚动窗口 |