VSC -> Zed 迁移

前言

距离 Time to Press the Stop Button 已经将近两年,这一波学习热潮总算是接近尾声。 从 My Cli Setup 开始陆陆续续尝试了很多新工具,也重构了不少项目,这些统一在 2025 年度总结 - 生活篇#后记 提到的开发篇再介绍,今天就简单讲讲从 VSCodium(下称 VSC)到 Zed 的迁移过程。

介绍

Zed 算是近两年比较新的编辑器,虽然看上去类似 VSCode,实际上因为基于 tree-sitter 和 LSP,可能还是更贴近 neovim。最早作为闭源 macOS only 编辑器没多少热度,开源并支持 Linux/Windows 后才逐渐起色。

虽然我最早知道 Zed 还是因为 zedless,但后者开发过于缓慢,还不发布二进制,作为单纯的 fork 的意义不大。不像 VSCode -> VSCodium,后者间接推动了 Open VSX Registry 的发展,除了 Eclipse 也有一大堆 VSC fork 在用,避免了 Visual Studio Marketplace 的 vendor lock-in。

迁移

设置

  • 虽然 Zed 官网也有 How to Migrate from VS Code to Zed,但写得太简单,只跟着这里走完立马使用只会浑身难受,建议过一遍自定义、设置项的文档再上手。
  • 内置的协作工具我觉得没什么用就直接关了,登录也是不可能登录的,直接隐藏按钮。
  • OpenCode ACP 简单试了下,效果不是很行。LLM Provider API Key 也是明文储存,非常难绷。虽然可以通过配置收紧默认权限,申请权限也可以拒绝,但拒绝了就停了,权限控制堪称笑话……
  • file_scan_exclusions 对应 VSC files.{exclude,watcherExclude},类似的还有 file_scan_inclusions,Zed 默认值要合理一点点,但自定义必须补全默认值,略冗长
  • file_types 逻辑和 VSC files.associations 反着来,更加合理

更新

为了防止供应链攻击 1,我从来不用自动更新,而是通过其他方式管理。

因为 Void 对 fork/Electron 极端排斥,只能下载 .deb 然后用 xdeb 转换成 xbps 再安装。由于 VSC 不支持 xdg-base-dir,安装后还要手动 patch dataFolderName

sudo sed -i 's|"dataFolderName": ".*"|"dataFolderName": ".local/share/VSCodium"|g' "/usr/share/codium/resources/app/product.json"

Zed 这点做得很好,开箱支持。由于支持架构少了几十种,也不需要在一百多个 GitHub release assets 中翻找 2,更新脚本写起来很简单,动态更新直接 rsync -a --update --delete --links 即可。

备份

Zed 没有 workspace 的概念,打开一个文件夹即是一个 project。Project history 保存在 ~/.local/share/zed/db/*/db.sqlite 的 workspaces 表 3,直接备份数据库即可,避免陷入重装要手动拖几十个文件夹的惨剧。

插件和 language server 列表当然也可以备份 ~/.local/share/zed/{extensions,languages},但都可以在 auto_install_extensions 设置项配置,没必要。

Linter

Zed 统一使用 LSP 对接,也可以调用外部 formatter/linter 处理 stdin,设计很合理。

好处说完了,该开喷了:

  • 启动 Zed 会自动下载 Node.js,哪怕系统已安装并且已经添加到 PATH 也如此。妥妥的流氓行径
  • 初次打开的文件类型,Zed 会自动下载对应 language server,这挺好,就是偶尔打开一次的文件还要装几百兆依赖有点蠢,好在被骂多了现在添加了提醒。但是,为了方便默认使用万恶的 prettier……

有点跑题了,回到 linter,简单列个表,算作 mise-as-linter#TLDR 的更新。 不过 VSC 用了这么多年,接触过的语言有点多,只能写一下目前已经配置的。

注意

  • Linter 和 Language Server 分开列,Zed 内置支持则用括号表示。
  • mise-as-linter 类似,这里的 linter 同时指代: linter, formatter, language server, extension。
  • 严格来说 LSP 指代 Language Server Protocol,即工具与 Language Server 交互的协议。而且 Zed 插件除了 language server,也有(为 tree-sitter 不支持的格式提供)syntax highlighter。为了简化逻辑,下文刻意混用,统一称作 LSP。
  • Zed 文档和插件命名很混乱,为了减少歧义,按以下优先级降序
    1. settings.json auto_install_extensions 的扩展名
    2. ~/.local/share/zed/{languages,extensions/installed} 的文件夹名
    3. GitHub zed-extensions 的 repo 名
    4. Zed 文档中的命名 4

列表

LanguageLinterLSP
Bashshellcheck, shfmtbasher
Zshshellcheck/
C/C++clangd(clangd)
JavaScriptbiomebiome
TypeScriptbiomevtsls
CSSbiomevscode-css-languageservice
HTMLbiomehtml
JSON/JSONCbiomejson-language-server
Luastylualua
Markdownmarkdownlint-cli2/
Nginx/nginx
Nix/nix
Nushellnu-lintnu+nu-lint
Pythonruff, tyruff+ty
Rlintr, stylerr
SQLsqlfluffsql
SystemD/ini
TOMLtombitoml+tombi
XML/xml
YAML/yaml

解释

  • Zsh
    • tree-sitter-bash 对于 zsh 非常排斥,可以看作 wontfix。虽然有新的 tree-sitter-zsh,但还没发布到 zed。
    • Linter/Formatter 方面倒是没太大问题,shellcheck 能用,只是有很多误报,shfmt-3.13.0 已经初步支持 zsh,未来可期。
  • C/C++: 之前在 VSC 还装了 CodeLLDB,但这么多年我 GDB 都只用过一两回,LLDB 装了也没用,迁移时直接卸载了……
  • Lua: 和 C/C++ 类似,从没用过 VSC 的 Lua Debug 插件,这里就不装了,配置 StyLua 为 external formatter
  • Markdown
    • 默认使用战五渣 prettier,配置 markdownlint-cli2 为 external formatter
    • 类似 LaTeX,相比于 VSC 的 Markdown All in One,Zed 的 Markdown 支持只能说够用,但远远不算上好用
  • Nginx: 很少需要写 Nginx 配置,gixy 自然用得少,暂时没配置
  • Nix: nixfmt 强制一行一个软件包并且不支持使用 nolint:on, nolint:off 动态开关,我显然不可能用,只安装插件提供基本的高亮
  • Nushell: 因为 nu-lint 不支持 XDG,而且 Zed 解析 settings.json 不支持 ~$HOME 这样的环境变量,也没有类似 VSC ${userHome} 的变量,只能在 nu-lint LSP 配置丑陋的绝对路径
{
  "lsp": {
    "nu-lint": { "binary": { "arguments": [ "--config", "/home/aaron/.config/nu-lint/config.toml", "--lsp" ] } }
  }
}
  • Python
    • LSP: Zed 虽然支持 ty,但为了兼容性默认会安装 ty, basedpyright, pyright, pylsp 四个 language servers,我直呼有病病?在配置里禁用 ty 之外的 LSP 并禁止自动安装对应插件 5
    • Formatter: 默认 ruff(总算是有个正常人),额外配置 source.organizeImports.ruffsource.fixAll.ruff 两个 code_actions_on_format
  • R
    • 除了 Zed 方面需要安装 R 插件,也要安装 languageserver 和 lintr 两个 R 包。
    • styler 是 languageserver 自带的 formatter,配合 lintr 够用。很少写 R,暂时没兴趣尝试 Posit(RStudio 开发公司)做的 air。
  • SQL: 配置 sqlfluff 为 external formatter
  • SystemD: 不是 typo,除了 ini 本体,zed-ini 真的支持 EditorConfig, SystemD Unit , Podman Quadlet 等一堆格式。和 Nginx 类似,很少需要写 SystemD 配置,systemdlint 也很少用,暂时没配置。
  • TOML: 之前用的 taplo 很少维护,插件直接被 Zed 移除了,我无语……好在测试下来 tombi 确实更实用,直接迁移
  • XML: Formatter 默认使用 prettier,用得很少,懒得和 prettier 斗智斗勇
  • YAML
    • 虽然装了 yamllint,但因为我很讨厌 YAML 又不用 Docker,基本只用于 GitHub Action,而 Zed 并不支持 zizmor/actionlint,这是少数停留在 VSC 的格式。
    • Formatter 默认使用 prettier,好在 yaml-language-server 也能格式化。

Prettier

单独一节专门 fuck prettier🖕biome 也有点 opinionated,但态度比 prettier 好太多,而且可以通过配置关闭。不过现在 oxc (oxfmt/oxlint) 似乎也能替代 biome,有空试试。

  • JavaScript: zed 默认用杀千刀的 prettier,必须禁用,这里将 biome 作为 LSP 使用,配置起来更简单。
{
  "languages": {
    "JavaScript": {
      "formatter": "language_server",
      "language_servers": [ "biome" ],
      "code_actions_on_format": {
        "source.fixAll.biome": true,
        "source.organizeImports.biome": true
      }
    },
    
  }
}
  • TypeScript/TSX: 和 JavaScript 类似,但保留默认 language server
  • CSS/HTML: biome 虽然支持 LSP,一样保留默认 language server,只当作 linter/formatter,配置起来也简单。
{
  "languages": {
    "CSS": { "formatter": { "language_server": { "name": "biome" } } }
  }
}
  • JSON/JSONC: 配置非常蛋疼,只有将 biome 配置为 external formatter 才能彻底覆盖掉人人喊打的 prettier,补充几行 argument 确保和 biome 全局配置一致,并且不影响 format on save
"JSON": {
  "formatter": {
	"external": {
	  "command": "biome",
	  "arguments": [
		"format",
		"--trailing-newline=false",
		"--files-ignore-unknown=true",
		"--stdin-file-path",
		"{buffer_path}",
		"-"
	  ]
	}
  },
  "prettier": {
	"allowed": false
  },
  "language_servers": [
	"json-language-server"
  ],
  "ensure_final_newline_on_save": false
}

其他

💡 Tip

该部分统一使用扩展名作为命名。

  • ahk: 只支持 v1 格式,不支持 v2,而且只支持 Windows,我就不能 Linux 写 + Windows 测试吗……
  • git-firefly: .gitignore 支持
  • rainbow-csv: 维护 VNDB-Calendar 和 game-stats 必备
  • log: 看似很有用其实没卵用,看日志一般 SSH 过去直接 less/moor,根本没机会用 GUI,更别提还要特地装个 Zed……
  • make: 已迁移到 mise,直接不安装
  • powershell: 很少写,只装了高亮,凑合用
  • go/rust/zig: 自带 formatter,没啥好写的
  • graphiviz/mermaid: 用到再安装
  • docker-compose, dockerfile, basedpyright, pyright, pylsp, eslint: 禁止安装,防止污染环境,可惜还有很多语言没配置,只能暂且饶 prettier 一条狗命

TODO

  • Code Runner: VSC 插件,支持近百种语言的一键运行。Zed 最近的几次更新在 shebang 和 code block 添加了运行按钮,能用,但非常凑合,后面还是得参考 Code Runner 配置 Tasks。
  • Code Snippet: Zed 文档写着支持,格式也和 VSC 几乎一样,实测并不能使用,由于 snippet 以别扭的 JSON 格式储存,直接复制也没卵用,只能手动管理……
  • LaTeX Workshop: 最近几年很少需要写 LaTeX,TinyTex 都没安装。未来如果有需要,可能尝试 Typst,之前扫过几眼官方 Tutorial、Guide for LaTeX Users 和小蓝书,不过当时顾虑生态,没深入了解,现在应该好上不少。
  • zizmor: zizmor LSP 支持还比较早期,就 VSC 做得还行,理论上配合 github-actions 可以凑合用,没搞定。这个都不行,gitleaks/trufflehog/trivy 就更不指望了。
  • mise: VSC Mise 插件还挺有用,不过功能很基础,后面可能手搓一个 Zed 版本

  1. 软件内置的更新程序是劫持重灾区,就连火绒的更新程序也曾被劫持,好在当年我因为手动配置代理而幸免于难…… ↩︎

  2. 为了避免这种情况,我写过 GitHub Release Highlight,预设关键词,在指定 repo 自动高亮对应 asset。不过现在基本都是 mise/scoop/appman/更新脚本,很少用到。 ↩︎

  3. 这命名其实有点讽刺,说没有 workspace 但是数据库里储存 project 的 table 就叫 workspace…… ↩︎

  4. 看到我最后才考虑破文档中的命名,想必你也能稍稍理解这难以忍受的 inconsistency…… ↩︎

  5. 别以为这样就结束了,Zed 随时可能添加新的 language server 并静默安装。因为默认禁用,不手动检查 ~/.local/share/zed/languages 或者进行磁盘检测你甚至根本发现不了……PyLSP 就是某次更新后自动下载安装的…… ↩︎

Vinfall's Geekademy

Sine īrā et studiō