Merge pull request #120 from afonsofrancof:cleanup_search

Move search bar widget to a separate file
This commit is contained in:
Chris Titus 2024-08-15 14:51:53 -05:00 committed by GitHub
commit fe76cfcf51
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 102 additions and 52 deletions

View File

@ -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<B: Backend>(terminal: &mut Terminal<B>, 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<B: Backend>(terminal: &mut Terminal<B>, 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<B: Backend>(terminal: &mut Terminal<B>, 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<B: Backend>(terminal: &mut Terminal<B>, 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;
}
_ => {}

81
src/search.rs Normal file
View File

@ -0,0 +1,81 @@
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.in_search_mode && self.search_input.is_empty() {
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()
}
}

View File

@ -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,
},
];