ShadowSave
语言文档:简体中文(README.md) | English(README.en.md)
ShadowSave 是一个 VS Code 扩展:编辑文件并保存时,不覆盖磁盘上的原文件,而是把内容写入独立的影子存储;只有明确执行“写回”,才会覆盖原文件。
影子内容保存在磁盘上(VS Code 扩展的 globalStorage),不是仅存在于内存,因此关闭 VS Code 后仍然保留。
工作方式
VS Code 扩展 API 无法取消内置保存,也不能接管 file: 协议。因此 ShadowSave 的做法是:
- 打开工作区文件时,自动把普通编辑器页替换为自定义
shadowsave: 文件系统上的影子页;
- 影子页的
Ctrl+S、自动保存、保存全部都写入扩展的独立存储;
- 原文件的路径、内容、修改时间保持不变;
- 只有执行 ShadowSave: 写回原文件 等明确命令时,才会写入原文件。
替换标签页时会保留当前光标、选区、语言模式和预览标签状态。影子标签带 S 角标,状态栏显示“影子: 文件名”。
安装
在 VS Code 中打开命令面板,执行 Extensions: Install from VSIX...,选择打包好的 shadowsave-0.1.0.vsix;或使用命令行:
code --install-extension shadowsave-0.1.0.vsix
安装后重新加载窗口。
快速开始
- 打开工作区内的文件,它会自动进入影子模式。
- 正常编辑、按
Ctrl+S。
- 打开命令面板,执行 ShadowSave: 写回原文件,确认后才会覆盖原文件。
- 写回后仍停留在影子模式,后续保存继续写影子。要恢复普通编辑,执行 ShadowSave: 退出当前文件的影子模式。
命令
| 命令 |
说明 |
ShadowSave: 以影子模式打开当前文件 |
手动进入影子模式;资源管理器右键文件也可使用 |
ShadowSave: 写回原文件 |
确认后把影子内容覆盖到原文件;默认先备份旧内容 |
ShadowSave: 显示影子文件操作 |
状态栏或命令面板中的操作菜单 |
ShadowSave: 从原文件重新载入影子内容 |
丢弃影子内容,重新从原文件复制 |
ShadowSave: 丢弃影子更改 |
删除影子,原文件不变 |
ShadowSave: 退出当前文件的影子模式 |
选择写回、丢弃或直接退出;退出后暂停该文件的自动影子模式 |
ShadowSave: 重新启用当前文件的自动影子模式 |
解除单文件暂停;没有活动文件时可从列表选择 |
ShadowSave: 切换自动影子模式 |
全局/工作区开关 |
ShadowSave: 打开已有的影子文件 |
从磁盘上的影子列表中选择打开 |
ShadowSave: 打开影子存储目录 |
在系统文件管理器中打开影子根目录 |
安全设计
- 不会自动写回。所有写回路径都需要用户明确操作(退出影子模式时的“写回并退出”也会二次确认)。
- 外部修改检测:影子创建时记录原文件内容哈希。写回前若发现原文件已被外部修改,会提示冲突,可选择查看差异或取消。
- 写回前备份:原文件旧内容保存到影子的
backups/ 目录,默认每个文件保留最近 10 份。
- 避免陈旧标签页:写回后会关闭仍打开着的旧原文件标签,防止之后误保存旧内容。
- 未保存内容保护:当原文件有未保存修改时,自动模式会先把这些修改移入影子,再还原原文件;显式进入影子模式时会先询问。如果该文件已有影子,会先把旧影子内容备份为
backups/conflict-*.bak,再换成新的内存内容,避免任一侧丢失。
- 大文件/排除项:自动模式默认跳过 10 MB 以上文件,以及
.git、node_modules。
配置
| 配置 |
默认值 |
说明 |
shadowSave.autoShadow |
true |
自动接管工作区文件 |
shadowSave.autoShadowWorkspaceOnly |
true |
只自动接管当前工作区内的文件 |
shadowSave.autoShadowExclude |
["**/.git/**", "**/node_modules/**"] |
自动模式排除的 glob |
shadowSave.maxFileSizeKB |
10240 |
自动模式最大文件大小;0 为不限制 |
shadowSave.confirmWriteBack |
true |
普通写回是否弹确认框;冲突提示不受此配置影响 |
shadowSave.backupOnWriteBack |
true |
写回前备份原文件 |
shadowSave.backupRetention |
10 |
每个影子保留的备份数量 |
语言 / Localization
扩展界面跟随 VS Code 的显示语言,目前支持:
- English(默认语言)
- 简体中文(VS Code 显示语言为
zh-cn 时自动启用)
清单中的命令名、设置说明使用 package.nls.json / package.nls.zh-cn.json;运行时提示、状态栏、按钮和错误信息使用 vscode.l10n 与 l10n/bundle.l10n.json / l10n/bundle.l10n.zh-cn.json。命令 ID、配置键和影子文件协议不随语言变化。
添加新语言时:
- 复制
package.nls.json 为 package.nls.<locale>.json 并翻译。
- 复制
l10n/bundle.l10n.json 为 l10n/bundle.l10n.<locale>.json,保留所有 {0} 占位符。
- 运行
npm run check:l10n 检查键和占位符一致性。
存储位置
影子根目录位于 VS Code 的扩展全局存储中,具体路径由 VS Code 决定。可通过 ShadowSave: 打开影子存储目录 直接打开。典型布局:
<globalStorage>/hornby-zhu.shadowsave/shadows/
<sha256>/
content.bin # 影子内容
meta.json # 原文件路径、时间、基线哈希等
backups/
1794365288743-9d9d4f.bak
每个原文件对应一个以规范化绝对路径的 SHA-256 为键的目录。影子存储跨工作区共享,键中包含完整路径,不会互相覆盖。
已知限制
- 语言服务兼容性:影子文件使用自定义 URI。部分语言服务器只识别
file: 或 untitled:,因此补全、诊断、跳转可能受限。扩展会尽量保留语言模式,但无法绕过语言服务器自身的限制。
- Git、任务、调试器、终端看到的是原文件,不是影子内容。
- 外部程序直接修改原文件不受扩展控制;下次写回时会通过哈希检测到冲突。
- 另存为会写到用户选择的新位置,不会覆盖原文件,但也不经过 ShadowSave 的写回流程。
- 不接管二进制文件、Notebook 单元格、无标题文档以及自定义编辑器。
- 从内存移入影子的未保存内容按 VS Code 文本模型处理,写回时通常为 UTF-8;已保存文件的首次影子拷贝按原始字节复制。
- 多个 VS Code 窗口同时编辑同一文件的影子时,后保存者覆盖先保存者。
开发
要求 Node.js 20+ 和 VS Code 1.95+。
npm install
npm run compile
npm test
npm test 会启动真实的 VS Code 扩展宿主并验证:
- 自动进入影子模式;
- 影子保存不改变原文件内容、大小和 mtime;
- 写回只发生一次且后续保存仍写影子;
- 从原文件重新载入;
- 退出影子模式与单文件自动接管暂停;
- 未保存修改自动移入影子(包括已有影子时的旧影子备份);
- 包含空格、百分号、井号和中文字符的文件名;
- 中英文语言包的键、占位符和清单占位符一致性。
npm test 会先运行 npm run check:l10n,再编译并启动扩展宿主。
默认自动查找本机 VS Code;也可设置:
$env:VSCODE_EXECUTABLE = "D:\Programs\VSCode\Code.exe"
npm test
修改或新增 vscode.l10n.t(...) 字符串后,运行以下命令重新生成英文默认语言包:
npm run l10n:export
开发调试:在 VS Code 中按 F5,会启动扩展开发宿主。
打包:
npm run package
License
MIT