FIXED CRUCIAL BUG of two same shortcuts defined in the config
This commit is contained in:
@@ -56,7 +56,9 @@ enter_highlight_mode = ["v"]
|
|||||||
exit_highlight_mode = ["esc"]
|
exit_highlight_mode = ["esc"]
|
||||||
|
|
||||||
[keybindings.edit]
|
[keybindings.edit]
|
||||||
exit_edit_mode = ["esc","ctrl+e"]
|
# exit_edit_mode = ["esc","ctrl+e"]
|
||||||
|
# exit_suggestion_mode = ["esc"]
|
||||||
|
exit = ["esc", "ctrl+e"]
|
||||||
delete_char_forward = ["delete"]
|
delete_char_forward = ["delete"]
|
||||||
delete_char_backward = ["backspace"]
|
delete_char_backward = ["backspace"]
|
||||||
next_field = ["enter"]
|
next_field = ["enter"]
|
||||||
@@ -66,7 +68,6 @@ move_right = ["right"]
|
|||||||
suggestion_down = ["ctrl+n", "tab"]
|
suggestion_down = ["ctrl+n", "tab"]
|
||||||
suggestion_up = ["ctrl+p", "shift+tab"]
|
suggestion_up = ["ctrl+p", "shift+tab"]
|
||||||
select_suggestion = ["enter"]
|
select_suggestion = ["enter"]
|
||||||
exit_suggestion_mode = ["esc"]
|
|
||||||
|
|
||||||
[keybindings.command]
|
[keybindings.command]
|
||||||
exit_command_mode = ["ctrl+g", "esc"]
|
exit_command_mode = ["ctrl+g", "esc"]
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
// src/modes/canvas/edit.rs
|
// src/modes/canvas/edit.rs
|
||||||
|
|
||||||
use crate::config::binds::config::Config;
|
use crate::config::binds::config::Config;
|
||||||
use crate::services::grpc_client::GrpcClient;
|
use crate::services::grpc_client::GrpcClient;
|
||||||
use crate::state::pages::{auth::{LoginState, RegisterState}};
|
use crate::state::pages::{auth::{LoginState, RegisterState}, canvas_state::CanvasState};
|
||||||
use crate::state::pages::canvas_state::CanvasState;
|
|
||||||
use crate::state::pages::form::FormState;
|
use crate::state::pages::form::FormState;
|
||||||
use crate::functions::modes::edit::{auth_e, form_e};
|
|
||||||
use crate::modes::handlers::event::EventOutcome;
|
use crate::modes::handlers::event::EventOutcome;
|
||||||
|
use crate::functions::modes::edit::{auth_e, form_e};
|
||||||
use crate::state::app::state::AppState;
|
use crate::state::app::state::AppState;
|
||||||
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
|
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
|
||||||
|
// Removed duplicate/unused imports
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum EditEventOutcome {
|
||||||
|
Message(String), // Return a message, stay in Edit mode
|
||||||
|
ExitEditMode, // Signal to exit Edit mode
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn handle_edit_event(
|
pub async fn handle_edit_event(
|
||||||
key: KeyEvent,
|
key: KeyEvent,
|
||||||
@@ -17,12 +22,12 @@ pub async fn handle_edit_event(
|
|||||||
login_state: &mut LoginState,
|
login_state: &mut LoginState,
|
||||||
register_state: &mut RegisterState,
|
register_state: &mut RegisterState,
|
||||||
ideal_cursor_column: &mut usize,
|
ideal_cursor_column: &mut usize,
|
||||||
command_message: &mut String,
|
// command_message: &mut String, // Removed as messages are returned
|
||||||
current_position: &mut u64,
|
current_position: &mut u64,
|
||||||
total_count: u64,
|
total_count: u64,
|
||||||
grpc_client: &mut GrpcClient,
|
grpc_client: &mut GrpcClient,
|
||||||
app_state: &AppState,
|
app_state: &AppState,
|
||||||
) -> Result<String, Box<dyn std::error::Error>> {
|
) -> Result<EditEventOutcome, Box<dyn std::error::Error>> {
|
||||||
|
|
||||||
// Global command mode check
|
// Global command mode check
|
||||||
if let Some("enter_command_mode") = config.get_action_for_key_in_mode(
|
if let Some("enter_command_mode") = config.get_action_for_key_in_mode(
|
||||||
@@ -30,8 +35,7 @@ pub async fn handle_edit_event(
|
|||||||
key.code,
|
key.code,
|
||||||
key.modifiers
|
key.modifiers
|
||||||
) {
|
) {
|
||||||
*command_message = "Switching to Command Mode...".to_string();
|
return Ok(EditEventOutcome::Message("Switching to Command Mode...".to_string()));
|
||||||
return Ok(command_message.clone());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Common actions (save/revert)
|
// Common actions (save/revert)
|
||||||
@@ -41,14 +45,15 @@ pub async fn handle_edit_event(
|
|||||||
key.modifiers
|
key.modifiers
|
||||||
) {
|
) {
|
||||||
if matches!(action, "save" | "revert") {
|
if matches!(action, "save" | "revert") {
|
||||||
let message = if app_state.ui.show_login {
|
// Ensure all branches result in Result<String, Error> before the final Ok(...) wrap
|
||||||
|
let message_string: String = if app_state.ui.show_login {
|
||||||
auth_e::execute_common_action(
|
auth_e::execute_common_action(
|
||||||
action,
|
action,
|
||||||
login_state,
|
login_state,
|
||||||
grpc_client,
|
grpc_client,
|
||||||
current_position,
|
current_position,
|
||||||
total_count
|
total_count
|
||||||
).await
|
).await? // Results in String on success
|
||||||
} else if app_state.ui.show_register {
|
} else if app_state.ui.show_register {
|
||||||
auth_e::execute_common_action(
|
auth_e::execute_common_action(
|
||||||
action,
|
action,
|
||||||
@@ -56,46 +61,66 @@ pub async fn handle_edit_event(
|
|||||||
grpc_client,
|
grpc_client,
|
||||||
current_position,
|
current_position,
|
||||||
total_count
|
total_count
|
||||||
).await
|
).await? // Results in String on success
|
||||||
} else {
|
} else {
|
||||||
form_e::execute_common_action(
|
let outcome = form_e::execute_common_action(
|
||||||
action,
|
action,
|
||||||
form_state, // Concrete FormState
|
form_state,
|
||||||
grpc_client,
|
grpc_client,
|
||||||
current_position,
|
current_position,
|
||||||
total_count
|
total_count
|
||||||
).await
|
).await?; // This returns EventOutcome on success
|
||||||
.map(|outcome| match outcome {
|
|
||||||
|
// Extract the message string from the EventOutcome
|
||||||
|
match outcome {
|
||||||
EventOutcome::Ok(msg) => msg,
|
EventOutcome::Ok(msg) => msg,
|
||||||
EventOutcome::Exit(msg) => format!("Exit requested: {}", msg),
|
EventOutcome::DataSaved(_, msg) => msg,
|
||||||
EventOutcome::DataSaved(save_outcome, msg) => format!("Data saved ({:?}): {}", save_outcome, msg),
|
_ => format!("Unexpected outcome from common action: {:?}", outcome),
|
||||||
EventOutcome::ButtonSelected { context, index } => {
|
|
||||||
"Unexpected action in edit mode".to_string()
|
|
||||||
}
|
}
|
||||||
})
|
};
|
||||||
}?;
|
// Wrap the resulting String message
|
||||||
return Ok(message);
|
return Ok(EditEventOutcome::Message(message_string));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Edit-specific actions
|
// Edit-specific actions
|
||||||
if let Some(action) = config.get_edit_action_for_key(key.code, key.modifiers) {
|
if let Some(action) = config.get_edit_action_for_key(key.code, key.modifiers) {
|
||||||
// --- Special Handling for Tab/Shift+Tab in Role Field ---
|
if action == "exit" {
|
||||||
|
if app_state.ui.show_register && register_state.in_suggestion_mode {
|
||||||
|
// Call the action, get Result<String, Error>
|
||||||
|
let msg = auth_e::execute_edit_action(
|
||||||
|
"exit_suggestion_mode",
|
||||||
|
key,
|
||||||
|
register_state,
|
||||||
|
ideal_cursor_column,
|
||||||
|
grpc_client,
|
||||||
|
current_position,
|
||||||
|
total_count,
|
||||||
|
).await?; // Results in String on success
|
||||||
|
// Wrap the String message
|
||||||
|
return Ok(EditEventOutcome::Message(msg));
|
||||||
|
} else {
|
||||||
|
// Signal exit
|
||||||
|
return Ok(EditEventOutcome::ExitEditMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special handling for role field suggestions
|
||||||
if app_state.ui.show_register && register_state.current_field() == 4 {
|
if app_state.ui.show_register && register_state.current_field() == 4 {
|
||||||
if !register_state.in_suggestion_mode && key.code == KeyCode::Tab && key.modifiers == KeyModifiers::NONE {
|
if !register_state.in_suggestion_mode && key.code == KeyCode::Tab && key.modifiers == KeyModifiers::NONE {
|
||||||
register_state.update_role_suggestions();
|
register_state.update_role_suggestions();
|
||||||
if !register_state.role_suggestions.is_empty() {
|
if !register_state.role_suggestions.is_empty() {
|
||||||
register_state.in_suggestion_mode = true;
|
register_state.in_suggestion_mode = true;
|
||||||
register_state.selected_suggestion_index = Some(0); // Select first suggestion
|
register_state.selected_suggestion_index = Some(0);
|
||||||
return Ok("Suggestions shown".to_string());
|
return Ok(EditEventOutcome::Message("Suggestions shown".to_string()));
|
||||||
} else {
|
} else { // Added else here for clarity
|
||||||
return Ok("No suggestions available".to_string());
|
return Ok(EditEventOutcome::Message("No suggestions available".to_string()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// --- End Special Handling ---
|
|
||||||
|
|
||||||
return if app_state.ui.show_login {
|
// Execute other edit actions
|
||||||
|
let msg = if app_state.ui.show_login {
|
||||||
auth_e::execute_edit_action(
|
auth_e::execute_edit_action(
|
||||||
action,
|
action,
|
||||||
key,
|
key,
|
||||||
@@ -104,7 +129,7 @@ pub async fn handle_edit_event(
|
|||||||
grpc_client,
|
grpc_client,
|
||||||
current_position,
|
current_position,
|
||||||
total_count
|
total_count
|
||||||
).await
|
).await? // Results in String
|
||||||
} else if app_state.ui.show_register {
|
} else if app_state.ui.show_register {
|
||||||
auth_e::execute_edit_action(
|
auth_e::execute_edit_action(
|
||||||
action,
|
action,
|
||||||
@@ -114,7 +139,7 @@ pub async fn handle_edit_event(
|
|||||||
grpc_client,
|
grpc_client,
|
||||||
current_position,
|
current_position,
|
||||||
total_count
|
total_count
|
||||||
).await
|
).await? // Results in String
|
||||||
} else {
|
} else {
|
||||||
form_e::execute_edit_action(
|
form_e::execute_edit_action(
|
||||||
action,
|
action,
|
||||||
@@ -124,22 +149,22 @@ pub async fn handle_edit_event(
|
|||||||
grpc_client,
|
grpc_client,
|
||||||
current_position,
|
current_position,
|
||||||
total_count
|
total_count
|
||||||
).await
|
).await? // Results in String
|
||||||
};
|
};
|
||||||
|
// Wrap the resulting String message
|
||||||
|
return Ok(EditEventOutcome::Message(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Character insertion
|
// Character insertion
|
||||||
if let KeyCode::Char(_) = key.code {
|
if let KeyCode::Char(_) = key.code {
|
||||||
// If in suggestion mode, exit it before inserting char
|
|
||||||
if app_state.ui.show_register && register_state.in_suggestion_mode {
|
if app_state.ui.show_register && register_state.in_suggestion_mode {
|
||||||
register_state.in_suggestion_mode = false;
|
register_state.in_suggestion_mode = false;
|
||||||
register_state.show_role_suggestions = false;
|
register_state.show_role_suggestions = false;
|
||||||
register_state.selected_suggestion_index = None;
|
register_state.selected_suggestion_index = None;
|
||||||
}
|
}
|
||||||
let is_role_field = app_state.ui.show_register && register_state.current_field() == 4;
|
|
||||||
// --- End Autocomplete Trigger ---
|
|
||||||
|
|
||||||
return if app_state.ui.show_login {
|
// Execute insert_char action
|
||||||
|
let msg = if app_state.ui.show_login {
|
||||||
auth_e::execute_edit_action(
|
auth_e::execute_edit_action(
|
||||||
"insert_char",
|
"insert_char",
|
||||||
key,
|
key,
|
||||||
@@ -148,7 +173,7 @@ pub async fn handle_edit_event(
|
|||||||
grpc_client,
|
grpc_client,
|
||||||
current_position,
|
current_position,
|
||||||
total_count
|
total_count
|
||||||
).await
|
).await? // Results in String
|
||||||
} else if app_state.ui.show_register {
|
} else if app_state.ui.show_register {
|
||||||
auth_e::execute_edit_action(
|
auth_e::execute_edit_action(
|
||||||
"insert_char",
|
"insert_char",
|
||||||
@@ -158,7 +183,7 @@ pub async fn handle_edit_event(
|
|||||||
grpc_client,
|
grpc_client,
|
||||||
current_position,
|
current_position,
|
||||||
total_count
|
total_count
|
||||||
).await
|
).await? // Results in String
|
||||||
} else {
|
} else {
|
||||||
form_e::execute_edit_action(
|
form_e::execute_edit_action(
|
||||||
"insert_char",
|
"insert_char",
|
||||||
@@ -168,23 +193,23 @@ pub async fn handle_edit_event(
|
|||||||
grpc_client,
|
grpc_client,
|
||||||
current_position,
|
current_position,
|
||||||
total_count
|
total_count
|
||||||
).await
|
).await? // Results in String
|
||||||
};
|
};
|
||||||
|
// Wrap the resulting String message
|
||||||
|
return Ok(EditEventOutcome::Message(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle Backspace/Delete for Autocomplete Trigger
|
// Handle Backspace/Delete
|
||||||
if matches!(key.code, KeyCode::Backspace | KeyCode::Delete) {
|
if matches!(key.code, KeyCode::Backspace | KeyCode::Delete) {
|
||||||
// If in suggestion mode, exit it before deleting char
|
|
||||||
if app_state.ui.show_register && register_state.in_suggestion_mode {
|
if app_state.ui.show_register && register_state.in_suggestion_mode {
|
||||||
register_state.in_suggestion_mode = false;
|
register_state.in_suggestion_mode = false;
|
||||||
register_state.show_role_suggestions = false;
|
register_state.show_role_suggestions = false;
|
||||||
register_state.selected_suggestion_index = None;
|
register_state.selected_suggestion_index = None;
|
||||||
}
|
}
|
||||||
let is_role_field = app_state.ui.show_register && register_state.current_field() == 4;
|
|
||||||
let action_str = if key.code == KeyCode::Backspace { "backspace" } else { "delete_char" };
|
|
||||||
|
|
||||||
// Execute the action first
|
let action_str = if key.code == KeyCode::Backspace { "backspace" } else { "delete_char" };
|
||||||
let result = if app_state.ui.show_register {
|
// Ensure both branches result in a String *before* wrapping
|
||||||
|
let result_msg: String = if app_state.ui.show_register {
|
||||||
auth_e::execute_edit_action(
|
auth_e::execute_edit_action(
|
||||||
action_str,
|
action_str,
|
||||||
key,
|
key,
|
||||||
@@ -193,14 +218,17 @@ pub async fn handle_edit_event(
|
|||||||
grpc_client,
|
grpc_client,
|
||||||
current_position,
|
current_position,
|
||||||
total_count
|
total_count
|
||||||
).await
|
).await? // Results in String
|
||||||
} else {
|
} else {
|
||||||
// Handle for login/form if needed, assuming auth_e covers RegisterState
|
// Return String directly, not Ok(String)
|
||||||
Ok("Action not applicable here".to_string()) // Placeholder
|
"Action not applicable here".to_string()
|
||||||
}?;
|
}; // Semicolon here ends the if/else expression
|
||||||
|
|
||||||
return Ok(result);
|
// Wrap the resulting String message
|
||||||
|
return Ok(EditEventOutcome::Message(result_msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(command_message.clone())
|
// Default return if no other handler matched
|
||||||
|
Ok(EditEventOutcome::Message("".to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -341,55 +341,14 @@ impl EventHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AppMode::Edit => {
|
AppMode::Edit => {
|
||||||
if config.get_edit_action_for_key(key_code, modifiers) == Some("exit_edit_mode") {
|
// First, check for common actions (save, revert, etc.) that apply in Edit mode
|
||||||
self.is_edit_mode = false;
|
// These might take precedence or have different behavior than the edit handler
|
||||||
self.edit_mode_cooldown = true;
|
if let Some(action) = config.get_common_action(key_code, modifiers) {
|
||||||
|
// Handle common actions like save, revert, force_quit, save_and_quit
|
||||||
let has_changes = if app_state.ui.show_login || app_state.ui.show_register{
|
// Ensure these actions return EventOutcome directly if they might exit the app
|
||||||
login_state.has_unsaved_changes()
|
|
||||||
} else {
|
|
||||||
form_state.has_unsaved_changes()
|
|
||||||
};
|
|
||||||
|
|
||||||
self.command_message = if has_changes {
|
|
||||||
"Exited edit mode (unsaved changes remain)".to_string()
|
|
||||||
} else {
|
|
||||||
"Read-only mode".to_string()
|
|
||||||
};
|
|
||||||
|
|
||||||
terminal.set_cursor_style(SetCursorStyle::SteadyBlock)?;
|
|
||||||
|
|
||||||
let current_input = if app_state.ui.show_login || app_state.ui.show_register{
|
|
||||||
login_state.get_current_input()
|
|
||||||
} else {
|
|
||||||
form_state.get_current_input()
|
|
||||||
};
|
|
||||||
let current_cursor_pos = if app_state.ui.show_login || app_state.ui.show_register{
|
|
||||||
login_state.current_cursor_pos()
|
|
||||||
} else {
|
|
||||||
form_state.current_cursor_pos()
|
|
||||||
};
|
|
||||||
|
|
||||||
if !current_input.is_empty() && current_cursor_pos >= current_input.len() {
|
|
||||||
let new_pos = current_input.len() - 1;
|
|
||||||
if app_state.ui.show_login || app_state.ui.show_register{
|
|
||||||
login_state.set_current_cursor_pos(new_pos);
|
|
||||||
self.ideal_cursor_column = login_state.current_cursor_pos();
|
|
||||||
} else {
|
|
||||||
form_state.set_current_cursor_pos(new_pos);
|
|
||||||
self.ideal_cursor_column = form_state.current_cursor_pos();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Ok(EventOutcome::Ok(self.command_message.clone()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(action) = config.get_action_for_key_in_mode(
|
|
||||||
&config.keybindings.common,
|
|
||||||
key_code,
|
|
||||||
modifiers
|
|
||||||
) {
|
|
||||||
match action {
|
match action {
|
||||||
"save" | "force_quit" | "save_and_quit" | "revert" => {
|
"save" | "force_quit" | "save_and_quit" | "revert" => {
|
||||||
|
// This call likely returns EventOutcome, handle it directly
|
||||||
return common_mode::handle_core_action(
|
return common_mode::handle_core_action(
|
||||||
action,
|
action,
|
||||||
form_state,
|
form_state,
|
||||||
@@ -404,27 +363,72 @@ impl EventHandler {
|
|||||||
total_count,
|
total_count,
|
||||||
).await;
|
).await;
|
||||||
},
|
},
|
||||||
|
// Handle other common actions if necessary
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
// If a common action was handled but didn't return/exit,
|
||||||
|
// we might want to stop further processing for this key event.
|
||||||
|
// Depending on the action, you might return Ok(EventOutcome::Ok(...)) here.
|
||||||
|
// For now, assume common actions either exit or don't prevent further processing.
|
||||||
}
|
}
|
||||||
|
|
||||||
let message = edit::handle_edit_event(
|
// If no common action took precedence, delegate to the edit-specific handler
|
||||||
|
let edit_result = edit::handle_edit_event(
|
||||||
key,
|
key,
|
||||||
config,
|
config,
|
||||||
form_state,
|
form_state,
|
||||||
login_state,
|
login_state,
|
||||||
register_state,
|
register_state,
|
||||||
&mut self.ideal_cursor_column,
|
&mut self.ideal_cursor_column,
|
||||||
&mut self.command_message,
|
|
||||||
current_position,
|
current_position,
|
||||||
total_count,
|
total_count,
|
||||||
grpc_client,
|
grpc_client,
|
||||||
app_state,
|
app_state,
|
||||||
).await?;
|
).await;
|
||||||
|
|
||||||
self.key_sequence_tracker.reset();
|
match edit_result {
|
||||||
return Ok(EventOutcome::Ok(message));
|
Ok(edit::EditEventOutcome::ExitEditMode) => {
|
||||||
},
|
// The edit handler signaled to exit the mode
|
||||||
|
self.is_edit_mode = false;
|
||||||
|
self.edit_mode_cooldown = true;
|
||||||
|
let has_changes = if app_state.ui.show_login { login_state.has_unsaved_changes() }
|
||||||
|
else if app_state.ui.show_register { register_state.has_unsaved_changes() }
|
||||||
|
else { form_state.has_unsaved_changes() };
|
||||||
|
self.command_message = if has_changes {
|
||||||
|
"Exited edit mode (unsaved changes remain)".to_string()
|
||||||
|
} else {
|
||||||
|
"Read-only mode".to_string()
|
||||||
|
};
|
||||||
|
terminal.set_cursor_style(SetCursorStyle::SteadyBlock)?;
|
||||||
|
// Adjust cursor position if needed
|
||||||
|
let current_input = if app_state.ui.show_login { login_state.get_current_input() }
|
||||||
|
else if app_state.ui.show_register { register_state.get_current_input() }
|
||||||
|
else { form_state.get_current_input() };
|
||||||
|
let current_cursor_pos = if app_state.ui.show_login { login_state.current_cursor_pos() }
|
||||||
|
else if app_state.ui.show_register { register_state.current_cursor_pos() }
|
||||||
|
else { form_state.current_cursor_pos() };
|
||||||
|
if !current_input.is_empty() && current_cursor_pos >= current_input.len() {
|
||||||
|
let new_pos = current_input.len() - 1;
|
||||||
|
let target_state: &mut dyn CanvasState = if app_state.ui.show_login { login_state } else if app_state.ui.show_register { register_state } else { form_state };
|
||||||
|
target_state.set_current_cursor_pos(new_pos);
|
||||||
|
self.ideal_cursor_column = new_pos;
|
||||||
|
}
|
||||||
|
return Ok(EventOutcome::Ok(self.command_message.clone()));
|
||||||
|
}
|
||||||
|
Ok(edit::EditEventOutcome::Message(msg)) => {
|
||||||
|
// Stay in edit mode, update message if not empty
|
||||||
|
if !msg.is_empty() {
|
||||||
|
self.command_message = msg;
|
||||||
|
}
|
||||||
|
self.key_sequence_tracker.reset(); // Reset sequence tracker on successful edit action
|
||||||
|
return Ok(EventOutcome::Ok(self.command_message.clone()));
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
// Handle error from the edit handler
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, // End AppMode::Edit
|
||||||
|
|
||||||
AppMode::Command => {
|
AppMode::Command => {
|
||||||
let outcome = command_mode::handle_command_event(
|
let outcome = command_mode::handle_command_event(
|
||||||
|
|||||||
Reference in New Issue
Block a user