From 9e1cd25603b6b1637d7159608d8b14d8c73eb203 Mon Sep 17 00:00:00 2001 From: afonsofrancof Date: Thu, 8 Aug 2024 23:45:49 +0100 Subject: [PATCH 1/2] Merge from main --- src/main.rs | 67 +++++++++------------------------------- src/search.rs | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/theme.rs | 6 ++++ 3 files changed, 106 insertions(+), 52 deletions(-) create mode 100644 src/search.rs diff --git a/src/main.rs b/src/main.rs index f7ae28ca..29836734 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,9 +2,11 @@ mod float; mod floating_text; mod list; mod running_command; +mod search; pub mod state; mod theme; +use crate::search::SearchBar; use std::{ io::{self, stdout}, time::Duration, @@ -24,9 +26,6 @@ use list::CustomList; use ratatui::{ backend::{Backend, CrosstermBackend}, layout::{Constraint, Direction, Layout}, - style::{Color, Style}, - text::Span, - widgets::{Block, Borders, Paragraph}, Terminal, }; use running_command::RunningCommand; @@ -79,13 +78,12 @@ fn main() -> std::io::Result<()> { } fn run(terminal: &mut Terminal, state: &AppState) -> io::Result<()> { - //Create the search field - let mut search_input = String::new(); //Create the command list let mut custom_list = CustomList::new(); //Create the float to hold command output let mut command_float = Float::new(60, 60); - let mut in_search_mode = false; + //Create the search bar + let mut search_bar = SearchBar::new(); loop { // Always redraw @@ -98,29 +96,8 @@ fn run(terminal: &mut Terminal, state: &AppState) -> io::Result<( .constraints([Constraint::Length(3), Constraint::Min(1)].as_ref()) .split(frame.size()); - //Set the search bar text (If empty use the placeholder) - let display_text = if search_input.is_empty() { - if in_search_mode { - Span::raw("") - } else { - Span::raw("Press / to search") - } - } else { - Span::raw(&search_input) - }; - - //Create the search bar widget - let mut search_bar = Paragraph::new(display_text) - .block(Block::default().borders(Borders::ALL).title("Search")) - .style(Style::default().fg(Color::DarkGray)); - - //Change the color if in search mode - if in_search_mode { - search_bar = search_bar.clone().style(Style::default().fg(Color::Blue)); - } - - //Render the search bar (First chunk of the screen) - frame.render_widget(search_bar, chunks[0]); + //Render the search bar + search_bar.draw(frame, chunks[0], state); //Render the command list (Second chunk of the screen) custom_list.draw(frame, chunks[1], state); //Render the command float in the custom_list chunk @@ -146,28 +123,14 @@ fn run(terminal: &mut Terminal, state: &AppState) -> io::Result<( //If that's the case, don't propagate input to other widgets if !command_float.handle_key_event(&key) { //Insert user input into the search bar - if in_search_mode { - match key.code { - KeyCode::Char(c) => { - search_input.push(c); - custom_list.filter(search_input.clone()); - } - KeyCode::Backspace => { - search_input.pop(); - custom_list.filter(search_input.clone()); - } - KeyCode::Esc => { - search_input = String::new(); - custom_list.filter(search_input.clone()); - in_search_mode = false - } - KeyCode::Enter => { - in_search_mode = false; - custom_list.reset_selection(); - } - _ => {} - } - } else if let Some(cmd) = custom_list.handle_key(key, state) { + //Send the keys to the search bar + if search_bar.is_search_active() { + let search_query = search_bar.handle_key(key); + custom_list.reset_selection(); + custom_list.filter(search_query); + } + // Else, send them to the list + else if let Some(cmd) = custom_list.handle_key(key, state) { command_float.set_content(Some(RunningCommand::new(cmd, state))); } else { // Handle keys while not in search mode @@ -176,7 +139,7 @@ fn run(terminal: &mut Terminal, state: &AppState) -> io::Result<( KeyCode::Char('q') => return Ok(()), //Activate search mode if the forward slash key gets pressed KeyCode::Char('/') => { - in_search_mode = true; + search_bar.activate_search(); continue; } _ => {} diff --git a/src/search.rs b/src/search.rs new file mode 100644 index 00000000..f58c0d5f --- /dev/null +++ b/src/search.rs @@ -0,0 +1,85 @@ +use crossterm::event::{KeyCode, KeyEvent}; +use ratatui::{ + layout::Rect, + style::Style, + text::Span, + widgets::{Block, Borders, Paragraph}, + Frame, +}; + +use crate::state::AppState; + +pub struct SearchBar { + search_input: String, + in_search_mode: bool, +} + +impl SearchBar { + pub fn new() -> Self { + SearchBar { + search_input: String::new(), + in_search_mode: false, + } + } + + pub fn activate_search(&mut self) { + self.in_search_mode = true; + } + + pub fn deactivate_search(&mut self) { + self.in_search_mode = false; + } + + pub fn is_search_active(&self) -> bool { + self.in_search_mode + } + + pub fn draw(&self, frame: &mut Frame, area: Rect, state: &AppState) { + //Set the search bar text (If empty use the placeholder) + let display_text = if self.search_input.is_empty() { + if self.in_search_mode { + Span::raw("") + } else { + Span::raw("Press / to search") + } + } else { + Span::raw(&self.search_input) + }; + + //Create the search bar widget + let mut search_bar = Paragraph::new(display_text) + .block(Block::default().borders(Borders::ALL).title("Search")) + .style(Style::default().fg(state.theme.unfocused_color)); + + //Change the color if in search mode + if self.in_search_mode { + search_bar = search_bar + .clone() + .style(Style::default().fg(state.theme.focused_color)); + } + + //Render the search bar (First chunk of the screen) + frame.render_widget(search_bar, area); + } + + pub fn handle_key(&mut self, event: KeyEvent) -> String { + //Insert user input into the search bar + match event.code { + KeyCode::Char(c) => { + self.search_input.push(c); + } + KeyCode::Backspace => { + self.search_input.pop(); + } + KeyCode::Esc => { + self.search_input = String::new(); + self.in_search_mode = false; + } + KeyCode::Enter => { + self.in_search_mode = false; + } + _ => {} + } + self.search_input.clone() + } +} diff --git a/src/theme.rs b/src/theme.rs index 4792cddc..45763eb8 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -8,6 +8,8 @@ pub struct Theme { pub cmd_icon: &'static str, pub success_color: Color, pub fail_color: Color, + pub focused_color: Color, + pub unfocused_color: Color, } pub const THEMES: [Theme; 2] = [ @@ -18,6 +20,8 @@ pub const THEMES: [Theme; 2] = [ cmd_icon: "[CMD]", success_color: Color::Green, fail_color: Color::Red, + focused_color: Color::LightBlue, + unfocused_color: Color::Gray, }, Theme { dir_color: Color::Blue, @@ -26,5 +30,7 @@ pub const THEMES: [Theme; 2] = [ cmd_icon: "  ", fail_color: Color::Rgb(199, 55, 44), success_color: Color::Rgb(5, 255, 55), + focused_color: Color::LightBlue, + unfocused_color: Color::Gray, }, ]; From 5cddfdb1623b40337e760d9b9f568310b036208c Mon Sep 17 00:00:00 2001 From: afonsofrancof Date: Fri, 2 Aug 2024 01:08:07 +0100 Subject: [PATCH 2/2] Simplified placeholder text logic Co-authored-by: Andrii Dokhniak --- src/search.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/search.rs b/src/search.rs index f58c0d5f..68827c24 100644 --- a/src/search.rs +++ b/src/search.rs @@ -36,12 +36,8 @@ impl SearchBar { pub fn draw(&self, frame: &mut Frame, area: Rect, state: &AppState) { //Set the search bar text (If empty use the placeholder) - let display_text = if self.search_input.is_empty() { - if self.in_search_mode { - Span::raw("") - } else { - Span::raw("Press / to search") - } + let display_text = if !self.in_search_mode && self.search_input.is_empty() { + Span::raw("Press / to search") } else { Span::raw(&self.search_input) };