1use crate::app::actions::{ActionMode, InputMode};
2use crate::app::{AppState, KeypressResult, NavState};
3use crate::keymap::{FileAction, NavAction};
4use crossterm::event::{KeyCode::*, KeyEvent};
5use std::time::{Duration, Instant};
6
7impl<'a> AppState<'a> {
8 pub fn handle_input_mode(&mut self, key: KeyEvent) -> KeypressResult {
11 let mode = if let ActionMode::Input { mode, .. } = &self.actions().mode() {
12 *mode
13 } else {
14 return KeypressResult::Continue;
15 };
16
17 match key.code {
18 Enter => {
19 match mode {
20 InputMode::NewFile => self.create_file(),
21 InputMode::NewFolder => self.create_folder(),
22 InputMode::Rename => self.rename_entry(),
23 InputMode::Filter => self.apply_filter(),
24 InputMode::ConfirmDelete => self.confirm_delete(),
25 }
26 self.exit_input_mode();
27 KeypressResult::Consumed
28 }
29
30 Esc => {
31 self.exit_input_mode();
32 KeypressResult::Consumed
33 }
34
35 Backspace => {
36 self.actions.input_buffer_mut().pop();
37 if matches!(mode, InputMode::Filter) {
38 self.apply_filter();
39 }
40 KeypressResult::Consumed
41 }
42
43 Char(c) => match mode {
44 InputMode::ConfirmDelete => {
45 self.process_confirm_delete_char(c);
46 KeypressResult::Consumed
47 }
48 InputMode::Filter => {
49 self.actions.input_buffer_mut().push(c);
50 self.apply_filter();
51 KeypressResult::Consumed
52 }
53 InputMode::Rename | InputMode::NewFile | InputMode::NewFolder => {
54 self.actions.input_buffer_mut().push(c);
55 if matches!(mode, InputMode::Filter) {
56 self.apply_filter();
57 }
58 KeypressResult::Consumed
59 }
60 },
61
62 _ => KeypressResult::Consumed,
63 }
64 }
65
66 pub fn process_confirm_delete_char(&mut self, c: char) {
69 if matches!(c, 'y' | 'Y') {
70 self.confirm_delete();
71 }
72 self.exit_input_mode();
73 }
74
75 pub fn exit_input_mode(&mut self) {
78 self.actions.exit_mode();
79 }
80
81 fn create_file(&mut self) {
82 if !self.actions.input_buffer().is_empty() {
83 self.actions
84 .action_create(&mut self.nav, false, &self.worker_tx);
85 }
86 }
87
88 fn create_folder(&mut self) {
89 if !self.actions.input_buffer().is_empty() {
90 self.actions
91 .action_create(&mut self.nav, true, &self.worker_tx);
92 }
93 }
94
95 fn rename_entry(&mut self) {
96 self.actions.action_rename(&mut self.nav, &self.worker_tx);
97 }
98
99 fn apply_filter(&mut self) {
100 self.actions.action_filter(&mut self.nav);
101 }
102
103 fn confirm_delete(&mut self) {
104 self.actions.action_delete(&mut self.nav, &self.worker_tx);
105 }
106
107 pub fn handle_nav_action(&mut self, action: NavAction) -> KeypressResult {
110 match action {
111 NavAction::GoUp => self.move_nav_if_possible(|nav| nav.move_up()),
112 NavAction::GoDown => self.move_nav_if_possible(|nav| nav.move_down()),
113 NavAction::GoParent => return self.handle_go_parent(),
114 NavAction::GoIntoDir => return self.handle_go_into_dir(),
115 NavAction::ToggleMarker => self.nav.toggle_marker(),
116 }
117 KeypressResult::Continue
118 }
119
120 fn move_nav_if_possible<F>(&mut self, f: F)
121 where
122 F: FnOnce(&mut NavState) -> bool,
123 {
124 if f(&mut self.nav) {
125 self.preview.mark_pending();
126 }
127 }
128
129 fn handle_go_parent(&mut self) -> KeypressResult {
130 if let Some(parent) = self.nav.current_dir().parent() {
131 let exited_name = self.nav.current_dir().file_name().map(|n| n.to_os_string());
132 let parent_path = parent.to_path_buf();
133 self.nav.save_position();
134 self.nav.set_path(parent_path);
135 self.nav.clear_filters();
137
138 self.request_dir_load(exited_name);
139 self.request_parent_content();
140 }
141 KeypressResult::Continue
142 }
143
144 fn handle_go_into_dir(&mut self) -> KeypressResult {
145 if let Some(entry) = self.nav.selected_shown_entry()
146 && entry.is_dir()
147 {
148 let new_path = self.nav.current_dir().join(entry.name());
149 self.nav.save_position();
150 self.nav.set_path(new_path);
151
152 self.request_dir_load(None);
153 self.request_parent_content();
154 }
155 KeypressResult::Continue
156 }
157
158 pub fn handle_file_action(&mut self, action: FileAction) -> KeypressResult {
161 match action {
162 FileAction::Open => return self.handle_open_file(),
163 FileAction::Delete => self.prompt_delete(),
164 FileAction::Copy => {
165 self.actions.action_copy(&self.nav, false);
166 self.notification_time = Some(Instant::now() + Duration::from_secs(2));
167 }
168 FileAction::Paste => self.actions.action_paste(&mut self.nav, &self.worker_tx),
169 FileAction::Rename => self.prompt_rename(),
170 FileAction::Create => self.prompt_create_file(),
171 FileAction::CreateDirectory => self.prompt_create_folder(),
172 FileAction::Filter => self.prompt_filter(),
173 }
174 KeypressResult::Continue
175 }
176
177 fn handle_open_file(&mut self) -> KeypressResult {
178 if let Some(entry) = self.nav.selected_shown_entry() {
179 let path = self.nav.current_dir().join(entry.name());
180 if let Err(e) = crate::utils::open_in_editor(self.config.editor(), &path) {
181 eprintln!("Error: {}", e);
182 }
183 KeypressResult::OpenedEditor
184 } else {
185 KeypressResult::Continue
186 }
187 }
188
189 fn prompt_delete(&mut self) {
192 let targets = self.nav.get_action_targets();
193 if targets.is_empty() {
194 return;
195 }
196 let prompt_text = format!(
197 "Delete {} item{}? [Y/N]",
198 targets.len(),
199 if targets.len() > 1 { "s" } else { "" }
200 );
201 self.enter_input_mode(InputMode::ConfirmDelete, prompt_text, None);
202 }
203
204 fn prompt_rename(&mut self) {
205 if let Some(entry) = self.nav.selected_shown_entry() {
206 let name = entry.name().to_string_lossy().to_string();
207 self.enter_input_mode(InputMode::Rename, "Rename: ".to_string(), Some(name));
208 }
209 }
210
211 fn prompt_create_file(&mut self) {
212 self.enter_input_mode(InputMode::NewFile, "New File: ".to_string(), None);
213 }
214
215 fn prompt_create_folder(&mut self) {
216 self.enter_input_mode(InputMode::NewFolder, "New Folder: ".to_string(), None);
217 }
218
219 fn prompt_filter(&mut self) {
220 let current_filter = self.nav.filter().to_string();
221 self.enter_input_mode(
222 InputMode::Filter,
223 "Filter: ".to_string(),
224 Some(current_filter),
225 );
226 }
227
228 pub fn enter_input_mode(&mut self, mode: InputMode, prompt: String, initial: Option<String>) {
229 let buffer = initial.unwrap_or_default();
230 self.actions
231 .enter_mode(ActionMode::Input { mode, prompt }, buffer);
232 }
233}