matchmaker/render/
state_effects.rs

1use super::State;
2use crate::{
3    MAX_EFFECTS, SSS, Selection, message::Event, ui::{PickerUI, PreviewUI, UI}
4};
5
6use arrayvec::ArrayVec;
7use ratatui::text::{Span, Text};
8
9#[derive(Debug, Clone)]
10pub enum Effect {
11    ClearPreviewSet,
12    Header(Text<'static>),
13    Footer(Text<'static>),
14    ClearFooter,
15    ClearHeader,
16    ClearSelections,
17    RevalidateSelectons,
18    /// Reload the nucleo matcher
19    /// Note that the reload interrupt handler is NOT triggered if this is produced from a dynamic handler
20    Reload,
21
22    Prompt(Span<'static>),
23    Input((String, u16)),
24    RestoreInputPromptMarker,
25
26    DisableCursor(bool),
27    SetIndex(u32),
28    TrySync,
29}
30#[derive(Debug, Default)]
31pub struct Effects(ArrayVec<Effect, MAX_EFFECTS>);
32
33#[macro_export]
34macro_rules! efx {
35    ( $( $x:expr ),* $(,)? ) => {
36        {
37            [$($x),*].into_iter().collect::<$crate::render::Effects>()
38        }
39    };
40}
41pub use crate::acs;
42
43
44impl<S: Selection> State<S> {
45    // note: apparently its important that this is a method on state to satisfy borrow checker
46    pub fn apply_effects<T: SSS>(
47        &mut self,
48        effects: Effects,
49        _ui: &mut UI,
50        picker_ui: &mut PickerUI<T, S>,
51        _preview_ui: &mut Option<PreviewUI>,
52    ) {
53        if !effects.is_empty() {
54            log::debug!("{effects:?}");
55        }
56        for effect in effects {
57            match effect {
58                // ----- preview -------
59                Effect::ClearPreviewSet => {
60                    self.preview_set = None;
61                }
62
63                // ----- displays -------
64                Effect::Header(text) => {
65                    picker_ui.header.set(text);
66                }
67                Effect::Footer(text) => {
68                    picker_ui.footer.set(text);
69                }
70                Effect::ClearHeader => {
71                    picker_ui.header.show = false;
72                }
73                Effect::ClearFooter => {
74                    picker_ui.footer.show = false;
75                }
76
77                // ----- input -------
78                Effect::Input((input, cursor)) => {
79                    picker_ui.input.set(input, cursor);
80                }
81                Effect::Prompt(prompt) => {
82                    picker_ui.input.prompt = prompt;
83                }
84                Effect::RestoreInputPromptMarker => {
85                    picker_ui.input.prompt = Span::from(picker_ui.input.config.prompt.clone());
86                }
87
88                // ----- results -------
89                Effect::DisableCursor(disabled) => {
90                    picker_ui.results.cursor_disabled = disabled;
91                }
92                Effect::SetIndex(index) => {
93                    log::info!("{:?}", picker_ui.results);
94                    picker_ui.results.cursor_jump(index);
95                }
96
97                // -------- selections ---------
98                Effect::ClearSelections => {
99                    picker_ui.selections.clear();
100                }
101                Effect::RevalidateSelectons => {
102                    picker_ui.selections.revalidate();
103                }
104
105                // ---------- misc -------------
106                // this may not be the best place for these? We're trying to trigger a handler
107                Effect::Reload => {
108                    // the reload handler is not triggered when a handler produces this effect
109                    picker_ui.worker.restart(false);
110                }
111                Effect::TrySync => {
112                    if !picker_ui.results.status.running {
113                        self.insert(Event::Synced);
114                    }
115                }
116
117            }
118        }
119    }
120}
121
122// ----------------------------------------------------
123
124impl PartialEq for Effect {
125    fn eq(&self, other: &Self) -> bool {
126        std::mem::discriminant(self) == std::mem::discriminant(other)
127    }
128}
129
130impl Eq for Effect {}
131
132impl Effects {
133    pub fn new() -> Self {
134        Self(ArrayVec::new())
135    }
136
137    /// Insert only if not already present
138    pub fn insert(&mut self, effect: Effect) -> bool {
139        if self.0.contains(&effect) {
140            false
141        } else {
142            self.0.push(effect);
143            true
144        }
145    }
146
147    pub fn len(&self) -> usize {
148        self.0.len()
149    }
150
151    pub fn is_empty(&self) -> bool {
152        self.0.is_empty()
153    }
154
155    pub fn append(&mut self, other: Self) {
156        for effect in other {
157            self.insert(effect);
158        }
159    }
160}
161
162impl IntoIterator for Effects {
163    type Item = Effect;
164    type IntoIter = arrayvec::IntoIter<Effect, 12>;
165
166    fn into_iter(self) -> Self::IntoIter {
167        self.0.into_iter()
168    }
169}
170
171impl FromIterator<Effect> for Effects {
172    fn from_iter<I: IntoIterator<Item = Effect>>(iter: I) -> Self {
173        let mut effects = Effects::new();
174        for e in iter {
175            effects.insert(e);
176        }
177        effects
178    }
179}