Vim 退出后如何恢复上次的工作状态?
每次关闭 Vim 再重新打开,窗口布局没了,文件列表清空,折叠消失了——这种"从零开始"的体验让人抓狂。Vim 内置的会话(session)和视图(view)功能,专门解决这个问题。
用 :mksession 保存完整工作环境
:mksession 把当前 Vim 的窗口布局、标签页、缓冲区列表、折叠状态、当前目录等信息序列化成一个 Vim 脚本文件:
vim" 保存到当前目录的 Session.vim :mksession " 指定路径 :mksession ~/sessions/project-a.vim " 文件已存在时强制覆盖 :mksession! ~/sessions/project-a.vim
会话文件本质上是一段 Vim 脚本,可以直接打开查看。里面记录了 tabnew、split、edit 等命令,Vim 逐行执行就能还原你的编辑环境。
用 :source 或 vim -S 恢复会话
恢复会话有两种方式:
vim" 在 Vim 内部加载 :source Session.vim
bash# 启动时直接加载 vim -S Session.vim # 等价写法 vim -S ~/sessions/project-a.vim
vim -S 是最常用的方式,可以把加载会话的命令写进项目目录的 Makefile 或 shell alias 里,一条命令就能回到上次的工作状态。
sessionoptions 控制保存范围
不是所有东西都需要保存到会话里。sessionoptions(缩写 ssop)决定了 :mksession 写入哪些内容:
vim" 查看当前设置 :set sessionoptions? " 典型配置 :set sessionoptions=buffers,curdir,folds,help,tabpages,winsize,terminal
常用选项说明:
buffers— 缓冲区列表(包括隐藏缓冲区)tabpages— 所有标签页,去掉则只保存当前标签页winsize— 窗口大小比例folds— 手动折叠信息curdir— 当前工作目录terminal— 终端窗口
实际使用中经常需要微调。比如你不希望会话保存终端窗口,因为重新打开时原来的 shell 进程已经不存在了:
vim:set sessionoptions-=terminal
不想保存空白窗口:
vim:set sessionoptions-=blank
:mkview 和 :loadview 保存单个窗口的状态
会话保存的是全局状态,但有时你只想保存某个窗口的折叠、滚动位置和本地选项。这时用视图:
vim" 保存当前窗口的视图 :mkview " 加载当前窗口的视图 :loadview
视图和会话的区别在于作用域——视图只管当前窗口,会话管整个 Vim 实例。视图默认保存在 viewdir 目录下,文件名由缓冲区路径编码而来:
vim" 查看 viewdir 位置 :set viewdir? " 自定义 viewdir :set viewdir=~/.vim/views
一个常见用法是在 vimrc 里自动保存和恢复视图:
vimautocmd BufWinLeave *.py mkview autocmd BufWinEnter *.py loadview
这样每次切换 Python 文件时,之前的折叠和滚动位置都能自动恢复。
会话与标签页、窗口、缓冲区的关系
理解这三者的关系有助于用好会话:
- 缓冲区(buffer):文件在内存中的实例,会话保存的是缓冲区列表,不是文件内容
- 窗口(window):缓冲区的视口,一个缓冲区可以出现在多个窗口中,会话保存窗口的布局和尺寸
- 标签页(tabpage):窗口的容器,每个标签页有自己的窗口布局,会话保存所有标签页(如果
sessionoptions包含tabpages)
关键点:会话恢复时,Vim 会先加载缓冲区列表,然后按照保存的布局重建窗口和标签页。如果文件已经被移动或删除,对应的窗口会变成空缓冲区。
项目级会话管理
给不同项目维护独立的会话文件是最实用的做法。在项目根目录保存一个 Session.vim,启动时用 vim -S 加载:
bash# 在项目目录下 cd ~/projects/my-app vim -S
更规范的做法是把会话文件放在统一目录,按项目名区分:
bashmkdir -p ~/.vim/sessions vim -S ~/.vim/sessions/my-app.vim
也可以在 vimrc 里根据当前目录自动选择会话:
vimlet g:session_dir = expand('~/.vim/sessions/') let g:session_file = g:session_dir . substitute(getcwd(), '/', '_', 'g') . '.vim'
自动保存和恢复会话
手动执行 :mksession 容易忘记。用自动命令在退出 Vim 时自动保存:
vim" 退出时自动保存会话 autocmd VimLeave * if v:this_session != '' | execute 'mksession!' v:this_session | endif
v:this_session 变量保存着当前会话文件的路径。如果还没加载过会话,这个变量为空字符串,此时不执行保存,避免在随意打开文件时产生多余的 Session.vim。
配合启动时自动加载:
vim" 启动时加载项目会话(无参数时) autocmd VimEnter * if argc() == 0 && filereadable(g:session_file) | execute 'source' g:session_file | endif
argc() == 0 确保只有直接输入 vim 不带文件参数时才加载会话,避免和 vim file.txt 这种用法冲突。
tpope/vim-obsession 插件
手动管理会话的自动命令虽然能工作,但需要处理各种边界情况(比如打开多个 Vim 实例、会话文件冲突)。tpope 的 vim-obsession 插件把这些细节都封装好了:
vim" 安装后,在项目目录执行 :Obsess ~/.vim/sessions/my-app.vim " 停止自动保存 :Obsess!
启动 Obsession 后,它会持续跟踪当前会话的变化,在合适时机自动更新会话文件。退出 Vim 时自动保存,不需要额外配置。
和手动方案相比,vim-obsession 的优势在于:
- 不会在未启动 Obsession 的情况下覆盖已有会话
- 正确处理多实例场景
- 和 vim-fugitive 等插件配合良好
如果你经常在多个项目之间切换,vim-obsession 基本上是必装的。
viminfo 和会话的分工
会话保存的是"你在看什么"——窗口、标签页、缓冲区布局。viminfo 保存的是"你做过什么"——命令历史、搜索历史、寄存器内容、标记位置。
vim" 保存 viminfo :wviminfo ~/.vim/viminfo " 加载 viminfo :rviminfo ~/.vim/viminfo
完整的恢复需要两者配合:会话还原布局,viminfo 还原操作历史。Vim 默认在退出时自动写入 viminfo,所以通常只需要手动管理会话部分即可。
Vim 的会话机制把"恢复工作环境"这件事从手动操作变成了可自动化的流程。从最基础的 :mksession / :source 开始,配合 sessionoptions 调整保存范围,再用自动命令或 vim-obsession 实现无人值守的保存恢复,这个渐进式的路径覆盖了从偶尔用到每天依赖的全部场景。