viminfo 是 vim 自定义的类文本日志格式,需用状态机逐行解析:跳过注释与空行,按首字符(!、:、=、>、~)分类处理;~后为无填充 base64 寄存器内容,须补足 = 后解码;命令/搜索历史需转义解析;路径含~需跨平台展开,编码需检测 bom 并适配 utf-8/utf-16。

viminfo 文件不是标准格式,直接用 C++ 解析需手动处理
viminfo 不是 JSON、INI 或 YAML,它没有统一 schema,而是 Vim 自定义的类文本日志格式:混合了注释(# 开头)、键值对(! 或 : 开头)、列表块(> 开头)、二进制 blob(~ 行后接 base64)以及版本/时间戳元信息。C++ 标准库不提供原生解析器,必须自己按行扫描 + 状态机驱动。
常见错误是试图用 std::getline + std::string::find('=') 粗暴切分——这会漏掉多行寄存器、跳过注释逻辑、把 base64 数据误判为普通值。
- 先跳过所有以
#开头的注释行和空行 - 识别行首标记:
!(全局设置)、:(命令历史)、=(寄存器)、>(搜索历史)、~(寄存器内容起始) - 遇到
~行后,下一行才是 base64 编码的寄存器内容,需调用 base64 解码(注意 Vim 使用的变种:末尾可能缺=,换行符已被移除)
读取寄存器内容时,base64 解码必须兼容 Vim 的编码规则
Vim 的 viminfo 寄存器字段(如 =*、=+)后面跟一个 ~ 行,再下一行才是 base64 字符串。但 Vim 的 base64 实现省略了填充符(=),且允许任意长度换行(实际写入时通常不换行,但规范允许)。标准 base64 库(如 Boost.Base64 或 OpenSSL)默认要求填充,直接解码会失败。
实操建议:
- 读到
~行后,用std::getline读取下一行,去掉首尾空白 - 手动补足 base64 填充:计算字符串长度 mod 4,缺 1 位补
==,缺 2 位补=,缺 3 位不合法(Vim 不会产生) - 使用无依赖的轻量 base64 解码函数(几十行即可),避免引入 Boost 或 OpenSSL;推荐用 RFC 4648 兼容实现,禁用 URL-safe 变体
- 解码后得到的是原始字节流,可能是 UTF-8 文本,也可能是二进制(如含
\0的寄存器),不要直接转std::string当 C 风格字符串用
解析命令/搜索历史时,注意转义与分隔符嵌套
viminfo 中的命令历史形如::h 100 /search\ pattern/,搜索历史形如:>/foo\+bar/。Vim 对斜杠、反斜杠、空格做了转义(\ 表示空格,\ 表示单个反斜杠),且历史条目本身以空格开头(: 或 > 后紧跟空格)。
关键点:
- 不能简单按空格分割——命令本身可能含空格(如
:e ~/file name.txt) - 要从第一个非空格字符开始,找到第一个未被转义的分隔符(通常是
/或")来界定模式边界 - 转义逻辑只在特定上下文生效:例如
:/a\ b/中的\是转义空格,但:s/a\ /x/中的\属于替换部分,解析器需结合命令类型判断 - 最稳妥做法:提取整行后,用正则
^:[^ ]+ +(.*)$捕获命令体,再对捕获内容做逐字符状态机解析(记录是否在引号内、是否刚读到\)
跨平台路径与编码问题:Windows 下的 ~ 和 UTF-16 路径
viminfo 文件本身是纯文本,但其中记录的文件路径(如跳转历史、缓冲区列表)可能含 ~(代表 home 目录),或在 Windows 上以 UTF-16 写入(尤其当 Vim 编译为 GUI 版且系统 locale 非 ASCII 时)。C++ 默认按字节读取,不会自动转换。
处理建议:
- 用
std::ifstream以std::ios::binary模式打开,避免 Windows 下\r\n被静默转为\n干扰行定位 - 检测 BOM:若前两字节为
0xFF 0xFE,说明是 UTF-16LE,需用std::codecvt_utf16(C++11)或手动转换;但多数 viminfo 是 UTF-8(即使含中文路径),可先尝试 UTF-8 解码,失败再 fallback -
~替换不能硬编码为/home/user:应调用getenv("HOME")(Unix)或getenv("USERPROFILE")(Windows),并确保路径分隔符统一(Vim 在 Windows 也常用/)
真正麻烦的是寄存器里存了二进制图像数据或终端 escape 序列——它们没长度标头,仅靠 base64 解码后的字节流存在,解析器必须知道“这个寄存器用途”才能决定是否丢弃或转义显示。这点没有银弹,得靠上层业务约定。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











