>> >> >> Reference << << << <<<<<<Ref>>>>>>
Vim
Modified: 2025-12-31 | Author:ljf12825

vi(历史背景 from Wikipedia)

vi是一款面向屏幕的文本编辑器,最初是为Unix操作系统创建的。vi的可移植行为子集以及它所支持的ex编辑器语言,被Single UNIX Specification 和 POSIX标准正式规范
vi实际上是更早的ex编辑器的一个模式(visual mode),而不是一个独立的程序
最初的ex只有行编辑能力,没有全屏显示。1976年,Bill Joy 为ex增加里visual编辑模式。ex启动进入行模式,vi启动进入visual模式
vi这个名字来自ex中的visual命令的最短不歧义缩写
vi的技术源头是ed(Unix最早的行编辑器),ed为电传打字机(TTY)设计,极其简陋。1976年,George Coulouris基于ed开发里em(editor for mortals),Bill Joy在UC Berkeley借鉴em改造ed,开发出ex,再在ex中加入全屏visual模式 -> vi. vi的很多思想(如模式编辑,.重复命令)借鉴自Xerox PARC的Bravo编辑器
Bill Joy使用的是ADM-3A终端,Esc键位就是现代键盘的TAB键位,没有独立方向键,而是和hjkl键共用,300波特率调制解调器非常慢。因此,命令设计极度简洁,支持“提前输入”,鼓励不离开主键区操作,这直接塑造了vi今天的操作方式
1978年,vi(ex 1.1)随BSD Unix发布,很多Unix系统免费自带vi,这是vi普及的决定性原因之一。后来AT&T System V,各商业Unix(Sun, HP, IBM, DEC)都内置并维护自己的vi变种。最终vi成为Unix世界的事实标准编辑器,并被POSIX明确要求支持
由于早期vi代码依赖AT&T Unix授权,无法自由分发,于是出现了大量兼容克隆:Elvis(1990), nvi(BSD官方替代),Vim(从Stevie演化而来),BusyBox vi, Neovim(Vim的现代重构)。BSD系统最终使用nvi,Linux和macOS世界则几乎全面采用Vim/Neovim
vi是一个模态编辑器(modal editor),学习曲线陡峭,但熟练后效率极高
原始vi(POSIX vi)的能力非常有限:无语法高亮,无插件系统,无LSP/补全,无现代编码支持(UTF-8)支持不完整,无多窗口/多标签(或极其原始)。它的定位是:最低可用编辑器,而不是高效开发环境。vi当年的核心使命是:在任何Unix系统上,在极端受限环境下,提供一个可视化文本编辑能力。而现在,终端性能不再是瓶颈,GUI编辑器普及,SSH环境也能跑功能完整的Vim,原始vi不需要再承担主力开发工具的角色,而是成为一种标准和哲学,活在现代vi分发版本中

Modal Editor

模态编辑器指的是编辑操作分不同“模式”来完成的文本编辑器,而不是像普通的编辑器那样随时都在“插入文字”状态

核心思想

在模态编辑器中,键盘的输入行为取决于当前模式

不同模式下,同样的键盘按键代表着不同的功能,这就是模态的本质

优势

缺点

Vim

Vim是一款免费开源的文本编辑器。Vim既提供终端屏幕用户界面,也提供图形用户界面(gvim)
Vim的文档将其描述为旧版vi文本编辑器的改进版本。在发布信息中,作者最初暗示Vim是Vi Imitation的缩写。但后来,由于作者所描述的功能已经超越了vi克隆版,因此其缩写改为Vi IMproved.

安装

大部分Linux发行版都自带Vim,但通常是精简版(vim-tiny),目的是提供默认语义,现代开发架构和教程默认vi存在。以及在最坏情况下保证正常使用。Linux允许同一软件多版本存在,通过alternatives进行管理。如果想要完整版本,需要手动安装

通过包管理器安装

通过包管理器安装的vim通常是系统编译好的Vim,能满足最低使用,但可能不会支持一些功能如剪贴板,语言支持等,且版本可能会滞后

sudo apt install vim 
sudo pacman -S vim 

从源码安装

从源码编译安装Vim可以让你根据自己的需求定制Vim的功能

  1. 安装必要的依赖
sudo apt update 
sudo apt install -y git build-essential ncurses-dev 

对于其他Linux发行版,安装方式可能不同,但大致依赖是git, build-essential(或gcc, make)和ncurses

  1. 获取Vim源码
git clone https://github.com/vim/vim.git
  1. 配置编译选项 进入Vim源码目录并执行./configure来设置编译选项。可以通过./configure --help查看可用的选项。以下是一些常用的编译选项

示例:如果只想编译一个支持Python3和最大功能的Vim,可以这样写

cd vim 
./configure --with-feature=huge --enable-python3interp --enable-multibyte

当运行./configure时,它会生成一个名为config.log的文件,里面详细记录了配置过程中检查每个功能是否可用的结果
在运行./configure后,它会生成一个Makefile文件,其中包含了配置的选项。在其中,可以找到一些启用的功能,尤其是和编译相关的设置

  1. 编译Vim 配置完成后,使用make命令进行编译。这一步会编译Vim的所有源代码,过程可能需要几分钟时间,取决于机器性能

  2. 安装Vim 编译完成后,可以用以下命令进行安装

sudo make install 
  1. 检查安装 安装完成后,可以通过以下命令检查Vim是否正确安装
vim --version 

如果显示了你配置时选择的功能选项,说明安装成功

  1. 卸载Vim 如果不再需要编译版的Vim,或者想要重新配置,使用以下命令卸载
sudo make uninstall

如果需要卸载其他版本的Vim,记得先删除系统的Vim或将其替换

使用

内置帮助

Vim自带一个完整、详细的帮助系统,可以在终端里直接访问
基本命令

:help " 打开帮助页
:help <topic> " 查询某个主题
:help user-manual " 打开用户手册

Vim Tutor

Vim Tutor是Vim自带的交互式入门教程,用于帮助新手快速掌握Vim的基础操作,它直接在终端中运行,不需要额外安装
在CLI中的

vimtutor 

这个命令会打开一个交互式教程文件,通常路径在

/usr/share/vim/vim<edition>/tutor/tutor<language>.txt

中文教程为

vimtutor zh 

配置

Vimscript

Vim

启动与退出\

模式切换
Vim有多种模式,常见的有:

普通模式
启动Vim时,默认进入普通模式,或从其他模式按Esc进入普通模式\

常见操作

  1. 导航:在普通模式下,移动光标是最常见的操作
  1. 删除文本
  1. 复制和粘贴
  1. 替换文本
  1. 撤销和重做
  1. 查找
  1. 替换
  1. 打开和关闭文件
  1. 其他操作

插入模式
在Vim中,插入模式可以直接输入文本,当处于插入模式时,可以像使用任何普通文本编辑器一样,输入和编辑内容
在Vim的普通模式下,可以通过输入以下指令进入插入模式:

  1. 在插入模式下的基本操作
  1. 退出插入模式
  1. 插入模式的快捷操作

插入模式使用场景\

  1. 直接输入文本:插入模式是直接输入或编辑文件内容的地方,通常是处理普通文本、代码注释、字符串等的场景
  2. 编写代码:虽然Vim的强大之处在于普通模式下的操作,但在插入模式下可以像使用普通编辑器一样快速编写代码

命令模式
在Vim中,命令模式允许执行一些文件级的操作,比如保存、退出、查找、替换、设置选项等
命令模式是Vim操作的核心之一,可以通过命令来控制Vim的行为\

如何进入命令模式:

场景命令模式操作

  1. 保存文件
  1. 退出Vim
  1. 查找和替换
  1. 文件跳转
  1. 撤销和重做
  1. 设置Vim选项
  1. 查看和跳转到文件行
  1. 帮助命令
  1. 执行外部命令
  1. 退出其他模式

命令模式的特点\

命令模式应用场景\

可视模式
可视模式允许选择文本进行操作

如何进入可视模式
在普通模式下:

可视模式操作
一旦进入可视模式,可以通过以下方式进行文本选择和编辑

  1. 选择文本
  1. 移动光标 在可视模式中,光标会随着移动而扩大或缩小选区
  1. 对选中的文本进行操作 一旦选择了文本,可以执行以下操作
  1. 撤销和重做
  1. 退出可视模式
  1. 扩展选区
  1. 块选择模式(Ctrl + v)
  1. 复制到剪贴板
  1. 多个操作

可视模式应用场景\

分屏操作\

指令教程\

插件管理
Vim的插件系统能够扩展和定制Vim的功能,使其更加适应工作流程。通过安装和使用插件,可以增强Vim的能力,比如自动完成、语法高亮、代码片段、文件浏览器等

插件管理器
要高效管理Vim插件,通常需要使用插件管理器。以下是一些常用的插件管理器

vim-plug的安装与配置 安装vim-plug,首先将vim-plug插件管理器下载到Vim配置目录中

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

这个命令会将pulg.vim文件下载到~/.vim/autodownload/目录下,并创建相应的目录结构 然后,可以在~/.vimrc文件中配置插件,插件声明用Plug关键字

" 启动插件管理器
call plug#begin('~/.vim/plugged')

" 列出需要安装的插件
Plug 'tpope/vim-sensible'  " 基础配置插件
Plug 'junegunn/fzf.vim'   " 文件搜索插件
Plug 'neoclide/coc.nvim'   " 自动完成插件

" 结束插件配置
call plug#end()

保存并退出.vimrc后,重新启动Vim,并运行以下命令来安装插件

:PlugInstall

vim-plug的使用 vim-plug是一个轻量级、易于使用的Vim插件管理器,可以帮助快速安装、更新和管理插件。与其他插件管理器相比,vim-plug配置简单,支持并行安装插件,并且具有高效的更新机制

更新插件

:PlugUpdate

删除插件

  1. 打开.vimrc文件
  2. 删除不需要的插件行
  3. 在Vim中
:PlugClean

常用vim-plug命令

插件的更多配置选项
可以在插件声明时指定一些额外的选项来控制插件行为

Plug 'junegunn/fzf.vim', { 'for': ['vim', 'bash'] }
Plug 'tpope/vim-fugitive', { 'on' : 'Gstatus' }
:PlugInstall --sync

常用的Vim插件\

  1. 自动补全插件
  1. 文件浏览器
  1. 语法高亮与代码格式
  1. 代码片段插件
  1. 增强的查找和替换
  1. 状态栏和界面增强
  1. 增强的搜索功能
  1. Git集成

插件配置和优化

" 配置 coc.nvim 自动补全
let g:coc_global_extensions = ['coc-tsserver', 'coc-python']


终端模式

Vim 8.1+

:term bash " 水平分割终端窗口
:vert term bash " 垂直分割终端窗口
:term " 启动默认shell

终端窗口操作

tabs

标签页是Vim中组织窗口的容器,每个标签页可以包含多个分割窗口

创建标签页

vim -p file1 file2 file3 # 用标签页打开多个文件
vim -p *.py  # 用标签页打开所有py文件
:tabnew <filename> " 新建标签页,<filename>可选
:tabedit <filename> " 同上,简写 :tabe
:tabs " 显示所有标签页列表
:tab split " 当前窗口移到新标签页
:tab sball " 为每个缓冲区开标签页
:tab ball " 同上
:tab help topic " 在新标签页打开帮助

标签页导航

:tabn[ext] " 下一个标签页
:tabp[revious] " 上一个标签页
:tabN[ext] " 上一个标签页
:tabfirst / :tabr " 第一个标签页
:tablast " 最后一个标签页

标签页操作

:tabc[lose] " 关闭当前标签页
:tabo[nly] " 关闭其他所有标签页,只留当前
:tabm[ove] [N] " 移动当前标签页到第N位置
:tabm 0 " 移到最前面
:tabm " 移到最后面
:tabm +1 " 向后移动一位
:tabm -1 " 向前移动一位

标签页与窗口的配合

Ctrl+w, T " 将当前窗口移到新标签页
Ctrl+w, c " 关闭当前窗口但不关闭标签页

Buffer

关系:文件 -> 缓冲区 -> 窗口 -> 标签页
      磁盘    内存      视图    容器

重要特性

set hidden:允许隐藏已修改的缓冲区

缓冲区状态

缓冲区有4种状态

  1. 活动(active):显示在窗口中
  2. 隐藏(hidden):已加载但未显示
  3. 未加载(inactive):在列表但未加载内容
  4. 已列出(listed):在:ls中显示

查看缓冲区

列出缓冲区

:ls " 列出所有缓冲区
:buffers " 同上
:files " 同上,显示更详细

示例输出

1 %a "file1.txt" line 1
2 #h "file2.py"  line 99 
3    "file3.js"  line 0 

状态标记

详细列表

:ls! " 显示所有缓冲区(包括未列出的)
:buffer " 显示当前缓冲区信息
:file " 显示当前文件名和状态

打开/创建缓冲区

从文件打开

:e file.txt " 编辑文件(新建缓冲区)
:enew " 新建空缓冲区
:view file.txt " 以只读方式打开
:badd file.txt " 添加到缓冲区列表但不显示

命令行打开

vim file1 file2 file3 # 打开多个文件到缓冲区
vim *.py # 通配符打开
vim -p file1 file2 # 用标签页打开

切换缓冲区

删除缓冲区

缓冲区操作

缓冲区与窗口

批量操作

终端窗口

vim 8.0 开始,vim内置了一个终端模拟器,可以在vim窗口里直接运行任何CLI工具
本质是一个特殊buffer(terminal buffer)

使用

打开

:terminal " 打开终端(缩写 :term)
:vert terminal " 垂直分割打开终端
:tab terminal " 在新标签页打开终端

使用默认$SHELL

指定shell或命令

:terminal bash
:terminal zsh
:terminal python
:terminal gdb a.out
:terminal make run

模式切换

调整位置

终端是一个buffer + job

横向分屏终端

:split | terminal

纵向分屏终端

:vsplit | terminal

底部固定终端

:botright split | terminal

固定高度

:botright 10split | terminal

复制/粘贴

复制终端输出

  1. 进入普通模式
  2. 像普通文本一样
    • v
    • y
    • /pattern

终端buffer在普通模式下是只读的,但可以选中

退出

设置

终端自动进入插入模式

vimrc

autocmd TermOpen* startinsert

禁用行号

autocmd TermOpen * setlocal nonumber norelativenumber

vimdiff

Vim diff 是在多个窗口中对齐显示差异
它不是只给你一份补丁文本,而是

本质是一个可编辑的、实时diff视图

进入Vim diff模式

在命令行中

vimdiff a.cpp b.cpp

vim -d a.cpp b.cpp

已在Vim里

:diffthis

在两个窗口分别执行

:diffthis

这两个窗口就进入diff模式

退出

:diffoff

Git工作流git difftool默认就会拉起Vim diff

使用

颜色/高亮(逻辑)

高亮含义
红色背景删除
绿色背景新增
蓝色/紫色修改
空白充填对齐占位

Vim diff会找最相似的行块,用虚拟空行把两边对齐,保证能横向比较,这些空行不能编辑,他们只是视觉占位

操作

在差异间跳转
]c 下一个差异
[c 上一个差异
选择改动

假设

左边 = 旧
右边 = 新

从另一边拉内容

同步滚动

默认开启

:set scrollbind

关闭

:set noscrollbind

diff配置

" 更易读的 diff
set diffopt=filler,context:3

" 忽略空白差异
set diffopt+=iwhite

" 更自然的算方法
set diffopt+=algorithm:patience

diff算法

行号跳转

:number " 跳转到number行

numbergg " 跳转到number行
numberG " 跳转到number行

numberk " 向上移动number行
numberj " 向下移动number行

number% " 跳转到number%处

插件 vim-markdown 快捷键

快捷键功能
zR展开所有折叠
zM折叠所有
zr展开一级折叠
zm折叠一级
zo打开当前折叠
zc关闭当前折叠
za切换折叠状态
zO递归打开
zC递归关闭

.swp 文件

Swap Files,Vim交换文件,这是Vim的崩溃恢复机制,类似于

文件命名格式:.sourcename.swp,是一个隐藏文件

主要作用

1.崩溃恢复

当异常退出Vim时,重新打开文件,Vim提示

[O]pen Read-Only   # 只读打开
(E)dit anyway      # 强制编辑(危险)
(R)ecover          # 恢复交换文件内容
(D)elete it        # 删除交换文件
(Q)uit             # 退出
(A)bort            # 中止

2.防止编辑冲突

如果另一个Vim实例正在编辑同一文件

" 如果另一个 Vim 实例正在编辑同一文件:
E325: ATTENTION
Found a swap file by the name ".filename.swp"
          owned by: username   pid: 1234
          dated: Thu Jan 1 12:00:00 2026

(1) Another program may be editing the same file.
(2) An edit session for this file crashed.

3.保存编辑状态

交换文件包括

工作原理

创建时机:
Vim在以下情况更新交换文件

  1. 打开文件时立即创建
  2. 每输入’updatecount’个字符后
  3. 每 ‘updatetime’毫秒后
  4. 切换到其他缓冲区时
  5. 执行某些命令时

相关设置

set updatetime=4000 " 每4秒保存一次(默认)
set updatecount=100 "每输入100字符保存一次

文件结构

[交换文件头]
├── 魔数(标识为 Vim 交换文件)
├── 原始文件名
├── 进程ID和时间戳
├── 文件修改时间
└── ...

[数据块]
├── 文本内容(增量变化)
├── 撤销历史
├── 寄存器内容
└── 标记信息

管理交换文件

基本命令

:sw " 在 Vim中管理交换文件
:sw! " 强制写入交换文件
:swp " 同 :sw
:swapname " 显示当前交换文件路径

" 列出所有交换文件
:swap!            " 显示所有可恢复的交换文件
:swap list        " 显示交换文件列表
:swap next        " 跳转到下一个交换文件
:swap prev        " 跳转到上一个交换文件

恢复编辑会话

" 方法1:启动时恢复
vim -r filename.txt " 恢复指定文件
vim -r

" 方法2:在Vim中恢复
:recover filename.txt " 从交换文件恢复
:recover! filename.txt " 强制恢复

" 方法3:手动比较
:diffthis   " 当前文件
:split filename.txt " 打开源文件
:diffthis " 对比模式
" 然后手动合并差异

交换文件位置控制

" 在 ~/.vimrc 中配置

" 1. 集中存放(推荐)
set directory=~/.vim/swap//   " 所有交换文件放这里
" 注意:末尾 // 表示保留完整路径结构

" 2. 项目特定目录
set directory=./.vim-swap//   " 放在项目内的 .vim-swap 目录

" 3. 多级目录(按文件路径组织)
set directory=~/.vim/swap/%:p:h   " 按原文件路径创建子目录

配置选项

启用/禁用
" 完全禁用(不推荐)
set noswapfile

" 针对特定文件类型禁用
autocmd FileType python setlocal noswapfile
autocmd FileType markdown setlocal noswapfile

" 条件启用
set swapfile                    " 默认启用
set swapsync=fsync              " 同步写入(更安全但更慢)
set swapsync=                   " 异步写入(默认)
行为控制
" 1. 只读文件的交换文件
set swapfile                    " 默认启用
set swapsync=fsync              " 同步到磁盘
set updatecount=50              " 每50字符保存
set updatetime=2000             " 每2秒保存

" 2. 大文件处理
" Vim 7.3+ 对大文件有特殊处理
set maxmem=500000               " 每个缓冲区最大内存(KB)
set maxmemtot=1000000           " 所有缓冲区最大内存(KB)

文件扩展名

" Vim 使用不同扩展名区分状态:
.swp   " 活跃的交换文件
.swo   " 旧的交换文件(如果 .swp 已存在)
.swn   " 更旧的版本
" Vim 会自动使用这些扩展名避免冲突

sign column

寄存器

Vim的寄存器是Vim内置的多个文本存储槽
每个寄存器用一个名字表示,存放内容来自y(复制),d(删除),c(修改),x(删除字符)
使用时通过

"registername + operation

例如

"ayw  " 复制一个单词到寄存器 a
"ap   " 从寄存器a粘贴

寄存器总览

类型名称说明
未命名"默认寄存器
数字0-9删除历史
命名a-z用户自定义
系统剪贴板+, *和系统交互
小删除-小范围删除
黑洞_什么都不保存
只读: . %命令/文件名
表达式=计算结果

未命名寄存器 "

Vim的默认剪贴板

所有y/d/c都会写入这里
p实际等价于

""p

这就是p默认的读取的寄存器

数字寄存器 0-9

0最近一次yank

yy " 存入0
dd " 不会影响0
"0p " 还能粘贴刚才复制的内容

1-9 删除历史

"1p
"2p

命名寄存器a-z

自定义寄存器
可以手动控制不会覆盖的内容

"ayw " 复制单词到 a 
"ap  " 粘贴 a 

大写 = 追加

"Ayy " 追加到 a

使用场景

系统剪贴板+/*

"+yy " 复制到系统剪贴板
"+p  " 从系统剪贴板粘贴

需要vim +clipboard

黑洞寄存器 _

不存入寄存器的删除

"_dd
"_daw

解决经典痛点:复制了一段代码 -> 想删几行 -> 结果复制的内容没了

小删除寄存器 -

x " 存入 - 
"-p

只读寄存器 :, ., %

表达式寄存器 =

Vim自带计算器

"=1+2*3
p

还能用函数

"=strlen("hello")

查看所有寄存器

:registers
" 或
:reg

查看指定寄存器内容

:reg + registername

追加到寄存器

大写寄存器名

"Ayy  " 追加一行到寄存器a

特殊粘贴

" 在插入模式下粘贴寄存器内容
<C-r>a " 插入模式下粘贴寄存器a的内容
<C-r>"  " 插入模式下粘贴默认寄存器的内容

.

在Vim中,.命令表示重复上一次操作的命令
适用于插入、删除、替换、修改等操作,可以配合移动命令使用,进行批量重复

iHello<Esc> " 插入 ’Hello'
.           " 再按 . 会在光标处插入同样的 'Hello'

可被重复的操作类型

.可以重复的操作大致有

iHello<Esc> " 插入文本
.           " 重复插入相同文本
dw           " 删除一个单词
.            " 再删除下一个单词
rX           " 将光标处字符替换成 X
.            " 再替换下一个字符
cwHello<Esc> " 改变一个词
.            " 再改变下一个单词

.重复的是上一次完整的编辑操作,而不是上一次键入的按键

示例

批量修改列

" 如果光标在多行同列位置
I# <Esc> " 在每行行首插入 #
j.       " 向下移动并重复插入

注意光标位置

宏(macro)

宏,记录一串按键,然后在别的地方重复执行
记录的是按键序列(包括移动、删除、搜索),不是语义,而是操作流程
非常适合:重复但有结构的编辑

使用

开始录制

q{寄存器}

例如

qa

表示把宏录到寄存器a

然后开始编辑操作

停止录制

q

命令行会显示

recording @a

播放宏

@a

执行多次

10@a

重复上一次宏

@@

示例

场景:每行末尾加;

原始文本

int a
int b
int c

步骤

1.光标放第一行 2.开始录宏

qa

3.执行操作

A;<Esc>j

4.停止

q

5.执行

2@a

结果

int a;
int b;
int c;

宏的本质:寄存器

宏其实就在寄存器里

查看宏内容

:reg a

可以看到

a A;<Esc>j

宏 = 可读、可编辑的文本

修改宏

1.直接编辑寄存器

:let @a = 'A;<Esc>j

2.粘出来改

"ap

修改后再复制回去

使用技巧

宏 + 计数

20@a

宏 + 搜索

/ERROR<CR>
qa
dd
n
q

宏 + Normal命令

:%normal @a

对每一行执行宏

递归宏

qa
...操作...
@a
q

宏 与 .

能力.
重复一次修改yesno
多步骤操作noyes
多次执行noyes
可编辑noyes

. 是最小宏

宏的使用场景

一次性任务使用.或手动

Insert mode ^O

Insert下,按下^O, 可临时执行一条普通模式命令,执行完立刻自殴打能够回到插入模式

在Vim帮助里,它叫:help i_CTRL-O,官方定义是:Execute one command in Normal mode

示例

按键效果
^O0跳到行首
^O^跳到第一个非空字符
^O$跳到行尾
^Ow下一个单词
^Ob上一个单词
^Ogg文件开头
^OG文件结尾
^Odw删除一个单词
^OD删除行尾
^Occ改整行并继续插入
^Ox删一个字符

mark