一键导入
gpui-actions
Actions and event handling in GPUI applications. Use when implementing user interactions, keyboard shortcuts, custom actions, or event-driven behavior.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Actions and event handling in GPUI applications. Use when implementing user interactions, keyboard shortcuts, custom actions, or event-driven behavior.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Async patterns and concurrency in GPUI applications. Use when implementing background tasks, async/await operations, task management, or concurrent operations.
UI element creation and composition with GPUI. Use when building element trees, creating custom components, implementing layouts, or working with conditional rendering.
Entity and context patterns for state management in GPUI. Use when managing component state, implementing entity lifecycle, handling subscriptions, or avoiding common entity access pitfalls.
Testing GPUI applications and components. Use when writing tests, testing async operations, simulating user input, or debugging test failures.
| name | gpui-actions |
| description | Actions and event handling in GPUI applications. Use when implementing user interactions, keyboard shortcuts, custom actions, or event-driven behavior. |
This skill covers actions, events, and user interaction handling in GPUI.
GPUI actions provide:
.on_click(), .on_mouse_down(), etc.Use the actions! macro for actions with no data:
use gpui::*;
actions!(my_app, [Save, Open, Close, Refresh]);
// These actions have no associated data
Use #[derive(Clone, PartialEq)] with the Action derive:
use gpui::*;
#[derive(Clone, PartialEq)]
struct SetCount {
value: usize,
}
impl_actions!(my_app, [SetCount]);
Doc comments on actions are displayed to users:
actions!(editor, [
/// Save the current file
Save,
/// Open a file
Open,
]);
use gpui::*;
impl Render for MyView {
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
div()
.child("Click me")
.on_click(|event, window, cx| {
println!("Clicked at: {:?}", event.position);
})
}
}
Use cx.listener() to access the entity:
impl Render for Counter {
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
div()
.child(format!("Count: {}", self.count))
.child(
div()
.child("Increment")
.on_click(cx.listener(|this, event, window, cx| {
this.count += 1;
cx.notify();
}))
)
}
}
div()
.on_mouse_down(|event, window, cx| {
// Mouse button pressed
})
.on_mouse_up(|event, window, cx| {
// Mouse button released
})
.on_mouse_move(|event, window, cx| {
// Mouse moved over element
})
.on_hover(|is_hovered, window, cx| {
// Hover state changed
})
div()
.on_key_down(|event, window, cx| {
if event.keystroke.key == "Enter" {
println!("Enter pressed");
}
})
.on_key_up(|event, window, cx| {
// Key released
})
.on_key_down(|event, window, cx| {
if event.keystroke.modifiers.control && event.keystroke.key == "s" {
println!("Ctrl+S pressed");
// Handle save action
}
})
use gpui::*;
actions!(my_app, [Increment, Decrement]);
struct Counter {
count: i32,
}
impl Render for Counter {
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
div()
.child(format!("Count: {}", self.count))
.on_action(cx.listener(|this, action: &Increment, window, cx| {
this.count += 1;
cx.notify();
}))
.on_action(cx.listener(|this, action: &Decrement, window, cx| {
this.count -= 1;
cx.notify();
}))
}
}
// Dispatch from window
window.dispatch_action(Save.boxed_clone(), cx);
// Dispatch from focus handle
focus_handle.dispatch_action(&Save, window, cx);
use gpui::*;
struct InputField {
focus_handle: FocusHandle,
text: SharedString,
}
impl InputField {
fn new(cx: &mut Context<Self>) -> Self {
Self {
focus_handle: cx.focus_handle(),
text: "".into(),
}
}
}
impl Render for InputField {
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
div()
.track_focus(&self.focus_handle)
.on_click(cx.listener(|this, _event, _window, cx| {
this.focus_handle.focus(cx);
}))
.child(self.text.clone())
}
}
div()
.track_focus(&self.focus_handle)
.on_focus(cx.listener(|this, _event, _window, cx| {
println!("Gained focus");
}))
.on_blur(cx.listener(|this, _event, _window, cx| {
println!("Lost focus");
}))
use gpui::*;
#[derive(IntoElement)]
struct Button {
label: SharedString,
on_click: Option<Box<dyn Fn(&mut App) + 'static>>,
}
impl Button {
fn new(label: impl Into<SharedString>) -> Self {
Self {
label: label.into(),
on_click: None,
}
}
fn on_click(mut self, handler: impl Fn(&mut App) + 'static) -> Self {
self.on_click = Some(Box::new(handler));
self
}
}
impl RenderOnce for Button {
fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
let mut div = div()
.px_4()
.py_2()
.bg(rgb(0x3b82f6))
.text_color(rgb(0xffffff))
.rounded(px(6.0))
.cursor_pointer()
.child(self.label);
if let Some(handler) = self.on_click {
div = div.on_click(move |_event, _window, cx| {
handler(cx);
});
}
div
}
}
actions!(form, [Submit, Cancel, Reset]);
struct LoginForm {
username: SharedString,
password: SharedString,
}
impl Render for LoginForm {
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
div()
.v_flex()
.gap_4()
.on_action(cx.listener(|this, _: &Submit, window, cx| {
println!("Submitting: {}", this.username);
// Handle submit
}))
.on_action(cx.listener(|this, _: &Cancel, window, cx| {
println!("Cancelled");
// Handle cancel
}))
.on_action(cx.listener(|this, _: &Reset, window, cx| {
this.username = "".into();
this.password = "".into();
cx.notify();
}))
.child("Login Form")
}
}
struct DraggableItem {
position: Point<Pixels>,
is_dragging: bool,
drag_offset: Point<Pixels>,
}
impl Render for DraggableItem {
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
div()
.absolute()
.left(self.position.x)
.top(self.position.y)
.w(px(100.0))
.h(px(100.0))
.bg(rgb(0x3b82f6))
.cursor_pointer()
.on_mouse_down(cx.listener(|this, event, _window, cx| {
this.is_dragging = true;
this.drag_offset = event.position - this.position;
cx.notify();
}))
.on_mouse_up(cx.listener(|this, _event, _window, cx| {
this.is_dragging = false;
cx.notify();
}))
.on_mouse_move(cx.listener(|this, event, _window, cx| {
if this.is_dragging {
this.position = event.position - this.drag_offset;
cx.notify();
}
}))
.child("Drag me")
}
}
div()
.on_click(|event, _window, cx| {
println!("Child clicked");
// Prevent parent from receiving event
event.stop_propagation();
})
track_focus() and FocusHandle| Mistake | Problem | Solution |
|---|---|---|
| Forgetting cx.notify() | UI doesn't update | Call after state changes |
| Not using cx.listener() | Can't access entity | Use cx.listener() |
| Nested event handlers | Confusing behavior | Use event propagation control |
| Missing focus tracking | Keyboard events don't work | Use .track_focus() |
| Not boxing actions | Type errors | Use .boxed_clone() for dispatch |
actions!() macro for simple actions.on_click(cx.listener(...)) for clickable elements.on_action() for action handlersFocusHandle for keyboard focuscx.notify() after state changeswindow.dispatch_action()