summaryrefslogtreecommitdiffstats
path: root/src/app
diff options
context:
space:
mode:
authorClementTsang <cjhtsang@uwaterloo.ca>2021-09-24 23:19:08 -0400
committerClementTsang <cjhtsang@uwaterloo.ca>2021-09-24 23:19:25 -0400
commitabcca77c1ddcd465906549263b27dc41e769a30a (patch)
treec4b81cdfbdfe83f71024f940fc7a92f1d5740311 /src/app
parent7ee85a82f794c44b3a0bb6a50e8075eff96bb4c8 (diff)
refactor: add process search conditions and error
Diffstat (limited to 'src/app')
-rw-r--r--src/app/widgets/base/text_input.rs21
-rw-r--r--src/app/widgets/base/time_graph.rs2
-rw-r--r--src/app/widgets/bottom_widgets/process.rs166
-rw-r--r--src/app/widgets/dialogs/process_kill.rs0
4 files changed, 156 insertions, 33 deletions
diff --git a/src/app/widgets/base/text_input.rs b/src/app/widgets/base/text_input.rs
index 47a5cb7b..1ca60910 100644
--- a/src/app/widgets/base/text_input.rs
+++ b/src/app/widgets/base/text_input.rs
@@ -297,7 +297,7 @@ impl Component for TextInput {
}
fn handle_key_event(&mut self, event: KeyEvent) -> ComponentEventResult {
- if event.modifiers.is_empty() {
+ if event.modifiers.is_empty() || event.modifiers == KeyModifiers::SHIFT {
match event.code {
KeyCode::Left => {
let original_cursor = self.cursor.cur_cursor();
@@ -356,16 +356,17 @@ impl Component for TextInput {
}
}
- fn handle_mouse_event(&mut self, event: MouseEvent) -> ComponentEventResult {
+ fn handle_mouse_event(&mut self, _event: MouseEvent) -> ComponentEventResult {
// We are assuming this is within bounds...
- let x = event.column;
- let widget_x = self.bounds.x + 2;
- if x >= widget_x {
- // TODO: Do this at some point after refactor
- ComponentEventResult::Redraw
- } else {
- ComponentEventResult::NoRedraw
- }
+ // let x = event.column;
+ // let widget_x = self.bounds.x + 2;
+ // if x >= widget_x {
+ // // TODO: Do this at some point after refactor
+ // ComponentEventResult::Redraw
+ // } else {
+ // ComponentEventResult::NoRedraw
+ // }
+ ComponentEventResult::Unhandled
}
}
diff --git a/src/app/widgets/base/time_graph.rs b/src/app/widgets/base/time_graph.rs
index 81ca9e15..47436f71 100644
--- a/src/app/widgets/base/time_graph.rs
+++ b/src/app/widgets/base/time_graph.rs
@@ -165,7 +165,7 @@ impl TimeGraph {
'-' => self.zoom_out(),
'+' => self.zoom_in(),
'=' => self.reset_zoom(),
- _ => ComponentEventResult::NoRedraw,
+ _ => ComponentEventResult::Unhandled,
}
}
diff --git a/src/app/widgets/bottom_widgets/process.rs b/src/app/widgets/bottom_widgets/process.rs
index ba1dcf2e..8a704848 100644
--- a/src/app/widgets/bottom_widgets/process.rs
+++ b/src/app/widgets/bottom_widgets/process.rs
@@ -3,12 +3,14 @@ use std::{borrow::Cow, collections::HashMap};
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers, MouseButton, MouseEvent, MouseEventKind};
use float_ord::FloatOrd;
use itertools::{Either, Itertools};
+use once_cell::unsync::Lazy;
use unicode_segmentation::GraphemeCursor;
use tui::{
backend::Backend,
layout::{Constraint, Direction, Layout, Rect},
- widgets::{Borders, TableState},
+ text::{Span, Spans},
+ widgets::{Borders, Paragraph, TableState},
Frame,
};
@@ -590,6 +592,20 @@ struct SearchModifiers {
enable_regex: bool,
}
+impl SearchModifiers {
+ fn toggle_case_sensitive(&mut self) {
+ self.enable_case_sensitive = !self.enable_case_sensitive;
+ }
+
+ fn toggle_whole_word(&mut self) {
+ self.enable_whole_word = !self.enable_whole_word;
+ }
+
+ fn toggle_regex(&mut self) {
+ self.enable_regex = !self.enable_regex;
+ }
+}
+
enum FlexColumn {
Flex(f64),
Hard(Option<u16>),
@@ -983,6 +999,24 @@ impl ProcessManager {
self.selected = ProcessManagerSelection::Processes;
}
}
+
+ /// Toggles the search case-sensitivity status for the [`ProcessManager`].
+ fn toggle_search_case_sensitive(&mut self) -> ComponentEventResult {
+ self.search_modifiers.toggle_case_sensitive();
+ ComponentEventResult::Signal(ReturnSignal::Update)
+ }
+
+ /// Toggle whether to search for the whole word for the [`ProcessManager`].
+ fn toggle_search_whole_word(&mut self) -> ComponentEventResult {
+ self.search_modifiers.toggle_whole_word();
+ ComponentEventResult::Signal(ReturnSignal::Update)
+ }
+
+ /// Toggle whether to search with regex for the [`ProcessManager`].
+ fn toggle_search_regex(&mut self) -> ComponentEventResult {
+ self.search_modifiers.toggle_regex();
+ ComponentEventResult::Signal(ReturnSignal::Update)
+ }
}
impl Component for ProcessManager {
@@ -1100,28 +1134,44 @@ impl Component for ProcessManager {
ProcessManagerSelection::Search => {
if event.modifiers.is_empty() {
match event.code {
- KeyCode::F(1) => {}
- KeyCode::F(2) => {}
- KeyCode::F(3) => {}
+ KeyCode::F(1) => {
+ return self.toggle_search_case_sensitive();
+ }
+ KeyCode::F(2) => {
+ return self.toggle_search_whole_word();
+ }
+ KeyCode::F(3) => {
+ return self.toggle_search_regex();
+ }
_ => {}
}
} else if let KeyModifiers::ALT = event.modifiers {
match event.code {
- KeyCode::Char('c') | KeyCode::Char('C') => {}
- KeyCode::Char('w') | KeyCode::Char('W') => {}
- KeyCode::Char('r') | KeyCode::Char('R') => {}
+ KeyCode::Char('c') | KeyCode::Char('C') => {
+ return self.toggle_search_case_sensitive();
+ }
+ KeyCode::Char('w') | KeyCode::Char('W') => {
+ return self.toggle_search_whole_word();
+ }
+ KeyCode::Char('r') | KeyCode::Char('R') => {
+ return self.toggle_search_regex();
+ }
_ => {}
}
}
let handle_output = self.search_input.handle_key_event(event);
if let ComponentEventResult::Signal(ReturnSignal::Update) = handle_output {
- self.process_filter = Some(parse_query(
- self.search_input.query(),
- self.is_searching_whole_word(),
- !self.is_case_sensitive(),
- self.is_searching_with_regex(),
- ));
+ if !self.search_input.query().is_empty() {
+ self.process_filter = Some(parse_query(
+ self.search_input.query(),
+ self.is_searching_whole_word(),
+ !self.is_case_sensitive(),
+ self.is_searching_with_regex(),
+ ));
+ } else {
+ self.process_filter = None;
+ }
}
handle_output
@@ -1190,7 +1240,7 @@ impl Widget for ProcessManager {
&mut self, painter: &Painter, f: &mut Frame<'_, B>, area: Rect, selected: bool,
expanded: bool,
) {
- let area = if self.show_search {
+ let draw_area = if self.show_search {
let search_constraints: [Constraint; 2] = [
Constraint::Min(0),
if self.block_border.contains(Borders::TOP) {
@@ -1199,7 +1249,7 @@ impl Widget for ProcessManager {
Constraint::Length(3)
},
];
- const INTERNAL_SEARCH_CONSTRAINTS: [Constraint; 2] = [Constraint::Length(1); 2];
+ const INTERNAL_SEARCH_CONSTRAINTS: [Constraint; 3] = [Constraint::Length(1); 3];
let vertical_split_area = Layout::default()
.margin(0)
@@ -1224,7 +1274,7 @@ impl Widget for ProcessManager {
.constraints(INTERNAL_SEARCH_CONSTRAINTS)
.split(search_block.inner(vertical_split_area[1]));
- if !internal_split_area.is_empty() {
+ if internal_split_area[0].height > 0 {
self.search_input.draw_text_input(
painter,
f,
@@ -1233,8 +1283,80 @@ impl Widget for ProcessManager {
);
}
- if internal_split_area.len() == 2 {
- // TODO: Draw buttons
+ if internal_split_area[1].height > 0 {
+ if let Some(Err(err)) = &self.process_filter {
+ f.render_widget(
+ Paragraph::new(tui::text::Span::styled(
+ err.to_string(),
+ painter.colours.invalid_query_style,
+ )),
+ internal_split_area[1],
+ );
+ }
+ }
+
+ if internal_split_area[2].height > 0 {
+ let case_text: Lazy<String> = Lazy::new(|| {
+ format!(
+ "Case({})",
+ if cfg!(target_os = "macos") {
+ "F1"
+ } else {
+ "Alt+C"
+ }
+ )
+ });
+
+ let whole_word_text: Lazy<String> = Lazy::new(|| {
+ format!(
+ "Whole({})",
+ if cfg!(target_os = "macos") {
+ "F2"
+ } else {
+ "Alt+W"
+ }
+ )
+ });
+
+ let regex_text: Lazy<String> = Lazy::new(|| {
+ format!(
+ "Regex({})",
+ if cfg!(target_os = "macos") {
+ "F3"
+ } else {
+ "Alt+R"
+ }
+ )
+ });
+
+ let case_style = if self.is_case_sensitive() {
+ painter.colours.currently_selected_text_style
+ } else {
+ painter.colours.text_style
+ };
+
+ let whole_word_style = if self.is_searching_whole_word() {
+ painter.colours.currently_selected_text_style
+ } else {
+ painter.colours.text_style
+ };
+
+ let regex_style = if self.is_searching_with_regex() {
+ painter.colours.currently_selected_text_style
+ } else {
+ painter.colours.text_style
+ };
+
+ f.render_widget(
+ Paragraph::new(Spans::from(vec![
+ Span::styled(&*case_text, case_style),
+ Span::raw(" "), // TODO: Smartly space it out in the future...
+ Span::styled(&*whole_word_text, whole_word_style),
+ Span::raw(" "),
+ Span::styled(&*regex_text, regex_style),
+ ])),
+ internal_split_area[2],
+ )
}
f.render_widget(search_block, vertical_split_area[1]);
@@ -1244,14 +1366,14 @@ impl Widget for ProcessManager {
area
};
- let area = if self.show_sort {
+ let draw_area = if self.show_sort {
const SORT_CONSTRAINTS: [Constraint; 2] = [Constraint::Length(10), Constraint::Min(0)];
let horizontal_split_area = Layout::default()
.margin(0)
.direction(Direction::Horizontal)
.constraints(SORT_CONSTRAINTS)
- .split(area);
+ .split(draw_area);
let sort_block = self
.block()
@@ -1267,7 +1389,7 @@ impl Widget for ProcessManager {
horizontal_split_area[1]
} else {
- area
+ draw_area
};
let process_selected =
@@ -1283,7 +1405,7 @@ impl Widget for ProcessManager {
f,
&self.display_data,
process_block,
- area,
+ draw_area,
process_selected,
self.show_scroll_index,
);
diff --git a/src/app/widgets/dialogs/process_kill.rs b/src/app/widgets/dialogs/process_kill.rs
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/app/widgets/dialogs/process_kill.rs