Skip to main content

rmux_core/hooks/
rules.rs

1use rmux_proto::{HookName, RmuxError, ScopeSelector};
2
3use super::types::{HookClass, HookGlobalRoot};
4
5/// Validates that a hook may be stored at the requested scope.
6pub fn validate_hook_scope(hook: HookName, scope: &ScopeSelector) -> Result<(), RmuxError> {
7    let is_valid = matches!(
8        (hook_class(hook), scope),
9        (
10            HookClass::Session,
11            ScopeSelector::Global | ScopeSelector::Session(_)
12        ) | (
13            HookClass::Window,
14            ScopeSelector::Global | ScopeSelector::Window(_)
15        ) | (
16            HookClass::Pane,
17            ScopeSelector::Global | ScopeSelector::Window(_) | ScopeSelector::Pane(_),
18        )
19    );
20
21    if is_valid {
22        Ok(())
23    } else {
24        Err(RmuxError::Server(format!(
25            "{} does not support {} scope",
26            hook_name(hook),
27            scope_name(scope)
28        )))
29    }
30}
31
32/// Validates that rmux ships the requested hook and that it may be stored at
33/// the requested scope.
34pub fn validate_hook_registration(hook: HookName, scope: &ScopeSelector) -> Result<(), RmuxError> {
35    if !hook_is_supported_for_registration(hook) {
36        return Err(RmuxError::Message(format!(
37            "{} is not supported: rmux does not dispatch this hook",
38            hook_name(hook)
39        )));
40    }
41
42    validate_hook_scope(hook, scope)
43}
44
45pub(super) const fn hook_inventory() -> [HookName; 70] {
46    [
47        HookName::AfterBindKey,
48        HookName::AfterCapturePane,
49        HookName::AfterCopyMode,
50        HookName::AfterDisplayMessage,
51        HookName::AfterDisplayPanes,
52        HookName::AfterKillPane,
53        HookName::AfterListBuffers,
54        HookName::AfterListClients,
55        HookName::AfterListKeys,
56        HookName::AfterListPanes,
57        HookName::AfterListSessions,
58        HookName::AfterListWindows,
59        HookName::AfterLoadBuffer,
60        HookName::AfterLockServer,
61        HookName::AfterNewSession,
62        HookName::AfterNewWindow,
63        HookName::AfterPasteBuffer,
64        HookName::AfterPipePane,
65        HookName::AfterQueue,
66        HookName::AfterRefreshClient,
67        HookName::AfterRenameSession,
68        HookName::AfterRenameWindow,
69        HookName::AfterResizePane,
70        HookName::AfterResizeWindow,
71        HookName::AfterSaveBuffer,
72        HookName::AfterSelectLayout,
73        HookName::AfterSelectPane,
74        HookName::AfterSelectWindow,
75        HookName::AfterSendKeys,
76        HookName::AfterSetBuffer,
77        HookName::AfterSetEnvironment,
78        HookName::AfterSetHook,
79        HookName::AfterSetOption,
80        HookName::AfterShowEnvironment,
81        HookName::AfterShowMessages,
82        HookName::AfterShowOptions,
83        HookName::AfterSplitWindow,
84        HookName::AfterUnbindKey,
85        HookName::AlertActivity,
86        HookName::AlertBell,
87        HookName::AlertSilence,
88        HookName::ClientActive,
89        HookName::ClientAttached,
90        HookName::ClientDetached,
91        HookName::ClientFocusIn,
92        HookName::ClientFocusOut,
93        HookName::ClientResized,
94        HookName::ClientSessionChanged,
95        HookName::ClientLightTheme,
96        HookName::ClientDarkTheme,
97        HookName::CommandError,
98        HookName::PaneDied,
99        HookName::PaneExited,
100        HookName::PaneFocusIn,
101        HookName::PaneFocusOut,
102        HookName::PaneModeChanged,
103        HookName::PaneSetClipboard,
104        HookName::PaneTitleChanged,
105        HookName::SessionClosed,
106        HookName::SessionCreated,
107        HookName::SessionRenamed,
108        HookName::SessionWindowChanged,
109        HookName::WindowLayoutChanged,
110        HookName::WindowLinked,
111        HookName::WindowPaneChanged,
112        HookName::WindowRenamed,
113        HookName::WindowResized,
114        HookName::WindowUnlinked,
115        HookName::PasteBufferChanged,
116        HookName::PasteBufferDeleted,
117    ]
118}
119
120pub(super) const fn hook_class(hook: HookName) -> HookClass {
121    match hook {
122        HookName::WindowLayoutChanged
123        | HookName::WindowPaneChanged
124        | HookName::WindowRenamed
125        | HookName::WindowResized => HookClass::Window,
126        HookName::PaneDied
127        | HookName::PaneExited
128        | HookName::PaneFocusIn
129        | HookName::PaneFocusOut
130        | HookName::PaneModeChanged
131        | HookName::PaneSetClipboard
132        | HookName::PaneTitleChanged => HookClass::Pane,
133        HookName::AfterBindKey
134        | HookName::AfterCapturePane
135        | HookName::AfterCopyMode
136        | HookName::AfterDisplayMessage
137        | HookName::AfterDisplayPanes
138        | HookName::AfterKillPane
139        | HookName::AfterListBuffers
140        | HookName::AfterListClients
141        | HookName::AfterListKeys
142        | HookName::AfterListPanes
143        | HookName::AfterListSessions
144        | HookName::AfterListWindows
145        | HookName::AfterLoadBuffer
146        | HookName::AfterLockServer
147        | HookName::AfterNewSession
148        | HookName::AfterNewWindow
149        | HookName::AfterPasteBuffer
150        | HookName::AfterPipePane
151        | HookName::AfterQueue
152        | HookName::AfterRefreshClient
153        | HookName::AfterRenameSession
154        | HookName::AfterRenameWindow
155        | HookName::AfterResizePane
156        | HookName::AfterResizeWindow
157        | HookName::AfterSaveBuffer
158        | HookName::AfterSelectLayout
159        | HookName::AfterSelectPane
160        | HookName::AfterSelectWindow
161        | HookName::AfterSendKeys
162        | HookName::AfterSetBuffer
163        | HookName::AfterSetEnvironment
164        | HookName::AfterSetHook
165        | HookName::AfterSetOption
166        | HookName::AfterShowEnvironment
167        | HookName::AfterShowMessages
168        | HookName::AfterShowOptions
169        | HookName::AfterSplitWindow
170        | HookName::AfterUnbindKey
171        | HookName::AlertActivity
172        | HookName::AlertBell
173        | HookName::AlertSilence
174        | HookName::ClientActive
175        | HookName::ClientAttached
176        | HookName::ClientDetached
177        | HookName::ClientFocusIn
178        | HookName::ClientFocusOut
179        | HookName::ClientResized
180        | HookName::ClientSessionChanged
181        | HookName::ClientLightTheme
182        | HookName::ClientDarkTheme
183        | HookName::CommandError
184        | HookName::SessionCreated
185        | HookName::SessionClosed
186        | HookName::SessionRenamed
187        | HookName::SessionWindowChanged
188        | HookName::WindowLinked
189        | HookName::WindowUnlinked
190        | HookName::PasteBufferChanged
191        | HookName::PasteBufferDeleted => HookClass::Session,
192    }
193}
194
195pub(super) const fn root_for_hook(hook: HookName) -> HookGlobalRoot {
196    match hook_class(hook) {
197        HookClass::Session => HookGlobalRoot::Session,
198        HookClass::Window | HookClass::Pane => HookGlobalRoot::Window,
199    }
200}
201
202pub(super) const fn hook_is_visible_in_show_hooks(hook: HookName) -> bool {
203    !matches!(
204        hook,
205        HookName::ClientLightTheme
206            | HookName::ClientDarkTheme
207            | HookName::CommandError
208            | HookName::PasteBufferChanged
209            | HookName::PasteBufferDeleted
210    )
211}
212
213const fn hook_is_supported_for_registration(hook: HookName) -> bool {
214    !matches!(
215        hook,
216        HookName::ClientLightTheme
217            | HookName::ClientDarkTheme
218            | HookName::CommandError
219            | HookName::PaneTitleChanged
220            | HookName::WindowResized
221            | HookName::PasteBufferChanged
222            | HookName::PasteBufferDeleted
223    )
224}
225
226const fn hook_name(hook: HookName) -> &'static str {
227    hook.as_str()
228}
229
230const fn scope_name(scope: &ScopeSelector) -> &'static str {
231    match scope {
232        ScopeSelector::Global => "global",
233        ScopeSelector::Session(_) => "session",
234        ScopeSelector::Window(_) => "window",
235        ScopeSelector::Pane(_) => "pane",
236    }
237}