gpui 应用起步模板
以下内容按 zed 主干 gpui(0.2.x)与 gpui-component 0.5.x 源码核实(zed crates/gpui/examples/hello_world.rs、gpui-component examples/hello_world)。
1. Cargo.toml
gpui 不发布 crates.io 正式版,统一用 git 依赖;gpui_platform 必须一并引入(平台后端 + 入口函数):
[package]
name = "my-app"
version = "0.1.0"
edition = "2024"
[dependencies]
gpui = { git = "https://github.com/zed-industries/zed" }
gpui_platform = { git = "https://github.com/zed-industries/zed", features = ["font-kit"] }
# Linux 需要窗口系统后端时:features = ["font-kit", "x11", "wayland"]
# 用组件库时再加:
gpui-component = { git = "https://github.com/longbridge/gpui-component" }
gpui-component-assets = { git = "https://github.com/longbridge/gpui-component" } # 图标资产,可选
[profile.dev.package]
# gpui 渲染相关 crate 在 dev 下也开优化,否则明显卡顿(上游同款配置)
gpui = { opt-level = 3 }
gpui_platform = { opt-level = 3 }
taffy = { opt-level = 3 }
resvg = { opt-level = 3 }
rustybuzz = { opt-level = 3 }
ttf-parser = { opt-level = 3 }
注意:crate 名 gpui-component,导入名 gpui_component。若与 gpui-component 同用,两处 git 的 zed 版本由 Cargo 统一解析;编译报 gpui 版本冲突时,以 gpui-component 锁定的 zed rev 为准。
2. 纯 gpui 最小应用
use gpui::{
App, Bounds, Context, SharedString, Window, WindowBounds, WindowOptions,
div, prelude::*, px, rgb, size,
};
use gpui_platform::application;
struct HelloWorld {
text: SharedString,
}
impl Render for HelloWorld {
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
div()
.flex()
.flex_col()
.gap_2()
.size_full()
.justify_center()
.items_center()
.bg(rgb(0x2e7d32))
.text_color(rgb(0xffffff))
.child(format!("Hello, {}!", self.text))
}
}
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()
},
|_window, cx| cx.new(|_| HelloWorld { text: "World".into() }),
)
.unwrap();
cx.activate(true); // macOS 置前;Windows/Linux 无害
});
}
要点:
use gpui::prelude::*;必带,否则.flex()/.child()/Render等 trait 方法全部找不到(E0599)。open_window构建闭包签名(&mut Window, &mut App) -> Entity<V>,必须返回cx.new(…)。- 入口是
gpui_platform::application();Application::new()已不存在。
3. gpui-component 应用(带 Root)
use gpui::{App, Window, WindowOptions, prelude::*};
use gpui_component::{ActiveTheme as _, Root, button::Button, h_flex};
struct Example;
impl Render for Example {
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
h_flex()
.size_full()
.justify_center()
.items_center()
.bg(cx.theme().background)
.child(Button::new("hi").primary().label("Hello"))
}
}
fn main() {
gpui_platform::application()
// 图标可用的前提:注册资产(或自定义 rust-embed AssetSource)
.with_assets(gpui_component_assets::Assets)
.run(move |cx| {
gpui_component::init(cx); // 必须最先调用
cx.spawn(async move |cx| {
cx.open_window(WindowOptions::default(), |window, cx| {
let view = cx.new(|_| Example);
// 每个窗口第一层视图必须是 Root,否则 Dialog/Sheet/Notification 图层缺失
cx.new(|cx| Root::new(view, window, cx).bg(cx.theme().background))
})
.expect("Failed to open window");
})
.detach();
});
}
三条硬性顺序:init(cx) 最先 → 窗口首层 Root → 主题访问 use gpui_component::ActiveTheme as _; 后 cx.theme()。
4. 常用 WindowOptions 字段
window_bounds: Option<WindowBounds>(Windowed/Maximized/Fullscreen)、titlebar: Option<TitlebarOptions>、focus、show、kind、is_movable、is_resizable、is_minimizable、window_background、app_id、window_min_size、window_decorations、icon。无 WindowBounds::Fixed。
5. 退出与窗口关闭
窗口关闭默认不退出应用,需要"最后窗口关闭即退出"时(已对照 examples/on_window_close_quit.rs):
cx.on_window_closed(|cx, _window_id| {
if cx.windows().is_empty() {
cx.quit();
}
})
.detach();
相关:代码里主动关窗用 window.remove_window();绑定快捷键 cx.bind_keys([KeyBinding::new("cmd-w", CloseWindow, None)]) 配合 actions!(example, [CloseWindow]) 与元素上的 .on_action(|_: &CloseWindow, window, _| window.remove_window())。
6. 下一步
- 布局/样式:
skill://gpui/references/layout-style.md - 实体与状态:
skill://gpui/references/entity.md - 动作与快捷键:
skill://gpui/references/action.md - 组件目录:
skill://gpui-component - 新旧 API 对照:
skill://gpui-migration