跳转至

将 Hex 的桌面 UI 从 GPUI 移植到 Rune

状态: 已完工并合并到 main:Rune 是 Hex 唯一的 UI 工具包,GPUI 已删除。每个界面都运行在 Rune 上:Linux 单进程窗口和 HUD、Windows 托盘应用和 HUD、macOS 菜单栏应用及其会议胶囊、每个窗格(通用、模式、Voice Action、历史记录、命令、会议、语音过滤器、活动、HUD 实验室)、引导之旅和转录选择器。macOS 听写 HUD 仍是原生 Metal NSPanel(dictation_indicator.rs,其弹簧动画由 rune_hud/spring.rs 提供)。Rune、rune-kit 和 rune-theme-opencode 已固定到 Rune 公共 MIT main 上的一个提交(https://github.com/anomalyco/rune.git;参见 rune-dependency.md 和 single-process.md)。在有人员检查过每种操作系统上的真实窗口清单之前,请勿合并到 main:Linux 已在真实会话中运行,macOS 已编译、测试并通过 SSH 无头启动,Windows 已交叉编译。

设计方向

Rune 前端使用 通过 Rune 组件库呈现的 OpenCode 设计语言(../design-system.md):

  • 控件来自 rune-kit(Button、IconButton、Switch、SegmentedControl、Select、Menu、Popover、TextInput、TextArea、Badge、Progress……)。
  • 所有颜色、层级、圆角、字体样式和动效 token 都来自 rune_theme_opencode::kit(dark)。
  • 窗口遵循 OpenCode Desktop 的布局:深色背景的侧边栏和一个凸起、圆角的内容面板,并跟随系统的浅色/深色外观。
  • desktop_i18n::tests::every_translated_string_has_every_language 会扫描 src/rune_ui.rs 以及每个窗格和宿主模块,确保所有面向用户的文本都以每种受支持的语言发布。

模块结构

src/rune_ui.rs                   app spec, shared state, host bridge, poll,
                                 drafts, shell (sidebar + panel), --snap scenes
src/rune_ui/controls.rs          cards, rows, switches, segmented, selects,
                                 buttons, keycaps, notes, text fields, Highlight
src/rune_ui/lists.rs             split list/detail, rows, group labels, tags,
                                 permission control, small_button, slider
src/rune_ui/platform.rs          Capabilities, PlatformState, PlatformRequest,
                                 NativeHost / Fixture seam
src/rune_ui/platform_settings.rs macOS and Windows General rows; Meetings settings
src/rune_ui/settings.rs          General pane and shortcut recorder
src/rune_ui/modes.rs             Modes pane (rules, corrections, OpenCode, transformations)
src/rune_ui/voice_action.rs      Voice Action pane
src/rune_ui/models.rs            OpenCode catalog, model and thinking pickers
src/rune_ui/history.rs           History pane
src/rune_ui/picker.rs            Transcription language/model picker modal
src/rune_ui/onboarding.rs        First-run setup tour across all platforms
src/rune_ui/commands.rs          Commands pane (macOS)
src/rune_ui/meetings.rs          Meetings pane (macOS)
src/rune_ui/meeting_capsules.rs  Offer, call-ended, recording, and ready capsules (macOS)
src/rune_ui/fun.rs               Voice Filter pane: Hex Microphone (macOS, experiment)
src/rune_ui/hud_lab.rs           Developer HUD Lab pane (macOS debug)
src/rune_ui/activity.rs          Developer Activity pane (debug)
src/rune_ui/linux_host.rs        In-process Linux host bridge
src/rune_ui/windows_host.rs      In-process Windows host bridge and keyboard-poll capture
src/rune_ui/macos_host.rs        In-process macOS host bridge, NativeHost, and chord monitor
src/rune_ui/tests.rs             Headless Linux UI tests and goldens
src/rune_ui/tests/panes.rs       macOS and Windows surface tests and goldens

界面与基准图

界面 状态 基准图(tests/golden/rune-*.png)
Shell 与通用(Linux) 侧边栏导航、状态卡片、桌面快捷键(X11 / portal / 命令)、听写、行为、应用行、退出 Hex、有可用更新时的更新按钮 rune-portal-{light,dark}、rune-commands-dark、rune-disabled-light、rune-capturing-dark、rune-chinese-dark、rune-menus-light
Voice Action 选择加入(opt-in)并检查快捷键冲突、录音器、可搜索的 OpenCode 模型与思考选择器、OpenCode 缺失/不可用提示 rune-voice-action-{light,dark}、rune-voice-action-off-light、rune-voice-action-unavailable-{light,dark}、rune-voice-action-models-dark
历史记录 搜索、保留期选择、两步“全部清除”、带复制和删除的详情、延迟与处理信息 rune-history-{light,dark}、rune-history-empty-light
模式 全局模式 + 自定义模式、可搜索的应用选择器、原生文件对话框(“Choose a file…”:FileChooser portal、NSOpenPanel、IFileOpenDialog)、网站规则、纠正、OpenCode 重写、可拖拽排序的变换、两步删除 rune-modes-{light,dark}、rune-modes-global-light、rune-modes-picker-{light,dark}
转录选择器 半透明遮罩上的模态框:语言、带推荐和 Streams 标签的模型卡片、使用/下载/取消/删除(两步)、实时进度 rune-picker-{light,dark}、rune-picker-downloading-{light,dark}
引导之旅 desktop::onboarding::Flow:Linux/Windows 欢迎页 → 模型设置 → 完成;macOS 额外提供麦克风/辅助功能行、系统设置指引、“试一试”练习字段和重新启动恢复 rune-onboarding-dark、rune-onboarding-setup-{light,dark}、rune-mac-onboarding*(10 个状态)
通用(macOS 与 Windows) 听写、输出和应用卡片,带可折叠的“高级”展开区(在 macOS 上适配 980×760),macOS 权限、登录时启动、显示 Dock 图标、快捷键边侧;Windows 监听器卡片、登录时启动、启动时启用;更新检查位于侧边栏版本下方 rune-mac-settings-{light,dark}、rune-mac-settings-advanced-light、rune-mac-settings-permissions-dark、rune-mac-settings-sides-dark、rune-windows-settings-light
命令(macOS) 按任务分组的目录、搜索、详情、创建/编辑配置、复制 Agent 提示词、带麦克风策略确认的启用卡片、命令模型重试/禁用提示 rune-mac-commands-{light,dark}、rune-mac-commands-confirm-light、rune-mac-commands-unavailable-dark
会议(macOS) 按天分组的列表、搜索、包含摘要及 You/Them 轮流话语的详情、复制转录文本、内联重命名、溢出菜单(复制摘要、显示、总结/重新生成、删除…)、两步删除、开始/停止录音;录音:设置开关(通话录音、日历、检测到的通话);关闭时的选择加入卡片 rune-meetings-{light,dark}、rune-meetings-settings-{light,dark}、rune-meetings-off-{light,dark}、rune-meetings-calendar-{light,dark}、rune-meetings-calendar-denied-dark、rune-meetings-recording-{light,dark}、rune-meetings-actions-dark、rune-meetings-delete-light、rune-meetings-rename-dark、rune-meetings-failed-dark、rune-meetings-empty-light
语音滤镜(macOS,实验) 驱动状态及安装/更新/卸载、九种语音滤镜模式、实时滑块、试用 5 秒录音器及双 rune::Shape 条形波形 rune-mac-voice-filter-{light,dark}、rune-mac-voice-filter-muted-dark、rune-mac-voice-filter-driver-missing-light
HUD Lab 与 Activity(调试) HUD Lab 状态/队列/样式/滑块控件和预设复制;Activity 实时事件列表和原始 JSON 检查器 rune-mac-hud-lab-{light,dark}、rune-mac-activity-light

在任何操作系统上无头运行:

cargo run -- app -- --list-scenes
cargo run -- app -- --snap /tmp/hex-modes.png --scene modes --theme light
cargo test rune_ui

HEX_UPDATE_GOLDENS=1 会重写 tests/golden/ 中的 53 个基准图(goldens)。在没有 GPU 的主机上,可使用 VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/lvp_icd.json 在 lavapipe 上渲染。

实测验证

  • Linux(apollo,niri Wayland,2026-10-22):
    • 在 Dax 会话中的真实窗口(app_id: hex;在 niri 的 prefer-no-csd 下无 CSD;在 2 倍缩放和 1.5 倍分数缩放下均清晰(1.5);窄至 640 px 时响应式行换行(之后))。
    • 单进程生命周期:启动 hex 会在已运行实例中打开窗口;关闭窗口后同一 PID 仍会响应;重新启动会再次打开窗口;hex quit 干净退出。
    • 无头 Sway(scripts/test-wayland-paste.sh 与 linux_rune_hud):hex dictation start 会显示顶部边缘的录音胶囊,stop 会在转写完成后将其隐藏;虚拟指针点击会穿透覆盖层。
    • CJK 回退字体(Noto Sans SC/JP)渲染中文界面无豆腐块(中文界面)。
  • macOS(hailmary,Command Line Tools 存根,2026-10-22):
    • 可通过 cargo clippy --all-targets -- -D warnings 编译,通过 macOS 单元测试和 Metal golden 渲染;带隔离数据根目录的调试版 hex app 启动后创建了 980×760 窗口,响应 hex dev status|show|hud,并在 Ctrl-C 时干净退出。
  • Windows(apollo 交叉检查,2026-10-22):
    • cargo xwin clippy --all-targets -- -D warnings 对 x86_64-pc-windows-msvc 和 aarch64-pc-windows-msvc 均通过。

需要人工查看

在基于 Rune 前端发布首个版本之前:

  • Linux: 文本字段上的指针悬停/按下状态和 I-beam 光标;用真实指针拖动变换;打开 FileChooser 门户对话框("选择文件…");Wayland wayland-data-control 复制/粘贴;IME 和搜索弹出框自动聚焦;录制实体 F 键或 Super 快捷键;X11 浮动窗口几何和 override-redirect HUD。
  • macOS: 在真实显示器上目检窗口、红绿灯 inset 和 El::window_drag;菜单栏状态项、Dock 重新打开、更新替换和重启;AppKit 仅修饰键/Fn 快捷键捕获;原生 Metal 听写 HUD(dictation_indicator.rs)和交互式 Rune 会议胶囊(meeting_capsules.rs);在真实应用的“模式”和“会议”中通过 NSOpenPanel 选择文件或文件夹(Pro 测试工具已检查面板配置、取消以及循环是否继续运行;未进行捕获)。
  • Windows(x64 和 ARM64): 首次实际启动 windows_rune.rs;托盘图标和菜单;重新启动时的焦点交接;键盘轮询快捷键捕获;windows_rune_hud.rs 位于任务栏上方的分层点击穿透覆盖层;登录时启动和自更新重启;“模式”中的“选择文件…” IFileOpenDialog(仅做过类型检查)。

剩余 Rune 与一致性差距

  • Rune 仍需要在 Hex 中绕过的粗糙边角: Pixels::set 不会唤醒其覆盖层(Windows HUD 发送空更新);没有圆角子裁剪(选择器手工将其左列做成圆角);没有仅修饰键按键事件(macOS 宿主保留了一个 NSEvent 监视器);事件循环在没有显示器时会 panic(Linux 捕获该展开)。这些问题已排在 Rune 当前核心工作之后。
  • 键盘导航(10 月 23 日落地): Rune 的焦点模型现已覆盖:按视觉顺序的 Tab 键及仅键盘焦点环、macOS Full Keyboard Access、菜单和选择框的方向键及类型选择、将焦点返回打开者的模态焦点陷阱、以及滚动到视野中的焦点。Hex 的侧边栏和列表窗格是源列表(Up/Down 选择、键入跳转到某行),Command-1…9 打开当前显示的窗格,切换行和快捷键录制器可获取焦点,转写选择器会困住焦点。列表方向键在两端停止,焦点跟随 Command+数字选择。仍待处理:“模型”和“应用”搜索弹出框(rune-kit Popover)不会困住焦点。
  • Windows 自定义标题栏:目前使用原生 Win32 标题栏。

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 hex19/hex