Add basic cursor movement + visuals + control to search

Add basic cursor movement + control to search
This commit is contained in:
ClementTsang 2020-01-16 21:33:06 -05:00
parent cc5c6f4d87
commit 40be97eaf4
3 changed files with 102 additions and 15 deletions

View file

@ -68,6 +68,7 @@ pub struct App {
searching_pid: bool, searching_pid: bool,
pub use_simple: bool, pub use_simple: bool,
current_regex: std::result::Result<regex::Regex, regex::Error>, current_regex: std::result::Result<regex::Regex, regex::Error>,
current_cursor_position: usize,
} }
impl App { impl App {
@ -112,6 +113,7 @@ impl App {
searching_pid: false, searching_pid: false,
use_simple: false, use_simple: false,
current_regex: BASE_REGEX.clone(), //TODO: [OPT] seems like a thing we can switch to lifetimes to avoid cloning current_regex: BASE_REGEX.clone(), //TODO: [OPT] seems like a thing we can switch to lifetimes to avoid cloning
current_cursor_position: 0,
} }
} }
@ -235,6 +237,10 @@ impl App {
} }
} }
pub fn get_cursor_position(&self) -> usize {
self.current_cursor_position
}
/// One of two functions allowed to run while in a dialog... /// One of two functions allowed to run while in a dialog...
pub fn on_enter(&mut self) { pub fn on_enter(&mut self) {
if self.show_dd { if self.show_dd {
@ -254,7 +260,18 @@ impl App {
pub fn on_backspace(&mut self) { pub fn on_backspace(&mut self) {
if let ApplicationPosition::ProcessSearch = self.current_application_position { if let ApplicationPosition::ProcessSearch = self.current_application_position {
self.current_search_query.pop(); if self.current_cursor_position > 0 {
self.current_cursor_position -= 1;
self.current_search_query
.remove(self.current_cursor_position);
// TODO: [OPT] this runs even while in simple... consider making this only run if they toggle back to regex!
self.current_regex = if self.current_search_query.is_empty() {
BASE_REGEX.clone()
} else {
regex::Regex::new(&(self.current_search_query))
};
}
} }
} }
@ -262,6 +279,44 @@ impl App {
&self.current_regex &self.current_regex
} }
pub fn on_up_key(&mut self) {
if !self.is_in_dialog() {
if let ApplicationPosition::ProcessSearch = self.current_application_position {
} else {
self.decrement_position_count();
}
}
}
pub fn on_down_key(&mut self) {
if !self.is_in_dialog() {
if let ApplicationPosition::ProcessSearch = self.current_application_position {
} else {
self.increment_position_count();
}
}
}
pub fn on_left_key(&mut self) {
if !self.is_in_dialog() {
if let ApplicationPosition::ProcessSearch = self.current_application_position {
if self.current_cursor_position > 0 {
self.current_cursor_position -= 1;
}
}
}
}
pub fn on_right_key(&mut self) {
if !self.is_in_dialog() {
if let ApplicationPosition::ProcessSearch = self.current_application_position {
if self.current_cursor_position < self.current_search_query.len() {
self.current_cursor_position += 1;
}
}
}
}
pub fn on_char_key(&mut self, caught_char: char) { pub fn on_char_key(&mut self, caught_char: char) {
// Forbid any char key presses when showing a dialog box... // Forbid any char key presses when showing a dialog box...
if !self.is_in_dialog() { if !self.is_in_dialog() {
@ -275,8 +330,11 @@ impl App {
self.last_key_press = current_key_press_inst; self.last_key_press = current_key_press_inst;
if let ApplicationPosition::ProcessSearch = self.current_application_position { if let ApplicationPosition::ProcessSearch = self.current_application_position {
self.current_search_query.push(caught_char); self.current_search_query
.insert(self.current_cursor_position, caught_char);
self.current_cursor_position += 1;
// TODO: [OPT] this runs even while in simple... consider making this only run if they toggle back to regex!
self.current_regex = if self.current_search_query.is_empty() { self.current_regex = if self.current_search_query.is_empty() {
BASE_REGEX.clone() BASE_REGEX.clone()
} else { } else {
@ -432,7 +490,7 @@ impl App {
// Network -(up)> MEM, -(right)> PROC // Network -(up)> MEM, -(right)> PROC
// PROC -(up)> Disk OR PROC_SEARCH if enabled, -(left)> Network // PROC -(up)> Disk OR PROC_SEARCH if enabled, -(left)> Network
// PROC_SEARCH -(up)> Disk, -(down)> PROC, -(left)> Network // PROC_SEARCH -(up)> Disk, -(down)> PROC, -(left)> Network
pub fn on_left(&mut self) { pub fn move_left(&mut self) {
if !self.is_in_dialog() { if !self.is_in_dialog() {
self.current_application_position = match self.current_application_position { self.current_application_position = match self.current_application_position {
ApplicationPosition::Process => ApplicationPosition::Network, ApplicationPosition::Process => ApplicationPosition::Network,
@ -445,7 +503,7 @@ impl App {
} }
} }
pub fn on_right(&mut self) { pub fn move_right(&mut self) {
if !self.is_in_dialog() { if !self.is_in_dialog() {
self.current_application_position = match self.current_application_position { self.current_application_position = match self.current_application_position {
ApplicationPosition::Mem => ApplicationPosition::Temp, ApplicationPosition::Mem => ApplicationPosition::Temp,
@ -456,7 +514,7 @@ impl App {
} }
} }
pub fn on_up(&mut self) { pub fn move_up(&mut self) {
if !self.is_in_dialog() { if !self.is_in_dialog() {
self.current_application_position = match self.current_application_position { self.current_application_position = match self.current_application_position {
ApplicationPosition::Mem => ApplicationPosition::Cpu, ApplicationPosition::Mem => ApplicationPosition::Cpu,
@ -477,7 +535,7 @@ impl App {
} }
} }
pub fn on_down(&mut self) { pub fn move_down(&mut self) {
if !self.is_in_dialog() { if !self.is_in_dialog() {
self.current_application_position = match self.current_application_position { self.current_application_position = match self.current_application_position {
ApplicationPosition::Cpu => ApplicationPosition::Mem, ApplicationPosition::Cpu => ApplicationPosition::Mem,

View file

@ -900,7 +900,7 @@ fn draw_disk_table<B: backend::Backend>(
fn draw_search_field<B: backend::Backend>( fn draw_search_field<B: backend::Backend>(
f: &mut Frame<B>, app_state: &mut app::App, draw_loc: Rect, f: &mut Frame<B>, app_state: &mut app::App, draw_loc: Rect,
) { ) {
let width = draw_loc.width - 18; // TODO [SEARCH] this is hardcoded... ew let width = draw_loc.width - 18; // TODO [SEARCH] this is hard-coded... ew
let query = app_state.get_current_search_query(); let query = app_state.get_current_search_query();
let shrunk_query = if query.len() < width as usize { let shrunk_query = if query.len() < width as usize {
query query
@ -908,7 +908,32 @@ fn draw_search_field<B: backend::Backend>(
&query[(query.len() - width as usize)..] &query[(query.len() - width as usize)..]
}; };
let search_text = [ // TODO: [SEARCH] Consider making this look prettier
let cursor_position = app_state.get_cursor_position();
// TODO: [SEARCH] This can be optimized...
let mut query_with_cursor: Vec<Text> = shrunk_query
.chars()
.enumerate()
.map(|(itx, c)| {
if itx == cursor_position {
Text::styled(
c.to_string(),
Style::default().fg(TEXT_COLOUR).bg(TABLE_HEADER_COLOUR),
)
} else {
Text::styled(c.to_string(), Style::default().fg(TEXT_COLOUR))
}
})
.collect::<Vec<_>>();
if cursor_position >= query.len() {
query_with_cursor.push(Text::styled(
" ".to_string(),
Style::default().fg(TEXT_COLOUR).bg(TABLE_HEADER_COLOUR),
))
}
let mut search_text = vec![
if app_state.is_searching_with_pid() { if app_state.is_searching_with_pid() {
Text::styled("\nPID", Style::default().fg(TABLE_HEADER_COLOUR)) Text::styled("\nPID", Style::default().fg(TABLE_HEADER_COLOUR))
} else { } else {
@ -919,8 +944,10 @@ fn draw_search_field<B: backend::Backend>(
} else { } else {
Text::styled(" (Regex): ", Style::default().fg(TABLE_HEADER_COLOUR)) Text::styled(" (Regex): ", Style::default().fg(TABLE_HEADER_COLOUR))
}, },
Text::raw(shrunk_query),
]; ];
search_text.extend(query_with_cursor);
// TODO: [SEARCH] Gotta make this easier to understand... it's pretty ugly cramming controls like this // TODO: [SEARCH] Gotta make this easier to understand... it's pretty ugly cramming controls like this
Paragraph::new(search_text.iter()) Paragraph::new(search_text.iter())
.block( .block(

View file

@ -227,8 +227,10 @@ fn main() -> error::Result<()> {
match event.code { match event.code {
KeyCode::End => app.skip_to_last(), KeyCode::End => app.skip_to_last(),
KeyCode::Home => app.skip_to_first(), KeyCode::Home => app.skip_to_first(),
KeyCode::Up => app.decrement_position_count(), KeyCode::Up => app.on_up_key(),
KeyCode::Down => app.increment_position_count(), KeyCode::Down => app.on_down_key(),
KeyCode::Left => app.on_left_key(),
KeyCode::Right => app.on_right_key(),
KeyCode::Char(character) => app.on_char_key(character), KeyCode::Char(character) => app.on_char_key(character),
KeyCode::Esc => app.on_esc(), KeyCode::Esc => app.on_esc(),
KeyCode::Enter => app.on_enter(), KeyCode::Enter => app.on_enter(),
@ -242,10 +244,10 @@ fn main() -> error::Result<()> {
match event.code { match event.code {
KeyCode::Char('c') => break, KeyCode::Char('c') => break,
KeyCode::Char('f') => app.toggle_searching(), // Note that this is fine for now, assuming '/' does not do anything other than search. KeyCode::Char('f') => app.toggle_searching(), // Note that this is fine for now, assuming '/' does not do anything other than search.
KeyCode::Left | KeyCode::Char('h') => app.on_left(), KeyCode::Left | KeyCode::Char('h') => app.move_left(),
KeyCode::Right | KeyCode::Char('l') => app.on_right(), KeyCode::Right | KeyCode::Char('l') => app.move_right(),
KeyCode::Up | KeyCode::Char('k') => app.on_up(), KeyCode::Up | KeyCode::Char('k') => app.move_up(),
KeyCode::Down | KeyCode::Char('j') => app.on_down(), KeyCode::Down | KeyCode::Char('j') => app.move_down(),
KeyCode::Char('p') => app.search_with_pid(), KeyCode::Char('p') => app.search_with_pid(),
KeyCode::Char('n') => app.search_with_name(), KeyCode::Char('n') => app.search_with_name(),
KeyCode::Char('r') => { KeyCode::Char('r') => {