
GPUI 十分钟上手用 Zed 自研的 Rust UI 框架画出自己的第一个 GPU 加速窗口【免费下载链接】zedCode at the speed of thought – Zed is a high-performance, multiplayer code editor from the creators of Atom and Tree-sitter.项目地址: https://gitcode.com/GitHub_Trending/ze/zedGPUI 是 Zed 编辑器自研并开源的 Rust UI 框架即时模式 保留模式混合架构GPU 加速渲染还能作为独立 crate 从 crates.io 直接安装。如果你想用 Rust 写一个跑大列表、渲染大段文本都不掉帧的桌面 GUI按下面 4 步配好依赖、开一个窗口、再花几分钟看懂它的状态模型就能真正跑起来。先用一个比喻看清 GPUI 帮你干什么 ️把 GPUI 想象成一家物业办公室。你不用自己砌砖、接电线只需要告诉物业每层有几间房、每间房做什么用途描述 UI实际施工和水电布线布局、GPU 渲染由它全包。物业还集中保管全楼所有房间的档案——每间房的数据状态都存在它手里你只能凭房卡Entity句柄进去查看或修改。几个关键事实先记下来你写的是描述不是画图指令每帧开始时 GPUI 调用窗口根视图的render方法你返回一棵由元素组成的 UI 树剩下的交给它变像素。重活由库干布局引擎是 taffy在 crates/gpui/Cargo.toml 中锁定0.13.0矢量路径用 lyonSVG 走 resvg/usvgmacOS 上的字形渲染依赖 fork 自 zed-font-kit 的font-kit。混合架构的具体含义即时模式部分每帧重新描述 UI保留模式部分靠全局 ID 在帧与帧之间识别同一个节点缓存住状态你不用自己管节点生命周期。当前版本0.2.2Apache-2.0仍处 pre-1.0版本间常有破坏性变更请用最新稳定版 Rust。十分钟跑通GPUI 依赖配置与最小可运行示例 第 1 步环境准备。装好最新稳定版 Rust 即可开工。macOS 用户额外需要 Xcode装完后先启动一次、按默认选项安装 macOS 组件和命令行工具xcode-select --install sudo xcode-select --switch /Applications/Xcode.app/Contents/DeveloperLinux 和 Windows 用户跳过这步。第 2 步GPUI 依赖怎么配。在Cargo.toml里加两行这是一个安全的跨平台组合gpui { version * } gpui_platform { version *, features [font-kit, wayland, x11] }只针对单一平台时可以裁剪gpui_platform的 featuremacOS只开font-kitMetal 渲染始终可用没有 font-kit 会退化成能排版但不画字形的占位文本系统Linux/FreeBSD至少开wayland或x11之一它们会顺带编译渲染器与文本系统Windows一个 feature 都不用开Win32 DirectWritefont-kit在这里无效。gpui 本体还有screen-capture、profiler、inspector、stacker等可选开关按需开启。第 3 步GPUI 最小可运行示例。下面这个精简版演示完整启动链路建 Application → 开窗口 → 注册根视图 → 用div描述 UI完整版带字体加载见 crates/gpui/examples/hello_world.rsuse gpui::{prelude::*, App, Context, Window, WindowBounds, WindowOptions, div, px, rgb, size, Bounds}; use gpui_platform::application; struct HelloWorld; impl Render for HelloWorld { fn render(mut self, _: mut Window, _: mut ContextSelf) - impl IntoElement { div().size(px(500.)).bg(rgb(0x505050)).text_color(rgb(0xffffff)) .justify_center().items_center().child(Hello, GPUI!) } } fn main() { application().run(|cx: mut App| { let bounds Bounds::centered(None, size(px(500.), px(500.)), cx); cx.open_window( WindowOptions { window_bounds: Some(WindowBounds::Windowed(bounds)), ..Default::default() }, |_, cx| cx.new(|_| HelloWorld), ).unwrap(); cx.activate(true); }); }第 4 步运行验证。在 Zed 仓库根目录需要 clone 时用 https://gitcode.com/GitHub_Trending/ze/zed 直接跑现成示例cargo run -p gpui --example hello_world屏幕中央弹出一个 500×500 的灰色窗口、中间写着 Hello, World!就算跑通了。Entity、View、Element三层分工各司其职理解 GPUI 只需要记住一个岗位分工的比喻Entity —— 货单。所有状态都存在名为App的仓库里cx.new(...)给你的不是货物本身而是一张带类型标签的货单。它像Rc一样引用计数但只有同时握着App引用时才能取出货物状态。View —— 前台接待。给结构体实现Rendertrait 它就成了视图每帧开头 GPUI 调用render你用 Tailwind 风格的链式 APIflex()、gap_3()、bg(rgb(...))这类拼出一棵元素树交上去不用关心怎么变像素。div元素就是这层的瑞士军刀。Element —— 木匠。UI 的底层积木对命令式 API 做了良好封装元素完全掌控自己与子节点的渲染方式是做高效大列表如uniform_list虚拟化列表、给代码编辑器写自定义布局时的正确选择。三层各配一个或多个上下文context作为与 GPUI 交互的统一入口这部分下一节顺带讲清。状态怎么流动创建、更新、观察、事件四种姿势 一句话结论App 拥有全部状态Entity 只是进出货仓的句柄。完整规则写在 crates/gpui/src/_ownership_and_data_flow.rs 的模块文档里四种姿势依次看创建实体拿到句柄并通过update修改状态application().run(|cx: mut App| { let counter: EntityCounter cx.new(|_| Counter { count: 0 }); counter.update(cx, |c, _| c.count 1); });update的回调里还能拿到一个ContextCounter——它额外携带绑定到哪个实体的信息并提供实体级服务比如cx.notify()通知观察者。想一个变了、跟着变用observenotifylet first: EntityCounter cx.new(|_| Counter { count: 0 }); let second cx.new(|cx| { cx.observe(first, |s, first, cx| s.count first.read(cx).count * 2).detach(); Counter { count: 0 } }); first.update(cx, |c, cx| { c.count 1; cx.notify(); });observe返回Subscription.detach()让它存活到两个实体任一销毁观察者回调拿到的是句柄要用read读状态。想发带内容的消息而非变了这个信号用subscribeemit发送方实现impl EventEmitterCounterChangeEvent for Counter {}在update里调cx.emit(event)接收方在cx.subscribe(first, |..., event, _| ...)里按事件类型处理。顺带交代三个入口够用即可App是根上下文拥有所有实体数据ContextT是包裹App的壳多了notify/emit且能解引用为App所以接受App的函数也能直接收它Window管窗口状态、有根视图但它本身不是上下文操作全局状态时得搭配mut App一起用。完整体系见 crates/gpui/docs/contexts.md。GPUI 键盘绑定闭环外加三大实用服务 ⌨️键盘交互闭环就四步定义 action → 元素上on_action→ 声明 key_context → keymap 里绑键。action 是你自定义的 struct负责把按键翻译成 UI 逻辑操作mod menu { actions!(gpui, [MoveUp, MoveDown]); }unit struct 用actions!宏最省事需要携带参数如方向、是否选中时改用#[gpui::action]定义带字段的结构体。接着在元素上绑处理器并声明 key contextdiv() .key_context(menu) .on_action(|this: mut Menu, _up: MoveUp, window, cx| { /* 上移 */ })最后在 keymap JSON 里按键——action 用全限定类型名标识带参 action 则附上序列化载荷{ context: menu, bindings: { up: menu::MoveUp, down: menu::MoveDown } }解析与上下文匹配在 crates/gpui/src/keymap.rs 与 crates/gpui/src/keymap/context.rs完整分发流程见 crates/gpui/docs/key_dispatch.md仓库 assets/keymaps/ 下的default-linux.json等文件是 Zed 的真实 keymap适合感受生产级绑定的规模。三个贴身服务合并说说平台服务退出应用、打开 URL 这类操作直接是App上的方法异步执行器与平台事件循环集成写 async 任务不需要自己接事件循环测试#[gpui::test]宏提供便捷的测试写法测试持有专门的TestAppContext可以模拟点击、按键等常见平台输入示例在 crates/gpui/examples/testing.rs。别忽略 GPUI 无障碍两个机制 一个坑 ♿对用屏幕阅读器和语音控制的用户来说无障碍做没做等于能不能用。GPUI 通过集成 AccessKit 提供程序化无障碍核心是两个机制全局 ID 决定是不是同一个节点。给元素设div().id(a)后GPUI 用祖先链上所有非空 ID 拼出GlobalElementId如[outer, inner]。同一帧内 ID 必须唯一跨帧 ID 相同即视为同一节点——屏幕阅读器通常只在有意义变化时播报所以你控制 ID 就控制了什么变化值得播报。role 决定是否上报。节点必须设置非None的rolebutton、label、table 等才会被告知辅助技术没设 role 的节点根本不上报。一个高频坑text!宏的 ID 派生自调用处在源码中的位置。在map/循环里只写了一次text!(todo)生成的所有文本共享同一 ID、又挂在同一祖先下全局 ID 全部撞车——release 构建下部分节点会被静默丢弃。两种修法text!(todo).with_id(index) // 或者用带唯一 ID 的节点包一层 div().id(index).child(text!(todo))另外两件事值得知道做自定义按钮组件时可用Text::new_inaccessible创建无 ID 文本避免父div的 label 在无障碍树里重复出现辅助技术还能针对特定节点派发动作用div().on_a11y_action()响应.on_click()已自动附带AccessibleAction::Click处理器。继续深入GPUI 源码入口导航 想看什么入口框架根模块与导出crates/gpui/src/gpui.rs、crates/gpui/src/prelude.rsApp 与上下文体系crates/gpui/src/app.rs、crates/gpui/docs/contexts.md所有权与数据流文档crates/gpui/src/_ownership_and_data_flow.rsView / Element / 样式crates/gpui/src/element.rs、crates/gpui/src/view.rs、crates/gpui/src/styled.rs内置元素库div、list、uniform_list、img、svgcrates/gpui/src/elements/键位与动作crates/gpui/src/action.rs、crates/gpui/docs/key_dispatch.md平台抽象与各平台后端crates/gpui/src/platform.rs、crates/gpui_macos/、crates/gpui_linux/、crates/gpui_windows/、crates/gpui_web/无障碍crates/gpui/src/_accessibility.rs可运行示例集cargo run -p gpui --example namecrates/gpui/examples/下一步建议按这个顺序走先跑通hello_world再依次看a11y无障碍最小示例、uniform_list虚拟化列表、testing测试写法。最后想看GPUI 造出来的真东西直接读 Zed 编辑器本体源码——编辑器、面板、标签页都是实现Render的 Entity仓库本身就是最大的实战教材。回到那条主线App 持有全部状态Entity 是句柄View 负责描述 UIElement 掌控渲染细节Context 贯穿一切服务——把这句话说顺了GPUI 就上手了。【免费下载链接】zedCode at the speed of thought – Zed is a high-performance, multiplayer code editor from the creators of Atom and Tree-sitter.项目地址: https://gitcode.com/GitHub_Trending/ze/zed创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考