@@ -61,15 +61,33 @@ pub fn run(
6161 }
6262 Event :: Resize ( cols, rows) => {
6363 renderer. update_size ( cols, rows) ;
64- overlays:: draw ( renderer, app_state) ;
64+ redraw_current_view (
65+ renderer,
66+ app_state,
67+ delete_paths,
68+ find_filter,
69+ ripgrep_filter,
70+ * favorites_active,
71+ favorites_items,
72+ * favorites_selected,
73+ ) ;
6574 }
6675 _ => { }
6776 }
6877 }
6978 handle_async_messages ( receiver, app_state, renderer) ;
70- app_state
71- . active_panel_mut ( )
72- . clear_notification_if_expired ( 3000 ) ;
79+ if clear_expired_notification ( app_state, 3000 ) {
80+ redraw_current_view (
81+ renderer,
82+ app_state,
83+ delete_paths,
84+ find_filter,
85+ ripgrep_filter,
86+ * favorites_active,
87+ favorites_items,
88+ * favorites_selected,
89+ ) ;
90+ }
7391 }
7492}
7593
@@ -91,13 +109,24 @@ fn route_input(
91109 favorites_selected : & mut usize ,
92110 two_pane : bool ,
93111) {
94- if handle_help ( event, app_state, renderer) {
112+ if let Some ( needs_redraw) = handle_help ( event, app_state) {
113+ if needs_redraw {
114+ redraw_current_view (
115+ renderer,
116+ app_state,
117+ delete_paths,
118+ find_filter,
119+ ripgrep_filter,
120+ * favorites_active,
121+ favorites_items,
122+ * favorites_selected,
123+ ) ;
124+ }
95125 return ;
96126 }
97- if handle_modal_overlays (
127+ if let Some ( needs_redraw ) = handle_modal_overlays (
98128 event,
99129 app_state,
100- renderer,
101130 fs_adapter,
102131 sender,
103132 delete_paths,
@@ -107,17 +136,37 @@ fn route_input(
107136 favorites_items,
108137 favorites_selected,
109138 ) {
139+ if needs_redraw {
140+ redraw_current_view (
141+ renderer,
142+ app_state,
143+ delete_paths,
144+ find_filter,
145+ ripgrep_filter,
146+ * favorites_active,
147+ favorites_items,
148+ * favorites_selected,
149+ ) ;
150+ }
110151 return ;
111152 }
112153 if two_pane && event. code == KeyCode :: Tab {
113154 app_state. switch_pane ( ) ;
114- overlays:: draw ( renderer, app_state) ;
155+ redraw_current_view (
156+ renderer,
157+ app_state,
158+ delete_paths,
159+ find_filter,
160+ ripgrep_filter,
161+ * favorites_active,
162+ favorites_items,
163+ * favorites_selected,
164+ ) ;
115165 return ;
116166 }
117- if shortcuts:: handle (
167+ if let Some ( needs_redraw ) = shortcuts:: handle (
118168 event,
119169 app_state,
120- renderer,
121170 vscode_adapter,
122171 delete_paths,
123172 find_filter,
@@ -126,41 +175,61 @@ fn route_input(
126175 favorites_items,
127176 favorites_selected,
128177 ) {
178+ if needs_redraw {
179+ redraw_current_view (
180+ renderer,
181+ app_state,
182+ delete_paths,
183+ find_filter,
184+ ripgrep_filter,
185+ * favorites_active,
186+ favorites_items,
187+ * favorites_selected,
188+ ) ;
189+ }
129190 return ;
130191 }
131- handle_mode_input (
192+ if handle_mode_input (
132193 event,
133194 app_state,
134195 renderer,
135196 fs_adapter,
136197 open_adapter,
137198 clipboard_adapter,
138199 sender,
139- ) ;
140- overlays:: draw ( renderer, app_state) ;
200+ ) {
201+ redraw_current_view (
202+ renderer,
203+ app_state,
204+ delete_paths,
205+ find_filter,
206+ ripgrep_filter,
207+ * favorites_active,
208+ favorites_items,
209+ * favorites_selected,
210+ ) ;
211+ }
141212}
142213
143- fn handle_help ( event : KeyEvent , app_state : & mut AppState , renderer : & mut TerminalRenderer ) -> bool {
214+ fn handle_help ( event : KeyEvent , app_state : & mut AppState ) -> Option < bool > {
144215 if app_state. show_help {
145216 if matches ! ( event. code, KeyCode :: F ( 1 ) | KeyCode :: Esc ) {
146217 app_state. show_help = false ;
218+ return Some ( true ) ;
147219 }
148- overlays:: draw ( renderer, app_state) ;
149- return true ;
220+ return Some ( false ) ;
150221 }
151222 if event. code == KeyCode :: F ( 1 ) {
152223 app_state. show_help = !app_state. show_help ;
153- overlays:: draw ( renderer, app_state) ;
154- return true ;
224+ return Some ( true ) ;
155225 }
156- false
226+ None
157227}
158228
159229#[ allow( clippy:: too_many_arguments) ]
160230fn handle_modal_overlays (
161231 event : KeyEvent ,
162232 app_state : & mut AppState ,
163- renderer : & mut TerminalRenderer ,
164233 fs_adapter : & StdFileSystem ,
165234 sender : & Sender < Message > ,
166235 delete_paths : & mut Option < Vec < PathBuf > > ,
@@ -169,41 +238,43 @@ fn handle_modal_overlays(
169238 favorites_active : & mut bool ,
170239 favorites_items : & [ String ] ,
171240 favorites_selected : & mut usize ,
172- ) -> bool {
241+ ) -> Option < bool > {
173242 if * favorites_active {
174- handle_favorites_input (
243+ return Some ( handle_favorites_input (
175244 event,
176245 favorites_active,
177246 favorites_items,
178247 favorites_selected,
179248 fs_adapter,
180249 app_state,
181- ) ;
182- overlays:: draw_with_favorites (
183- renderer,
184- app_state,
185- * favorites_active,
186- favorites_items,
187- * favorites_selected,
188- ) ;
189- return true ;
250+ ) ) ;
190251 }
191252 if delete_paths. is_some ( ) {
192- handle_delete_confirmation ( event, delete_paths, fs_adapter, app_state) ;
193- overlays:: draw_with_delete ( renderer, app_state, delete_paths. as_ref ( ) ) ;
194- return true ;
253+ return Some ( handle_delete_confirmation (
254+ event,
255+ delete_paths,
256+ fs_adapter,
257+ app_state,
258+ ) ) ;
195259 }
196260 if find_filter. is_some ( ) {
197- handle_find_input ( event, find_filter, sender, fs_adapter, app_state) ;
198- overlays:: draw_with_find ( renderer, app_state, find_filter. as_ref ( ) ) ;
199- return true ;
261+ return Some ( handle_find_input (
262+ event,
263+ find_filter,
264+ sender,
265+ fs_adapter,
266+ app_state,
267+ ) ) ;
200268 }
201269 if ripgrep_filter. is_some ( ) {
202- handle_ripgrep_input ( event, ripgrep_filter, fs_adapter, app_state) ;
203- overlays:: draw_with_ripgrep ( renderer, app_state, ripgrep_filter. as_ref ( ) ) ;
204- return true ;
270+ return Some ( handle_ripgrep_input (
271+ event,
272+ ripgrep_filter,
273+ fs_adapter,
274+ app_state,
275+ ) ) ;
205276 }
206- false
277+ None
207278}
208279
209280fn handle_mode_input (
@@ -214,7 +285,7 @@ fn handle_mode_input(
214285 open_adapter : & SystemOpenAdapter ,
215286 clipboard_adapter : & mut SystemClipboard ,
216287 sender : & Sender < Message > ,
217- ) {
288+ ) -> bool {
218289 let panel = app_state. active_panel_mut ( ) ;
219290 match & panel. mode {
220291 PanelMode :: Normal => handle_normal_mode (
@@ -239,6 +310,37 @@ fn handle_mode_input(
239310 }
240311}
241312
313+ #[ allow( clippy:: too_many_arguments) ]
314+ fn redraw_current_view (
315+ renderer : & mut TerminalRenderer ,
316+ app_state : & AppState ,
317+ delete_paths : & Option < Vec < PathBuf > > ,
318+ find_filter : & Option < String > ,
319+ ripgrep_filter : & Option < String > ,
320+ favorites_active : bool ,
321+ favorites_items : & [ String ] ,
322+ favorites_selected : usize ,
323+ ) {
324+ if favorites_active {
325+ overlays:: draw_with_favorites ( renderer, app_state, true , favorites_items, favorites_selected) ;
326+ } else if delete_paths. is_some ( ) {
327+ overlays:: draw_with_delete ( renderer, app_state, delete_paths. as_ref ( ) ) ;
328+ } else if find_filter. is_some ( ) {
329+ overlays:: draw_with_find ( renderer, app_state, find_filter. as_ref ( ) ) ;
330+ } else if ripgrep_filter. is_some ( ) {
331+ overlays:: draw_with_ripgrep ( renderer, app_state, ripgrep_filter. as_ref ( ) ) ;
332+ } else {
333+ overlays:: draw ( renderer, app_state) ;
334+ }
335+ }
336+
337+ fn clear_expired_notification ( app_state : & mut AppState , timeout_ms : u64 ) -> bool {
338+ let panel = app_state. active_panel_mut ( ) ;
339+ let had_notification = panel. notification . is_some ( ) ;
340+ panel. clear_notification_if_expired ( timeout_ms) ;
341+ had_notification && panel. notification . is_none ( )
342+ }
343+
242344fn handle_async_messages (
243345 receiver : & Receiver < Message > ,
244346 app_state : & mut AppState ,
@@ -270,3 +372,36 @@ fn handle_async_messages(
270372 }
271373 }
272374}
375+
376+ #[ cfg( test) ]
377+ mod tests {
378+ use super :: * ;
379+ use crossterm:: event:: KeyEvent ;
380+
381+ #[ test]
382+ fn help_overlay_ignores_unmapped_keys_without_redraw ( ) {
383+ let mut state = AppState :: new ( false ) ;
384+ state. show_help = true ;
385+
386+ assert_eq ! (
387+ handle_help( KeyEvent :: from( KeyCode :: Char ( 'x' ) ) , & mut state) ,
388+ Some ( false )
389+ ) ;
390+ }
391+
392+ #[ test]
393+ fn help_toggle_requests_redraw ( ) {
394+ let mut state = AppState :: new ( false ) ;
395+
396+ assert_eq ! ( handle_help( KeyEvent :: from( KeyCode :: F ( 1 ) ) , & mut state) , Some ( true ) ) ;
397+ }
398+
399+ #[ test]
400+ fn clearing_expired_notification_marks_dirty ( ) {
401+ let mut state = AppState :: new ( false ) ;
402+ state. active_panel_mut ( ) . set_notification ( "Test" . to_string ( ) ) ;
403+ std:: thread:: sleep ( std:: time:: Duration :: from_millis ( 10 ) ) ;
404+
405+ assert ! ( clear_expired_notification( & mut state, 1 ) ) ;
406+ }
407+ }
0 commit comments