use super::keybinding_editor::KeybindingEditor;
use super::Editor;
use crate::input::handler::InputResult;
use crate::view::keybinding_editor::{handle_keybinding_editor_input, KeybindingEditorAction};
use crate::view::ui::point_in_rect;
use crossterm::event::{KeyEvent, MouseButton, MouseEvent, MouseEventKind};
impl Editor {
pub fn open_keybinding_editor(&mut self) {
let config_path = self.dir_context.config_path().display().to_string();
let cmd_registry = self.command_registry.read().unwrap();
let keybindings = self.keybindings.read().unwrap();
self.keybinding_editor = Some(KeybindingEditor::new(
&self.config,
&keybindings,
&self.mode_registry,
&cmd_registry,
config_path,
));
}
pub fn handle_keybinding_editor_input(&mut self, event: &KeyEvent) -> InputResult {
let mut editor = match self.keybinding_editor.take() {
Some(e) => e,
None => return InputResult::Ignored,
};
let action = handle_keybinding_editor_input(&mut editor, event);
match action {
KeybindingEditorAction::Consumed => {
self.keybinding_editor = Some(editor);
InputResult::Consumed
}
KeybindingEditorAction::Close => {
self.set_status_message("Keybinding editor closed".to_string());
InputResult::Consumed
}
KeybindingEditorAction::SaveAndClose => {
self.save_keybinding_editor_changes(&editor);
InputResult::Consumed
}
KeybindingEditorAction::StatusMessage(msg) => {
self.set_status_message(msg);
self.keybinding_editor = Some(editor);
InputResult::Consumed
}
}
}
fn save_keybinding_editor_changes(&mut self, editor: &KeybindingEditor) {
if !editor.has_changes {
return;
}
for remove in editor.get_pending_removes() {
self.config_mut().keybindings.retain(|kb| {
!(kb.action == remove.action
&& kb.key == remove.key
&& kb.modifiers == remove.modifiers
&& kb.when == remove.when)
});
}
let new_bindings = editor.get_custom_bindings();
for binding in new_bindings {
self.config_mut().keybindings.push(binding);
}
*self.keybindings.write().unwrap() =
crate::input::keybindings::KeybindingResolver::new(&self.config);
let config_value = match serde_json::to_value(&self.config.keybindings) {
Ok(v) => v,
Err(e) => {
self.set_status_message(format!("Failed to serialize keybindings: {}", e));
return;
}
};
let mut changes = std::collections::HashMap::new();
changes.insert("/keybindings".to_string(), config_value);
let resolver = crate::config_io::ConfigResolver::new(
self.dir_context.clone(),
self.working_dir.clone(),
);
match resolver.save_changes_to_layer(
&changes,
&std::collections::HashSet::new(),
crate::config_io::ConfigLayer::User,
) {
Ok(()) => {
self.set_status_message("Keybinding changes saved".to_string());
}
Err(e) => {
self.set_status_message(format!("Failed to save keybindings: {}", e));
}
}
}
pub fn is_keybinding_editor_active(&self) -> bool {
self.keybinding_editor.is_some()
}
pub fn handle_keybinding_editor_mouse(
&mut self,
mouse_event: MouseEvent,
) -> anyhow::Result<bool> {
let mut editor = match self.keybinding_editor.take() {
Some(e) => e,
None => return Ok(false),
};
let col = mouse_event.column;
let row = mouse_event.row;
let layout = &editor.layout;
if !point_in_rect(layout.modal_area, col, row) {
self.keybinding_editor = Some(editor);
return Ok(false);
}
match mouse_event.kind {
MouseEventKind::ScrollUp => {
if editor.edit_dialog.is_none() && !editor.showing_confirm_dialog {
editor.select_prev();
}
}
MouseEventKind::ScrollDown => {
if editor.edit_dialog.is_none() && !editor.showing_confirm_dialog {
editor.select_next();
}
}
MouseEventKind::Down(MouseButton::Left) => {
if editor.showing_confirm_dialog {
if let Some((save_r, discard_r, cancel_r)) = layout.confirm_buttons {
if point_in_rect(save_r, col, row) {
self.save_keybinding_editor_changes(&editor);
return Ok(true);
} else if point_in_rect(discard_r, col, row) {
self.set_status_message("Keybinding editor closed".to_string());
return Ok(true);
} else if point_in_rect(cancel_r, col, row) {
editor.showing_confirm_dialog = false;
}
}
self.keybinding_editor = Some(editor);
return Ok(true);
}
if editor.edit_dialog.is_some() {
if let Some((save_r, cancel_r)) = layout.dialog_buttons {
if point_in_rect(save_r, col, row) {
if let Some(err) = editor.apply_edit_dialog() {
self.set_status_message(err);
}
self.keybinding_editor = Some(editor);
return Ok(true);
} else if point_in_rect(cancel_r, col, row) {
editor.edit_dialog = None;
self.keybinding_editor = Some(editor);
return Ok(true);
}
}
if let Some(r) = layout.dialog_key_field {
if point_in_rect(r, col, row) {
if let Some(ref mut dialog) = editor.edit_dialog {
dialog.focus_area = 0;
dialog.mode = crate::app::keybinding_editor::EditMode::RecordingKey;
}
}
}
if let Some(r) = layout.dialog_action_field {
if point_in_rect(r, col, row) {
if let Some(ref mut dialog) = editor.edit_dialog {
dialog.focus_area = 1;
dialog.mode =
crate::app::keybinding_editor::EditMode::EditingAction;
}
}
}
if let Some(r) = layout.dialog_context_field {
if point_in_rect(r, col, row) {
if let Some(ref mut dialog) = editor.edit_dialog {
dialog.focus_area = 2;
dialog.mode =
crate::app::keybinding_editor::EditMode::EditingContext;
}
}
}
self.keybinding_editor = Some(editor);
return Ok(true);
}
if let Some(search_r) = layout.search_bar {
if point_in_rect(search_r, col, row) {
editor.start_search();
self.keybinding_editor = Some(editor);
return Ok(true);
}
}
let table_area = layout.table_area;
let first_row_y = layout.table_first_row_y;
if point_in_rect(table_area, col, row) && row >= first_row_y {
let clicked_row = (row - first_row_y) as usize;
let new_selected = editor.scroll.offset as usize + clicked_row;
if new_selected < editor.display_rows.len() {
editor.selected = new_selected;
if editor.selected_is_section_header() {
editor.toggle_section_at_selected();
}
}
}
}
_ => {}
}
self.keybinding_editor = Some(editor);
Ok(true)
}
}