navigation in the menu but needs refactoring

This commit is contained in:
filipriec
2025-05-29 16:11:41 +02:00
parent 799d8471c9
commit 668eeee197
7 changed files with 329 additions and 118 deletions

View File

@@ -1,5 +1,5 @@
// src/modes/handlers/event.rs
use crossterm::event::Event;
use crossterm::event::{Event, KeyEvent};
use crossterm::cursor::SetCursorStyle;
use crate::services::grpc_client::GrpcClient;
use crate::services::auth::AuthClient;
@@ -35,6 +35,7 @@ use crate::modes::{
canvas::{edit, read_only, common_mode},
general::{navigation, dialog},
};
use crate::modes::general::command_navigation::{NavigationState, handle_command_navigation_event};
use crate::functions::modes::navigation::{admin_nav, add_table_nav};
use crate::config::binds::key_sequences::KeySequenceTracker;
use tokio::sync::mpsc;
@@ -43,7 +44,7 @@ use crate::tui::functions::common::register::RegisterResult;
use crate::functions::modes::navigation::add_table_nav::SaveTableResultSender;
use crate::functions::modes::navigation::add_logic_nav::SaveLogicResultSender;
use crate::functions::modes::navigation::add_logic_nav;
use crossterm::event::{KeyCode, KeyModifiers};
use crossterm::event::KeyCode;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EventOutcome {
@@ -53,6 +54,15 @@ pub enum EventOutcome {
ButtonSelected { context: UiContext, index: usize },
}
impl EventOutcome {
pub fn get_message_if_ok(&self) -> String {
match self {
EventOutcome::Ok(msg) => msg.clone(),
_ => String::new(),
}
}
}
pub struct EventHandler {
pub command_mode: bool,
pub command_input: String,
@@ -67,10 +77,7 @@ pub struct EventHandler {
pub register_result_sender: mpsc::Sender<RegisterResult>,
pub save_table_result_sender: SaveTableResultSender,
pub save_logic_result_sender: SaveLogicResultSender,
pub find_file_palette_active: bool,
pub find_file_options: Vec<String>,
pub find_file_selected_index: Option<usize>,
pub find_file_input: String,
pub navigation_state: NavigationState,
}
impl EventHandler {
@@ -94,23 +101,18 @@ impl EventHandler {
register_result_sender,
save_table_result_sender,
save_logic_result_sender,
find_file_palette_active: false,
find_file_options: vec![
"src/main.rs".to_string(),
"src/lib.rs".to_string(),
"Cargo.toml".to_string(),
"README.md".to_string(),
"config.toml".to_string(),
"src/ui/handlers/ui.rs".to_string(),
"src/modes/handlers/event.rs".to_string(),
"another_file.txt".to_string(),
"yet_another_one.md".to_string(),
],
find_file_selected_index: None,
find_file_input: String::new(),
navigation_state: NavigationState::new(),
})
}
pub fn is_navigation_active(&self) -> bool {
self.navigation_state.active
}
pub fn activate_find_file(&mut self, options: Vec<String>) {
self.navigation_state.activate_find_file(options);
}
#[allow(clippy::too_many_arguments)]
pub async fn handle_event(
&mut self,
@@ -130,26 +132,28 @@ impl EventHandler {
total_count: u64,
current_position: &mut u64,
) -> Result<EventOutcome> {
// Handle find file palette first
if self.find_file_palette_active {
if let Event::Key(key) = event {
if key.code == KeyCode::Esc {
self.find_file_palette_active = false;
self.find_file_input.clear();
self.find_file_selected_index = None;
self.command_message = "Find File palette closed".to_string();
return Ok(EventOutcome::Ok(self.command_message.clone()));
let mut current_mode = ModeManager::derive_mode(app_state, self, admin_state);
// Handle active command navigation first
if current_mode == AppMode::General && self.navigation_state.active {
if let Event::Key(key_event) = event {
let outcome = handle_command_navigation_event(
&mut self.navigation_state,
key_event,
config,
).await?;
if !self.navigation_state.active {
self.command_message = outcome.get_message_if_ok();
current_mode = ModeManager::derive_mode(app_state, self, admin_state);
}
if let KeyCode::Char(c) = key.code {
self.find_file_input.push(c);
} else if key.code == KeyCode::Backspace {
self.find_file_input.pop();
}
return Ok(EventOutcome::Ok("Palette event consumed".to_string()));
app_state.update_mode(current_mode);
return Ok(outcome);
}
app_state.update_mode(current_mode);
return Ok(EventOutcome::Ok(String::new()));
}
let current_mode = ModeManager::derive_mode(app_state, self, admin_state);
app_state.update_mode(current_mode);
let current_view = {
@@ -166,34 +170,29 @@ impl EventHandler {
buffer_state.update_history(current_view);
if app_state.ui.dialog.dialog_show {
if let Some(dialog_result) = dialog::handle_dialog_event(
&event,
config,
app_state,
login_state,
register_state,
buffer_state,
admin_state,
).await {
return dialog_result;
if let Event::Key(key_event) = event {
if let Some(dialog_result) = dialog::handle_dialog_event(
&Event::Key(key_event),
config, app_state, login_state, register_state, buffer_state, admin_state,
).await {
return dialog_result;
}
} else if let Event::Resize(_,_) = event {
// Handle resize if needed
}
return Ok(EventOutcome::Ok(String::new()));
}
if let Event::Key(key) = event {
let key_code = key.code;
let modifiers = key.modifiers;
if let Event::Key(key_event) = event {
let key_code = key_event.code;
let modifiers = key_event.modifiers;
if UiStateHandler::toggle_sidebar(&mut app_state.ui, config, key_code, modifiers) {
let message = format!("Sidebar {}",
if app_state.ui.show_sidebar { "shown" } else { "hidden" }
);
let message = format!("Sidebar {}", if app_state.ui.show_sidebar { "shown" } else { "hidden" });
return Ok(EventOutcome::Ok(message));
}
if UiStateHandler::toggle_buffer_list(&mut app_state.ui, config, key_code, modifiers) {
let message = format!("Buffer {}",
if app_state.ui.show_buffer_list { "shown" } else { "hidden" }
);
let message = format!("Buffer {}", if app_state.ui.show_buffer_list { "shown" } else { "hidden" });
return Ok(EventOutcome::Ok(message));
}
@@ -224,10 +223,9 @@ impl EventHandler {
match current_mode {
AppMode::General => {
if app_state.ui.show_admin
&& auth_state.role.as_deref() == Some("admin") {
if app_state.ui.show_admin && auth_state.role.as_deref() == Some("admin") {
if admin_nav::handle_admin_navigation(
key,
key_event,
config,
app_state,
admin_state,
@@ -243,7 +241,7 @@ impl EventHandler {
let sender_clone = self.save_logic_result_sender.clone();
if add_logic_nav::handle_add_logic_navigation(
key,
key_event,
config,
app_state,
&mut admin_state.add_logic_state,
@@ -262,7 +260,7 @@ impl EventHandler {
let sender_clone = self.save_table_result_sender.clone();
if add_table_nav::handle_add_table_navigation(
key,
key_event,
config,
app_state,
&mut admin_state.add_table_state,
@@ -275,7 +273,7 @@ impl EventHandler {
}
let nav_outcome = navigation::handle_navigation_event(
key,
key_event,
config,
form_state,
app_state,
@@ -286,7 +284,9 @@ impl EventHandler {
&mut self.command_mode,
&mut self.command_input,
&mut self.command_message,
&mut self.navigation_state,
).await;
match nav_outcome {
Ok(EventOutcome::ButtonSelected { context, index }) => {
let message = match context {
@@ -300,24 +300,22 @@ impl EventHandler {
format!("Intro Option {} selected", index)
}
UiContext::Login => {
let login_action_message = match index {
match index {
0 => {
login::initiate_login(login_state, app_state, self.auth_client.clone(), self.login_result_sender.clone())
},
1 => login::back_to_main(login_state, app_state, buffer_state).await,
_ => "Invalid Login Option".to_string(),
};
login_action_message
}
}
UiContext::Register => {
let register_action_message = match index {
match index {
0 => {
register::initiate_registration(register_state, app_state, self.auth_client.clone(), self.register_result_sender.clone())
},
1 => register::back_to_login(register_state, app_state, buffer_state).await,
_ => "Invalid Login Option".to_string(),
};
register_action_message
}
}
UiContext::Admin => {
admin::handle_admin_selection(app_state, admin_state);
@@ -331,7 +329,7 @@ impl EventHandler {
}
other => return other,
}
},
}
AppMode::ReadOnly => {
if config.get_read_only_action_for_key(key_code, modifiers) == Some("enter_highlight_mode_linewise")
@@ -426,7 +424,7 @@ impl EventHandler {
let (_should_exit, message) = read_only::handle_read_only_event(
app_state,
key,
key_event,
config,
form_state,
login_state,
@@ -442,7 +440,7 @@ impl EventHandler {
&mut self.ideal_cursor_column,
).await?;
return Ok(EventOutcome::Ok(message));
},
}
AppMode::Highlight => {
if config.get_highlight_action_for_key(key_code, modifiers) == Some("exit_highlight_mode") {
@@ -461,7 +459,7 @@ impl EventHandler {
}
let (_should_exit, message) = read_only::handle_read_only_event(
app_state, key, config, form_state, login_state,
app_state, key_event, config, form_state, login_state,
register_state,
&mut admin_state.add_table_state,
&mut admin_state.add_logic_state,
@@ -500,7 +498,7 @@ impl EventHandler {
}
let edit_result = edit::handle_edit_event(
key,
key_event,
config,
form_state,
login_state,
@@ -551,10 +549,9 @@ impl EventHandler {
return Err(e.into());
}
}
},
}
AppMode::Command => {
// Handle immediate command mode actions
if config.is_exit_command_mode(key_code, modifiers) {
self.command_input.clear();
self.command_message.clear();
@@ -565,46 +562,54 @@ impl EventHandler {
if config.is_command_execute(key_code, modifiers) {
let outcome = command_mode::handle_command_event(
key, config, app_state, login_state, register_state, form_state,
key_event, config, app_state, login_state, register_state, form_state,
&mut self.command_input, &mut self.command_message,
grpc_client, command_handler, terminal, current_position, total_count,
).await?;
self.command_mode = false;
self.key_sequence_tracker.reset();
let new_mode = ModeManager::derive_mode(app_state, self, admin_state);
app_state.update_mode(new_mode);
return Ok(outcome);
}
// Handle backspace
if key_code == KeyCode::Backspace {
self.command_input.pop();
self.key_sequence_tracker.reset();
return Ok(EventOutcome::Ok(String::new()));
}
// Handle character input and sequences
if let KeyCode::Char(c) = key_code {
if c == 'f' {
self.key_sequence_tracker.add_key(key_code);
let sequence = self.key_sequence_tracker.get_sequence();
if config.matches_key_sequence_generalized(&sequence) == Some("find_file_palette_toggle") {
if app_state.ui.show_form || app_state.ui.show_intro {
self.find_file_palette_active = true;
self.find_file_input.clear();
self.find_file_selected_index = if self.find_file_options.is_empty() {
None
} else {
Some(0)
};
let options = vec![
"src/main.rs".to_string(),
"src/lib.rs".to_string(),
"Cargo.toml".to_string(),
"README.md".to_string(),
"config.toml".to_string(),
"src/ui/handlers/ui.rs".to_string(),
"src/modes/handlers/event.rs".to_string(),
"another_file.txt".to_string(),
"yet_another_one.md".to_string(),
];
self.activate_find_file(options);
self.command_mode = false;
self.command_input.clear();
self.command_message = "Find File:".to_string();
self.key_sequence_tracker.reset();
app_state.update_mode(AppMode::General);
return Ok(EventOutcome::Ok("Find File palette activated".to_string()));
} else {
self.key_sequence_tracker.reset();
self.command_input.push('f');
self.command_input.push('f');
if sequence.len() > 1 && sequence[0] == KeyCode::Char('f') {
self.command_input.push('f');
}
self.command_message = "Find File not available in this view.".to_string();
return Ok(EventOutcome::Ok(self.command_message.clone()));
}
@@ -623,11 +628,12 @@ impl EventHandler {
return Ok(EventOutcome::Ok(String::new()));
}
// Reset tracker for other keys
self.key_sequence_tracker.reset();
return Ok(EventOutcome::Ok(String::new()));
}
}
} else if let Event::Resize(_,_) = event {
return Ok(EventOutcome::Ok("Resized".to_string()));
}
self.edit_mode_cooldown = false;

View File

@@ -23,7 +23,7 @@ impl ModeManager {
event_handler: &EventHandler,
admin_state: &AdminState,
) -> AppMode {
if event_handler.find_file_palette_active {
if event_handler.navigation_state.active {
return AppMode::General;
}
@@ -82,14 +82,14 @@ impl ModeManager {
}
// Mode transition rules
pub fn can_enter_command_mode(current_mode: AppMode) -> bool {
!matches!(current_mode, AppMode::Edit) // Can't enter from Edit mode
pub fn can_enter_command_mode(current_mode: AppMode) -> bool {
!matches!(current_mode, AppMode::Edit)
}
pub fn can_enter_edit_mode(current_mode: AppMode) -> bool {
matches!(current_mode, AppMode::ReadOnly) // Only from ReadOnly
matches!(current_mode, AppMode::ReadOnly)
}
pub fn can_enter_read_only_mode(current_mode: AppMode) -> bool {
matches!(current_mode, AppMode::Edit | AppMode::Command | AppMode::Highlight)
}