Claude-skill-registry gpui-event
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.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/gpui-event" ~/.claude/skills/majiayu000-claude-skill-registry-gpui-event && rm -rf "$T"
manifest:
skills/data/gpui-event/SKILL.mdsource content
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