命令、格式化器和 hooks
有些功能不需要一直显示一个页面:用户可以从 Cmd+K 执行一次操作,也可以让插件在格式化文本或保存文件后执行。本篇先做一个能显示通知的命令,再把同一个 extension 扩展为文本处理工具。
1. 添加一个 Cmd+K 命令
Section titled “1. 添加一个 Cmd+K 命令”创建 plugin.json 和 src/extension.ts:
{ "apiVersion": 1, "id": "example.hello-command", "name": "Hello Command", "version": "0.1.0", "requires": { "pluginApi": "3.0.0" }, "extension": "./src/extension.ts", "actions": [ { "id": "hello", "title": "Hello: show a message", "context": "workspace" } ], "placements": [ { "location": "command-palette", "action": "hello" } ]}actions 声明命令,command-palette 将它放入 Cmd+K。context: "workspace" 表示不需要选中某个文件。extension 指向注册处理函数的代码,它不是用于绘制页面的 mount。
2. 注册命令处理函数
Section titled “2. 注册命令处理函数”在 src/extension.ts 中填写:
import type { Activate } from "@eidos.space/plugin-sdk"
const activate: Activate = (ctx) => { ctx.subscriptions.add( ctx.capabilities.actions.register("hello", async ({ capabilities }) => { await capabilities.ui.notify("Hello from your plugin!") }) )}export default activate注册 ID 必须与清单的 hello 一致。执行命令时,宿主传入本次调用的 capabilities。示例使用它显示通知,并把注册句柄加入订阅,方便结束时清理。
3. 从 Cmd+K 验证
Section titled “3. 从 Cmd+K 验证”在 Lite 加载清单并启用插件。打开 Cmd+K,搜索 Hello: show a message,执行后应出现通知。
如果命令要打开自己声明的页面,在处理函数中检查并调用 capabilities.ui.navigate(viewId, route)。如果操作需要持续持有 WebSocket 或蓝牙连接,让命令向后台任务发送消息;命令本身不承担常驻生命周期。
为文本提供格式化器
Section titled “为文本提供格式化器”格式化器适合用户主动执行的文本整理。例如,删除每行末尾的空格。在上面的清单中添加:
{ "formatters": [ { "id": "trim", "title": "Trim trailing spaces", "extensions": [".txt"] } ]}在已有 activate 函数内部添加:
ctx.subscriptions.add( ctx.capabilities.formatters.register("trim", { format({ text, signal }) { signal.throwIfAborted() return { text: text.replace(/[ \t]+$/gm, "") } }, }))打开测试 .txt 文件,使用宿主的格式化入口选择此格式化器。它只返回新的文本,由宿主应用可撤销编辑;处理函数不需要自行写磁盘。不要假定格式化就意味着保存。
保存后自动处理:使用 hook
Section titled “保存后自动处理:使用 hook”如果你希望每次本地保存后自动清理空格,可改用 hook。它与格式化器是两种触发方式,先分别测试,不必同时启用。
将最低 API 调整为 3.3.0,在清单中添加:
{ "requires": { "pluginApi": "3.3.0" }, "hooks": [ { "id": "trim-on-save", "title": "Trim trailing spaces on save", "event": "document.saved", "extensions": [".txt"], "access": "write" } ]}保留 extension 入口,在 activate 内添加:
ctx.subscriptions.add( ctx.capabilities.hooks.register("trim-on-save", ({ event, signal }) => { signal.throwIfAborted() const text = event.document.text.replace(/[ \t]+$/gm, "") if (text !== event.document.text) return { text } }))给测试文本的行尾加空格,再保存,检查结果。hook 返回修改计划,宿主负责校验版本并应用。没有变化时不返回计划;hook 自己产生的修改不会再次触发 hook。
hook 只处理本次事件的文档,没有文件系统、数据库、网络、DOM 或 Node API。处理器也会收到 settings 配置快照。除 document.saved 外,还可以监听 file.renamed;后者提供 previousPath,保存事件提供 previousText。
打开文件、启用插件、云同步和局域网更新都不触发 hook。hook 失败不会撤销已经成功的保存或重命名。返回 name 可以提出同目录、同扩展名的新文件名;宿主保护同名文件和较新的文档版本,并维护 Markdown 引用。多个 hook 按插件 ID 和声明顺序运行,第一个有效写计划生效。
Lite 支持可编辑文本文件;Android、iOS 支持 Markdown;CLI Serve 不支持 hook。
批量处理表格记录
Section titled “批量处理表格记录”表格动作使用独立的 actions.registerTableProvider,不能把普通命令上下文当成记录写接口。一次批处理分为:
getItems根据表格结构返回菜单项。run使用target.count和target.readRows读取目标记录。- 写入前,用真实结果样本调用并等待
task.declareOutputs,确定允许写入的字段。 - 用读取时返回的
readToken调用target.update,通过task.report报告进度。
批次之间检查 signal。用户取消时保留已完成的修改。完整的 provider、菜单和任务类型见 Actions API;不要直接复制普通命令的权限假设到批处理。