rmux_core/hooks/
deferred.rs1use rmux_proto::{HookName, ScopeSelector, WindowTarget};
2
3use super::rules::{hook_class, root_for_hook};
4use super::types::HookClass;
5use super::{HookDispatch, HookStore};
6
7impl HookStore {
8 pub fn dispatch_deferred_from(
15 &mut self,
16 snapshot: &mut Self,
17 scope: &ScopeSelector,
18 hook: HookName,
19 ) -> Vec<HookDispatch> {
20 let (resolved_scope, one_shot_indices) = snapshot.resolved_dispatch_binding(scope, hook);
21 let dispatches = snapshot.dispatch(scope, hook);
22 if dispatches.is_empty() {
23 return dispatches;
24 }
25 for index in one_shot_indices {
26 let _ = self.unset(resolved_scope.clone(), hook, Some(index));
27 }
28 dispatches
29 }
30
31 pub(super) fn resolved_dispatch_binding(
32 &self,
33 scope: &ScopeSelector,
34 hook: HookName,
35 ) -> (ScopeSelector, Vec<u32>) {
36 let local_scope = match hook_class(hook) {
37 HookClass::Session => match scope {
38 ScopeSelector::Session(session_name) => {
39 Some(ScopeSelector::Session(session_name.clone()))
40 }
41 ScopeSelector::Window(target) => {
42 Some(ScopeSelector::Session(target.session_name().clone()))
43 }
44 ScopeSelector::Pane(target) => {
45 Some(ScopeSelector::Session(target.session_name().clone()))
46 }
47 ScopeSelector::Global => None,
48 },
49 HookClass::Window => match scope {
50 ScopeSelector::Window(target) => Some(ScopeSelector::Window(target.clone())),
51 ScopeSelector::Pane(target) => Some(ScopeSelector::Window(
52 WindowTarget::with_window(target.session_name().clone(), target.window_index()),
53 )),
54 ScopeSelector::Global | ScopeSelector::Session(_) => None,
55 },
56 HookClass::Pane => match scope {
57 ScopeSelector::Pane(target) => Some(ScopeSelector::Pane(target.clone())),
58 ScopeSelector::Global | ScopeSelector::Session(_) | ScopeSelector::Window(_) => {
59 None
60 }
61 },
62 };
63
64 if let Some(local_scope) = local_scope {
65 let indices = self.one_shot_indices_for_exact_scope(&local_scope, hook);
66 let has_binding = match &local_scope {
67 ScopeSelector::Session(session_name) => self
68 .sessions
69 .get(session_name)
70 .is_some_and(|bindings| bindings.command(hook).is_some()),
71 ScopeSelector::Window(target) => self.window_command(target, hook).is_some(),
72 ScopeSelector::Pane(target) => self.pane_command(target, hook).is_some(),
73 ScopeSelector::Global => false,
74 };
75 if has_binding {
76 return (local_scope, indices);
77 }
78 }
79
80 let global_scope = ScopeSelector::Global;
81 let indices = self.one_shot_indices_for_exact_scope(&global_scope, hook);
82 (global_scope, indices)
83 }
84
85 fn one_shot_indices_for_exact_scope(&self, scope: &ScopeSelector, hook: HookName) -> Vec<u32> {
86 match scope {
87 ScopeSelector::Global => self
88 .global_bindings(root_for_hook(hook))
89 .one_shot_indices(hook),
90 ScopeSelector::Session(session_name) => self
91 .sessions
92 .get(session_name)
93 .map_or_else(Vec::new, |bindings| bindings.one_shot_indices(hook)),
94 ScopeSelector::Window(target) => self
95 .windows
96 .get(target)
97 .or_else(|| {
98 self.window_aliases
99 .get(target)
100 .and_then(|window_id| self.windows_by_id.get(window_id))
101 })
102 .map_or_else(Vec::new, |bindings| bindings.one_shot_indices(hook)),
103 ScopeSelector::Pane(target) => self
104 .panes
105 .get(target)
106 .or_else(|| {
107 self.pane_aliases
108 .get(target)
109 .and_then(|(_, pane_id)| self.panes_by_id.get(pane_id))
110 })
111 .map_or_else(Vec::new, |bindings| bindings.one_shot_indices(hook)),
112 }
113 }
114}