mirror of
https://github.com/ChrisTitusTech/linutil.git
synced 2024-12-24 12:29:44 +00:00
Merge from main
This commit is contained in:
parent
4c38069b83
commit
9e1cd25603
67
src/main.rs
67
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<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;
|
||||
}
|
||||
_ => {}
|
||||
|
|
85
src/search.rs
Normal file
85
src/search.rs
Normal file
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
},
|
||||
];
|
||||
|
|
Loading…
Reference in New Issue
Block a user