原生视图与组件

原生渲染器、组件目录、快照/补丁协议与视频组件。

插件界面由 IDE 的原生渲染器(native.*)与原生组件节点组成,均通过快照/补丁协议同步。插件端使用 SDK 的类型化 facade(self.views.*)或组件构建器(pyrite_sdk.api.components),IDE 端用 Flutter 渲染。

渲染器目录

[[contributes.views]]renderer 决定 IDE 如何渲染该视图:

渲染器SDK facade数据节点用途
native.formself.views.form()FormField表单、配置面板
native.treeself.views.tree()TreeItem文件树、结构树
native.virtualListself.views.virtual_list()VirtualListItem大规模虚拟列表
native.tableself.views.table()TableRowItem / TableColumn数据表格
native.markdownself.views.markdown()MarkdownContent文档视图
native.logself.views.log()LogEntry日志、串口输出
native.outlineself.views.outline()OutlineItem大纲、符号列表
native.variableInspectorself.views.variable_inspector()VariableEntry / VariableScope设备变量检查器

Manifest 的 renderer 只接受注册表中的 native.* 值。其他值会在清单校验阶段以稳定错误码拒绝。

组件目录

pyrite_sdk.api.components 提供声明式组件构建器(c.Rowc.TextFieldc.Button 等),组件是普通字典,序列化为快照/补丁节点,由 IDE 的组件注册表校验(COMPONENT_SCHEMA_VERSION = 1)。

分类组件
布局RowColumnFlexGridWrapSplitViewTabs / TabSectionToolbar
文本与展示TextIconImageVideoMarkdownCodeBlockBadge
输入TextFieldNumberFieldSelectCheckboxSwitchSlider
菜单与对话框MenuMenuBarContextMenuDropdownDialogTooltip
操作ButtonIconButton
数据VirtualListTreeViewDataTablePropertyGrid

组件事件通过 ide.view.event 帧投递,绑定方式为构造参数(on_press=on_change=)或 .on(event, handler)

媒体与资源

ImageVideo 等媒体组件的 src 必须使用 self.resources.asset("assets/...") 生成的 PluginResourceplugin-resource:///...)。路径必须是 assets/ 下的相对路径,禁止 ..、前导 / 或反斜杠。

IDE 端视频组件由 features/plugin_view/plugin_video_player.dartPluginVideoPlayer 实现,并基于 video_player 提供 play、pause、seek、volume、speed、loop 和 fullscreen 控制:

video = c.Video(
    self.resources.asset("assets/demo.mp4"),
    id="demo",
    width=480,
    height=270,
    autoplay=True,
    show_controls=True,
)
video.controller.play()       # VideoController.play()
video.controller.seek_to(3000)  # 跳转到 3000ms

快照/补丁协议

每个视图实例维护一个 ViewModel,采用 revision 跟踪:

  1. 首次发送完整快照sdk.view.snapshot)。
  2. 之后发送增量补丁sdk.view.patch),每个补丁携带 baseRevision 与目标 revision
  3. 同一时刻最多一个补丁在途;等待确认期间产生的操作合并进下一个补丁。
  4. IDE 确认(ide.view.ack)后 revision 前移;拒绝(ide.view.nack)时插件自动 resync() 重发快照。
with view.model.batch():
    view.model.insert("a", {"label": "A"})
    view.model.update("b", {"label": "B"})
    view.model.move("c", 0)

协议限制

限制
MAX_SNAPSHOT_NODES20 000 节点 / 快照
MAX_PATCH_OPS2 000 操作 / 补丁
MAX_VIEW_PAYLOAD_BYTES2 MB / 快照或补丁负载

超过限制会在插件侧抛出 ViewProtocolError,不会发送到 IDE。补丁负载过大时 SDK 会按 1/2 递归收缩操作数。

Tree / List / Table 在 IDE 端使用虚拟化与稳定 ID,因此增量补丁基于稳定的节点 ID 定位,而不是行号。

组件树页面结构

AppBarScaffoldCanvaslib/core/sdk/component_schema.dart 中注册,由 lib/features/plugin_view/component_builder.dart 构建。

  • AppBar 使用 40 像素工具栏高度,只接受 IconButtonMenuDropdown 子组件。组件树构建器没有 Manifest 标题菜单上下文,因此这里只渲染组件树自身的操作。
  • Scaffold 将第一个 AppBar 子节点作为顶部栏,其他子节点作为正文。正文放在 Expanded 中,保证滚动组件得到有限主轴约束。
  • Canvaslib/features/plugin_view/plugin_canvas.dart 实现。持久基础层来自 props.ops,命令式调用写入仅存在于 PluginCanvasState 的覆盖层。

Canvas 在宿主侧维护图片缓存、几何命中索引和视口变换。平移、缩放、悬停高亮、拖动预览及框选不需要插件参与;只有订阅的 tapdraghoverpointer 事件会发送到 SDK。高频事件使用合并节流,基础层和覆盖层分别隔离保存栈,无法配对的 restore 不会影响组件外部的 Flutter Canvas。

sdk.view.component.invoke 的 Canvas 分支提供 push_opsset_opsclearclear_layerhit_test。SDK 在 src/pyrite_sdk/api/components.py 中对绘制调用执行 2 MiB 参数检查,src/pyrite_sdk/api/canvas.py 生成冻结 schema 对应的操作字典。跨仓协议样例位于 test/fixtures/protocol/protocol_v1_components.json,IDE 与 SDK 必须使用内容一致的副本。

渲染路径与同步边界

plugin_view_surface.dart 根据快照首节点选择渲染路径。带 type 的组件树交给 ComponentBuilder;普通数据节点交给 Manifest 指定的 native.* 渲染器。两类节点不能放进同一个模型。

渲染器 facade 会插入协议角色节点。appBarActionappBarMenuplaceholderviewConfigcontextMenuProvider 由宿主消费,不属于插件业务数据。修改渲染器时,要保留角色分流及稳定 ID 语义。

ViewModelStore 以插件 ID、会话 ID、视图 ID 和实例 ID 隔离模型。侧边栏实例采用 container:<containerId>,标签页采用宿主分配的 tab:<n>。修订断层或缺少快照会触发 nack 和 resync;非法操作与已关闭视图只返回 nack。恢复投递与隐藏视图重新可见时,SDK 发送完整快照,宿主不能依赖命令式覆盖层继续存在。

导航栏滚动

Desktop 与 Tablet 的侧栏导航由 lib/features/function_page.dart 构建。NavigationRail 外层依次使用 LayoutBuilderSingleChildScrollViewConstrainedBoxIntrinsicHeight

  1. LayoutBuilder 读取可用高度。
  2. ConstrainedBox 将最小高度限制为视口高度,使短内容仍填满侧栏。
  3. IntrinsicHeight 允许 NavigationRail 在目的项过多时按内容增长。
  4. SingleChildScrollView 在内容超过视口时提供滚动。

尾部操作仍作为 NavigationRail.trailing 布局在内容末端。调整侧栏结构时,要同时验证短列表的底部位置与长列表的滚动可达性,并覆盖 Desktop 和 Tablet 两处分支。

更多信息

On this page