Skip to main content

rmux_core/
lifecycle.rs

1use rmux_proto::{HookName, PaneTarget, ScopeSelector, SessionName, Target, WindowTarget};
2
3/// A typed server lifecycle event that may dispatch a registered hook.
4#[derive(Debug, Clone, PartialEq, Eq)]
5pub enum LifecycleEvent {
6    /// A client attached to a session.
7    ClientAttached {
8        /// The session associated with the event.
9        session_name: SessionName,
10        /// The best available rmux client identifier.
11        client_name: Option<String>,
12    },
13    /// A client detached from a session.
14    ClientDetached {
15        /// The session associated with the event.
16        session_name: SessionName,
17        /// The best available rmux client identifier.
18        client_name: Option<String>,
19    },
20    /// A client switched to another session.
21    ClientSessionChanged {
22        /// The session associated with the event.
23        session_name: SessionName,
24        /// The best available rmux client identifier.
25        client_name: Option<String>,
26    },
27    /// A session was created.
28    SessionCreated {
29        /// The session associated with the event.
30        session_name: SessionName,
31    },
32    /// A session was closed.
33    SessionClosed {
34        /// The session associated with the event.
35        session_name: SessionName,
36        /// The removed session ID captured at notification time, when known.
37        session_id: Option<u32>,
38    },
39    /// A session was renamed.
40    SessionRenamed {
41        /// The session associated with the event.
42        session_name: SessionName,
43    },
44    /// A session's active window changed.
45    SessionWindowChanged {
46        /// The session associated with the event.
47        session_name: SessionName,
48    },
49    /// A window was linked into a session.
50    WindowLinked {
51        /// The session associated with the event.
52        session_name: SessionName,
53        /// The linked window, when it is known at the call site.
54        target: Option<WindowTarget>,
55    },
56    /// A window was unlinked from a session.
57    WindowUnlinked {
58        /// The session associated with the event.
59        session_name: SessionName,
60        /// The unlinked window, when it is known at the call site.
61        target: Option<WindowTarget>,
62        /// The removed window ID captured at notification time, when known.
63        window_id: Option<u32>,
64        /// The removed window name captured at notification time, when known.
65        window_name: Option<String>,
66    },
67    /// A window was renamed.
68    WindowRenamed {
69        /// The targeted window.
70        target: WindowTarget,
71    },
72    /// A window layout changed.
73    WindowLayoutChanged {
74        /// The targeted window.
75        target: WindowTarget,
76    },
77    /// A window's active pane changed.
78    WindowPaneChanged {
79        /// The targeted window.
80        target: WindowTarget,
81    },
82    /// A bell alert fired for a window.
83    AlertBell {
84        /// The targeted window.
85        target: WindowTarget,
86    },
87    /// An activity alert fired for a window.
88    AlertActivity {
89        /// The targeted window.
90        target: WindowTarget,
91    },
92    /// A silence alert fired for a window.
93    AlertSilence {
94        /// The targeted window.
95        target: WindowTarget,
96    },
97    /// A pane exited or was removed from service.
98    PaneExited {
99        /// The targeted pane.
100        target: PaneTarget,
101        /// The removed pane ID captured at notification time, when known.
102        pane_id: Option<u32>,
103        /// The removed window ID captured at notification time, when known.
104        window_id: Option<u32>,
105        /// The removed window name captured at notification time, when known.
106        window_name: Option<String>,
107    },
108    /// A pane mode or display overlay state changed.
109    PaneModeChanged {
110        /// The targeted pane.
111        target: PaneTarget,
112    },
113    /// A paste buffer was created or replaced.
114    PasteBufferChanged {
115        /// The affected paste buffer name.
116        buffer_name: String,
117    },
118    /// A paste buffer was deleted or evicted.
119    PasteBufferDeleted {
120        /// The affected paste buffer name.
121        buffer_name: String,
122    },
123    /// A `select-window`-family command completed successfully.
124    AfterSelectWindow {
125        /// The selected window.
126        target: WindowTarget,
127    },
128    /// A `select-pane`-family command completed successfully.
129    AfterSelectPane {
130        /// The selected pane.
131        target: PaneTarget,
132    },
133    /// A `send-keys` command completed successfully.
134    AfterSendKeys {
135        /// The targeted pane.
136        target: PaneTarget,
137    },
138    /// A `set-option` command completed successfully.
139    AfterSetOption {
140        /// The session associated with the option scope, when one exists.
141        session_name: Option<SessionName>,
142    },
143}
144
145impl LifecycleEvent {
146    /// Returns the hook name corresponding to this lifecycle event.
147    #[must_use]
148    pub const fn hook_name(&self) -> HookName {
149        match self {
150            Self::ClientAttached { .. } => HookName::ClientAttached,
151            Self::ClientDetached { .. } => HookName::ClientDetached,
152            Self::ClientSessionChanged { .. } => HookName::ClientSessionChanged,
153            Self::SessionCreated { .. } => HookName::SessionCreated,
154            Self::SessionClosed { .. } => HookName::SessionClosed,
155            Self::SessionRenamed { .. } => HookName::SessionRenamed,
156            Self::SessionWindowChanged { .. } => HookName::SessionWindowChanged,
157            Self::WindowLinked { .. } => HookName::WindowLinked,
158            Self::WindowUnlinked { .. } => HookName::WindowUnlinked,
159            Self::WindowRenamed { .. } => HookName::WindowRenamed,
160            Self::WindowLayoutChanged { .. } => HookName::WindowLayoutChanged,
161            Self::WindowPaneChanged { .. } => HookName::WindowPaneChanged,
162            Self::AlertBell { .. } => HookName::AlertBell,
163            Self::AlertActivity { .. } => HookName::AlertActivity,
164            Self::AlertSilence { .. } => HookName::AlertSilence,
165            Self::PaneExited { .. } => HookName::PaneExited,
166            Self::PaneModeChanged { .. } => HookName::PaneModeChanged,
167            Self::PasteBufferChanged { .. } => HookName::PasteBufferChanged,
168            Self::PasteBufferDeleted { .. } => HookName::PasteBufferDeleted,
169            Self::AfterSelectWindow { .. } => HookName::AfterSelectWindow,
170            Self::AfterSelectPane { .. } => HookName::AfterSelectPane,
171            Self::AfterSendKeys { .. } => HookName::AfterSendKeys,
172            Self::AfterSetOption { .. } => HookName::AfterSetOption,
173        }
174    }
175
176    /// Returns the event scope used for hook resolution.
177    #[must_use]
178    pub fn scope(&self) -> ScopeSelector {
179        match self {
180            Self::ClientAttached { session_name, .. }
181            | Self::ClientDetached { session_name, .. }
182            | Self::ClientSessionChanged { session_name, .. }
183            | Self::SessionCreated { session_name }
184            | Self::SessionClosed { session_name, .. }
185            | Self::SessionRenamed { session_name }
186            | Self::SessionWindowChanged { session_name }
187            | Self::WindowLinked { session_name, .. }
188            | Self::WindowUnlinked { session_name, .. } => {
189                ScopeSelector::Session(session_name.clone())
190            }
191            Self::WindowRenamed { target }
192            | Self::WindowLayoutChanged { target }
193            | Self::WindowPaneChanged { target }
194            | Self::AlertBell { target }
195            | Self::AlertActivity { target }
196            | Self::AlertSilence { target }
197            | Self::AfterSelectWindow { target } => ScopeSelector::Window(target.clone()),
198            Self::PaneExited { target, .. }
199            | Self::PaneModeChanged { target }
200            | Self::AfterSelectPane { target }
201            | Self::AfterSendKeys { target } => ScopeSelector::Pane(target.clone()),
202            Self::PasteBufferChanged { .. } | Self::PasteBufferDeleted { .. } => {
203                ScopeSelector::Global
204            }
205            Self::AfterSetOption {
206                session_name: Some(session_name),
207            } => ScopeSelector::Session(session_name.clone()),
208            Self::AfterSetOption { session_name: None } => ScopeSelector::Global,
209        }
210    }
211
212    /// Returns the session associated with this lifecycle event, when one exists.
213    #[must_use]
214    pub fn session_name(&self) -> Option<&SessionName> {
215        match self {
216            Self::ClientAttached { session_name, .. }
217            | Self::ClientDetached { session_name, .. }
218            | Self::ClientSessionChanged { session_name, .. }
219            | Self::SessionCreated { session_name }
220            | Self::SessionClosed { session_name, .. }
221            | Self::SessionRenamed { session_name }
222            | Self::SessionWindowChanged { session_name }
223            | Self::WindowLinked { session_name, .. }
224            | Self::WindowUnlinked { session_name, .. } => Some(session_name),
225            Self::WindowRenamed { target }
226            | Self::WindowLayoutChanged { target }
227            | Self::WindowPaneChanged { target }
228            | Self::AlertBell { target }
229            | Self::AlertActivity { target }
230            | Self::AlertSilence { target }
231            | Self::AfterSelectWindow { target } => Some(target.session_name()),
232            Self::PaneExited { target, .. }
233            | Self::PaneModeChanged { target }
234            | Self::AfterSelectPane { target }
235            | Self::AfterSendKeys { target } => Some(target.session_name()),
236            Self::AfterSetOption { session_name } => session_name.as_ref(),
237            Self::PasteBufferChanged { .. } | Self::PasteBufferDeleted { .. } => None,
238        }
239    }
240
241    /// Returns the event client identifier when one is available.
242    #[must_use]
243    pub fn client_name(&self) -> Option<&str> {
244        match self {
245            Self::ClientAttached { client_name, .. }
246            | Self::ClientDetached { client_name, .. }
247            | Self::ClientSessionChanged { client_name, .. } => client_name.as_deref(),
248            _ => None,
249        }
250    }
251
252    /// Returns the event window target when one is available.
253    #[must_use]
254    pub fn window_target(&self) -> Option<WindowTarget> {
255        match self {
256            Self::WindowLinked { target, .. } | Self::WindowUnlinked { target, .. } => {
257                target.clone()
258            }
259            Self::WindowRenamed { target }
260            | Self::WindowLayoutChanged { target }
261            | Self::WindowPaneChanged { target }
262            | Self::AlertBell { target }
263            | Self::AlertActivity { target }
264            | Self::AlertSilence { target }
265            | Self::AfterSelectWindow { target } => Some(target.clone()),
266            Self::PaneExited { target, .. }
267            | Self::PaneModeChanged { target }
268            | Self::AfterSelectPane { target }
269            | Self::AfterSendKeys { target } => Some(WindowTarget::with_window(
270                target.session_name().clone(),
271                target.window_index(),
272            )),
273            _ => None,
274        }
275    }
276
277    /// Returns the event pane target when one is available.
278    #[must_use]
279    pub fn pane_target(&self) -> Option<&PaneTarget> {
280        match self {
281            Self::PaneExited { target, .. }
282            | Self::PaneModeChanged { target }
283            | Self::AfterSelectPane { target }
284            | Self::AfterSendKeys { target } => Some(target),
285            _ => None,
286        }
287    }
288
289    /// Returns the event session ID captured at notification time, when one exists.
290    #[must_use]
291    pub const fn session_id(&self) -> Option<u32> {
292        match self {
293            Self::SessionClosed { session_id, .. } => *session_id,
294            _ => None,
295        }
296    }
297
298    /// Returns the event window ID captured at notification time, when one exists.
299    #[must_use]
300    pub const fn window_id(&self) -> Option<u32> {
301        match self {
302            Self::WindowUnlinked { window_id, .. } | Self::PaneExited { window_id, .. } => {
303                *window_id
304            }
305            _ => None,
306        }
307    }
308
309    /// Returns the event window name captured at notification time, when one exists.
310    #[must_use]
311    pub fn window_name_snapshot(&self) -> Option<&str> {
312        match self {
313            Self::WindowUnlinked { window_name, .. } | Self::PaneExited { window_name, .. } => {
314                window_name.as_deref()
315            }
316            _ => None,
317        }
318    }
319
320    /// Returns the event pane ID captured at notification time, when one exists.
321    #[must_use]
322    pub const fn pane_id(&self) -> Option<u32> {
323        match self {
324            Self::PaneExited { pane_id, .. } => *pane_id,
325            _ => None,
326        }
327    }
328
329    /// Returns the paste buffer name when one is available.
330    #[must_use]
331    pub fn buffer_name(&self) -> Option<&str> {
332        match self {
333            Self::PasteBufferChanged { buffer_name } | Self::PasteBufferDeleted { buffer_name } => {
334                Some(buffer_name)
335            }
336            _ => None,
337        }
338    }
339
340    /// Returns the best available current target for hook execution.
341    #[must_use]
342    pub fn current_target(&self) -> Option<Target> {
343        match self {
344            Self::WindowLinked {
345                session_name,
346                target: Some(target),
347            }
348            | Self::WindowUnlinked {
349                session_name,
350                target: Some(target),
351                ..
352            } => Some(Target::Window(WindowTarget::with_window(
353                session_name.clone(),
354                target.window_index(),
355            ))),
356            Self::WindowLinked { session_name, .. }
357            | Self::WindowUnlinked { session_name, .. }
358            | Self::ClientAttached { session_name, .. }
359            | Self::ClientDetached { session_name, .. }
360            | Self::ClientSessionChanged { session_name, .. }
361            | Self::SessionCreated { session_name }
362            | Self::SessionClosed { session_name, .. }
363            | Self::SessionRenamed { session_name }
364            | Self::SessionWindowChanged { session_name } => {
365                Some(Target::Session(session_name.clone()))
366            }
367            Self::WindowRenamed { target }
368            | Self::WindowLayoutChanged { target }
369            | Self::WindowPaneChanged { target }
370            | Self::AlertBell { target }
371            | Self::AlertActivity { target }
372            | Self::AlertSilence { target }
373            | Self::AfterSelectWindow { target } => Some(Target::Window(target.clone())),
374            Self::PaneExited { target, .. }
375            | Self::PaneModeChanged { target }
376            | Self::AfterSelectPane { target }
377            | Self::AfterSendKeys { target } => Some(Target::Pane(target.clone())),
378            Self::AfterSetOption {
379                session_name: Some(session_name),
380            } => Some(Target::Session(session_name.clone())),
381            Self::AfterSetOption { session_name: None }
382            | Self::PasteBufferChanged { .. }
383            | Self::PasteBufferDeleted { .. } => None,
384        }
385    }
386}