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,
|
||||
pub use_simple: bool,
|
||||
current_regex: std::result::Result<regex::Regex, regex::Error>,
|
||||
current_cursor_position: usize,
|
||||
}
|
||||
|
||||
impl App {
|
||||
|
@ -112,6 +113,7 @@ impl App {
|
|||
searching_pid: false,
|
||||
use_simple: false,
|
||||
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...
|
||||
pub fn on_enter(&mut self) {
|
||||
if self.show_dd {
|
||||
|
@ -254,7 +260,18 @@ impl App {
|
|||
|
||||
pub fn on_backspace(&mut self) {
|
||||
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
|
||||
}
|
||||
|
||||
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) {
|
||||
// Forbid any char key presses when showing a dialog box...
|
||||
if !self.is_in_dialog() {
|
||||
|
@ -275,8 +330,11 @@ impl App {
|
|||
self.last_key_press = current_key_press_inst;
|
||||
|
||||
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() {
|
||||
BASE_REGEX.clone()
|
||||
} else {
|
||||
|
@ -432,7 +490,7 @@ impl App {
|
|||
// Network -(up)> MEM, -(right)> PROC
|
||||
// PROC -(up)> Disk OR PROC_SEARCH if enabled, -(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() {
|
||||
self.current_application_position = match self.current_application_position {
|
||||
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() {
|
||||
self.current_application_position = match self.current_application_position {
|
||||
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() {
|
||||
self.current_application_position = match self.current_application_position {
|
||||
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() {
|
||||
self.current_application_position = match self.current_application_position {
|
||||
ApplicationPosition::Cpu => ApplicationPosition::Mem,
|
||||
|
|
|
@ -900,7 +900,7 @@ fn draw_disk_table<B: backend::Backend>(
|
|||
fn draw_search_field<B: backend::Backend>(
|
||||
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 shrunk_query = if query.len() < width as usize {
|
||||
query
|
||||
|
@ -908,7 +908,32 @@ fn draw_search_field<B: backend::Backend>(
|
|||
&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() {
|
||||
Text::styled("\nPID", Style::default().fg(TABLE_HEADER_COLOUR))
|
||||
} else {
|
||||
|
@ -919,8 +944,10 @@ fn draw_search_field<B: backend::Backend>(
|
|||
} else {
|
||||
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
|
||||
Paragraph::new(search_text.iter())
|
||||
.block(
|
||||
|
|
14
src/main.rs
14
src/main.rs
|
@ -227,8 +227,10 @@ fn main() -> error::Result<()> {
|
|||
match event.code {
|
||||
KeyCode::End => app.skip_to_last(),
|
||||
KeyCode::Home => app.skip_to_first(),
|
||||
KeyCode::Up => app.decrement_position_count(),
|
||||
KeyCode::Down => app.increment_position_count(),
|
||||
KeyCode::Up => app.on_up_key(),
|
||||
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::Esc => app.on_esc(),
|
||||
KeyCode::Enter => app.on_enter(),
|
||||
|
@ -242,10 +244,10 @@ fn main() -> error::Result<()> {
|
|||
match event.code {
|
||||
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::Left | KeyCode::Char('h') => app.on_left(),
|
||||
KeyCode::Right | KeyCode::Char('l') => app.on_right(),
|
||||
KeyCode::Up | KeyCode::Char('k') => app.on_up(),
|
||||
KeyCode::Down | KeyCode::Char('j') => app.on_down(),
|
||||
KeyCode::Left | KeyCode::Char('h') => app.move_left(),
|
||||
KeyCode::Right | KeyCode::Char('l') => app.move_right(),
|
||||
KeyCode::Up | KeyCode::Char('k') => app.move_up(),
|
||||
KeyCode::Down | KeyCode::Char('j') => app.move_down(),
|
||||
KeyCode::Char('p') => app.search_with_pid(),
|
||||
KeyCode::Char('n') => app.search_with_name(),
|
||||
KeyCode::Char('r') => {
|
||||
|
|
Loading…
Reference in a new issue