fresh/app/
keybinding_editor_actions.rs1use super::keybinding_editor::KeybindingEditor;
6use super::Editor;
7use crate::input::handler::InputResult;
8use crate::view::keybinding_editor::{handle_keybinding_editor_input, KeybindingEditorAction};
9use crate::view::ui::point_in_rect;
10use crossterm::event::{KeyEvent, MouseButton, MouseEvent, MouseEventKind};
11
12impl Editor {
13 pub fn open_keybinding_editor(&mut self) {
15 let config_path = self.dir_context.config_path().display().to_string();
16 let cmd_registry = self.command_registry.read().unwrap();
17 self.keybinding_editor = Some(KeybindingEditor::new(
18 &self.config,
19 &self.keybindings,
20 &self.mode_registry,
21 &cmd_registry,
22 config_path,
23 ));
24 }
25
26 pub fn handle_keybinding_editor_input(&mut self, event: &KeyEvent) -> InputResult {
28 let mut editor = match self.keybinding_editor.take() {
29 Some(e) => e,
30 None => return InputResult::Ignored,
31 };
32
33 let action = handle_keybinding_editor_input(&mut editor, event);
34
35 match action {
36 KeybindingEditorAction::Consumed => {
37 self.keybinding_editor = Some(editor);
38 InputResult::Consumed
39 }
40 KeybindingEditorAction::Close => {
41 self.set_status_message("Keybinding editor closed".to_string());
43 InputResult::Consumed
44 }
45 KeybindingEditorAction::SaveAndClose => {
46 self.save_keybinding_editor_changes(&editor);
48 InputResult::Consumed
49 }
50 KeybindingEditorAction::StatusMessage(msg) => {
51 self.set_status_message(msg);
52 self.keybinding_editor = Some(editor);
53 InputResult::Consumed
54 }
55 }
56 }
57
58 fn save_keybinding_editor_changes(&mut self, editor: &KeybindingEditor) {
60 if !editor.has_changes {
61 return;
62 }
63
64 for remove in editor.get_pending_removes() {
66 self.config.keybindings.retain(|kb| {
67 !(kb.action == remove.action
68 && kb.key == remove.key
69 && kb.modifiers == remove.modifiers
70 && kb.when == remove.when)
71 });
72 }
73
74 let new_bindings = editor.get_custom_bindings();
76 for binding in new_bindings {
77 self.config.keybindings.push(binding);
78 }
79
80 self.keybindings = crate::input::keybindings::KeybindingResolver::new(&self.config);
82
83 let config_value = match serde_json::to_value(&self.config.keybindings) {
85 Ok(v) => v,
86 Err(e) => {
87 self.set_status_message(format!("Failed to serialize keybindings: {}", e));
88 return;
89 }
90 };
91
92 let mut changes = std::collections::HashMap::new();
93 changes.insert("/keybindings".to_string(), config_value);
94
95 let resolver = crate::config_io::ConfigResolver::new(
96 self.dir_context.clone(),
97 self.working_dir.clone(),
98 );
99
100 match resolver.save_changes_to_layer(
101 &changes,
102 &std::collections::HashSet::new(),
103 crate::config_io::ConfigLayer::User,
104 ) {
105 Ok(()) => {
106 self.set_status_message("Keybinding changes saved".to_string());
107 }
108 Err(e) => {
109 self.set_status_message(format!("Failed to save keybindings: {}", e));
110 }
111 }
112 }
113
114 pub fn is_keybinding_editor_active(&self) -> bool {
116 self.keybinding_editor.is_some()
117 }
118
119 pub fn handle_keybinding_editor_mouse(
122 &mut self,
123 mouse_event: MouseEvent,
124 ) -> anyhow::Result<bool> {
125 let mut editor = match self.keybinding_editor.take() {
126 Some(e) => e,
127 None => return Ok(false),
128 };
129
130 let col = mouse_event.column;
131 let row = mouse_event.row;
132 let layout = &editor.layout;
133
134 if !point_in_rect(layout.modal_area, col, row) {
137 self.keybinding_editor = Some(editor);
138 return Ok(false);
139 }
140
141 match mouse_event.kind {
142 MouseEventKind::ScrollUp => {
143 if editor.edit_dialog.is_none() && !editor.showing_confirm_dialog {
145 editor.select_prev();
146 }
147 }
148 MouseEventKind::ScrollDown => {
149 if editor.edit_dialog.is_none() && !editor.showing_confirm_dialog {
150 editor.select_next();
151 }
152 }
153 MouseEventKind::Down(MouseButton::Left) => {
154 if editor.showing_confirm_dialog {
156 if let Some((save_r, discard_r, cancel_r)) = layout.confirm_buttons {
157 if point_in_rect(save_r, col, row) {
158 self.save_keybinding_editor_changes(&editor);
159 return Ok(true);
160 } else if point_in_rect(discard_r, col, row) {
161 self.set_status_message("Keybinding editor closed".to_string());
162 return Ok(true);
163 } else if point_in_rect(cancel_r, col, row) {
164 editor.showing_confirm_dialog = false;
165 }
166 }
167 self.keybinding_editor = Some(editor);
168 return Ok(true);
169 }
170
171 if editor.edit_dialog.is_some() {
173 if let Some((save_r, cancel_r)) = layout.dialog_buttons {
175 if point_in_rect(save_r, col, row) {
176 if let Some(err) = editor.apply_edit_dialog() {
178 self.set_status_message(err);
179 }
180 self.keybinding_editor = Some(editor);
181 return Ok(true);
182 } else if point_in_rect(cancel_r, col, row) {
183 editor.edit_dialog = None;
185 self.keybinding_editor = Some(editor);
186 return Ok(true);
187 }
188 }
189 if let Some(r) = layout.dialog_key_field {
191 if point_in_rect(r, col, row) {
192 if let Some(ref mut dialog) = editor.edit_dialog {
193 dialog.focus_area = 0;
194 dialog.mode = crate::app::keybinding_editor::EditMode::RecordingKey;
195 }
196 }
197 }
198 if let Some(r) = layout.dialog_action_field {
199 if point_in_rect(r, col, row) {
200 if let Some(ref mut dialog) = editor.edit_dialog {
201 dialog.focus_area = 1;
202 dialog.mode =
203 crate::app::keybinding_editor::EditMode::EditingAction;
204 }
205 }
206 }
207 if let Some(r) = layout.dialog_context_field {
208 if point_in_rect(r, col, row) {
209 if let Some(ref mut dialog) = editor.edit_dialog {
210 dialog.focus_area = 2;
211 dialog.mode =
212 crate::app::keybinding_editor::EditMode::EditingContext;
213 }
214 }
215 }
216 self.keybinding_editor = Some(editor);
217 return Ok(true);
218 }
219
220 if let Some(search_r) = layout.search_bar {
222 if point_in_rect(search_r, col, row) {
223 editor.start_search();
224 self.keybinding_editor = Some(editor);
225 return Ok(true);
226 }
227 }
228
229 let table_area = layout.table_area;
231 let first_row_y = layout.table_first_row_y;
232 if point_in_rect(table_area, col, row) && row >= first_row_y {
233 let clicked_row = (row - first_row_y) as usize;
234 let new_selected = editor.scroll.offset as usize + clicked_row;
235 if new_selected < editor.display_rows.len() {
236 editor.selected = new_selected;
237 if editor.selected_is_section_header() {
238 editor.toggle_section_at_selected();
239 }
240 }
241 }
242 }
243 _ => {}
244 }
245
246 self.keybinding_editor = Some(editor);
247 Ok(true)
248 }
249}