diff --git a/client/config.toml b/client/config.toml index a10e1e7..5109841 100644 --- a/client/config.toml +++ b/client/config.toml @@ -11,6 +11,7 @@ force_quit = ["ctrl+shift+q"] save_and_quit = ["ctrl+shift+s"] move_up = ["Up"] move_down = ["Down"] +toggle_sidebar = ["ctrl+t"] # MODE SPECIFIC # READ ONLY MODE diff --git a/client/src/components/handlers.rs b/client/src/components/handlers.rs index 3507b73..d0095f5 100644 --- a/client/src/components/handlers.rs +++ b/client/src/components/handlers.rs @@ -4,9 +4,11 @@ pub mod preview_card; pub mod command_line; pub mod status_line; pub mod canvas; +pub mod sidebar; pub use command_line::render_command_line; pub use form::*; pub use preview_card::render_preview_card; pub use status_line::render_status_line; pub use canvas::*; +pub use sidebar::*; diff --git a/client/src/components/handlers/sidebar.rs b/client/src/components/handlers/sidebar.rs new file mode 100644 index 0000000..d58db50 --- /dev/null +++ b/client/src/components/handlers/sidebar.rs @@ -0,0 +1,29 @@ +// src/components/handlers/sidebar.rs +use ratatui::{ + widgets::{Block, Borders, List, ListItem}, + layout::Rect, + style::Style, + text::Text, + Frame, +}; +use crate::config::colors::Theme; + +pub fn render_sidebar(f: &mut Frame, area: Rect, theme: &Theme) { + let sidebar_block = Block::default() + .borders(Borders::RIGHT) + .border_style(Style::default().fg(theme.border)) + .style(Style::default().bg(theme.bg)); + + let items = vec![ + ListItem::new(Text::from(" Navigation ")), + ListItem::new(Text::from(" Search ")), + ListItem::new(Text::from(" Settings ")), + ]; + + let list = List::new(items) + .block(sidebar_block) + .highlight_style(Style::default().fg(theme.highlight)) + .highlight_symbol(">>"); + + f.render_widget(list, area); +} diff --git a/client/src/modes/handlers/event.rs b/client/src/modes/handlers/event.rs index 0c9303e..b4460a4 100644 --- a/client/src/modes/handlers/event.rs +++ b/client/src/modes/handlers/event.rs @@ -1,6 +1,6 @@ // src/modes/handlers/event.rs -use crossterm::event::Event; +use crossterm::event::{Event, KeyCode, KeyModifiers}; use crossterm::cursor::SetCursorStyle; use crate::tui::terminal::{ core::TerminalCore, @@ -9,6 +9,8 @@ use crate::tui::terminal::{ }; use crate::config::config::Config; use crate::ui::handlers::form::FormState; +use crate::ui::handlers::rat_state::UiStateHandler; +use crate::state::state::AppState; use crate::modes::handlers::{edit, command_mode, read_only}; use crate::config::key_sequences::KeySequenceTracker; use super::common; @@ -44,22 +46,36 @@ impl EventHandler { grpc_client: &mut GrpcClient, command_handler: &mut CommandHandler, form_state: &mut FormState, - is_saved: &mut bool, + app_state: &mut crate::state::state::AppState, total_count: u64, current_position: &mut u64, ) -> Result<(bool, String), Box> { if let Event::Key(key) = event { + let key_code = key.code; + let modifiers = key.modifiers; + + if UiStateHandler::toggle_sidebar( + &mut app_state.ui, + config, + key_code, + modifiers, + ) { + return Ok((false, format!("Sidebar {}", + if app_state.ui.show_sidebar { "shown" } else { "hidden" } + ))); + } + if let Some(action) = config.get_action_for_key_in_mode( &config.keybindings.common, - key.code, - key.modifiers + key_code, + modifiers ) { match action { "save" => { let message = common::save( form_state, grpc_client, - is_saved, + &mut app_state.is_saved, current_position, total_count, ).await?; @@ -94,7 +110,7 @@ impl EventHandler { &mut self.command_input, &mut self.command_message, grpc_client, - is_saved, + &mut app_state.is_saved, current_position, total_count, ).await?; @@ -107,7 +123,7 @@ impl EventHandler { } if self.is_edit_mode { - if config.is_exit_edit_mode(key.code, key.modifiers) { + if config.is_exit_edit_mode(key_code, modifiers) { if form_state.has_unsaved_changes { self.command_message = "Unsaved changes! Use :w to save or :q! to discard".to_string(); return Ok((false, self.command_message.clone())); @@ -131,7 +147,7 @@ impl EventHandler { form_state, &mut self.ideal_cursor_column, &mut self.command_message, - is_saved, + &mut app_state.is_saved, current_position, total_count, grpc_client, @@ -140,7 +156,7 @@ impl EventHandler { self.key_sequence_tracker.reset(); return Ok((false, result)); } else { - if let Some(action) = config.get_read_only_action_for_key(key.code, key.modifiers) { + if let Some(action) = config.get_read_only_action_for_key(key_code, modifiers) { if action == "enter_command_mode" { self.command_mode = true; self.command_input.clear(); @@ -149,7 +165,7 @@ impl EventHandler { } } - if config.is_enter_edit_mode_before(key.code, key.modifiers) { + if config.is_enter_edit_mode_before(key_code, modifiers) { self.is_edit_mode = true; self.edit_mode_cooldown = true; self.command_message = "Edit mode".to_string(); @@ -157,7 +173,7 @@ impl EventHandler { return Ok((false, self.command_message.clone())); } - if config.is_enter_edit_mode_after(key.code, key.modifiers) { + if config.is_enter_edit_mode_after(key_code, modifiers) { let current_input = form_state.get_current_input(); if !current_input.is_empty() && form_state.current_cursor_pos < current_input.len() { form_state.current_cursor_pos += 1; diff --git a/client/src/state/state.rs b/client/src/state/state.rs index d1330ba..8ef3012 100644 --- a/client/src/state/state.rs +++ b/client/src/state/state.rs @@ -2,11 +2,21 @@ use std::env; +#[derive(Default)] +pub struct UiState { + pub show_sidebar: bool, + // Add other UI-related states here +} + pub struct AppState { + // Core editor state pub is_saved: bool, pub current_dir: String, pub total_count: u64, pub current_position: u64, + + // UI preferences + pub ui: UiState, } impl AppState { @@ -19,9 +29,11 @@ impl AppState { current_dir, total_count: 0, current_position: 0, + ui: UiState::default(), }) } + // Existing methods remain unchanged pub fn update_total_count(&mut self, total_count: u64) { self.total_count = total_count; } diff --git a/client/src/text.txt b/client/src/text.txt new file mode 100644 index 0000000..c76f808 --- /dev/null +++ b/client/src/text.txt @@ -0,0 +1 @@ +cat src/modes/handlers/event.rs src/state/state.rs src/ui/handlers.rs src/ui/handlers/render.rs src/ui/handlers/ui.rs src/components/handlers.rs diff --git a/client/src/ui/handlers.rs b/client/src/ui/handlers.rs index a84185e..cbee7e7 100644 --- a/client/src/ui/handlers.rs +++ b/client/src/ui/handlers.rs @@ -3,5 +3,7 @@ pub mod ui; pub mod form; pub mod render; +pub mod rat_state; pub use ui::run_ui; +pub use rat_state::*; diff --git a/client/src/ui/handlers/rat_state.rs b/client/src/ui/handlers/rat_state.rs new file mode 100644 index 0000000..93b8060 --- /dev/null +++ b/client/src/ui/handlers/rat_state.rs @@ -0,0 +1,45 @@ +// src/ui/handlers/rat_state.rs +use crossterm::event::{KeyCode, KeyModifiers}; +use crate::config::config::Config; +use crate::state::state::UiState; + +pub struct UiStateHandler; + +impl UiStateHandler { + pub fn toggle_sidebar( + ui_state: &mut UiState, + config: &Config, + key: KeyCode, + modifiers: KeyModifiers, + ) -> bool { + if let Some(action) = config.get_action_for_key_in_mode(&config.keybindings.common, key, modifiers) { + if action == "toggle_sidebar" { + ui_state.show_sidebar = !ui_state.show_sidebar; + return true; + } + } + false + } + + // Keep your existing handle_ui_action method if you need it for other UI actions + pub fn handle_ui_action( + ui_state: &mut UiState, + config: &Config, + key: KeyCode, + modifiers: KeyModifiers, + ) -> bool { + let mut action_performed = false; + + // Check for sidebar toggle + if let Some(action) = config.get_action_for_key_in_mode(&config.keybindings.common, key, modifiers) { + if action == "toggle_sidebar" { + ui_state.show_sidebar = !ui_state.show_sidebar; + action_performed = true; + } + } + + // Add other UI actions here following the same pattern + + action_performed + } +} diff --git a/client/src/ui/handlers/render.rs b/client/src/ui/handlers/render.rs index c92f033..e1799cd 100644 --- a/client/src/ui/handlers/render.rs +++ b/client/src/ui/handlers/render.rs @@ -5,6 +5,7 @@ use crate::config::colors::Theme; use ratatui::layout::{Constraint, Direction, Layout}; use ratatui::Frame; use super::form::FormState; +use crate::state::state::UiState; pub fn render_ui( f: &mut Frame, @@ -17,6 +18,7 @@ pub fn render_ui( command_input: &str, command_mode: bool, command_message: &str, + ui_state: &UiState, ) { let root = Layout::default() .direction(Direction::Vertical) @@ -45,6 +47,10 @@ pub fn render_ui( &theme, ); + if ui_state.show_sidebar { + crate::components::handlers::sidebar::render_sidebar(f, main_chunks[0], theme); + } + // Status line render_status_line(f, root[1], current_dir, theme, is_edit_mode); diff --git a/client/src/ui/handlers/ui.rs b/client/src/ui/handlers/ui.rs index 5ae5398..0a21bb2 100644 --- a/client/src/ui/handlers/ui.rs +++ b/client/src/ui/handlers/ui.rs @@ -59,9 +59,13 @@ pub async fn run_ui() -> Result<(), Box> { &event_handler.command_input, event_handler.command_mode, &event_handler.command_message, + &app_state.ui, ); })?; + let total_count = app_state.total_count; + let mut current_position = app_state.current_position; + let event = event_reader.read_event()?; let (should_exit, message) = event_handler.handle_event( event, @@ -70,11 +74,13 @@ pub async fn run_ui() -> Result<(), Box> { &mut grpc_client, &mut command_handler, &mut form_state, - &mut app_state.is_saved, - app_state.total_count, - &mut app_state.current_position, + &mut app_state, + total_count, + &mut current_position, ).await?; + app_state.current_position = current_position; + // Handle position changes and update form state if !event_handler.is_edit_mode { let current_input = form_state.get_current_input();