Vim

[count]<C-a> 从当前光标处正向查找一个数字进行自增
[count]<C-x> 从当前光标处正向查找一个数字进行自减

. 重复命令, 会重复进入插入模式那一刻起(包括进入插入模式的按键本身),
直到返回普通模式为止的输入或上一个普通模式下的操作(daw这样的命令会被视作一个操作),
可以被看作一个微型的宏命令.

j. 在下一行里重复之前的操作
n. 在下一个匹配里重复之前的操作
在为 . 范式预备插入模式命令时, 使用方向键(<Up> <Down> <Left> <Right>)会产生撤销块,
导致连续的命令被中断(可以想象成是用 <Esc> 退出了插入模式, 然后用 hjkl 做了移动)
. 范式优于使用count的命令, 例如 dw. 要优于 d2w, 原因在于估计count的值很不直观, 多按几次 . 反而好控制.

i 进入插入模式
gi 在上一次退出插入模式的位置进入插入模式
<C-u> 删除至行首(此快捷键在Bash也可使用)
<C-w> 删除上一个单次(此快捷键在Bash也可使用)
<C-r>{register} 插入寄存器内容(插入模式下)
<C-r>={expression}<CR> 插入表达式寄存器, 将输出表达式的计算结果
<C-r><C-p>{register} 插入寄存器内容(paste模式)

Vim使用基于树而不是队列的历史记录, 撤销前的内容会作为一个分支保留.

按分支操作是把树当作一般的文本编辑器里的队列, 因此无法访问其他分支.

u 按分支撤销 undo
U 按分支撤销对整行的操作
<C-r> 按分支重做 redo

按时间操作是按时间顺序访问树.

g- 按时间回退改动
g+ 按时间前进改动

在输入前几个字之后按 <C-n> 将出现自动补全窗口(如果只有一个, 则直接补全),
<C-n> 切换到下一个补全项, 按 <C-p> 切换到上一个补全项.

<C-x><C-i> 补全整行
<C-x><C-j> 补全标签
<C-x><C-f> 补全文件名

gd 跳转到下一个当前光标处的内容定义的位置
gD 跳转到下一个当前光标处的内容定义的位置(从文件开头查找)

使用 ctags -R 生成标签文件tags.

每次保存ts文件时自动生成标签文件(autocmd自动命令):
autocmd BufWritePost *.ts silent! !ctags -R &

以下命令需要标签文件tags才能使用
<C-]> 跳转到定义 在VSCode里可直接使用
<C-t> 跳转回原文件 在VSCode里可直接使用
:tn 下一个标签 tag next
:tp 上一个标签 tag previous
:ts 打开标签列表菜单 tag select

<C-o> 在插入模式下进入插入-普通模式, 在该模式下可以完成一个普通模式动作,
然后自动回到插入模式, 该模式的优点在于可以省去一个进入插入模式的按键
<C-o>:w<CR> 快速保存
<C-[> 切换到普通模式, 跟用<Esc>退回普通模式似乎没有区别

插入模式 <C-v>{code} 插入非常用字符(三位数的十进制字符编码)
插入模式 <C-v>u{code} 插入Unicode字符(四位十六进制字符编码)
插入模式 <C-v>{nondigit} 按照原义插入字符, 例如 <C-v><Tab> 插入制表符(无视expandtab设置)
插入模式 <C-k>{char1}{char2} 插入二合字符, 例如 <C-k>12 插入 ½, <C-k><< 插入 «
ga 显示当前光标字符的编码

vi时代的缓冲区列表, vim时代用于批量执行命令.
由于vim不会将打开的文件自动填入参数列表, 因此避免将不必要的文件卷入命令执行.

:args {arglist} 填充参数列表, 例如 :args index.html app.js 即可打开两个文件,
参数列表可使用glob模式批量添加, 甚至执行命令 :args `cat .chapters` 以文件内容作为参数
:first
:next
:previous
:last

:arg {file1} {file2} 定义参数列表
:arg **/*.ts 递归定义参数列表(将所有ts文件放进参数列表)
:argdo {ex-command} 对参数列表中的所有文件执行一条命令
:argdo %s/\<animal\>/creature/ge | update 将参数列表内的文件执行替换, 并保存(update, 等价于 :write)
:args 显示参数列表

vim时代的参数列表的替代品, vim多文件编辑的本质是一次将多个文件内容读入多个缓冲区, 保存则为将缓冲区内容写入文件.

:b[uffer] n 切换到第n个文件
:bfirst 列表中第一个文件
:blast 列表中最后一个文件
:bn[ext] 切换到下一个文件
:bp[rev] 切换到上一个文件
:b file 按文件名切换
:ls:buffers:files 列出打开的文件, 这是vim引入的功能, vi只有 :args
<C-^> 在当前文件和轮换文件之间快速切换
:bufdo 类似argdo, 在打开的缓冲区上执行Ex命令
:bd[elete] N1 N2 N3 删除缓冲区(即退出编辑), 也可用 :n1,n2bd 批量删除, 按Tab可自动补全文件名
:qa[ll] 关闭所有缓冲区
:wa[ll] 写入所有缓冲区
:wn[ext] 写入当前缓冲区并切换到下一个缓冲区

内置文件浏览器, 支持sftp, scp等协议.

:Ex:Explore 打开Netrw
:e {directory} 指定目录打开Netrw
:Vex 左右分割打开Netrw
:Sex 上下分割打开Netrw
:Lex 左右分割打开Netrw, 并将Netrw窗口置于最左侧

Enter 打开文件
- 上级目录
D 删除文件或目录
R 重命名文件或目录

知名的侧边文件浏览器插件, 支持鼠标.

:NERDTree 打开NERDTree
:NERDTreeToggle 开关NERDTree
Entero 打开文件

vim -On file1 file2 左右分屏打开多文件 open
vim -on file1 file2 上下分屏打开多文件
vim + file 打开文件并跳转至最后一行

<C-w>s:sp[lit] 水平分屏当前文件 split
:sp[lit] {file} 水平分屏当前文件 or 新文件
<C-w>v:vsp[lit] 垂直分屏当前文件 vertical
:vsp[lit] {file} 垂直分屏当前文件 or 新文件

<C-w>h 切到左窗口
<C-w>l 切到右窗口(以此类推上 kj)
<C-w>H 移动至左侧窗口
<C-w>L 移动至右侧窗口(以此类推上 KJ)
<C-w>w 循环切换窗口, 也可以直接 <C-w><C-w>

<C-w>+ 加大窗口
<C-w>- 减小窗口
<C-w>= 所有窗口等高等宽
<C-w>_ 最大化当前窗口高度
<C-w>| 最大化当前窗口宽度
[N]<C-w>_ 设置当前窗口高度为N行
[N]<C-w>| 设置当前窗口宽度为N列

<C-w>c 关闭当前窗口 close
<C-w>q 关闭当前窗口并退出 quit
<C-w>o:on[ly] 关闭当前窗口以外的所有窗口

  • :lcd {path} 为当前窗口设置工作目录
  • :pwd 查看工作目录
  • :windo lcd {path} 为所有窗口设置工作目录
  • :edit {filename} 相对当前工作目录打开文件
  • :edit! 放弃修改重新载入当前文件, 通常用于录制宏时对操作过的文件进行撤销,
    以便将宏应用于所有缓冲区文件时不会重复运行
  • :e[dit] %<Tab>%<Tab> 补全当前缓冲区文件(即当前文件)的路径, 便于相对当前文件路径打开其他文件
  • :e[dit] %:h<Tab> 上一补全命令的相对路径版本, :h 是一种文件名修饰符(用 :h ::h 查看说明文件)
  • :e[dit] . 打开目录, 空格可以省略
  • :find {filename} 不使用完整路径打开文件文件,
    例如 :find Main.js 输入文件名后也可以用 <Tab> 补全文件路径
    (建议补全路径, 否则在有同名文件的情况下只会打开第一个)
  • :set path+=app/** 添加find的查找路径
  • :set path? 查看当前path路径
  • gf 打开当前光标处的文件(受path和suffxiesadd影响)
  • :set suffixesadd+=.jsgf 功能添加 .js 扩展名
  • :!mkdir -p %:h 在写入不存在目录的文件时, 创建那个目录
  • :w !sudo tee % >/dev/null 以root权限写入
    原理为将当前缓冲区(文件)内容作为输入重定向给具有root权限的tee, 再由tee写入到对应文件,
    用/dev/null屏蔽掉多余的打印内容
  • :clo[se] 关闭当前窗口(只剩一个窗口时不能关闭, 这是与:quit的主要区别)
  • :on[ly] 只保留当前窗口, 关闭其他窗口

vimdiff {filename1} {filename2}

]c 跳转到上一个冲突
[c 跳转到下一个冲突
do 将文件修改应用于当前窗口中的文件 diff obtain
dp 将当前窗口中的文件修改推送给另一个文件 diff put
:diffg[et] {file} 相当于do, 在同时比较3个文件以上时, 需要后接文件名
:diffp[ut] {file} 相当于dp, 在同时比较3个文件以上时, 需要后接文件名

在git处理合并冲突时使用vimdiff
git mergetool
左上角的窗口为本地修改(当前分支)
中上的窗口为共同祖先
右上角的窗口为远程修改(合并进来的分支)
下方的窗口为合并结果(需要通过编辑解决冲突的文件)
:diffg L 使用本修改 LOCAL
:diffg B 使用共同祖先 BASE
:diffg R 使用远程修改 REMOTE
:wqa 保存并退出
删除 .orig 文件(合并冲突的备份)
:w `date` 使用Shell命令的输出作为文件名保存

:set foldmethod=indent 启用基于缩进的折叠功能
:set foldmethod=syntax 启用基于语法的折叠功能(需要Vim能够识别该语法)
:set foldmethod=diff 处于diff时采用的折叠方式

zo 打开折叠 open
zc 关闭折叠 close
za 切换折叠状态
zR 打开所有折叠
zM 关闭所有折叠

::tabnewtabe[dit] {filename} 打开一个新的标签页
<C-w>T 把当前窗口移到一个新标签页
:tabc[lose] 关闭当前标签页及其所有窗口
:tabo[nly] 只保留当前标签页,关闭其他所有标签页
:tabn[ext] {N}{N}gt 切换到标签页N
gt:tabn[ext] 切换到下一标签页
gT:tabp[revious] 切换到上一标签页
:tabmove [N] 将标签页移动至N, 0为第一个标签页, 若省略N, 则移到最后一个标签页

:x 保存退出(相当于 :wq?)
:qa! 强制退出所有文件 quit all
:e file 打开另一个文件
:e! 放弃对文件的所有修改, 恢复原样
ZZ 保存当前文件并退出(:wq 的别名)

Ctrl+G 显示当前编辑文件状态信息(文件名, 当前行, 总行数, 百分比等)
<C-O> (在查找等操作之后)返回上一次光标所处的位置, 可重复使用
<C-I> 反向的 <C-O>

r 修改单个字符, 在可视模式下, 将以单个字符填充所有选中的字符 replace
s 删除当前字符并进入插入模式
S 删除当前行并进入插入模式(会保持缩进, 功能与cc一样)
c{motion} 删除并进入插入模式
cc 删除整行并进入插入模式(会保持缩进)
cw 删除单词并进入插入模式
C 删除至行尾(和 D 不同, 不会回退到上一个字符)
D 剪切至行尾(会回退到上一个字符, 相当于 d$)

gj 根据屏幕行向下移动
gk 根据屏幕行向上移动
g^ 移动到屏幕行的第一个非空字符
g$ 移动到屏幕行的行尾

v <motion> :w filename 将选区内容保存为新文件

:h index 查看Vim默认的按键绑定
:map {key} 查看以对应按键key开头的映射
:unmap {key} 取消对应的重映射
:mapclear 清除所有重映射

:map ^M I#<ESC> 设置递归快捷键映射, 例子意为Ctrl+M映射为I#<ESC>(在行首插入#然后退出插入模式)
:noremap ^M I#<ESC> 设置非递归映射
:nnoremap ^M I#<ESC> 设置正常模式下的非递归映射
:vnoremap ^M I#<ESC> 设置可视模式下的非递归映射
:inoremap ^M I#<ESC> 设置插入模式下的非递归映射
:ab email [email protected] 设置字符宏, 输入email(需要追加一个空白字符)会被自动替换为 [email protected]

:ce 居中 center
:le 靠左 left
:ri 靠右 right

进入块视图模式, 选中多行文本, 用 I 在选中内容前批量插入字符 //.

进入块视图模式, 选中需要删除的内容, 用 d 命令删除.

  • 0 行首
  • ^_ 非空白字符行首
  • $ 行尾
  • g_ 非空白字符行尾
  • w 移动光标到下一个"狭义单词(以符号为分隔符)的开头" word
  • W 移动光标到下一个"广义单词(以空格为分隔符)的开头"
  • b 移动光标到上一个"狭义单词(以符号为分隔符)的开头 backward
  • B 移动光标到上一个"广义单词(以空格为分隔符)的开头"
  • e 移动光标到下一个"狭义单词(以符号为分隔符)的结尾"
    (如果当前光标在一个单词的非结尾处, 那么下一个"单词的结尾"即是当前单词的结尾处, 而非"下一个单词"的结尾)
  • E 移动光标到下一个"广义单词(以空格为分隔符)的结尾"
  • ge 移动光标到上一个"单词的结尾"
  • fa 移动光标到本行下一个字符为a的位置 find
  • Fa 移动光标到本行上一个字符为a的位置
  • ta 移动光标到a前的一个字符, till, 这个命令通常用于dt.(删除至下一个句号前)这样的动作
  • Ta 移动光标到a后的一个字符
  • ( 移动至句首(以". "作为一句, 注意句号后的空格)
  • ) 移动至句尾(以". "作为一句, 注意句号后的空格)
  • { 移动到上一个段落(空白行)
  • } 移动到下一个段落(空白行)
  • ; 向后重复 f, t 操作
  • , 向前重复 f, t 操作
  • d/something 删除至something, 这提供了正则删除能力
  • ggH1G[[`` 文件首行
  • G]] 文件末行
  • H 光标移动至编辑区(window)首行 head line of window
  • M 光标移动至编辑区(window)中间 middle line of window
  • L 光标移动至编辑区(window)末尾 last line of window
  • nG 移动光标到第n行
  • nH 移动光标到第n行( ngg 同理)
  • % 在配对的括号字符上来回移动, 有效字符为 ()[]{}
  • * 查找当前光标处的单词
  • # 反向查找当前光标处的单词(这两个命令实际上是为了快捷使用而创建出来的宏命令)
  • g* 查找当前光标处的单词, 但不使用单词界定符
  • g# 反向查找当前光标处的单词, 但不适用单词界定符
  • n% 到文件n%的位置

可视范围
zz 当前行置于屏幕中间
zt 当前行置于屏幕顶端 top
zb 当前行置于屏幕底端 bottom
<C-f> 下一页 forward
<C-b> 上一页 back
<C-u> 上半页 up
<C-d> 下半页 down
<C-e> 向下一行
<C-y> 向上一行

dfa 删除至下一个字符 a
dnfa 删除至第n个字符 a
dH 删除至文本首
dG 删除至文本尾
daw 删除光标位置所处的单词至下一个单词的第一个字符(dw只删除当前光标位置到下一个单词的第一个字符)
yw 复制单词
yfa 复制至下一个字符a
ynfa 复制至第n个字符a
y$ 复制至行尾
yH 复制至文本首
yG 复制至文本尾
J 合并下一行内容至本行(删除两行之间的换行符和其他空白符) 两行中间会有一个空格
gJ 两行中间没有空格的 J
:1,10m20 将1到10行的内容移动到20行后 move

i inside,不包括文本对象边界,只针对内容
a around,包括文本对象边界

s 句子 sentence
w 狭义单词 word
W 广义单词
p 段落
t HTML标签
" 双引号
' 单引号
( 括号
< 尖括号
[ 方括号
{ 花括号
可以用 v{i|a}{文本对象} 方式直接框选相关内容

P 复制至光标前 paste

插件

<Leader><Leader>w 开启基于单词的EasyMotion, 最常用(同理, 还有 W, b, B, e, E, ge, gE)
<Leader><Leader>f 开启正向查找字符的EasyMotion(同理, 还有 F, t, T)
<Leader><Leader>{方向键} 朝对应的文本方向开启EasyMotion
在搜索时 <Leader><Leader>n 开启用于跳转到搜索结果的EasyMotion(同理, 还有 N)

<Leader> 先导键, 默认为 \
let mapleader = "\<space>" 将先导键修改为空格(于 .vimrc 中设置)

u 转小写字母 等于普通模式下的 gu{motion} 例如 guit
U 转大写字母 等于普通模式下的 gU{motion} 例如 gUit
注意可视模式下的命令用 . 重复执行时,选取和动作会被视为两条命令,
将导致一些问题(例如选区长度被固定为一定数量的字符).
正确的方法是使用 g 开头的命令一次完成选取和动作, 这样 . 命令就可以正确执行.

o 光标跳转至选区另一端, 该命令用于调整选区范围
gv 重选中上次选区

{number}| 跳转到指定列
{number}gg:{number} 跳转到指定行
:+{number} 向下相对跳转到指定行
:-{number} 向上相对跳转到指定行

ma 标记此处为a
'a 跳转至a标记
:marks 查看所有标记
:delm! 删除所有标记
m{a-z} 缓冲区范围内的位置标记
m{A-Z} (多文件)全局范围内的位置标记
'{a-zA-Z} 跳转到标记所在行
`{a-zA-Z} 跳转到标记所在行和列
`` 跳转到上次跳转之前的位置, 常见用法是配合 % 跳转修改成对括号, %r{w}``r{w}
`< 上次高亮选区的起始位置
`> 上次高亮选区的结束位置
同理也存在 ' 相应的跳转, 只不过 ' 跳转到对应行

不常用的跳转:
`. 上次修改(即跳转到改变列表的最后一位)
`^ 上次插入
gi 跳转到上次插入位置并进入插入模式(相当于 `^i)
`[ 上次修改或复制的起始位置
`] 上次修改或复制的结束位置

Vim 8.1开始提供的模式, 可在Vim内打开一个终端窗口.

:term[inal] 打开终端
:term {command} 打开终端并执行命令

r (进入单字符替换模式)替换光标当前字符 replace
R (进入替换模式)替换光标后的所有字符(用 <ESC> 停止)
Vr{char} 替换整行字符为char

~ 改变当前字符的大小写
n~ 改变n个字符的大小写
g~~ 改变整行的大小写
gUU 改变整行至大写
guu 改变整行至小写
3gUU 改变三行至大写
gUw 改变单词至大写
guw 改变单词至小写

<C-v> 块可视化模式(可以无视行的长度选中文本块, 但在Terminus里无法使用, 疑似因为 <C-v> 被屏蔽)
在块可视化模式内用 IA, 可以实现在选中的文本块的行前或后添加文本(将批量作用到选中文本块的每一行)

  • va""" 文本块内部, 可用此命令选中该文本块的所有内容, " 可替换为其他文本块字符,
    例如 (, ', {, [
  • vi" 同上, 但不选中 " 本身

<C-n><C-p> 代码提示(编辑模式下)

qa 开始录制宏并保存到寄存器a
aA 开始录制宏并追加到寄存器a
q 停止宏录制
@a 应用位于寄存器a的宏
@@ 应用上一个宏
[email protected] 应用a宏n次
:'<,'>normal @a 进入V模式后批量运行宏a, 在这种运行方式里宏a在一行中运行失败不会中断其他行的运行
:argdo normal @a 批量运行宏a至参数列表中的文件, 有必要对录制文件执行 :edit! 撤销修改, 避免重复运行
:argdo execute ":normal @a" | update 批量运行宏a至参数列表中的文件并保存

:new 打开新的缓冲区
"ap 输出宏a的内容
_"ay$ 将新缓冲区的内容复制回宏a

:reg 查看所有寄存器
:reg {register} 查看寄存器

:put a 输出寄存器a的内容到下一行
"add:d a 将行内容写回寄存器a, 用 "ay$ 写回寄存器时可以免去行尾的换行符

"" 无名寄存器 即 d, s, x, y, c 命令默认使用的寄存器
"_ 黑洞寄存器, "_d{motion}, 删除的内容不会进入任何寄存器
"0 复制专用寄存器, 当使用 y 命令时, 相关内容不仅会进入无名寄存器, 也会进入此寄存器,
此寄存器被用于解决 d 等命令覆盖无名寄存器以至复制内容消失的问题;
但实际上也可以用 v 选中需要被替换的文本, 直接用 p 命令覆盖, 就不需要使用此寄存器
"{a-z} 寄存器, "ad{motion} 可将内容输入进寄存器a, "ap 粘贴寄存器a信息
"{A-Z} 追加寄存器, 将寄存器名从小写改为大写字母时, 新内容不会覆盖原寄存器, 而是追加到原内容之后
"+ 系统剪贴板
"* X11窗口系统的主剪贴板(primary), 与鼠标中间有关, Windows和macOS无此概念,
该功能可在编译Vim时被禁用(xterm_clipboard)
"= 表达式寄存器, 可用来计算

只读寄存器
"% 当前文件名
"# 轮换文件名
". 上次插入的文本
": 上次执行的Ex命令
"/ 上次查找的模式

Vim的copy使用y(yank)而不是c是历史原因, 在添加复制命令时, c键已经被用于change命令, 而y键还未被使用

  • 命令行模式按下 <c-d>, 显示所有补全项
  • 命令行模式按下 <Tab>, 自动补全
  • 命令行模式 <C-r><C-w> 复制光标单词(word)插入至命令行,
    在使用s命令进行文本替换时比较有用, 在开启insearch的情况下, 也可以用来直接补全匹配词
  • 命令行模式 <C-r><C-a> 复制光标字串(WORD)插入至命令行

单词(word)的定义: 符合英文语法的单词(单词可以被符号隔开, 比如 we're 算两个单词)
字串(WORD)的定义: 任何以空格字符分隔开的非空白字符

>> 缩进行
:[range]> {count} 缩进行的ex命令形式
<< 反缩进行
:[range]< {count} 反缩进行的ex命令形式
>G 缩进至文件末尾
<G 反缩进至文件末尾

:1 首行
:$ 尾行
:0 虚拟行(位于首行上方)
:. 当前行
:'m 包含位置标记m的行
:'< 高亮选区起始
:'> 高亮选取结束
:% 整个文件, 相当于 :1,$
:.,.+3 选取当前行(.)和后三行
:/<html>/,/<\/html>/ 正则选区
:/<html>/+1,/<\/html>/-1 正则选区(偏移n行, +1 可省略为 +)

:copy 复制选区, 详见 :h :copy
:move 移动选区, 详见 :h :move
:normal 执行普通模式命令, 详见 :h :normal, 例如 :'<,'>normal . 意为对高亮选区里的每一行使用 . 命令
:@: 或直接在普通模式下 @:@@ 重复上一条Ex命令
:shell 打开一个新的shell, exit后即可回到Vim窗口
(如果不想打开新的shell, 也可以用 <C-z> 暂停Vim, 回到原来的shell里, 做完其他事后再用fg回到Vim)
:term 以分屏的形式打开一个shell, 常用
:sil[ent] 屏蔽输出

n1,n2d 删除n1到n2(等同于sed的 d 命令)
同理存在 :#,#s 在范围内查找
g标志位指一整行范围(来源于行编辑器ed), 而不是全局(% 才是全局)
:%s/find/replace/i 大小写不敏感的替换 ignoreCases
:%s/find/replace/gc 需要人工确认的全局替换 check

  • magic
    此为默认模式, 只有极少数符号不需要转义
  • no magic
    所有符号都需要用反斜线 \ 转义
  • very magic
    数字, 字母, 下划线以外的字符都是特殊字符, 通过在正则表达式首加入 \v 启用此模式

:%s/\(\w\)/\1/g 捕获并替换, 括号在very magic模式以外的情况下必须转义
\c 此元字符在正则中强制忽略大小写敏感
\C 此元字符在正则中强制大小写敏感
\v 此元字符在正则中开启very magic模式
(符合Python, Perl, Ruby语法的正则模式),
该模式下 _, 数字, 字母以外的字符都被当作特殊字符, 避免大量使用转义, 有效节省字符数和增强可读性

/\<word\> 搜索整个单词
/\bword\b 搜索整个单词(Vim for VSCode)
\< 单词开始
\> 单词结尾
<\w+> very magic模式下的单词边界零宽度元字符(单词定界符),
<> 包裹字符部分(在一般模式下需要对 <> 转义)
%(a|b) very magic模式下的非储存匹配, 在圆括号前加上 %,
匹配内容不会被存入寄存器 \1, 类似于正则的 (?:pattern)

\V 此元字符在正则中强制只有 \ 带有特殊含义(实际上在正向查找时有 / 作为结束符,
反向查找时有 ? 作为结束符, 所以是三个, 在查找URL时非常容易碰到此情况), 在只想按照原义匹配时很有用
\x 此元字符代表 [0-9a-fA-F], 即十六进制数

\zs 零宽度元字符 匹配边界开始 功能类似于正则的断言 (assert) (?=pattern) (?!pattern) (?<=pattern)
\zs 零宽度元字符 匹配边界结束 功能类似于正则的断言 (assert) (?=pattern) (?!pattern) (?<=pattern)
例子: 假设有一段文本 Goodbye World, Hello World,
需要匹配World, 但只匹配前面是Hello的World, 使用 /Hello \zsWorld<CR> 即可完成匹配(高亮项目为World)

在查找时使用寄存器的方法: /\V<C-r>a<CR> 其中 <C-r>a 即输出寄存器a的值
在查找时使用寄存器并转义的方法: /\V<C-r>=escape(@a, getcmdtype().'\') 其中escape是内置转义函数,
getcmdtype 自动识别当前查找是正向还是反向并返回对应字符, . 是Vim脚本的字符串连接操作符
/<CR> 正向查找上一次匹配
?<CR> 反向查找上一次匹配
gn 匹配状态下的可视模式, 正向选中内容
(光标不在最后一个字符时将选中匹配项的剩余字符, 光标在最后一个字符时将选中至下一个匹配项的第一个字符)
gN 匹配状态下的可视模式, 反向选中内容
衍生:
gUgn 匹配内容转大写
dgn 删除匹配内容
cgn 修改匹配内容

/pattern/e 设置匹配搜索结果时光标的位置在匹配内容的末尾, 可用 :h search-offset 查看更多值

:%s//{string}/g 重复上一次匹配并替换(查找内容为空时会使用上一次匹配的模式),
用于分步完成替换操作(先用 / 完成匹配)
:%s///gn 统计上一匹配的匹配数量, 标志位n抑制替换操作
<C-r>/ 输入上一次的查找模式
~ 在替换域中使用此符号, 则意味着使用上一次替换的替换域
标志位 e 屏蔽错误提示(例如"找不到匹配的模式")
标志位 & 重复上一次substitute命令的标志位
\={script} 执行表达式脚本, 可在substitute命令中使用
\[email protected]{register} 调用寄存器内容, 可在substitute命令中使用
\=submatch(0)-1 匹配项数字 -1, 可用于HTML标签的h2替换为h1, h3替换为h2

  • g& 相当于 :%s//~/g 意为在当前文件里重复执行上一次替换(在忘记输入 %g 的情况下使用)
  • & 重复上一次替换命令
  • :'<,'>&& 在选区中重复上一次替换命令
    (第一个 & 是重复上一次替换命令, 第二个 & 是重复替换标志位,
    需要两个 & 是因为第一个 & 并不会记住标志位)

:%s/\v(<man>|<dog>)/\={"dog":"man","man":"dog"}[submatch(1)]/g
交换替换 The dog bit the mandogman, 其中 {} 是Vim脚本里的字典数据类型

局限于一个窗口版本的快速恢复列表, 大多数快速恢复列表命令前加上 l 即可

:lgrep
:lmake
:lopen
:lclose
:lnext
:lprev
:lwindow

一个Vim会话中只有一个快速恢复列表

:vimgrep //g % 将当前文件里上一次的匹配放进quickfix列表, % 为当前文本路径
:grep 也可直接在Vim里调用外部grep程序, 运行结果会保存在quickfix列表里, 性能更好, 但支持不如vimgrep

:copen 打开quickfix列表, 像Vim一样编辑
:cclose 关闭quickfix列表, 像Vim一样编辑
:cp[rev] 跳转到quickfix列表的上一项
:cn[ext] 跳转到quickfix列表的下一项
:vimgrep /{pattern} **/*.txt 查找当前目录下的所有txt文件
:cfdo 对quickfix列表项目运行批处理, 有必要先 :set hidden
:set hidden 忽略未保存退出(切换缓冲区)
:cfdo update 保存所有quickfix列表文件(如果有更新的话)
:cfdo %s//{string}/g | update 替换保存二合一命令(| 是Vim的命令分隔符, 不是管道符号)

:[range] g[lobal] /{pattern}/ [cmd]
在整个文件(global命令的范围默认即为 %)里对匹配到的行执行命令, 缺省的 cmdprint;
需要注意的是, 命令仍然支持指定范围, 所以 [cmd] 也可以看作 [range][cmd]

  • :v[global]:g[lobal]!:g[lobal] 的非匹配版本, 不匹配的行将执行cmd, v 指invert
  • :g//d 删除所有匹配文本, 比如 :g/\v\<\/?\w+\>/d 可删除所有HTML标签
  • :g/TODO 收集TODO行
  • qaq:g/TODO/yank A 清空寄存器a, 将所有TOOD收集进寄存器a
    (使用大写 A 是为了让每一行都能被追加进寄存器, 而不是覆盖)
  • :g/TODO/t$ 收集TODO并复制到文件尾
  • :g/{/ .+1,/}/-1 sort 排序CSS属性, 请注意 .+1,/}/-1 sort 是此条命令的cmd部分
    这条命令符合如下模式:
    :g/{start}/ .,{finish} [cmd] 只将global用作匹配起点, 用 .,{finish} 模式框选需要用cmd处理的部分
  • :[range]copy {address} 复制内容到指定位置, 别名 :t copyTo
  • :[range]move {address} 移动内容到指定位置, 别名 :m
  • :'<,'>sort 排序选中行

grep的来历即为 :g/re/p g是global, re是正则表达式, p是打印

:[range]!{command} 执行Linux命令, 如果存在range, 则将以命令输出替换相关内容(过滤)
:r[ead] filename 将文本文件的内容输入到当前光标处
:r[ead] !{command} 执行Linux命令并输入到当前光标处(空格可以省略)
:w[rite] !cat 这是read的相反命令, 将缓冲区写入shell命令, 注意空格不可省略, :w! 将改变语义为强制写入

w | !node %| 合并两条命令, 其中 % 会被替换为当前文件名

jumps 查看跳转列表(jump list)
<C-o> 反向遍历跳转列表
<C-i><Tab> 正向遍历跳转列表
changes 查看改变列表(change list)
g; 反向遍历改变列表
g, 正向遍历改变列表

普通模式下 q: 调出历史Ex命令行窗口, 回车执行当前行命令
普通模式下 q/ 调出历史查找命令行窗口, 回车执行当前行命令
输入Ex命令时, 可用 <C-f> 将当前输入的内容切换到命令行窗口编辑

创建 .vim 文件, 可以用于Ex命令的批处理, 在批处理中不需要在语句首使用:
:source batch.vim 在打开的文件中执行批处理=
:args 显示参数列表(当 vim *.txt 一次性打开多个文件时, 可以看到参数列表里有多个文件)
:n[ext] 移动到下一个文件
:pre[vious] 移动到上一个文件
:first 移动到首个文件
:argdo source batch.vim 对参数列表里的每一个文件执行batch.vim批处理

Vim脚本(用于宏)
:let i=0 赋值
:echo i 打印
:let i+=1 递增
<C-r>=i<CR> 在插入模式下用表达式寄存器输入i的值
:echo @a 打印宏内容
:let @a=substitute(@a, 'old', 'new', 'g') 赋值替换宏内文本

:set:se 显示所有修改过的配置
:set all 显示所有配置项
:set option? 显示option的值
:set option! 取消option的值
:set option& 重置option的值为默认值
:set nooptions 取消option的值
:ver 显示 vim 的信息
:setlocal 只对当前缓冲区生效的配置
:bufdo setlocal 对当前打开的所有缓冲区生效的配置
:windo setlocal 对当前打开的所有窗口生效的配置

:set nu 显示绝对行号 number
:set nonu 取消显示绝对行号 number
:set relativenumber 显示相对行号(会覆盖绝对行号)
:n 前往第n行(相当于 nG, ngg, nH)

:set ic:set ignorecase 使查找命令不区分大小写
:set noic 使查找命令区分大小写 no ignore cases
:set smartcase 智能大小写敏感性(当出现大写字符时, 自动敏感)

:set hls[earch] 高亮匹配内容
:set nohls[earch] 关闭高亮
:noh[lsearch] 临时关闭高亮(至下一次搜索)
:set incsearch 在搜索输入关键字时, 就匹配第一个结果

:set nowrapscan 关闭搜索时找不到内容就自动从文件头部继续搜索的特性

:set ft=html 设置文件类型为html(file type)

:set history=200 将历史命令保存上限设置为200条

:set paste 进入paste模式, 该模式下autoindent等妨碍粘贴的选项将被关闭
(在gVim等GUI版本里, 无需设置paste, 粘贴会被自动识别, 不会打乱文本)

:set nopaste 退出paste模式
:set pastetoggle=<f5> 将paste模式的开关设置为F5
:so[urce] {file} 执行Vim脚本, 一般用来更新.vimrc的修改
:so[urce] $MYVIMRC 跨平台的vimrc更新命令
:so% 执行当前编辑的Vim脚本
:edit $MYVIMRC 跨平台的vimrc文件编辑命令

:set directory=$HOME/.vim/swap// 设置交互文件的保存路径(默认为当前文件的位置)
:set noswapfile 关闭交互文件功能

:set undofile 启动持久性撤销(退出文件后仍然保留编辑历史记录)

.vimrc 里启动持久性撤销并设置撤销文件的保存路径

set undofile
if !isdirectory("$HOME/.vim/undodir")
call mkdir("$HOME/.vim/undodir", "p")
endif
set undodir="$HOME/.vim/undodir"

:h[elp] {keyword} 在帮助文件里查找关键字
:h[elp] {keyword} <C-d> 输入一个不完整的关键字, 显示帮助文件里所有包含此关键字的标签.