跳转到主要内容
代码插件是一个 WebAssembly 组件(组件模型,WASI preview 2),在 IDE 内部由 wasmtime 运行。它不能直接访问文件、网络、环境变量或进程。除纯计算外,它做的一切都要通过 IDE 提供的函数,而每个函数都会检查用户授予的能力。

组成部分

宿主内部如何组织,见贡献者文档中的 插件宿主。

World、导入与导出

插件 API 是一个 WIT 包。基础 world plugin 列出组件可以导入的宿主 interface(插件调用它们),以及组件必须导出的插件 interface(IDE 调用它们):
  • 导入:log、ui、storage、fs、workspace、editor、decorations、invocation、vcs、commit、events、tasks、diagnostics、net、secrets、process、ipc、output、auth、command-runner、views、run、run-targets、database、mcp、settings。
  • 导出:lifecycle(activate、deactivate)、commands(执行命令)、event-handler(处理一批事件)。
可选功能各自是一个独立的 world:它 include plugin 并多一个导出。只有清单声明了对应的贡献时,插件才需要导出它: 在 Rust 里把参数列出来即可:register_plugin!(MyPlugin, providers, views)。每个可选 world 还有一个只含导出的孪生 world(syntax、editor-providers、views-provider 等),由组件工具与 plugin 合并。

双向调用

  • IDE → 插件(导出):用户执行命令时 IDE 调用 commands.run;有订阅的事件时调用 event-handler.handle 并传入一批事件;编辑器需要补全、悬停等时调用 provider 函数;绘制视图时调用 view-provider.render。
  • 插件 → IDE(导入):在上述任一调用中,插件可以调用 editor.text-editor.document、workspace.project.read-file、net.fetch 等宿主函数。缺少能力时宿主函数返回 error::denied("<capability>"),插件继续运行,可以降级处理。 1.x 的所有调用都是同步的:宿主调用返回前插件实例一直阻塞;编辑器 provider 每次调用都会收到完整的文档文本。位置坐标是从 0 开始的行号和 UTF-16 列,与编辑器和 LSP 一致(syntax provider 使用 UTF-8 字节偏移,由 IDE 转换)。

沙箱

每个插件都有自己的 wasmtime Store:
  • 没有预打开的目录、没有环境变量、没有网络,也不继承 stdin/stdout;
  • WASI 只提供时钟和随机数;
  • stderr 会被捕获:eprintln! 的输出写进 IDE 日志,panic 的信息会随崩溃一起显示。
文件、网络、进程、套接字和密钥都只能通过宿主函数访问,每个函数都受某个能力约束。路径会先解析到真实位置再检查,所以符号链接无法逃出项目根目录或已授权的目录。 Web 视图和 Web 自定义编辑器运行在 <iframe sandbox="allow-scripts"> 中,从 IDE 自己的 openidea-plugin URL scheme 加载:opaque origin,没有网络、Cookie 或存储,没有 IDE API,只能加载页面自己的文件。页面通过 postMessage 与插件代码通信。

限制

每次调用插件都有上限: 等待用户操作(选择器、输入框、确认框)的时间不计入时间限制。各个宿主函数还有自己的上限(文件大小、句柄数、响应大小等),详见 plugins/README.md。

线程与崩溃

每个活跃插件运行在自己的线程上(一个持有该插件运行时的 actor)。调用方把任务排进队列并等待回复,所以同一实例内的调用永远不会并发。编辑器调用方可以在软截止时间放弃等待,而调用本身继续执行到硬截止时间;任何线程都可以取消调用。墙钟限制通过 wasmtime 的 epoch 中断实现。 panic、trap、权限违规或超出限制都会丢弃该实例。用户只会收到一次提示,下次需要时插件重新启动;连续崩溃时重启前的等待时间逐次翻倍(1 秒、2 秒……最长 60 秒)。连续崩溃三次后,插件在本次会话中被标记为 失败,设置 › 插件 中会显示原因;点 重启、关闭再打开,或 从磁盘重新加载 都能让它重新启动。只要有一次调用正常返回,计数就会清零。插件崩溃不会影响 IDE 本身。 设置 › 插件 会显示每个插件的激活次数、近期调用延迟(p95)、崩溃次数、超时的编辑器结果和空闲回收次数。

远程项目

插件代码在项目所在的机器上运行。窗口打开远程项目时,桌面端会把已启用的代码插件及其授权发送给 openidea-server,由它在文件旁边运行:文件读取、搜索、进程、网络请求和诊断都作用于远程机器,process: 程序也在那里解析。密钥始终留在桌面端的钥匙串中,服务器在请求需要时向桌面端索取。远程插件的视图、通知、状态栏项和终端照常显示在窗口中。 目前的限制:项目插件(.openidea/plugins)还不能在远程项目中运行;插件在服务器上的存储初始为空。

异步与 API 2.0

1.x API 有意设计为同步。WASI 0.3 异步组件计划在 API 2.0 引入,宿主中会有一个适配层让 1.x 插件继续运行。见 API 版本与兼容。