Vim命令最全用法指南

Vim 命令最全用法指南

本文旨在成为最全面的 Vim 中文参考手册,涵盖从入门到高级的所有核心用法。


目录

  1. Vim 简介与安装
  2. Vim 的四种模式详解
  3. 移动与导航命令
  4. 插入与编辑命令
  5. 删除与剪切命令
  6. 复制、粘贴与寄存器
  7. 查找与替换
  8. 可视化模式
  9. 多文件编辑(Buffer / Window / Tab)
  10. 分屏操作
  11. 标记与跳转
  12. 文本对象(Text Objects)
  13. 宏录制与回放
  14. 命令行模式与 Ex 命令
  15. Vim 配置(.vimrc)
  16. 插件管理
  17. 常用插件推荐
  18. Vim 与 NeoVim 的区别
  19. Vim 模式在其他工具中的应用
  20. 高级技巧与工作流
  21. 实战场景合集
  22. 故障排查与常见问题
  23. 常用速查表

1. Vim 简介与安装

1.1 什么是 Vim?

Vim(Vi IMproved)是 Bram Moolenaar 于 1991 年创建的文本编辑器,是 Unix 经典编辑器 vi 的增强版。它的核心设计哲学是完全键盘操作——双手无需离开主键位即可完成所有编辑工作。

Vim 的主要特点:

  • 模态编辑:不同的模式对应不同的操作(Normal、Insert、Visual 等)
  • 无处不在:Linux/macOS 系统自带,SSH 远程开发必备用
  • 极高的编辑效率:熟练后编辑速度远超鼠标操作
  • 强大的扩展性:支持脚本、插件、自定义配置
  • 语言生态:几乎所有编程语言都有对应的 Vim 插件

1.2 安装 Vim

Ubuntu / Debian

sudo apt update
sudo apt install vim

CentOS / RHEL / Fedora

sudo yum install vim          # CentOS/RHEL
sudo dnf install vim          # Fedora

macOS

# macOS 自带的是精简版 vim,建议通过 Homebrew 安装完整版
brew install vim

Arch Linux

sudo pacman -S vim

Windows

  • 方式一:从 vim.org 下载安装包
  • 方式二:使用 Scoop:scoop install vim
  • 方式三:使用 Chocolatey:choco install vim
  • 方式四:使用 WSL(推荐):在 WSL 中 sudo apt install vim

从源码编译(启用所有功能)

git clone https://github.com/vim/vim.git
cd vim/src
make distclean
./configure --with-features=huge --enable-python3interp --enable-cscope --enable-gui=gtk3
make
sudo make install

验证安装

vim --version

输出示例(关键信息):

VIM - Vi IMproved 9.1 (2024 Jan 02, compiled ...)
Included patches: 1-XXX
Compiled by root@hostname
Huge version without GUI.  Features included (+) or not (-):
+acl               +cscope           +job               +python3
+autocmd           +cursorbind       +jumplist          +quickfix
...

注意:确保 +clipboard、+python3、+lua 等特性为 +,否则某些功能(如系统剪贴板)无法使用。

1.3 Vim vs Vi

特性 Vi Vim
撤销 只能撤销一次 无限撤销
模式 3 种 6+ 种
分屏 不支持 支持
插件 不支持 支持
语法高亮 不支持 支持
脚本 不支持 Vimscript
可视模式 不支持 支持

1.4 第一次启动 Vim

vim              # 打开空白 Vim
vim filename     # 打开(或创建)文件
vim +42 file     # 打开文件并跳转到第 42 行
vim +/pattern f  # 打开文件并跳转到第一个匹配 pattern 的位置
vim -R file      # 只读模式打开
vim -d f1 f2     # diff 模式比较两个文件
vim -O f1 f2     # 垂直分屏打开两个文件
vim -o f1 f2     # 水平分屏打开两个文件
vim -p f1 f2 f3  # 以 Tab 页方式打开三个文件

应用场景:SSH 登录服务器后需要快速编辑配置文件,vim /etc/nginx/nginx.conf 即可开始编辑。


2. Vim 的四种模式详解

Vim 的核心设计是模态编辑——同一个按键在不同模式下含义完全不同。这是 Vim 学习曲线的最大障碍,但也是其效率的根源。

2.1 Normal 模式(普通模式)

用途:浏览代码、执行命令、删除/复制/粘贴文本。这是 Vim 的默认模式,也是你大部分时间应该在的模式。

进入方式:

  • Vim 启动时默认进入 Normal 模式
  • 在任何其他模式下按 Esc 回到 Normal 模式
" 在 Normal 模式下按 x 删除光标处字符
" 在 Normal 模式下按 dd 删除整行

应用场景:你正在浏览代码,需要快速跳转到某个函数定义。在 Normal 模式下输入 :/function_name 即可搜索。

💡 核心原则:让手保持在主键位(home row),大部分操作都在 Normal 模式下完成。

2.2 Insert 模式(插入模式)

用途:输入文本,和普通编辑器一样。

进入方式(从 Normal 模式):

命令 含义 光标位置
i 在光标前插入 当前字符前
I 在当前行开头插入 行首非空字符
a 在光标后插入 当前字符后
A 在当前行末尾插入 行尾
o 在下方新开一行插入 新行
O 在上方新开一行插入 新行
s 删除当前字符并插入 删除处
S 删除当前行并插入 行首
gi 在上次插入位置插入 上次离开 Insert 的位置
gI 在第一列插入 第 0 列

示例:

假设光标在单词 "hello" 的 'e' 上:
i  → 在 'h' 和 'e' 之间插入
a  → 在 'e' 和 'l' 之间插入
I  → 跳到行首 'h' 前插入
A  → 跳到 'o' 后插入
o  → 在下一行插入
O  → 在上一行插入

退出方式:

  • Esc:回到 Normal 模式
  • Ctrl-[:等同于 Esc(不用够到 Esc 键)
  • Ctrl-C:强制回到 Normal 模式(不触发 InsertLeave 自动命令)

Insert 模式下的特殊键:

按键 功能
Ctrl-h 删除前一个字符(等同 Backspace)
Ctrl-w 删除前一个单词
Ctrl-u 删除到行首
Ctrl-t 缩进(向右移一个 shiftwidth)
Ctrl-d 反缩进(向左移一个 shiftwidth)
Ctrl-n 自动补全(向下搜索)
Ctrl-p 自动补全(向上搜索)
Ctrl-r 插入寄存器内容
Ctrl-o 执行一个 Normal 命令后返回 Insert
Ctrl-a 插入上次插入的文本

应用场景:写代码时,o 快速在下方新建一行开始写,比用鼠标点击行尾再回车快得多。

2.3 Visual 模式(可视化模式)

用途:选中文本后进行操作(类似鼠标选中)。

命令 含义
v 字符级可视化选择
V 行级可视化选择
Ctrl-v 块级可视化选择(矩形选择)
gv 重新选中上次的选择区域

选中后可执行的操作:

操作 命令
删除 d 或 x
复制(拉取) y
替换 c
替换字符 r
大写 U
小写 u
翻转大小写 ~
缩进 >
反缩进 <
自动缩进 =
查找 /(在选中范围内)
保存到文件 :w filename(选中部分另存为)
外部命令过滤 !

应用场景:选中一段代码后按 > 缩进,或按 = 自动格式化。

2.4 Command-Line 模式(命令行模式)

用途:输入 Ex 命令(以 : 开头)、搜索(/ 或 ?)、过滤(!)。

进入方式:

  • : → Ex 命令模式
  • / → 向下搜索
  • ? → 向上搜索
  • !(Visual 模式下)→ 外部命令过滤

示例:

:w              保存
:wq             保存并退出
:q!             不保存退出
:%s/old/new/g   全文替换
:!ls            执行 shell 命令 ls

命令行模式下的编辑键:

按键 功能
Tab 自动补全命令/文件名
Ctrl-r 插入寄存器
Ctrl-w 删除前一个单词
Ctrl-u 删除到行首
Ctrl-b / Home 光标移到行首
Ctrl-e / End 光标移到行尾
↑ / ↓ 浏览命令历史

2.5 替换模式(Replace Mode)

命令 含义
R 进入替换模式(覆盖已有字符)
r{char} 替换当前字符为 {char},自动回到 Normal
gR 虚拟替换模式(不影响 Tab 展开对齐)

示例:

原文:Hello World
光标在 'H' 上,按 R,输入 "HI" → HI llo World
光标在 'H' 上,按 rH → 不变
光标在 'H' 上,按 rA → Aello World

应用场景:快速修正打错的几个字符而不需要进入 Insert 模式。

2.6 模式切换关系图

                    ┌──────────┐
         Esc        │  Normal  │  ← 默认模式
    ┌──────────────→│          │←──────────────┐
    │               └────┬─────┘               │
    │                    │                      │
    │           i I a A o O s S gi              │
    │                    │                      │
    │                    ▼                      │
    │               ┌──────────┐                │
    │     Esc       │ Insert   │                │
    │ ┌────────────→│          │                │
    │ │             └──────────┘                │
    │ │                                           │
    │ │   v V Ctrl-v                              │
    │ │          │                                │
    │ │          ▼                                │
    │ │   ┌──────────┐      Esc                   │
    │ │   │ Visual   │────────────────────────────┘
    │ │   │          │
    │ │   └──────────┘
    │ │                    ┌──────────┐
    │ │                    │Command   │
    │ └───── : / ? ───────→│ Line     │─── Esc ──→ Normal
    │                      └──────────┘
    │
    └──────────────────────────────────────────

记忆口诀:Esc 是万能回 home 键——任何时候不知道在什么模式,按两下 Esc 回到 Normal。


3. 移动与导航命令

Vim 的移动命令极其丰富,掌握它们是高效编辑的基础。

3.1 基本移动(字符级)

命令 含义 助记
h 左 ←
j 下 ↓ (j 像向下的钩子)
k 上 ↑
l 右 →
        ↑ k
   ← h     l →
        ↓ j

数字前缀:5j = 向下移动 5 行,10l = 向右移动 10 个字符。

💡 提示:方向键也可以用,但在 Vim 哲学中,h/j/k/l 效率更高。很多 Vim 高手会在 .vimrc 中禁用方向键来强迫自己学习。

3.2 单词级移动

命令 含义 说明
w 下一个单词开头 word - 以标点和空格分隔
W 下一个 WORD 开头 以空格分隔(更粗粒度)
b 上一个单词开头 back
B 上一个 WORD 开头
e 下一个单词结尾 end
E 下一个 WORD 结尾
ge 上一个单词结尾
gE 上一个 WORD 结尾

word vs WORD 的区别:

foo_bar baz_qux
  • w 的移动路径:foo → _ → bar → baz → _ → qux(6 步)
  • W 的移动路径:foo_bar → baz_qux(2 步)

应用场景:

  • 写代码时 w 更精确(可以停在每个变量名部分)
  • 写文章时 W 更高效(跳过整个词组)

3.3 行内移动

命令 含义 说明
0 行首 数字 0,绝对的第一个字符
^ 第一个非空字符 跳过行首空格/Tab
$ 行尾
g_ 最后一个非空字符
_ 第一个非空字符(同 ^) 带计数:N_ 跳到第 N 行
` ` 第 N 列
+ 下一行首个非空字符
- 上一行首个非空字符

示例:

    def hello_world():
        pass
  • 光标在 hello 的 e 上
  • 0 → 跳到行首(d 前的空格处第 0 列)
  • ^ → 跳到 d(第一个非空字符)
  • $ → 跳到 ) 后的行尾

3.4 字符查找(行内)

命令 含义
f{char} 向后查找字符 {char},光标停在该字符上
F{char} 向前查找字符
t{char} 向后查找字符 {char},光标停在其前一个字符
T{char} 向前查找字符 {char},光标停在其后一个字符
; 重复上次 f/F/t/T 查找
, 反向重复上次 f/F/t/T 查找

示例:

const result = calculate_sum(a, b, c, d, e)
  • 光标在行首 c(const 的 c)
  • f( → 跳到 (
  • f, → 跳到第一个 ,
  • ; → 跳到第二个 ,
  • dt) → 删除从光标到 ) 前的所有内容(删除参数)

应用场景:修改函数参数时,f( 快速跳到括号处,ci( 直接修改括号内所有内容。

3.5 括号匹配

命令 含义
% 跳到匹配的括号 ()、[]、{}

示例:

if (condition) {
    do_something();
}
  • 光标在 { 上,按 % → 跳到 }
  • 光标在 ( 上,按 % → 跳到 )

应用场景:快速检查括号是否匹配,或者在函数的开头和结尾之间跳转。

3.6 屏幕级移动

命令 含义
H 跳到屏幕顶部(High)
M 跳到屏幕中部(Middle)
L 跳到屏幕底部(Low)
Ctrl-f 向下翻一页(Forward / Page Down)
Ctrl-b 向上翻一页(Backward / Page Up)
Ctrl-d 向下翻半页(Down)
Ctrl-u 向上翻半页(Up)
Ctrl-e 屏幕向下滚动一行(光标不动,文字下移)
Ctrl-y 屏幕向上滚动一行
zt 当前行移到屏幕顶部
zz 当前行移到屏幕中部
zb 当前行移到屏幕底部

应用场景:

  • 看长函数时用 Ctrl-d/Ctrl-u 翻半页浏览
  • zz 把当前行移到屏幕中间,方便查看上下文

3.7 文件级移动

命令 含义
gg 跳到文件第一行
G 跳到文件最后一行
:N 或 NG 跳到第 N 行(如 42G 或 :42 跳到第 42 行)
50% 跳到文件 50% 处
:0 跳到第 0 行(文件开头,同 gg)
:$ 跳到最后一行(同 G)

3.8 跳转与回退

命令 含义
Ctrl-o 跳回上一个位置(older)
Ctrl-i 跳到下一个位置(newer,与 Tab 相同)
` ` 在上次跳转的两个位置之间切换
' . 跳到上次修改的行
`. 跳到上次修改的确切位置
`" 跳到上次退出文件时的位置
`^ 跳到上次 Insert 模式的位置

示例:

1. 你在第 10 行编辑代码
2. 用 :100 跳到第 100 行查看定义
3. 按 Ctrl-o 回到第 10 行
4. 按 Ctrl-i 再次回到第 100 行

应用场景:在多文件之间跳转查看定义后快速回到编辑位置,Ctrl-o 是最常用的导航命令之一。

3.9 其他移动命令

命令 含义
( 上一句(以 ./?/! 分隔)
) 下一句
{ 上一段(以空行分隔)
} 下一段
[[ 上一节(以 { 在第一列分隔)
]] 下一节
[] 上一节的末尾
][ 下一节的开头
:# 跳到第 # 列

应用场景:在写 Markdown 或文章时,} 快速跳到下一段,{ 跳到上一段。


4. 插入与编辑命令

4.1 所有插入方式

(已在 2.2 节详细介绍,这里做汇总)

命令 含义 场景
i 光标前插入 在现有文字中插入
I 行首插入 在行开头加注释/修饰符
a 光标后插入 在字符后追加内容
A 行尾追加 最常用的追加方式
o 下方新行插入 在当前行后新建一行
O 上方新行插入 在当前行前新建一行
s 删字符插入 修改打错的字符
S 删行插入 重写整行
gi 上次插入位置 继续上次编辑
gI 第 0 列插入 在绝对行首插入

4.2 数字与插入命令组合

数字可以与插入命令组合,实现批量操作:

3iHello Esc    → 插入 "HelloHelloHello"(3 次重复)
3o Esc          → 新建 3 个空行
5a- Esc         → 在光标后插入 5 个 "-"

⚠️ 注意:在 Insert 模式下按 Esc 才会触发重复,Vim 会重复你从进入 Insert 到退出之间输入的所有内容。

4.3 Insert 模式下的便捷操作

按键 功能 场景
Ctrl-r = 计算表达式并插入 Ctrl-r = 然后 3*4 Enter → 插入 12
Ctrl-r " 插入未命名寄存器(上次删除/复制) 快速粘贴
Ctrl-r 0 插入 yank 寄存器 粘贴复制的文本
Ctrl-r + 插入系统剪贴板 粘贴外部内容
Ctrl-r a 插入寄存器 a 插入命名寄存器内容
Ctrl-o 执行一个 Normal 命令后返回 Insert Ctrl-o $ 跳到行尾继续输入

示例:在 Insert 模式下需要快速插入计算结果:

按 i 进入 Insert
按 Ctrl-r =
输入 1024*768
按 Enter
→ 插入 "786432"

应用场景:写文档时需要插入一个计算结果,不必退出 Insert 模式去算。


5. 删除与剪切命令

5.1 基本删除

命令 含义
x 删除光标处字符(等同 dl)
X 删除光标前字符(等同 dh)
dd 删除整行(剪切到寄存器)
D 删除到行尾(等同 d$)
d0 删除到行首
d^ 删除到行首非空字符
dw 删除一个单词
dW 删除一个 WORD
daw 删除一个单词(含周围空格)
diw 删除一个单词(不含空格)
de 删除到单词末尾
dE 删除到 WORD 末尾
db 删除到单词开头
dgge 删除到上一个单词末尾
dgg 删除到文件开头
dG 删除到文件末尾
d) 删除到下一句开头
d} 删除到下一段开头
dt{char} 删除到字符 {char} 前
df{char} 删除到字符 {char}(含该字符)
d% 删除到匹配的括号

5.2 数字组合

数字前缀可以让删除命令执行 N 次:

3x      → 删除 3 个字符
3dd     → 删除 3 行(剪切 3 行)
d3w     → 删除 3 个单词
d5j     → 删除当前行和下面 5 行
d10G    → 删除从当前行到第 10 行
d.,$    → 删除从当前位置到文件末尾

5.3 撤销与重做

命令 含义
u 撤销(undo)
Ctrl-r 重做(redo)
U 撤销对当前行的所有修改
g- 以前的撤销状态
g+ 较新的撤销状态

5.4 行合并与拆分

命令 含义
J 合并下一行到当前行(用空格连接)
gJ 合并下一行到当前行(不加空格)
i Enter 在插入模式下换行

示例:

合并前:
Hello
World

光标在 "Hello" 行,按 J →
合并后:
Hello World

应用场景:从 PDF 网页复制的文本经常被人为断行,用 J 快速合并。

5.5 特殊删除

命令 含义
:g/^$/d 删除所有空行
:g/^\s*$/d 删除所有空白行(含空格/Tab)
:g/pattern/d 删除所有包含 pattern 的行
:v/pattern/d 删除所有不包含 pattern 的行
:%d 删除整个文件内容

应用场景:处理日志文件时 :g/DEBUG/d 删除所有 DEBUG 级别日志。


6. 复制、粘贴与寄存器

6.1 基本复制粘贴

命令 含义
yy 或 Y 复制当前行(yank)
yw 复制一个单词
y$ 复制到行尾
y0 复制到行首
yG 复制到文件末尾
ygg 复制到文件开头
p 在光标后粘贴
P 在光标前粘贴
gp 粘贴并将光标移到粘贴内容末尾
gP 粘贴并将光标移到粘贴内容开头

示例:

第 1 行:Hello
第 2 行:World
  • 光标在第 1 行,yy 复制 "Hello"
  • p 粘贴 → "Hello" 出现在第 2 行(下一行)
  • P 粘贴 → "Hello" 出现在第 1 行(上一行)

6.2 数字组合

3yy     → 复制 3 行
5p      → 粘贴 5 次
y3w     → 复制 3 个单词
ytp     → 复制到字符 'p' 前
yfp     → 复制到字符 'p'(含 p)

6.3 寄存器(Registers)

寄存器是 Vim 的剪贴板系统。Vim 不只有一个剪贴板,而是有多个命名寄存器。

寄存器类型

寄存器 名称 说明
" 未命名寄存器 默认存放最近一次删除/复制的内容
0 yank 寄存器 专门存放最近一次复制的内容
:delmarks! 删除所有 a-z 标记

应用场景:编辑大文件时,用 ma 在函数定义处设标记,编辑完后 `a 快速跳回。用 mA 设置全局标记,在多文件间跳转。


12. 文本对象(Text Objects)

文本对象是 Vim 中最强大的功能之一。它允许你对"语义单元"(单词、句子、段落、括号内容等)进行操作。

12.1 语法

[count] {operator} {a|i} {object}
  • a = around(包含周围的分隔符/空格)
  • i = inside(不包含分隔符)

12.2 文本对象列表

对象 i (inside) a (around) 说明
w iw 词内 aw 词+周围空格 word
W iW WORD内 aW WORD+周围空格 WORD
s is 句内 as 句+周围空格 sentence
p ip 段内 ap 段+周围空行 paragraph
t it 标签内 at 含标签 HTML/XML tag
( 或 ) 或 b i( 括号内 a( 含括号 parentheses
[ 或 ] i[ a[ square brackets
{ 或 } 或 B i{ a{ curly braces
< 或 > i< a< angle brackets
' i' a' single quotes
" i" a" double quotes
` i` a` backticks
, i, a, comma-separated (vim 8.2+)

12.3 与操作符组合

组合 含义
ciw 修改当前单词(change inside word)
caw 修改当前单词(含空格)
di( 删除括号内的内容
da( 删除括号及其内容
ci" 修改引号内的内容
ca" 修改引号及其内容
di{ 删除花括号内的内容
cit 修改 HTML 标签内的内容
dat 删除整个 HTML 标签
yi[ 复制方括号内的内容
viB 选中花括号内的内容(含大括号)
=i{ 格式化花括号内的代码
>ip 缩进当前段落

示例:

假设光标在括号内的任意位置:
call_function(arg1, arg2, arg3)
   ↑ 光标在这里

ci( → 清空括号内容并进入 Insert 模式
结果: call_function()
       (光标在 () 内,Insert 模式)

di( → 删除括号内容
结果: call_function()

da( → 删除括号及内容
结果: call_function
       (括号也没了)
假设光标在引号内:
name = "John Doe"
            ↑ 光标在这里

ci" → 清空引号内容并插入
结果: name = ""
       (Insert 模式)

di" → 删除引号内容
结果: name = ""
HTML 标签操作:
<div class="container">Hello World</div>
                       ↑ 光标在这里

cit → 修改标签内容
结果: <div class="container"></div>
       (Insert 模式)

cat → 删除整个标签
结果: (整行消失)

dat → 同上,删除整个标签

应用场景:

  • 写代码时 ci( 修改函数参数
  • 写 HTML 时 cit 修改标签内容
  • 写 JSON 时 ci" 修改字符串值
  • di{ 删除代码块内容

12.4 自定义文本对象

你可以通过插件或 Vimscript 创建自定义文本对象:

" 示例:创建下划线文本对象(如 snake_case_variable)
" 需要 vim-textobj-user 插件
call textobj#user#plugin('underscore', {
\   '-': {
\     'select-i': 'i_',
\     'select-a': 'a_',
\   }
\ })

13. 宏录制与回放

宏是 Vim 的杀手级功能——录制一系列操作并重复执行。

13.1 录制与回放

命令 含义
q{register} 开始录制到寄存器
q 停止录制
@{register} 执行寄存器中的宏
@@ 重复执行上次的宏
{N}@{register} 执行宏 N 次
:reg {register} 查看寄存器中的宏内容

13.2 录制示例

场景:给一系列行添加引号

原始:
apple
banana
cherry
date

操作:
1. 光标到第一行行首(gg)
2. qa → 开始录制到寄存器 a
3. I" → 在行首插入引号
4. Esc
5. A" → 在行尾追加引号
6. Esc
7. j → 移动到下一行
8. q → 停止录制
9. 3@a → 对下面 3 行重复执行

结果:
"apple"
"banana"
"cherry"
"date"

场景:给一系列数字加 1

原始:
1. First item
2. Second item
3. Third item

操作:
1. 光标到第一个数字上
2. qa → 开始录制
3. Ctrl-a → 数字加 1(变成 2)
4. j → 下一行
5. q → 停止
6. 2@a → 执行 2 次

结果:
2. First item
3. Second item
4. Third item

13.3 递归宏

递归宏利用 Vim 的特性:当宏在执行过程中调用自己时,会形成递归,直到不能执行为止。

场景:删除所有空行

1. qa → 开始录制到 a
2. /\<CR> → 搜索空行(这里 \< 代表空行匹配,实际用 /^$)
   实际操作:
   qa
   /^$<CR>
   dd
   q
   
3. 这时寄存器 a 内容为:/^$<CR>dd
4. 999@a → 执行 999 次
   每次执行:搜索空行 → 如果找到就 dd 删除 → 继续下一次
   如果搜索失败(没有空行了),宏自动停止

⚠️ 递归宏要求:宏内部必须包含会失败的搜索/移动作为终止条件。

13.4 编辑宏

宏存储在寄存器中,可以像编辑文本一样编辑宏:

1. :put a → 将寄存器 a 的内容粘贴到当前行下方
2. 编辑这一行的内容(修改宏)
3. 0 "ay$ → 将修改后的行重新存入寄存器 a
4. dd → 删除这一行

应用场景:录制的宏有细微错误,不必重新录制,直接编辑宏内容即可。

13.5 多行执行宏

方法一:在 Visual 模式下选择行,然后 :normal @a

1. V 选中所有要执行宏的行
2. :normal @a
→ Vim 对每行执行宏 a

方法二:用 :g 命令

:g/pattern/normal @a    " 对所有匹配 pattern 的行执行宏 a
:%normal @a              " 对所有行执行宏 a

方法三:用行范围

:5,20normal @a    " 第 5-20 行执行宏 a

14. 命令行模式与 Ex 命令

14.1 文件操作

命令 含义
:w 保存
:w file 另存为
:w! 强制保存(覆盖只读)
:w >> file 追加到文件
:q 退出
:q! 强制退出(不保存)
:wq 或 :x 保存并退出
ZZ 保存并退出(Normal 模式快捷键)
ZQ 不保存退出(Normal 模式快捷键)
:wa 保存所有
:wqa 保存所有并退出
:qa! 强制退出所有
:e file 打开文件
:e! 重新加载当前文件(放弃修改)
:e# 编辑上一个文件
:r file 读取文件内容插入到当前行下方
:saveas file 另存为并切换到新文件

14.2 外部命令

命令 含义
:!{cmd} 执行 shell 命令
!!{cmd} 用命令输出替换当前行
:r !{cmd} 读取命令输出并插入
:{range}!{cmd} 用命令过滤指定行
:%!{cmd} 用命令过滤整个文件
:sh 临时进入 shell(exit 回到 Vim)
:terminal 在 Vim 内开终端(Vim 8+)

示例:

:!ls -la              " 查看 当前目录
:!python3 %           " 运行当前 Python 文件(% 代表当前文件名)
:!make                " 执行 make
:r !date              " 插入当前日期
:r !cal               " 插入日历
:r !seq 1 10          " 插入 1-10 的数字序列
:%!sort               " 全文排序
:%!jq .               " 用 jq 格式化 JSON
:5,10!sort            " 第 5-10 行排序
:'<,'>!python3 -m json.tool  " 格式化选中的 JSON
!!date                " 用 date 输出替换当前行

应用场景:

  • :%!jq . 格式化 JSON 文件
  • :%!column -t 对齐 CSV 列
  • :r !git log --oneline -5 插入最近的 Git 提交记录

14.3 行范围操作

范围 含义
:1,5d 删除第 1-5 行
:.,$d 删除从当前行到末尾
:1,.d 删除从开头到当前行
:/foo/,/bar/d 删除从 foo 到 bar 之间的行
:/^+/-1 当前行减 1
:'a,'bd 从标记 a 到标记 b 删除

Ex 命令(行操作):

命令 含义
:{range}d 删除
:{range}y 复制
:{range}t{addr} 复制到 {addr} 行下方(copy/co/t)
:{range}m{addr} 移动到 {addr} 行下方(move/mo)
:{range}s/old/new/g 替换
:{range}normal {cmds} 对每行执行 Normal 模式命令
:{range}join 合并行

示例:

:5,10t20     " 将第 5-10 行复制到第 20 行下方
:5,10m20     " 将第 5-10 行移动到第 20 行下方
:5,10m0      " 将第 5-10 行移到文件开头
:'<,'>t.     " 复制选中区域到当前行下方
:%normal I//  " 每行行首加 //

14.4 映射(Mapping)

命令 含义
:map lhs rhs 所有模式映射
:nnoremap lhs rhs Normal 模式递归映射(推荐)
:vnoremap lhs rhs Visual 模式映射
:inoremap lhs rhs Insert 模式映射
:cnoremap lhs rhs Command 模式映射
:noremap lhs rhs 所有模式非递归映射
:nunmap lhs 取消 Normal 映射
:nmap 查看所有 Normal 映射
:imap 查看所有 Insert 映射

💡 建议:始终使用 noremap 系列(非递归),避免递归映射导致的无限循环。

特殊键表示:

按键 表示法
<CR> Enter
<Esc> Escape
<Tab> Tab
<Space> 空格
<BS> Backspace
<C-x> Ctrl-x
<M-x> Alt-x(Meta)
<S-x> Shift-x
<F1>-<F12> 功能键
<Leader> mapleader 变量(默认 \)
<LocalLeader> 局部 leader

映射示例:

" 按 jk 快速退出 Insert 模式
inoremap jk <Esc>

" Leader + w 保存
nnoremap <Leader>w :w<CR>

" Leader + q 退出
nnoremap <Leader>q :q<CR>

" 快速拆分窗口
nnoremap <Leader>vs :vsplit<CR>
nnoremap <Leader>sp :split<CR>

" 快捷编辑 vimrc
nnoremap <Leader>ev :vsplit $MYVIMRC<CR>
nnoremap <Leader>sv :source $MYVIMRC<CR>

14.5 缩写(Abbreviation)

命令 含义
:iab lhs rhs Insert 模式缩写
:ab lhs rhs 所有模式缩写
:cab lhs rhs Command 模式缩写
:una lhs 取消缩写
:ab 查看所有缩写

示例:

:iab @@ user@example.com       " 输入 @@ 自动替换为邮箱
:iab teh the                    " 自动纠错
:iab tnx thanks                 " 快速输入
:cab W w                        " 防止 :W 报错(大小写)

💡 缩写只在输入完整词后输入非词字符(空格/标点/Enter)时触发。

14.6 其他常用 Ex 命令

命令 含义
:version 显示 Vim 版本信息
:help {topic} 打开帮助文档
:set {option} 设置选项
:syntax on 开启语法高亮
:filetype on 开启文件类型检测
:colorscheme {name} 切换配色方案
:source {file} 执行 Vimscript 文件
:redir > file 将命令输出重定向到文件
:silent {cmd} 静默执行命令
:echo {expr} 显示消息
:echom {expr} 显示消息(记录到历史)
:messages 查看消息历史
:retab 将 Tab 转为空格(或反向)

15. Vim 配置(.vimrc)

15.1 .vimrc 的位置

系统 路径
Linux/macOS ~/.vimrc
Windows $HOME/_vimrc 或 $VIM/_vimrc
NeoVim ~/.config/nvim/init.vim 或 init.lua

15.2 基础配置

" ============================================
" Vim 基础配置
" ============================================

" --- 基本行为 ---
set nocompatible            " 关闭 vi 兼容模式
set encoding=UTF-8          " 编码设为 UTF-8
set fileencoding=UTF-8      " 文件编码
set backspace=indent,eol,start  " Backspace 正常工作

" --- 显示 ---
set number                  " 显示行号
set relativenumber          " 显示相对行号(推荐!)
set cursorline              " 高亮当前行
set cursorcolumn            " 高亮当前列
set showmatch               " 高亮匹配的括号
set matchtime=2             " 括号匹配高亮持续时间(0.1秒单位)
set scrolloff=5             " 光标上下保留 5 行可见
set sidescrolloff=5         " 左右滚动保留 5 列
set wrap                    " 自动换行
set linebreak               " 智能换行(不在单词中间断开)
set showcmd                 " 显示输入的命令
set wildmenu                " 命令行补全菜单
set laststatus=2            " 始终显示状态栏
set ruler                   " 显示光标位置
set signcolumn=yes          " 始终显示标志列

" --- 缩进 ---
set autoindent              " 自动缩进
set smartindent             " 智能缩进
set tabstop=4               " Tab 显示为 4 个空格宽
set shiftwidth=4            " 缩进宽度 4
set softtabstop=4           " Tab/Backspace 处理 4 个空格
set expandtab               " Tab 转为空格
set shiftround              " 缩进对齐到 shiftwidth 的倍数
set smarttab                " 在行首时合理处理 Tab

" --- 搜索 ---
set incsearch               " 增量搜索(边输边搜)
set hlsearch                " 高亮搜索结果
set ignorecase              " 忽略大小写
set smartcase               " 智能大小写(有大写时不忽略)

" --- 文件处理 ---
set autoread                " 文件被外部修改时自动读取
set autowrite               " 切换 buffer 时自动保存
set hidden                  " 允许隐藏未保存的 buffer
set backup                  " 创建备份文件
set undofile                " 持久化撤销历史
set undodir=~/.vim/undodir  " 撤销历史目录
set swapfile                " 交换文件(防止崩溃丢失)
set updatecount=100         " 每 100 字符更新交换文件

" --- 编辑体验 ---
set mouse=a                 " 启用鼠标
set clipboard=unnamedplus   " 系统剪贴板(Linux)
set splitright              " 新窗口在右边
set splitbelow              " 新窗口在下面
set timeoutlen=1000         " 按键序列超时
set ttimeoutlen=50          " 键码序列超时
set updatetime=300          " CursorHold 触发时间(ms)
set virtualedit=block       " 可视块模式可越过行尾
set whichwrap=b,s,<,>,[,]   " 方向键可跨行
set completeopt=menu,menuone,noselect  " 补全菜单设置

" --- 性能 ---
set lazyredraw              " 执行宏时不重绘
set regexpengine=0          " 正则引擎(0=自动, 1=旧, 2=NFA)
set ttyfast                 " 快速终端连接

" --- 视觉 ---
syntax on                   " 语法高亮
filetype plugin indent on   " 文件类型检测
colorscheme desert          " 配色方案

15.3 快捷键映射

" 修改 Leader 键
let mapleader = " "
let maplocalleader = "\\"

" 退出
nnoremap <Leader>q :q<CR>
nnoremap <Leader>w :w<CR>
nnoremap <Leader>x :x<CR>
nnoremap <Leader>Q :qa!<CR>

" 窗口切换
nnoremap <C-h> <C-w>h
nnoremap <C-j> <C-w>j
nnoremap <C-k> <C-w>k
nnoremap <C-l> <C-w>l

" Buffer 切换
nnoremap <S-l> :bn<CR>
nnoremap <S-h> :bp<CR>
nnoremap <Leader>d :bd<CR>

" 快速 ESC
inoremap jk <Esc>
inoremap kj <Esc>

" 取消搜索高亮
nnoremap <Esc> :nohlsearch<CR>

" 快速移动
nnoremap J 5j
nnoremap K 5k
nnoremap H ^
nnoremap L $

" 选中整个文件
nnoremap <Leader>a ggVG

" 快速重载 vimrc
nnoremap <Leader>sv :source $MYVIMRC<CR>

" 快速编辑 vimrc
nnoremap <Leader>ev :vsplit $MYVIMRC<CR>

" 复制到系统剪贴板
vnoremap <Leader>y "+y
nnoremap <Leader>y "+y
nnoremap <Leader>Y "+Y

" 从系统剪贴板粘贴
nnoremap <Leader>p "+p
nnoremap <Leader>P "+P

" 上下移动选中行
vnoremap J :m '>+1<CR>gv=gv
vnoremap K :m '<-2<CR>gv=gv

" 缩进后保持选中
vnoremap < <gv
vnoremap > >gv

15.4 自动命令(autocmd)

" 文件类型相关设置
augroup filetype_settings
    autocmd!
    autocmd FileType python setlocal tabstop=4 shiftwidth=4 expandtab
    autocmd FileType javascript setlocal tabstop=2 shiftwidth=2 expandtab
    autocmd FileType html setlocal tabstop=2 shiftwidth=2 expandtab
    autocmd FileType css setlocal tabstop=2 shiftwidth=2 expandtab
    autocmd FileType markdown setlocal wrap spell
    autocmd FileType yaml setlocal tabstop=2 shiftwidth=2 expandtab
    autocmd FileType json setlocal tabstop=2 shiftwidth=2 expandtab
augroup END

" 进入/离开窗口时切换相对行号
augroup toggle_relative
    autocmd!
    autocmd BufEnter,FocusGained * set relativenumber
    autocmd BufLeave,FocusLost   * set norelativenumber
augroup END

" 保存时自动去除行尾空格
augroup trim_whitespace
    autocmd!
    autocmd BufWritePre * %s/\s\+$//e
augroup END

" 自动创建目录
augroup auto_mkdir
    autocmd!
    autocmd BufWritePre * call mkdir(expand('<afile>:p:h'), 'p')
augroup END

15.5 常用配色方案

配色 说明
desert Vim 自带经典配色
slate Vim 自带深色配色
molokai 流行的 TextMate 风格配色
gruvbox 暖色系,保护视力
solarized 经典的 Solarized 配色
dracula 暗色主题
nord 北欧风格冷色系
tokyonight Tokyo Night 主题
catppuccin 柔和的配色
onedark Atom 风格配色

安装第三方配色:

# 方式一:直接下载到 colors 目录
mkdir -p ~/.vim/colors
curl -o ~/.vim/colors/gruvbox.vim https://raw.githubusercontent.com/morhetz/gruvbox/master/colors/gruvbox.vim

# 方式二:通过插件管理器安装(推荐,见第 16 节)

16. 插件管理

16.1 Vim 8 原生包管理

Vim 8+ 内置了包管理功能,不需要任何第三方插件管理器。

目录结构:

~/.vim/pack/
├── {pack-name}/         " 任意名称的包(如 "myplugins")
│   ├── start/           " 启动时自动加载的插件
│   │   ├── plugin-a/
│   │   └── plugin-b/
│   └── opt/             " 按需加载的插件
│       ├── plugin-c/
│       └── plugin-d/

安装插件:

# 安装 surround 插件
mkdir -p ~/.vim/pack/plugins/start
git clone https://github.com/tpope/vim-surround.git ~/.vim/pack/plugins/start/vim-surround

# 安装 commentary 插件
git clone https://github.com/tpope/vim-commentary.git ~/.vim/pack/plugins/start/vim-commentary

# 按需加载插件(:packadd plugin-name 才加载)
git clone https://github.com/preservim/nerdtree.git ~/.vim/pack/plugins/opt/nerdtree

管理命令:

:packadd {plugin}    " 手动加载可选插件
:packl               " 加载所有 start 插件
:helptags ALL        " 为所有插件生成帮助标签

更新插件:

# 进入每个插件目录执行 git pull
for dir in ~/.vim/pack/*/start/*/; do
    (cd "$dir" && git pull)
done

16.2 vim-plug 插件管理器

vim-plug 是最流行的 Vim 插件管理器,轻量且高效。

安装:

curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
    https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim

配置(在 .vimrc 中):

call plug#begin('~/.vim/plugged')

" --- 基础插件 ---
Plug 'tpope/vim-sensible'          " 合理的默认设置
Plug 'tpope/vim-surround'          " 操纵环绕字符(括号/引号/标签)
Plug 'tpope/vim-commentary'        " 快速注释 gcc
Plug 'tpope/vim-repeat'            " 让 . 命令支持插件操作
Plug 'tpope/vim-fugitive'          " Git 集成
Plug 'tpope/vim-unimpaired'        " 常用配对快捷键

" --- 文件浏览 ---
Plug 'preservim/nerdtree'          " 文件树
Plug 'Xuyuanp/nerdtree-git-plugin' " NERDTree Git 标记

" --- 模糊搜索 ---
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
Plug 'junegunn/fzf.vim'            " FZF 集成

" --- UI 增强 ---
Plug 'vim-airline/vim-airline'     " 状态栏
Plug 'vim-airline/vim-airline-themes'
Plug 'ryanoasis/vim-devicons'      " 文件图标

" --- LSP 和补全 ---
Plug 'neoclide/coc.nvim', {'branch': 'release'}  " CoC 补全

" --- 语法和语言 ---
Plug 'sheerun/vim-polyglot'        " 多语言语法包
Plug 'dense-analysis/ale'          " 异步 Lint 引擎

" --- 编辑增强 ---
Plug 'junegunn/vim-easy-align'     " 对齐
Plug 'terryma/vim-multiple-cursors' " 多光标
Plug 'godlygeek/tabular'           " 文本对齐
Plug 'matze/vim-move'              " 上下移动行

" --- 主题 ---
Plug 'morhetz/gruvbox'
Plug 'dracula/vim', { 'as': 'dracula' }

call plug#end()

vim-plug 命令:

:PlugInstall       " 安装所有 Plug 声明的插件
:PlugUpdate        " 更新所有插件
:PlugClean         " 删除未声明的插件
:PlugUpgrade       " 更新 vim-plug 自身
:PlugStatus        " 查看插件状态
:PlugDiff          " 查看更新差异

16.3 其他插件管理器

管理器 特点
vim-plug 最流行,简单易用,并行安装
packer.nvim NeoVim 专用,Lua 配置
Vundle 老牌管理器,已不太维护
Pathogen 最早的管理器,简单直接
dein.vim 高性能,按需加载

17. 常用插件推荐

17.1 必装插件

插件 功能 常用命令
vim-surround 操纵环绕字符 cs"' ds" ysw"
vim-commentary 快速注释 gcc gc gcap
vim-repeat 增强 . 命令 支持插件操作的重复
vim-fugitive Git 集成 :G :Gstatus :Gdiff
fzf.vim 模糊搜索 :Files :Rg :Buffers

17.2 vim-surround 详解

" old text" → 在引号内任意位置
cs"'        " 改为双引号:"old text"
cs'<q>      " 改为 <q> 标签:<q>old text</q>
cst"        " 标签改回引号:"old text"
ds"         " 删除引号:old text
ysw)        " 给下一个单词加圆括号:(old) text
yss)        " 给整行加圆括号:(old text)
S<div>      " 可视模式下用标签包围

17.3 vim-commentary 详解

gcc         " 注释/取消注释当前行
gc          " 可视模式:注释选中区域
gcip        " 注释当前段落
gcap        " 注释当前段落
gcG         " 注释到文件末尾
:7,10Commentary  " 注释第 7-10 行

17.4 vim-fugitive 详解

:G                  " 打开 Git status(类似 git status)
:Gstatus            " 同上
:Gdiff              " 显示与 HEAD 的差异
:Gblame             " 显示 Git blame
:Gcommit            " Git commit
:Gpush              " Git push
:Gpull              " Git pull
:Glog               " Git log
:Gread              " git checkout -- file(恢复文件)
:Gwrite             " git add file(暂存文件)
:Gmove              " git mv
:Gremove            " git rm
:Gbrowse            " 在浏览器中打开当前行

在 :Gstatus 窗口中:

  • - = 暂存/取消暂存
    | U | D | D | p | |

17.5 fzf.vim 详解

:Files               " 模糊搜索文件
:Buffers             " 搜索已打开的 buffer
:Lines               " 在所有 buffer 中搜索行
:Rg pattern          " 用 ripgrep 搜索内容
:GFiles              " Git 跟踪的文件
:GFiles?             " Git status 文件
:History             " 最近的文件
:Commands            " 搜索 Vim 命令
:Helptags            " 搜索帮助文档
:Snippets            " 搜索代码片段
:Marks               " 搜索标记
:Windows             " 搜索窗口
:Colors              " 搜索配色方案

" 推荐映射
nnoremap <Leader>f :Files<CR>
nnoremap <Leader>b :Buffers<CR>
nnoremap <Leader>g :Rg<CR>
nnoremap <Leader>l :Lines<CR>
nnoremap <Leader>h :History<CR>

17.6 其他推荐插件

插件 说明
vim-easy-align 轻松对齐文本:gaip=
vim-multiple-cursors 多光标编辑
vim-move Alt-j/Alt-k 上下移动行
auto-pairs 自动补全括号/引号
vim-snippets 代码片段集合
ultisnips 代码片段引擎
tagbar 标签栏(需要 ctags)
indentLine 显示缩进线
vim-tmux-navigator Vim 和 tmux 无缝切换
vim-devicons 文件类型图标
nvim-treesitter NeoVim 语法解析(超强的语法高亮)
telescope.nvim NeoVim 模糊搜索(FZF 的替代)
nvim-lspconfig NeoVim LSP 配置
nvim-cmp NeoVim 补全引擎
gitsigns.nvim Git 标记(增删改行标记)
which-key.nvim 显示可用快捷键提示

18. Vim 与 NeoVim 的区别

18.1 NeoVim 简介

NeoVim(Nv)是 Vim 的现代化分支,由 Thiago de Arruda 于 2014 年发起。目标是改进代码质量、可扩展性和嵌入能力。

18.2 主要区别

特性 Vim NeoVim
配置语言 Vimscript Vimscript + Lua
内置终端 :terminal(Vim 8+) 内置终端(一等公民)
LSP 支持 需要插件(CoC/ALE) 内置 LSP 客户端
异步任务 job_start()(Vim 8+) 更完善的异步 API
Tree-sitter 不支持 内置支持
UI 终端 UI 可分离 UI(GUI/Web/终端)
插件 API Vimscript Lua API + Vimscript
启动速度 快 更快(Lua 配置)
内置补全 Ctrl-n/p 内置 LSP 补全

18.3 NeoVim 配置

-- ~/.config/nvim/init.lua

-- 基础设置
vim.opt.number = true
vim.opt.relativenumber = true
vim.opt.tabstop = 4
vim.opt.shiftwidth = 4
vim.opt.expandtab = true
vim.opt.smartindent = true
vim.opt.wrap = false
vim.opt.incsearch = true
vim.opt.hlsearch = true
vim.opt.ignorecase = true
vim.opt.smartcase = true
vim.opt.termguicolors = true
vim.opt.scrolloff = 8
vim.opt.signcolumn = "yes"
vim.opt.clipboard = "unnamedplus"

-- Leader 键
vim.g.mapleader = " "

-- 快捷键
vim.keymap.set("n", "<leader>w", ":w<CR>")
vim.keymap.set("n", "<leader>q", ":q<CR>")
vim.keymap.set("i", "jk", "<Esc>")
vim.keymap.set("n", "<C-h>", "<C-w>h")
vim.keymap.set("n", "<C-j>", "<C-w>j")
vim.keymap.set("n", "<C-k>", "<C-w>k")
vim.keymap.set("n", "<C-l>", "<C-w>l")

18.4 选择建议

  • 新手:先学 Vim,掌握基础后再考虑切换
  • SSH 远程开发:Vim 足够(无需额外安装 NeoVim)
  • 本地开发:推荐 NeoVim(LSP、Tree-sitter 体验更好)
  • 已有 Vim 配置:NeoVim 兼容 .vimrc,可以平滑迁移

19. Vim 模式在其他工具中的应用

Vim 的模态编辑理念影响了大量工具,很多工具都支持 Vim 快捷键。

19.1 VS Code Vim 插件

安装 VS Code 的 Vim 插件(由 VSCodeVim 团队开发)后,几乎所有的 Vim 快捷键都可以使用。

常用配置(settings.json):

{
  "vim.easymotion": true,
  "vim.incsearch": true,
  "vim.useSystemClipboard": true,
  "vim.useCtrlKeys": true,
  "vim.hlsearch": true,
  "vim.insertModeKeyBindings": [
    { "before": ["j", "k"], "after": ["<Esc>"] }
  ],
  "vim.normalModeKeyBindingsNonRecursive": [
    { "before": ["<leader>", "w"], "commands": [":w"] },
    { "before": ["<leader>", "q"], "commands": [":q"] }
  ],
  "vim.leader": "<space>"
}

19.2 IntelliJ / JetBrains IDE Vim 插件

安装 IdeaVim 插件:

  • 支持 Normal/Insert/Visual 模式
  • 支持大部分 Vim 命令
  • 配置文件:~/.ideavimrc(格式同 .vimrc)

19.3 Bash / Zsh Readline Vim 模式

在 ~/.bashrc 或 ~/.zshrc 中添加:

# Bash
set -o vi

# Zsh
bindkey -v

启用后,命令行的编辑模式变为 Vim 风格:

  • 默认是 Insert 模式
  • Esc 进入 Normal 模式
  • 支持 h/j/k/l、w/b/e、dd/yy/p、/ 搜索历史等

19.4 tmux

tmux 的 copy mode 支持 Vim 快捷键:

# ~/.tmux.conf
setw -g mode-keys vi
bind-key -T copy-mode-vi 'v' send -X begin-selection
bind-key -T copy-mode-vi 'y' send -X copy-selection

19.5 其他支持 Vim 模式的工具

工具 说明
Less / Man 按 h 查看帮助,支持 j/k/G/g 等
MySQL CLI 支持 Vim 模式编辑
IPython / Jupyter %config TerminalInteractiveShell.editing_mode = 'vi'
Python REPL 安装 gnureadline 并设置 set -o vi
JupyterLab 安装 jupyterlab-vim 扩展
Obsidian Vim 编辑器插件
Notion 不原生支持,但有社区脚本
浏览器 Vimium(Chrome)、Tridactyl(Firefox)、Vimari(Safari)
Gmail 键盘快捷键(部分 Vim 风格)
Slack Vim 风格快捷键(设置中开启)

19.6 浏览器 Vim 插件示例(Vimium)

安装 Vimium 后,可以用 Vim 风格快捷键浏览网页:

快捷键 功能
h/j/k/l 滚动
gg 页面顶部
G 页面底部
/ 页面内搜索
f 显示链接字母提示,按字母打开链接
r 刷新
x 关闭 Tab
t 新建 Tab
J/K 切换 Tab

20. 高级技巧与工作流

20.1 . 命令(重复上次修改)

. 是 Vim 中最强大的命令之一——它重复你上一次的修改操作。

操作序列         . 的效果
dw              删除下一个单词
x               删除下一个字符
>>              缩进下一行
ci(             修改下一个括号内容
A;text<Esc>     在行尾追加 ;text

应用场景:需要修改多个类似的单词时:

  1. cw 修改第一个单词
  2. j. 在下一行重复修改
  3. j. 继续...

20.2 Ctrl-n / Ctrl-p 自动补全

在 Insert 模式下:

按键 功能
Ctrl-n 向下搜索补全(当前 buffer 中的词)
Ctrl-p 向上搜索补全
Ctrl-x Ctrl-n 补全当前 buffer 中的关键字
Ctrl-x Ctrl-i 补全包含文件中的关键字
Ctrl-x Ctrl-] 补全标签(需要 ctags)
Ctrl-x Ctrl-k 补全字典(需要 set dictionary)
Ctrl-x Ctrl-l 补全整行
Ctrl-x Ctrl-f 补全文件名
Ctrl-x Ctrl-o 全能补全(omni completion,语言相关)
Ctrl-x Ctrl-u 用户自定义补全
Ctrl-x Ctrl-v Vim 命令行补全
Ctrl-x Ctrl-s 拼写建议

20.3 = 自动缩进

命令 含义
== 自动缩进当前行
=ap 自动缩进当前段落
gg=G 自动缩进整个文件
=i{ 自动缩进花括号内
:%normal == 所有行自动缩进

20.4 g 系列命令

命令 含义
g~{motion} 翻转大小写
gu{motion} 转小写
gU{motion} 转大写
gJ 合并行(不加空格)
gq{motion} 格式化文本(自动换行)
gw{motion} 格式化文本(不移动光标)
gQQ 格式化模式
gg 到文件首行
G 到文件末行
gd 跳转到本地定义
gD 跳转到全局定义
gi 回到上次 Insert 位置
gv 重选上次 Visual 区域
gP 粘贴在前面(光标在开头)
gp 粘贴在后面(光标在末尾)
g. 跳转到上次修改位置
g, 向前浏览 changelist
g; 向后浏览 changelist
g& 在所有行重复上次替换
g_ctrl-g 显示详细字数统计
gH Select 模式
g_CTRL-a (Insert模式)数字加 1
g_CTRL-x (Insert模式)数字减 1

20.5 Quickfix 列表

Quickfix 是 Vim 的错误/搜索结果列表。

命令 含义
:make 运行 make,结果进入 quickfix
:copen 打开 quickfix 窗口
:cclose 关闭 quickfix 窗口
:cn 或 :cnext 下一条错误
:cp 或 :cprev 上一条错误
:cfirst 第一条
:clast 最后一条
:cnf 下一个文件的第一条
:cpf 上一个文件的第一条
:cc N 跳到第 N 条
:grep pattern *.py 搜索并将结果放入 quickfix
:vimgrep /pattern/ **/*.py Vim 内置 grep
:cdo cmd 对每条 quickfix 条目执行命令
:cfdo cmd 对每个文件执行命令

示例工作流:

:vimgrep /TODO/ **/*.py    " 搜索所有 TODO
:copen                      " 打开结果列表
" 在结果中用 Enter 跳转
:cn                         " 下一条
:cp                         " 上一条

20.6 Location 列表

Location 列表类似于 Quickfix,但是每个窗口有自己的 Location 列表。

命令 含义
:lopen 打开 location 窗口
:lclose 关闭
:lnext 下一条
:lprev 上一条
:lvimgrep /pattern/ files 搜索到 location 列表

20.7 拼写检查

:set spell         " 开启拼写检查
:set spelllang=en  " 设置语言(可以多种:en,fr,es)
:set nospell       " 关闭
命令 含义
]s 下一个拼写错误
[s 上一个拼写错误
z= 显示修正建议
zg 将当前词加入好词列表(good)
zw 将当前词加入坏词列表(wrong)
zug 撤销 zg
1z= 直接使用第一个建议

20.8 折叠(Folding)

命令 含义
zc 关闭当前折叠(close)
zo 打开当前折叠(open)
za 切换折叠状态(toggle)
zC 关闭所有嵌套折叠
zO 打开所有嵌套折叠
zA 切换所有嵌套折叠
zr 减少折叠层级(全部打开一级)
zR 打开所有折叠
zm 增加折叠层级(全部关闭一级)
zM 关闭所有折叠
zj 下一个折叠
zk 上一个折叠
[z 当前折叠开头
]z 当前折叠结尾
zd 删除当前折叠

折叠方法:

:set foldmethod=manual    " 手动折叠(zf{motion})
:set foldmethod=indent    " 按缩进折叠
:set foldmethod=expr      " 按表达式折叠
:set foldmethod=syntax    " 按语法折叠
:set foldmethod=marker    " 按标记折叠({{{ }}})

20.9 Diff 模式

vimdiff file1 file2        " 比较两个文件
vim -d file1 file2         " 同上
命令 含义
]c 下一个差异
[c 上一个差异
do 从另一窗口获取(diff obtain)
dp 推送到另一窗口(diff put)
:diffupdate 刷新差异

应用场景:Git 合并冲突解决时非常有用。

20.10 会话(Session)

:mksession! mysession.vim    " 保存当前会话(窗口布局、buffer 等)
:source mysession.vim        " 恢复会话
vim -S mysession.vim         " 启动时恢复会话

应用场景:项目开发时保存窗口布局,下次打开快速恢复。

20.11 标签文件(Tags / ctags)

# 生成标签文件
ctags -R .

# 在 Vim 中使用
vim -t function_name        " 启动时跳转到函数定义
命令 含义
Ctrl-] 跳转到光标下标签的定义
Ctrl-t 从标签跳转返回
:tag name 跳转到 name 的定义
:tn 下一个匹配的标签
:tp 上一个匹配
:ts name 列出所有匹配选择
:tags 查看标签栈

21. 实战场景合集

场景一:日常代码编辑工作流

目标:高效编辑一个 Python 项目

" 1. 打开项目
vim main.py

" 2. 分屏打开相关文件
:vsplit utils.py        " 右侧打开 utils.py
:split test_main.py     " 下方打开测试文件

" 3. 在窗口间切换
Ctrl-w h/j/k/l

" 4. 快速跳转函数定义
:tag my_function        " 需要 ctags

" 5. 搜索项目中的关键词(需要 fzf 插件)
:Rg import

" 6. 修改函数参数
ci(                     " 修改括号内参数

" 7. 注释一段代码
V5j                     " 选中 6 行
gc                      " 注释/取消注释

" 8. 格式化代码
=                       " 可视模式下自动缩进

" 9. 保存所有
:wa

场景二:批量编辑 CSV / 日志文件

目标:处理一个 CSV 文件,只保留特定列

name,age,city,country
Alice,25,New York,USA
Bob,30,London,UK
Carol,28,Tokyo,Japan
" 只保留 name 和 city 列:
" 1. 用外部命令 awk 处理
:%!awk -F, '{print $1","$3}'

" 结果:
" name,city
" Alice,New York
" Bob,London
" Carol,Tokyo

" 或者只保留年龄大于 26 的行
:%!awk -F, 'NR==1 || $2>26'

场景三:多行批量注释 / 取消注释

def old_function():
    result = compute()
    log_result(result)
    notify(result)
    return result

方法一:可视块模式

" 注释:
1. Ctrl-v 选中要注释的行的行首
2. Shift-i (I) 输入 #
3. Esc

" 取消注释:
1. Ctrl-v 选中 # 所在列
2. d

方法二:vim-commentary 插件

gcc        " 注释/取消注释当前行
gcip       " 注释整个段落
V5j gc     " 注释选中的 6 行

方法三:命令行

:5,8s/^/#/    " 第 5-8 行加注释
:5,8s/^#//    " 第 5-8 行去注释

场景四:代码格式化与对齐

目标:将变量赋值语句对齐

name = "Alice"
age = 25
city = "NYC"
country = "USA"

方法一:vim-easy-align 插件

" 选中所有行,按 = 对齐
vip
:EasyAlign =

结果:

name    = "Alice"
age     = 25
city    = "NYC"
country = "USA"

方法二:tabular 插件

:Tabularize /=

方法三:外部 column 命令

:%!column -t -s=

场景五:在多个文件中搜索替换

目标:将所有 .py 文件中的 old_name 替换为 new_name

" 方法一:用 vimgrep + cdo
:vimgrep /old_name/ **/*.py
:cdo s/old_name/new_name/g | update

" 方法二:用外部命令(更快)
" 退出 Vim 后用 sed
" sed -i 's/old_name/new_name/g' *.py

" 方法三:在 Vim 中用 arg
:args **/*.py
:argdo %s/old_name/new_name/g | update

场景六:编辑远程文件

" 方法一:直接用 scp 路径(需要 netrw 插件,Vim 自带)
:e scp://user@server//path/to/file
:e scp://user@server/~/relative/path

" 方法二:用 sshfs 挂载后编辑
" sshfs user@server:/path /mnt/remote
" vim /mnt/remote/file

" 方法三:通过 ssh + vim
ssh user@server -t vim /path/to/file

场景七:Git 合并冲突解决

<<<<<<< HEAD
这是当前分支的代码
=======
这是另一分支的代码
>>>>>>> feature-branch
" 方法一:手动解决
/<<<<<<<          " 搜索冲突标记
dd                " 删除 <<<<<<< 行
/=======
V/>>>>>>>
" 选中到 >>>>>>> 部分删除,保留需要的代码

" 方法二:使用 vim-fugitive
:Gdiff            " 打开三路 diff
" 在 working copy 中用 do/dp 选择保留哪个版本
:Gwrite           " 标记为已解决

" 方法三:用 :g 命令快速删除所有冲突标记行
:g/^<<<<<<<\|^=======\|^>>>>>>>/d
" ⚠️ 注意:这会删除标记行,但你需要手动合并代码

场景八:Markdown 写作工作流

" 推荐的 Markdown 写作配置
augroup markdown_writing
    autocmd!
    autocmd FileType markdown setlocal wrap
    autocmd FileType markdown setlocal spell
    autocmd FileType markdown setlocal textwidth=80
    autocmd FileType markdown setlocal concealcursor=n
augroup END

" 快捷键映射(仅 Markdown)
autocmd FileType markdown nnoremap <buffer> <leader>1 m`I# <Esc>```
autocmd FileType markdown nnoremap <buffer> <leader>2 m`I## <Esc>```
autocmd FileType markdown nnoremap <buffer> <leader>3 m`I### <Esc>```
autocmd FileType markdown nnoremap <buffer> <leader>b m`i**<Esc>``i*<Esc>lviwU
autocmd FileType markdown nnoremap <buffer> <leader>i m`i*<Esc>
autocmd FileType markdown nnoremap <buffer> <leader>c m`I- [ ] <Esc>

" 格式化表格
" 选中表格行后:
:'<,'>!column -t -s '|'

" 预览(需要插件或外部工具)
" 安装 markdown-preview.nvim 插件

场景九:处理大文件

" 打开大文件前禁用某些功能(提升性能)
" 在 .vimrc 中添加:
autocmd BufReadPre *.log let b:large_file = 1
autocmd BufReadPre *.log setlocal noswapfile nowrap norelativenumber

" 或者手动操作大文件:
: set nowrap              " 关闭自动换行
: set noswapfile          " 关闭交换文件
: syntax off              " 关闭语法高亮
: set foldmethod=manual   " 手动折叠

" 跳转到特定行
:100000            " 跳到第 10 万行
G                  " 文件末尾
gg                 " 文件开头

" 只查看文件
vim -R huge.log    " 只读模式
vim -u NONE -R huge.log  " 不加载任何配置,最快

" 用外部命令处理
:%!grep ERROR     " 只保留 ERROR 行
:%!tail -1000     " 只保留最后 1000 行
:%!head -1000     " 只保留前 1000 行

场景十:调试与 Quickfix 工作流

" 1. 设置 makeprg(如果不用 make)
:set makeprg=python3\ %
" 或
:set makeprg=npm\ run\ build

" 2. 运行 :make
:make

" 3. 打开 quickfix 窗口查看错误
:copen

" 4. 在错误间跳转
:cn    " 下一个错误
:cp    " 上一个错误
:cc 3  " 跳到第 3 个错误

" 5. 修复错误后重新运行
:make

22. 故障排查与常见问题

22.1 常见问题

Q: 退出 Vim?

:q       " 退出
:q!      " 强制退出(不保存)
:wq      " 保存退出
ZZ       " 保存退出(Normal 模式)
ZQ       " 不保存退出(Normal 模式)

Q: 如何关闭搜索高亮?

:nohlsearch    " 或 :noh
" 永久关闭:set nohlsearch

Q: 粘贴时代码缩进混乱?

" 方法一:使用粘贴模式
:set paste       " 进入粘贴模式
" 粘贴内容
:set nopaste     " 退出粘贴模式

" 方法二(推荐):配置 clipboard
:set clipboard=unnamedplus    " Linux
:set clipboard=unnamed        " macOS

" 方法三:用寄存器
"+p    " 从系统剪贴板粘贴

Q: 中文字符显示乱码?

:set encoding=UTF-8
:set fileencoding=UTF-8
:set fileencodings=ucs-bom,UTF-8,GBK,GB18030,big5,euc-jp,euc-kr,latin1

Q: 如何恢复崩溃前的文件?

" Vim 崩溃后,交换文件 .file.swp 存在
vim file.original
" Vim 会提示:
" Swap file ".file.swp" already exists!
" [O]pen Read-Only, (E)dit anyway, (R)ecover, (D)elete, (Q)uit, (A)bort:

" 选择 R 恢复
" 恢复后保存,然后删除交换文件
:w
:!rm .file.swp

Q: Backspace 或方向键不正常?

:set backspace=indent,eol,start
" 或在 .vimrc 中
set nocompatible

Q: 如何重复上次 Ex 命令?

:@:     " 重复上次的 : 命令

Q: Tab 显示为 4 个空格但按 Tab 键还是插入 Tab?

:set expandtab     " Tab 键插入空格
:set tabstop=4     " 已有 Tab 显示为 4 个空格宽
:set shiftwidth=4  " 缩进宽度

" 将已有 Tab 转为空格
:retab

Q: 如何显示隐藏字符?

:set list           " 显示隐藏字符
:set nolist         " 关闭
:set listchars=tab:▸\ ,trail:·,eol:¬,space:.

Q: 如何切换大小写?

~       " 翻转当前字符大小写
g~~     " 翻转当前行
guu     " 当前行转小写
gUU     " 当前行转大写
guw     " 当前单词转小写
gUw     " 当前单词转大写

Q: 如何在多行行首插入相同文本?

" 方法一:可视块
Ctrl-v   " 选中行
I        " 在行首插入
text     " 输入文本
Esc      " 应用到所有行

" 方法二:命令
:%normal Iprefix_

Q: 系统剪贴板不工作?

" 检查是否支持剪贴板
:echo has('clipboard')
" 如果输出 0,需要安装 vim-gtk 或 vim-x11

" Ubuntu/Debian
" sudo apt install vim-gtk

" macOS
" set clipboard=unnamed

Q: 如何记住这么多命令?

  • 不需要一次全记住
  • 从最常用的开始:h j k l i w q :w :q
  • 每天学一个新命令
  • 用 :help 查阅
  • 打印速查表贴在显示器旁

23. 常用速查表

23.1 初学者必备 20 命令

命令 功能
i 进入插入模式
Esc 回到普通模式
:w 保存
:q 退出
:wq 保存并退出
:q! 不保存退出
h j k l 左 下 上 右
w b 下一个/上一个单词
gg G 文件开头/末尾
dd 删除整行
yy 复制整行
p 粘贴
u 撤销
Ctrl-r 重做
/word 搜索 word
n N 下一个/上一个搜索结果
x 删除字符
o 下方新行
a 光标后插入
:help 帮助

23.2 进阶常用 50 命令

命令 功能
ciw 修改当前单词
ci( 修改括号内
ci" 修改引号内
da( 删除括号(含括号)
dt) 删除到 ) 前
df) 删除到 ) (含))
. 重复上次修改
* 搜索光标下的词
:%s/old/new/g 全文替换
:noh 取消搜索高亮
V 行选择
Ctrl-v 块选择
> / < 缩进/反缩进
=ap 格式化段落
gg=G 格式化整个文件
ctrl-o / ctrl-i 跳回/跳前
f( ; 行内查找括号
0 ^ $ 行首/非空行首/行尾
H M L 屏幕顶/中/底
zz 当前行居中
Ctrl-d / Ctrl-u 半屏翻页
ma \a` 设标记 a / 跳到 a
qa ... q 录制宏 a
@a 执行宏 a
@@ 重复上次宏
"ayy "ap 复制到寄存器 a / 粘贴
"+yy "+p 系统剪贴板复制/粘贴
:e file 打开文件
:ls :bn :bp buffer 列表/下一个/上一个
:sp :vs 分屏
Ctrl-w h/j/k/l 窗口切换
:tabnew gt gT 新 Tab/下一个/上一个
:g/pattern/d 删除匹配行
:v/pattern/d 删除不匹配行
r R 替换字符/替换模式
~ gUU guu 大小写翻转/全大写/全小写
J 合并行
>> << 缩进/反缩进
m{A-Z} \` 全局标记
Ctrl-] Ctrl-t 标签跳转/返回
:sort 排序
:!cmd 执行 shell 命令
:r !cmd 插入命令输出
:%!cmd 过滤整个文件
:set paste 粘贴模式
:set nu rnu 行号/相对行号
set et ts=4 sw=4 Tab 设为 4 空格
gd 跳转到定义
gi 回到上次编辑位置
gv 重选上次选择

23.3 移动命令速查

            ┌─ ↑ k ─┐    ┌─── K (5k) ───┐
       ← h ─┤       ├─ l → │              │
            └─ ↓ j ─┘    └─── J (5j) ───┘

  0 ^ $          词级          文件级
  ├─┤├──┤        w W e E B     gg ──→ 文件首
  行首 非空 行尾  b b e e b     G  ──→ 文件末
                              :42→ 第42行

  屏幕级          查找           跳转
  H ──→ 顶        f/F/t/T       Ctrl-o ←── 上一个位置
  M ──→ 中        ; / ,         Ctrl-i →── 下一个位置
  L ──→ 底        / ? n N       `` ───── 两个位置切换

23.4 文本对象速查

操作符 + i/a + 对象

     ┌────── 操作符 ──────┐
     │ d c y v > < = ~ r │
     └───────────────────┘
              ↓
     ┌── i / a ──┐
     │ i = 内    │
     │ a = 含环绕 │
     └───────────┘
          ↓
     ┌──── 对象 ────┐
     │ w W s p t    │
     │ ( [ { < '    │
     │ " ` , . ; :  │
     └──────────────┘

常用组合:
ciw  ci(  ci"  ci{  cit
diw  di(  di"  di{  dit
yi(  yi"  yi{

23.5 模式切换速查

Normal(默认)
  │
  ├── i I a A o O s S gi →→→ Insert
  ├── v V Ctrl-v →→→ Visual
  ├── R gR →→→ Replace
  ├── : / ? →→→ Command-line
  └── Esc ←── 从任何模式回到 Normal

23.6 命令行速查

文件操作
:w  :q  :wq  :x  :q!  ZZ  ZQ

外部命令
:!cmd  :r !cmd  :%!cmd

替换
:s/old/new/      当前行
:s/old/new/g     当前行全部
:%s/old/new/g    全文
:%s/old/new/gc   确认
:'<,'>s/old/new/g 选中区域

全局命令
:g/pattern/d     删除匹配
:v/pattern/d     删除不匹配
:g/pattern/m$    移到末尾
:g/pattern/t.    复制到当前行

结语

Vim 的学习曲线确实陡峭,但一旦掌握,它将成为你最强大的编辑工具。关键要点:

  1. 先学基础:模式切换 + h/j/k/l + 基本编辑命令
  2. 每日练习:每天学一个新命令,比一次性学完更有效
  3. 使用 .vimrc:逐步定制你的编辑环境
  4. 少用鼠标:强迫自己用键盘完成所有操作
  5. 用 :help:Vim 的内置帮助文档是最权威的参考

"Vim 不是学完的,是练出来的。"


posted @ 2026-09-29 09:48  直角漫步  阅读(299)  评论(0)    收藏  举报