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 use crate::config::MenuExt;
16 let config_path = self.dir_context.config_path().display().to_string();
17 let cmd_registry = self.command_registry.read().unwrap();
18 let keybindings = self.keybindings.read().unwrap();
19 let menu_names: Vec<String> = self
23 .menus
24 .menus
25 .iter()
26 .chain(self.menu_state.plugin_menus.iter())
27 .map(|m| m.match_id().to_string())
28 .collect();
29 self.keybinding_editor = Some(KeybindingEditor::new(
30 &self.config,
31 &keybindings,
32 &self.mode_registry,
33 &cmd_registry,
34 config_path,
35 &menu_names,
36 ));
37 }
38
39 pub fn handle_keybinding_editor_input(&mut self, event: &KeyEvent) -> InputResult {
41 let mut editor = match self.keybinding_editor.take() {
42 Some(e) => e,
43 None => return InputResult::Ignored,
44 };
45
46 let action = handle_keybinding_editor_input(&mut editor, event);
47
48 match action {
49 KeybindingEditorAction::Consumed => {
50 self.keybinding_editor = Some(editor);
51 InputResult::Consumed
52 }
53 KeybindingEditorAction::Close => {
54 self.set_status_message("Keybinding editor closed".to_string());
56 InputResult::Consumed
57 }
58 KeybindingEditorAction::SaveAndClose => {
59 self.save_keybinding_editor_changes(&editor);
61 InputResult::Consumed
62 }
63 KeybindingEditorAction::StatusMessage(msg) => {
64 self.set_status_message(msg);
65 self.keybinding_editor = Some(editor);
66 InputResult::Consumed
67 }
68 }
69 }
70
71 fn save_keybinding_editor_changes(&mut self, editor: &KeybindingEditor) {
73 if !editor.has_changes {
74 return;
75 }
76
77 for remove in editor.get_pending_removes() {
79 self.config_mut().keybindings.retain(|kb| {
80 !(kb.action == remove.action
81 && kb.key == remove.key
82 && kb.modifiers == remove.modifiers
83 && kb.when == remove.when)
84 });
85 }
86
87 let new_bindings = editor.get_custom_bindings();
89 for binding in new_bindings {
90 self.config_mut().keybindings.push(binding);
91 }
92
93 *self.keybindings.write().unwrap() =
95 crate::input::keybindings::KeybindingResolver::new(&self.config);
96
97 let config_value = match serde_json::to_value(&self.config.keybindings) {
99 Ok(v) => v,
100 Err(e) => {
101 self.set_status_message(format!("Failed to serialize keybindings: {}", e));
102 return;
103 }
104 };
105
106 let mut changes = std::collections::HashMap::new();
107 changes.insert("/keybindings".to_string(), config_value);
108
109 let resolver = crate::config_io::ConfigResolver::new(
110 self.dir_context.clone(),
111 self.working_dir.clone(),
112 );
113
114 match resolver.save_changes_to_layer(
115 &changes,
116 &std::collections::HashSet::new(),
117 crate::config_io::ConfigLayer::User,
118 ) {
119 Ok(()) => {
120 self.set_status_message("Keybinding changes saved".to_string());
121 }
122 Err(e) => {
123 self.set_status_message(format!("Failed to save keybindings: {}", e));
124 }
125 }
126 }
127
128 pub fn is_keybinding_editor_active(&self) -> bool {
130 self.keybinding_editor.is_some()
131 }
132
133 pub fn handle_keybinding_editor_mouse(
136 &mut self,
137 mouse_event: MouseEvent,
138 ) -> anyhow::Result<bool> {
139 let mut editor = match self.keybinding_editor.take() {
140 Some(e) => e,
141 None => return Ok(false),
142 };
143
144 let col = mouse_event.column;
145 let row = mouse_event.row;
146 let layout = &editor.layout;
147
148 if !point_in_rect(layout.modal_area, col, row) {
151 self.keybinding_editor = Some(editor);
152 return Ok(false);
153 }
154
155 match mouse_event.kind {
156 MouseEventKind::ScrollUp => {
157 if editor.edit_dialog.is_none() && !editor.showing_confirm_dialog {
159 editor.select_prev();
160 }
161 }
162 MouseEventKind::ScrollDown => {
163 if editor.edit_dialog.is_none() && !editor.showing_confirm_dialog {
164 editor.select_next();
165 }
166 }
167 MouseEventKind::Down(MouseButton::Left) => {
168 if editor.showing_confirm_dialog {
170 if let Some((save_r, discard_r, cancel_r)) = layout.confirm_buttons {
171 if point_in_rect(save_r, col, row) {
172 self.save_keybinding_editor_changes(&editor);
173 return Ok(true);
174 } else if point_in_rect(discard_r, col, row) {
175 self.set_status_message("Keybinding editor closed".to_string());
176 return Ok(true);
177 } else if point_in_rect(cancel_r, col, row) {
178 editor.showing_confirm_dialog = false;
179 }
180 }
181 self.keybinding_editor = Some(editor);
182 return Ok(true);
183 }
184
185 if editor.edit_dialog.is_some() {
187 if let Some((save_r, cancel_r)) = layout.dialog_buttons {
189 if point_in_rect(save_r, col, row) {
190 if let Some(err) = editor.apply_edit_dialog() {
192 self.set_status_message(err);
193 }
194 self.keybinding_editor = Some(editor);
195 return Ok(true);
196 } else if point_in_rect(cancel_r, col, row) {
197 editor.edit_dialog = None;
199 self.keybinding_editor = Some(editor);
200 return Ok(true);
201 }
202 }
203 if let Some(r) = layout.dialog_key_field {
205 if point_in_rect(r, col, row) {
206 if let Some(ref mut dialog) = editor.edit_dialog {
207 dialog.focus_area = 0;
208 dialog.mode = crate::app::keybinding_editor::EditMode::RecordingKey;
209 }
210 }
211 }
212 if let Some(r) = layout.dialog_action_field {
213 if point_in_rect(r, col, row) {
214 if let Some(ref mut dialog) = editor.edit_dialog {
215 dialog.focus_area = 1;
216 dialog.mode =
217 crate::app::keybinding_editor::EditMode::EditingAction;
218 }
219 }
220 }
221 if let Some(r) = layout.dialog_context_field {
222 if point_in_rect(r, col, row) {
223 if let Some(ref mut dialog) = editor.edit_dialog {
224 dialog.focus_area = 2;
225 dialog.mode =
226 crate::app::keybinding_editor::EditMode::EditingContext;
227 }
228 }
229 }
230 self.keybinding_editor = Some(editor);
231 return Ok(true);
232 }
233
234 if let Some(search_r) = layout.search_bar {
236 if point_in_rect(search_r, col, row) {
237 editor.start_search();
238 self.keybinding_editor = Some(editor);
239 return Ok(true);
240 }
241 }
242
243 let table_area = layout.table_area;
245 let first_row_y = layout.table_first_row_y;
246 if point_in_rect(table_area, col, row) && row >= first_row_y {
247 let clicked_row = (row - first_row_y) as usize;
248 let new_selected = editor.scroll.offset as usize + clicked_row;
249 if new_selected < editor.display_rows.len() {
250 editor.selected = new_selected;
251 if editor.selected_is_section_header() {
252 editor.toggle_section_at_selected();
253 }
254 }
255 }
256 }
257 _ => {}
258 }
259
260 self.keybinding_editor = Some(editor);
261 Ok(true)
262 }
263}