1use cli_boilerplate_automation::{broc::EnvVars, env_vars};
2use std::{
3 collections::HashSet,
4 ops::Deref,
5};
6
7use crate::{
8 SSS, Selection, Selector, action::ActionExt, message::Event, nucleo::{Status, injector::WorkerInjector}, ui::{OverlayUI, PickerUI, PreviewUI, Rect, UI}
9};
10
11#[derive(Default)]
15pub struct State<S: Selection> {
16 pub current: Option<(u32, S)>,
17 pub input: String,
18 pub col: Option<usize>,
19
20 pub(crate) preview_run: String,
21 pub(crate) preview_set: Option<String>,
22 pub iterations: u32,
23 pub preview_show: bool,
24 pub layout: [Rect; 4],
25 pub overlay_index: Option<usize>,
26
27 pub(crate) matcher_running: bool,
28 pub(crate) events: HashSet<Event>,
29}
30
31pub struct MMState<'a, T: SSS, S: Selection> {
32 pub(crate) state: &'a State<S>,
33
34 pub picker_ui: &'a PickerUI<'a, T, S>,
35 pub ui: &'a UI,
36 pub preview_ui: Option<&'a PreviewUI>,
37}
38
39impl<'a, T: SSS, S: Selection> MMState<'a, T, S> {
40 pub fn previewer_area(&self) -> Option<&Rect> {
41 self.preview_ui.map(|ui| &ui.area)
42 }
43
44 pub fn ui_area(&self) -> &Rect {
45 &self.ui.area
46 }
47
48 pub fn current_raw(&self) -> Option<&T> {
49 self.picker_ui.worker.get_nth(self.picker_ui.results.index())
50 }
51 pub fn map_selected_to_vec<U>(&self, mut f: impl FnMut(&S) -> U) -> Vec<U> {
53 if !self.picker_ui.selections.is_empty() {
54 self.picker_ui.selections.map_to_vec(f)
55 } else {
56 self.current.iter().map(|s| f(&s.1)).collect()
57 }
58 }
59
60 pub fn injector(&self) -> WorkerInjector<T> {
61 self.picker_ui.worker.injector()
62 }
63
64 pub fn widths(&self) -> &Vec<u16> {
65 self.picker_ui.results.widths()
66 }
67
68 pub fn status(&self) -> &Status { &self.picker_ui.results.status
70 }
71
72 pub fn selections(&self) -> &Selector<T, S> {
73 &self.picker_ui.selections
74 }
75
76 pub fn make_env_vars(&self) -> EnvVars {
77 env_vars! {
78 "FZF_LINES" => self.ui_area().height.to_string(),
79 "FZF_COLUMNS" => self.ui_area().width.to_string(),
80 "FZF_TOTAL_COUNT" => self.status().item_count.to_string(),
81 "FZF_MATCH_COUNT" => self.status().matched_count.to_string(),
82 "FZF_SELECT_COUNT" => self.selections().len().to_string(),
83 "FZF_POS" => self.current.as_ref().map_or("".to_string(), |x| format!("{}", x.0)),
84 "FZF_QUERY" => self.input.clone(),
85 }
86 }
87
88 }
92
93impl<S: Selection> State<S> {
94 pub fn new() -> Self {
95 Self {
97 current: None,
98
99 preview_run: String::new(),
100 preview_set: None,
101 preview_show: false,
102 layout: [Rect::default(); 4],
103 overlay_index: None,
104 col: None,
105
106 input: String::new(),
107 iterations: 0,
108 matcher_running: true,
109
110 events: HashSet::new(),
111 }
112 }
113 pub(crate) fn take_current(&mut self) -> Option<S> {
115 self.current.take().map(|x| x.1)
116 }
117
118 pub fn preview_payload(&self) -> &String {
119 &self.preview_run
120 }
121
122 pub fn contains(&self, event: &Event) -> bool {
123 self.events.contains(event)
124 }
125
126 pub fn insert(&mut self, event: Event) -> bool {
127 self.events.insert(event)
128 }
129
130 pub fn preview_set_payload(&self) -> &Option<String> {
131 &self.preview_set
132 }
133
134 pub(crate) fn update_current<T: SSS>(
136 &mut self,
137 picker_ui: &PickerUI<T, S>,
138 ) {
140 let current_raw = picker_ui.worker.get_nth(picker_ui.results.index());
141 let new_current = current_raw.map(picker_ui.selections.identifier);
142
143 let changed = self.current.as_ref().map(|x| x.0) != new_current.as_ref().map(|x| x.0);
144 if changed {
145 self.current = new_current;
146 self.insert(Event::CursorChange);
147 }
148 }
149
150 pub(crate) fn update_input(&mut self, new_input: &str) -> bool {
151 let changed = self.input != new_input;
152 if changed {
153 self.input = new_input.to_string();
154 self.insert(Event::QueryChange);
155 }
156 changed
157 }
158
159 pub(crate) fn update_preview(&mut self, context: &str) -> bool {
160 let changed = self.preview_run != context;
161 if changed {
162 self.preview_run = context.into();
163 self.insert(Event::PreviewChange);
164 }
165 changed
166 }
167
168 pub(crate) fn update_preview_set(&mut self, context: String) -> bool {
169 let next = Some(context);
170 let changed = self.preview_set != next;
171 if changed {
172 self.preview_set = next;
173 self.insert(Event::PreviewSet);
174 }
175 changed
176 }
177
178 pub(crate) fn update_preview_unset(&mut self) {
179 self.preview_set = None;
180 self.insert(Event::PreviewSet);
181 }
182
183 pub(crate) fn update_layout(&mut self, context: [Rect; 4]) -> bool {
184 let changed = self.layout != context;
185 if changed {
186 self.insert(Event::Resize);
187 self.layout = context;
188 }
189 changed
190 }
191
192 pub(crate) fn update_preview_ui(&mut self, preview_ui: &PreviewUI) -> bool {
194 let next = preview_ui.is_show();
195 let changed = self.preview_show != next;
196 self.preview_show = next;
197 if changed && next {
199 self.insert(Event::PreviewChange);
200 };
201 changed
202 }
203
204
205 pub(crate) fn update<'a, T: SSS, A: ActionExt>(&'a mut self, picker_ui: &'a PickerUI<T, S>, overlay_ui: &'a Option<OverlayUI<A>>){
206 if self.iterations == 0 {
207 self.insert(Event::Start);
208 }
209 self.iterations += 1;
210
211 self.update_input(&picker_ui.input.input);
212 self.col = picker_ui.results.col();
213
214 if self.matcher_running != picker_ui.results.status.running {
215 if !picker_ui.results.status.running {
216 self.insert(Event::Synced);
217 }
218 self.matcher_running = picker_ui.results.status.running;
219 };
220
221 if let Some(o) = overlay_ui {
222 if self.overlay_index != o.index() {
223 self.insert(Event::OverlayChange);
224 self.overlay_index = o.index()
225 }
226 self.overlay_index = o.index()
227 }
228 self.update_current(picker_ui);
229 }
230
231
232
233 pub(crate) fn dispatcher<'a, T: SSS>(&'a self, ui: &'a UI, picker_ui: &'a PickerUI<T, S>, preview_ui: Option<&'a PreviewUI>) -> MMState<'a, T, S> {
235 MMState {
236 state: self,
237 picker_ui,
238 ui,
239 preview_ui,
240 }
241 }
242
243 fn reset(&mut self) {
244 }
246
247 pub(crate) fn events(
248 &mut self,
249 ) -> HashSet<Event> {
250 self.reset();
251 std::mem::take(&mut self.events) }
254}
255
256impl<S: Selection> std::fmt::Debug for State<S> {
258 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
259 f.debug_struct("State")
260 .field("input", &self.input)
261 .field("preview_payload", &self.preview_run)
262 .field("iterations", &self.iterations)
263 .field("preview_show", &self.preview_show)
264 .field("layout", &self.layout)
265 .field("events", &self.events)
266 .finish_non_exhaustive()
267 }
268}
269
270impl<'a, T: SSS, S: Selection> Deref for MMState<'a, T, S> {
271 type Target = State<S>;
272
273 fn deref(&self) -> &Self::Target {
274 self.state
275 }
276}