mirror of
https://github.com/ClementTsang/bottom
synced 2024-11-22 20:23:12 +00:00
Add basic cursor movement + visuals + control to search
Add basic cursor movement + control to search
This commit is contained in:
parent
cc5c6f4d87
commit
40be97eaf4
3 changed files with 102 additions and 15 deletions
70
src/app.rs
70
src/app.rs
|
@ -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,
|
||||||
|
|
|
@ -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(
|
||||||
|
|
14
src/main.rs
14
src/main.rs
|
@ -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') => {
|
||||||
|
|
Loading…
Reference in a new issue