行号槽标记和行号槽按钮属于编辑器提供者,见 语言功能。
文件图标见 图标主题。
声明工具窗口
没有
web 的视图需要代码(wasm)。显示视图会激活插件(on-view:<id>)。
分组与条件显示
secondary,即使这个视图当前被隐藏;所有标签页都隐藏时窗口消失。
标签页在首次选中时加载,之后只要仍然适用就保持挂载,所以切换标签时网页视图的状态不会丢。上下文变化、文件新建或删除、
项目切换时会重新计算 when。这些字段只控制可见性,不授予任何访问权限。
渲染视图
注册register_plugin!(MyPlugin, views) 并实现 openidea_plugin::views::Views(WIT 导出 view-provider)。
视图就是数据:工具栏、主体和状态行。IDE 用自己的组件绘制(主题、键盘操作、快速搜索),再把用户的操作发回来。
摘自 TODO Finder 示例:
host::refresh_view(view),IDE 会再次调用 render。host::reveal_view(view)
在发起调用的窗口中把插件的某个视图切到前台。对工具窗口来说,ctx.editor() 是窗口中当前活动的文本编辑器,
所以工具栏按钮可以操作用户正在编辑的内容。
主体类型
工具栏按钮:
View::new(body).button(Button::new("refresh", "Refresh").icon("refresh")),状态行:.status("12 items")。
事件
ViewEvent 包括 Button(id)、Activate(key)(双击或回车)、Select(key)、Expand(key)、Collapse(key)、
Field(key, value)(复选框为 true/false)、Cell { row, column, value }、InsertRow(before)、
DeleteRows(rows),以及来自 HTML 主体的 Message(text)。表格行的单击和空格用 event.table_select() 解码,
双击和回车用 event.table_activate()(API 1.3,从 0 开始的绝对行号)。
后续 API 新增的主体、字段和事件以 Other { kind, data } 传递:IDE 不认识某种主体时会提示需要更新,
不认识的字段类型则直接省略。条目右键菜单使用 viewItem.context(见 命令与动作 中的“菜单”一节)。
自定义编辑器
自定义编辑器打开与 patterns 匹配的文件,编辑的是该文件的文本文档:priority = "default"时匹配的文件直接用插件编辑器打开;option时可通过 打开方式 选择。 作为文本打开 会打开文本编辑器。layout = "split"或"preview"时,文件在文本编辑器中打开,插件编辑器显示在旁边,标签栏中出现 仅编辑器 / 编辑器和预览 / 仅预览 切换,和 Markdown 一样;取值决定文件打开时的初始布局。"tab"(默认)是独立的标签页。- 在
render和handle中,ctx.editor()就是该编辑器的文档。用document()读取, 用apply_edits(version, edits)修改。同一文件的文本编辑器会同步变化,撤销/重做共用一份历史, 保存、修改标记和关闭提示都归文档所有。
editor.read 和 editor.write。
HTML 主体
Body::Html 在沙箱 frame 中运行:不透明源(opaque origin),CSP 只允许其内联脚本、内联样式和 data: 图片,
没有网络,也没有 IDE API。它只能通过 openidea.postMessage(text) 和 openidea.onMessage(fn) 与插件通信,
消息以 ViewEvent::Message 送达,插件用 host::post_view_message(view, text) 回复。
Regex Tester 就是这样工作的。
重新渲染会重新加载 frame,所以状态应由页面自己保存。
frame 会跟随 IDE 主题变化而无需重新加载。其根元素带有 data-theme="light|dark" 以及以下 CSS 变量(均为具体颜色值):
脚本还可以使用
openidea.theme({ dark, vars })和 openidea.onThemeChange(fn)。变量只会增加,不会删除。
网页视图
视图或自定义编辑器也可以是包内附带的网页,用来实现声明式主体表达不了的界面(画布、图表编辑器等)。不需要代码:- 页面所在目录(绝不是包根目录)属于声明的一部分:其下每个文件都会被检查(最多 4096 个文件、256 MiB,不允许链接), 随包安装和签名。
- 页面从 IDE 自己的 URL scheme 加载到
<iframe sandbox="allow-scripts">中:不透明源,没有网络、cookie 和存储, 只能访问页面自己的文件。请使用相对路径构建(Vite:base: "./")。 - 页面脚本运行前就能用到与 HTML 主体相同的
openidea对象,另外还有:
页面获得焦点时,它自己不处理的 IDE 快捷键(保存、关闭、查找操作等)仍然有效;编辑类按键交给页面。
声明
clipboard 权限后,页面可以使用 navigator.clipboard。
自定义顶栏(API 1.3)。不分组的工具窗口网页视图可以声明 header = "none":页面就绪后,IDE 用右上角的
选项、隐藏 按钮取代标准的工具窗口标题栏,并设置 --openidea-corner-inset-width(64px)和
--openidea-corner-inset-height(34px),页面可据此为自己的顶栏留出位置:
web-src/ 中的
Vite + React 页面由 plugins/build.sh official/graphviz 构建到 web/,插件代码把 Graphviz 报告的错误发布为问题。
页面协议(API 1.3)
声明engines.openidea = "^1.3" 后,页面可以通过 openidea.postMessage 发送 JSON 消息,请 IDE 打开更多东西。
这些协议只运行通过 process:<program> 授权的程序,工作目录是窗口所在的受信任项目根目录,从不经过 shell:
消息字段和限制见 插件指南;
crates/ide-plugin/tests/fixtures/ 下已构建的 web-pty、web-log、web-content 测试插件演示了这些协议。
服务视图与详情面板
location = "services"(API 1.3)把视图的树放进 服务 工具窗口,与 Docker 和运行配置并列,而不是单独开一个工具窗口:
render、handle、工具栏(作用于选中节点)和 viewItem.context 菜单与工具窗口中一样。
树旁的面板来自 detail-provider 导出:注册 register_plugin!(MyPlugin, views, details) 并实现
openidea_plugin::details::Details:
host::refresh_view(view) 后会重新请求。
标签页可以是 Pane::Message、只读的 Pane::Text(最多 1 MiB)或 ProcessLog:IDE 在项目根目录运行该程序
(需要 process:<program> 授权)并跟踪输出(去除 ANSI,保留最后 5000 行,提供 软换行、清除,结束时显示退出码)。
开关会追加其 args 并重启程序。面板关闭或服务窗口隐藏时程序停止。
列表与详情视图(API 1.3)。任意位置的树或列表视图都可以声明 detail = true,在选中条目旁显示同样的
Details 标签页,中间有可调整的分隔条。宿主在条目的 select 事件之后以及 refresh_view 之后请求详情。
由代码打开的标签页和终端
以下函数需在窗口的命令或事件中调用:装饰
装饰(API 1.4,WITdecorations.wit)用于在编辑器和项目树中添加标注。需要 project.read,路径必须在打开的项目内。
- 样式映射到主题 token:
highlight、search、added、modified、removed、warning、error、info、underline、strikethrough、muted。未知样式会被忽略。 - 一个装饰集(
set_id)属于插件和项目,该项目的所有窗口共享。设置时替换该集合在这个文件上的全部条目;clear_decorations(set_id)和clear_file_decorations(set_id)在所有地方移除整个集合。 - 限制:每个插件最多 50 个编辑器集合和 50 个树集合,每个文件最多 10,000 个编辑器条目,元数据总计 4 MiB。 禁用、卸载或崩溃时会撤回;空闲回收时保留。
Project::vcs_blame 的结果变成行尾装饰。