Use when you have a written implementation plan to execute in a separate session with review checkpoints
npx skills add longbridge/gpui-component --skill "gpui-event"
Install specific skill from multi-skill repository
# Description
Event handling and subscriptions in GPUI. Use when implementing events, observers, or event-driven patterns. Supports custom events, entity observations, and event subscriptions for coordinating between components.
# SKILL.md
name: gpui-event
description: Event handling and subscriptions in GPUI. Use when implementing events, observers, or event-driven patterns. Supports custom events, entity observations, and event subscriptions for coordinating between components.
Overview
GPUI provides event system for component coordination:
Event Mechanisms:
- Custom Events: Define and emit type-safe events
- Observations: React to entity state changes
- Subscriptions: Listen to events from other entities
- Global Events: App-wide event handling
Quick Start
Define and Emit Events
#[derive(Clone)]
enum MyEvent {
DataUpdated(String),
ActionTriggered,
}
impl MyComponent {
fn update_data(&mut self, data: String, cx: &mut Context<Self>) {
self.data = data.clone();
// Emit event
cx.emit(MyEvent::DataUpdated(data));
cx.notify();
}
}
Subscribe to Events
impl Listener {
fn new(source: Entity<MyComponent>, cx: &mut App) -> Entity<Self> {
cx.new(|cx| {
// Subscribe to events
cx.subscribe(&source, |this, emitter, event: &MyEvent, cx| {
match event {
MyEvent::DataUpdated(data) => {
this.handle_update(data.clone(), cx);
}
MyEvent::ActionTriggered => {
this.handle_action(cx);
}
}
}).detach();
Self { source }
})
}
}
Observe Entity Changes
impl Observer {
fn new(target: Entity<Target>, cx: &mut App) -> Entity<Self> {
cx.new(|cx| {
// Observe entity for any changes
cx.observe(&target, |this, observed, cx| {
// Called when observed.update() calls cx.notify()
println!("Target changed");
cx.notify();
}).detach();
Self { target }
})
}
}
Common Patterns
1. Parent-Child Communication
// Parent emits events
impl Parent {
fn notify_children(&mut self, cx: &mut Context<Self>) {
cx.emit(ParentEvent::Updated);
cx.notify();
}
}
// Children subscribe
impl Child {
fn new(parent: Entity<Parent>, cx: &mut App) -> Entity<Self> {
cx.new(|cx| {
cx.subscribe(&parent, |this, parent, event, cx| {
this.handle_parent_event(event, cx);
}).detach();
Self { parent }
})
}
}
2. Global Event Broadcasting
struct EventBus {
listeners: Vec<WeakEntity<dyn Listener>>,
}
impl EventBus {
fn broadcast(&mut self, event: GlobalEvent, cx: &mut Context<Self>) {
self.listeners.retain(|weak| {
weak.update(cx, |listener, cx| {
listener.on_event(&event, cx);
}).is_ok()
});
}
}
3. Observer Pattern
cx.observe(&entity, |this, observed, cx| {
// React to any state change
let state = observed.read(cx);
this.sync_with_state(state, cx);
}).detach();
Best Practices
β Detach Subscriptions
// β
Detach to keep alive
cx.subscribe(&entity, |this, source, event, cx| {
// Handle event
}).detach();
β Clean Event Types
#[derive(Clone)]
enum AppEvent {
DataChanged { id: usize, value: String },
ActionPerformed(ActionType),
Error(String),
}
β Avoid Event Loops
// β Don't create mutual subscriptions
entity1.subscribe(entity2) β emits event
entity2.subscribe(entity1) β emits event β infinite loop!
Reference Documentation
- API Reference: See api-reference.md
- Event definition, emission, subscriptions
- Observations, global events
-
Subscription lifecycle
-
Patterns: See patterns.md
- Event-driven architectures
- Communication patterns
- Best practices and pitfalls
# Supported AI Coding Agents
This skill is compatible with the SKILL.md standard and works with all major AI coding agents:
Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.