From 818d920835f4f13a1eba369c49b7a6471e4cf77d Mon Sep 17 00:00:00 2001 From: ClementTsang Date: Thu, 27 Feb 2020 23:39:05 -0500 Subject: [PATCH 01/11] Fixed cursor issue. --- src/app.rs | 70 ++++++++++++++++++++++++++----- src/canvas.rs | 84 ++++++++++++++++++++----------------- src/canvas/drawing_utils.rs | 42 ++++++++++++++++--- src/main.rs | 2 + 4 files changed, 143 insertions(+), 55 deletions(-) diff --git a/src/app.rs b/src/app.rs index 5131b720..5c12b269 100644 --- a/src/app.rs +++ b/src/app.rs @@ -8,8 +8,8 @@ use data_farmer::*; use crate::{canvas, constants, utils::error::Result}; mod process_killer; -use unicode_segmentation::{GraphemeCursor}; -use unicode_width::UnicodeWidthStr; +use unicode_segmentation::GraphemeCursor; +use unicode_width::{UnicodeWidthChar, UnicodeWidthStr}; const MAX_SEARCH_LENGTH: usize = 200; @@ -33,7 +33,7 @@ pub enum ScrollDirection { } #[derive(Debug)] -pub enum SearchDirection { +pub enum CursorDirection { LEFT, RIGHT, } @@ -73,6 +73,10 @@ pub struct AppSearchState { pub is_blank_search: bool, pub is_invalid_search: bool, pub grapheme_cursor: GraphemeCursor, + pub cursor_direction: CursorDirection, + pub cursor_bar: usize, + /// This represents the position in terms of CHARACTERS, not graphemes + pub char_cursor_position: usize, } impl Default for AppSearchState { @@ -84,11 +88,21 @@ impl Default for AppSearchState { is_invalid_search: false, is_blank_search: true, grapheme_cursor: GraphemeCursor::new(0, 0, true), + cursor_direction: CursorDirection::RIGHT, + cursor_bar: 0, + char_cursor_position: 0, } } } impl AppSearchState { + /// Returns a reset but still enabled app search state + pub fn reset() -> Self { + let mut app_search_state = AppSearchState::default(); + app_search_state.is_enabled = true; + app_search_state + } + pub fn is_invalid_or_blank_search(&self) -> bool { self.is_blank_search || self.is_invalid_search } @@ -549,6 +563,10 @@ impl App { .cur_cursor() } + pub fn get_char_cursor_position(&self) -> usize { + self.process_search_state.search_state.char_cursor_position + } + /// One of two functions allowed to run while in a dialog... pub fn on_enter(&mut self) { if self.delete_dialog_state.is_showing_dd { @@ -620,19 +638,14 @@ impl App { #[allow(unused_variables)] pub fn skip_word_backspace(&mut self) { if let WidgetPosition::ProcessSearch = self.current_widget_selected { - if self.process_search_state.search_state.is_enabled { - } + if self.process_search_state.search_state.is_enabled {} } } pub fn clear_search(&mut self) { if let WidgetPosition::ProcessSearch = self.current_widget_selected { - self.process_search_state.search_state.grapheme_cursor = - GraphemeCursor::new(0, 0, true); - self.process_search_state.search_state.current_search_query = String::default(); - self.process_search_state.search_state.is_blank_search = true; - self.process_search_state.search_state.is_invalid_search = false; self.update_process_gui = true; + self.process_search_state.search_state = AppSearchState::reset(); } } @@ -663,7 +676,8 @@ impl App { if self.process_search_state.search_state.is_enabled && self.get_cursor_position() > 0 { self.search_walk_back(self.get_cursor_position()); - self.process_search_state + let removed_char = self + .process_search_state .search_state .current_search_query .remove(self.get_cursor_position()); @@ -677,6 +691,9 @@ impl App { true, ); + self.process_search_state.search_state.char_cursor_position -= + UnicodeWidthChar::width(removed_char).unwrap_or(0); + self.update_regex(); self.update_process_gui = true; } @@ -710,7 +727,15 @@ impl App { pub fn on_left_key(&mut self) { if !self.is_in_dialog() { if let WidgetPosition::ProcessSearch = self.current_widget_selected { + let prev_cursor = self.get_cursor_position(); self.search_walk_back(self.get_cursor_position()); + if self.get_cursor_position() < prev_cursor { + let str_slice = &self.process_search_state.search_state.current_search_query + [self.get_cursor_position()..prev_cursor]; + self.process_search_state.search_state.char_cursor_position -= + UnicodeWidthStr::width(str_slice); + self.process_search_state.search_state.cursor_direction = CursorDirection::LEFT; + } } } else if self.delete_dialog_state.is_showing_dd && !self.delete_dialog_state.is_on_yes { self.delete_dialog_state.is_on_yes = true; @@ -720,7 +745,16 @@ impl App { pub fn on_right_key(&mut self) { if !self.is_in_dialog() { if let WidgetPosition::ProcessSearch = self.current_widget_selected { + let prev_cursor = self.get_cursor_position(); self.search_walk_forward(self.get_cursor_position()); + if self.get_cursor_position() > prev_cursor { + let str_slice = &self.process_search_state.search_state.current_search_query + [prev_cursor..self.get_cursor_position()]; + self.process_search_state.search_state.char_cursor_position += + UnicodeWidthStr::width(str_slice); + self.process_search_state.search_state.cursor_direction = + CursorDirection::RIGHT; + } } } else if self.delete_dialog_state.is_showing_dd && self.delete_dialog_state.is_on_yes { self.delete_dialog_state.is_on_yes = false; @@ -738,6 +772,8 @@ impl App { .len(), true, ); + self.process_search_state.search_state.char_cursor_position = 0; + self.process_search_state.search_state.cursor_direction = CursorDirection::LEFT; } } } @@ -756,6 +792,14 @@ impl App { .len(), true, ); + self.process_search_state.search_state.char_cursor_position = + UnicodeWidthStr::width( + self.process_search_state + .search_state + .current_search_query + .as_str(), + ); + self.process_search_state.search_state.cursor_direction = CursorDirection::RIGHT; } } } @@ -840,6 +884,10 @@ impl App { true, ); self.search_walk_forward(self.get_cursor_position()); + + self.process_search_state.search_state.char_cursor_position += + UnicodeWidthChar::width(caught_char).unwrap_or(0); + self.update_regex(); self.update_process_gui = true; } diff --git a/src/canvas.rs b/src/canvas.rs index 024cf6bf..ecd95759 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -4,7 +4,7 @@ use crate::{ data_conversion::{ConvertedCpuData, ConvertedProcessData}, utils::error, }; -use std::cmp::{max, min}; +use std::cmp::max; use std::collections::HashMap; use tui::{ backend, @@ -1162,27 +1162,31 @@ impl Painter { &self, f: &mut Frame<'_, B>, app_state: &mut app::App, draw_loc: Rect, ) { let width = max(0, draw_loc.width as i64 - 34) as u64; // TODO: [REFACTOR] Hard coding this is terrible. - let query = app_state.get_current_search_query().as_str(); - let grapheme_indices = UnicodeSegmentation::grapheme_indices(query, true).rev(); // Reverse due to us wanting to draw from back -> front let cursor_position = app_state.get_cursor_position(); - let right_border = min(UnicodeWidthStr::width(query), width as usize); + let char_cursor_position = app_state.get_char_cursor_position(); - let mut itx = 0; - let mut query_with_cursor: Vec> = if let app::WidgetPosition::ProcessSearch = - app_state.current_widget_selected - { - let mut res = Vec::new(); - if cursor_position >= query.len() { - res.push(Text::styled( - " ", - self.colours.currently_selected_text_style, - )) - } + let start_position: usize = get_search_start_position( + width as usize, + &app_state.process_search_state.search_state.cursor_direction, + &mut app_state.process_search_state.search_state.cursor_bar, + char_cursor_position, + app_state.is_resized, + ); - res.extend( - grapheme_indices + let query = app_state.get_current_search_query().as_str(); + debug!( + "query: {}, width: {}, cursor: {}, start position: {}", + query, width, char_cursor_position, start_position + ); + let grapheme_indices = UnicodeSegmentation::grapheme_indices(query, true); + let mut current_grapheme_posn = 0; + let query_with_cursor: Vec> = + if let app::WidgetPosition::ProcessSearch = app_state.current_widget_selected { + let mut res = grapheme_indices .filter_map(|grapheme| { - if itx >= right_border { + current_grapheme_posn += UnicodeWidthStr::width(grapheme.1); + + if current_grapheme_posn <= start_position { None } else { let styled = if grapheme.0 == cursor_position { @@ -1190,32 +1194,34 @@ impl Painter { } else { Text::styled(grapheme.1, self.colours.text_style) }; - itx += UnicodeWidthStr::width(grapheme.1); Some(styled) } }) - .collect::>(), - ); + .collect::>(); - res - } else { - // This is easier - we just need to get a range of graphemes, rather than - // dealing with possibly inserting a cursor (as none is shown!) - grapheme_indices - .filter_map(|grapheme| { - if itx >= right_border { - None - } else { - let styled = Text::styled(grapheme.1, self.colours.text_style); - itx += UnicodeWidthStr::width(grapheme.1); - Some(styled) - } - }) - .collect::>() - }; + if cursor_position >= query.len() { + res.push(Text::styled( + " ", + self.colours.currently_selected_text_style, + )) + } - // I feel like this is most definitely not the efficient way of doing this but eh - query_with_cursor.reverse(); + res + } else { + // This is easier - we just need to get a range of graphemes, rather than + // dealing with possibly inserting a cursor (as none is shown!) + grapheme_indices + .filter_map(|grapheme| { + current_grapheme_posn += UnicodeWidthStr::width(grapheme.1); + if current_grapheme_posn <= start_position { + None + } else { + let styled = Text::styled(grapheme.1, self.colours.text_style); + Some(styled) + } + }) + .collect::>() + }; let mut search_text = vec![if app_state.is_grouped() { Text::styled("Search by Name: ", self.colours.table_header_style) diff --git a/src/canvas/drawing_utils.rs b/src/canvas/drawing_utils.rs index 5fb67373..2196bffe 100644 --- a/src/canvas/drawing_utils.rs +++ b/src/canvas/drawing_utils.rs @@ -72,11 +72,43 @@ pub fn get_variable_intrinsic_widths( #[allow(dead_code, unused_variables)] pub fn get_search_start_position( - num_rows: u64, scroll_direction: &app::ScrollDirection, scroll_position_bar: &mut u64, - currently_selected_position: u64, is_resized: bool, -) -> u64 { - //TODO: [Scroll] Gotta fix this too lol - 0 + num_columns: usize, cursor_direction: &app::CursorDirection, cursor_bar: &mut usize, + current_cursor_position: usize, is_resized: bool, +) -> usize { + if is_resized { + *cursor_bar = 0; + } + + match cursor_direction { + app::CursorDirection::RIGHT => { + if current_cursor_position < *cursor_bar + num_columns { + // If, using previous_scrolled_position, we can see the element + // (so within that and + num_rows) just reuse the current previously scrolled position + *cursor_bar + } else if current_cursor_position >= num_columns { + // Else if the current position past the last element visible in the list, omit + // until we can see that element + *cursor_bar = current_cursor_position - num_columns; + *cursor_bar + } else { + // Else, if it is not past the last element visible, do not omit anything + 0 + } + } + app::CursorDirection::LEFT => { + if current_cursor_position <= *cursor_bar { + // If it's past the first element, then show from that element downwards + *cursor_bar = current_cursor_position; + *cursor_bar + } else if current_cursor_position >= *cursor_bar + num_columns { + *cursor_bar = current_cursor_position - num_columns; + *cursor_bar + } else { + // Else, don't change what our start position is from whatever it is set to! + *cursor_bar + } + } + } } pub fn get_start_position( diff --git a/src/main.rs b/src/main.rs index 4d65d2ca..47a63229 100644 --- a/src/main.rs +++ b/src/main.rs @@ -399,6 +399,8 @@ fn handle_key_event_or_break( KeyCode::Char('u') => app.clear_search(), KeyCode::Char('a') => app.skip_cursor_beginning(), KeyCode::Char('e') => app.skip_cursor_end(), + // Can't do now, CTRL+BACKSPACE doesn't work and graphemes + // are hard to iter while truncating last (eloquently). // KeyCode::Backspace => app.skip_word_backspace(), _ => {} } From f0f1ee129e6fcc5f06c613f9aec07e7e23fbaca7 Mon Sep 17 00:00:00 2001 From: ClementTsang Date: Fri, 28 Feb 2020 01:12:45 -0500 Subject: [PATCH 02/11] Minor side update * Update PR template to be a bit more specific * Update README to state what version of rust I dev on in contributions * Update rustfmt to remove another unstable line --- .github/pull_request_template.md | 3 ++- README.md | 2 +- rustfmt.toml | 1 - 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 04b4e337..0f4b7955 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -14,6 +14,7 @@ _Remove the irrelevant one:_ - [x] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) +- [x] Other (something else) ## Test methodology @@ -24,7 +25,7 @@ _Please state how this was tested:_ _Please ensure all are ticked (and actually done):_ - [ ] Change has been tested to work -- [ ] Code has been linted using rustfmt +- [ ] Areas your change affects has been linted using rustfmt - [ ] Code has been self-reviewed - [ ] Code has been tested and no new breakage is introduced - [ ] Documentation has been added/updated if needed diff --git a/README.md b/README.md index 487ce596..64794241 100644 --- a/README.md +++ b/README.md @@ -206,7 +206,7 @@ Note that `q` is disabled while in the search widget. ## Contribution -Contribution is welcome! Just submit a PR. +Contribution is welcome! Just submit a PR. Note that I develop and test on stable Rust. If you spot any issue with nobody assigned to it, or it seems like no work has started on it, feel free to try and do it! diff --git a/rustfmt.toml b/rustfmt.toml index eefab4d3..c7c801a9 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -11,4 +11,3 @@ reorder_modules = true reorder_impl_items = true tab_spaces = 4 format_strings = true -space_after_colon = true From 05d4982a1a4774c2a3d71fcac3d387b15a56212c Mon Sep 17 00:00:00 2001 From: ClementTsang Date: Fri, 28 Feb 2020 19:54:20 -0500 Subject: [PATCH 03/11] Treat backspace as a cursor left movement. --- src/app.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app.rs b/src/app.rs index 5c12b269..b2313e08 100644 --- a/src/app.rs +++ b/src/app.rs @@ -693,6 +693,7 @@ impl App { self.process_search_state.search_state.char_cursor_position -= UnicodeWidthChar::width(removed_char).unwrap_or(0); + self.process_search_state.search_state.cursor_direction = CursorDirection::LEFT; self.update_regex(); self.update_process_gui = true; From 6d0136fa2646a8e75c5022e252224b116589f7f7 Mon Sep 17 00:00:00 2001 From: ClementTsang Date: Fri, 28 Feb 2020 21:15:08 -0500 Subject: [PATCH 04/11] Remove a debug line. --- src/canvas.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/canvas.rs b/src/canvas.rs index ecd95759..38070a5e 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -1174,10 +1174,6 @@ impl Painter { ); let query = app_state.get_current_search_query().as_str(); - debug!( - "query: {}, width: {}, cursor: {}, start position: {}", - query, width, char_cursor_position, start_position - ); let grapheme_indices = UnicodeSegmentation::grapheme_indices(query, true); let mut current_grapheme_posn = 0; let query_with_cursor: Vec> = From 2f5b5e72694e6b827e8299f6d027f1ec8e0f2c4e Mon Sep 17 00:00:00 2001 From: ClementTsang Date: Fri, 28 Feb 2020 21:15:36 -0500 Subject: [PATCH 05/11] Move windows to separate dependency. --- Cargo.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 035173e7..a8b183a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,6 @@ heim = "0.0.10" log = "0.4.8" regex = "1.3.4" sysinfo = "0.11" -winapi = "0.3.8" crossterm = "0.16" tui = {version = "0.8", features = ["crossterm"], default-features = false } lazy_static = "1.4.0" @@ -40,6 +39,9 @@ serde = {version = "1.0", features = ["derive"] } unicode-segmentation = "1.6.0" unicode-width = "0.1.7" +[target.'cfg(windows)'.dependencies] +winapi = "0.3.8" + [dev-dependencies] assert_cmd = "0.12" predicates = "1" From bbdd7786ceb6a40ddfdca9c409997fccd6b7dfba Mon Sep 17 00:00:00 2001 From: ClementTsang Date: Fri, 28 Feb 2020 22:24:24 -0500 Subject: [PATCH 06/11] Optimized imports as per clion --- src/app.rs | 17 ++++---- src/app/data_farmer.rs | 3 +- src/app/data_harvester.rs | 1 + src/app/data_harvester/network.rs | 3 +- src/app/data_harvester/processes.rs | 11 ++++-- src/app/data_harvester/temperature.rs | 3 +- src/app/process_killer.rs | 13 ++++--- src/canvas.rs | 32 +++++++-------- src/canvas/canvas_colours.rs | 6 ++- src/canvas/canvas_colours/colour_utils.rs | 4 +- src/data_conversion.rs | 22 ++++++----- src/main.rs | 47 +++++++++++------------ tests/arg_rate_tests.rs | 3 +- 13 files changed, 91 insertions(+), 74 deletions(-) diff --git a/src/app.rs b/src/app.rs index b2313e08..ad5f9c5d 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,16 +1,17 @@ -pub mod data_harvester; -use data_harvester::{processes, temperature}; use std::time::Instant; -pub mod data_farmer; -use data_farmer::*; - -use crate::{canvas, constants, utils::error::Result}; -mod process_killer; - use unicode_segmentation::GraphemeCursor; use unicode_width::{UnicodeWidthChar, UnicodeWidthStr}; +use data_farmer::*; +use data_harvester::{processes, temperature}; + +use crate::{canvas, constants, utils::error::Result}; + +pub mod data_harvester; +pub mod data_farmer; +mod process_killer; + const MAX_SEARCH_LENGTH: usize = 200; #[derive(Debug, Clone, Copy)] diff --git a/src/app/data_farmer.rs b/src/app/data_farmer.rs index 9741c563..c32a62d3 100644 --- a/src/app/data_farmer.rs +++ b/src/app/data_farmer.rs @@ -1,4 +1,3 @@ -use crate::data_harvester::{cpu, disks, mem, network, processes, temperature, Data}; /// In charge of cleaning, processing, and managing data. I couldn't think of /// a better name for the file. Since I called data collection "harvesting", /// then this is the farmer I guess. @@ -16,6 +15,8 @@ use crate::data_harvester::{cpu, disks, mem, network, processes, temperature, Da use std::time::Instant; use std::vec::Vec; +use crate::data_harvester::{cpu, Data, disks, mem, network, processes, temperature}; + pub type TimeOffset = f64; pub type Value = f64; pub type JoinedDataPoints = (Value, Vec<(TimeOffset, Value)>); diff --git a/src/app/data_harvester.rs b/src/app/data_harvester.rs index bee29eb7..80d46a9e 100644 --- a/src/app/data_harvester.rs +++ b/src/app/data_harvester.rs @@ -1,6 +1,7 @@ //! This is the main file to house data collection functions. use std::{collections::HashMap, time::Instant}; + use sysinfo::{System, SystemExt}; pub mod cpu; diff --git a/src/app/data_harvester/network.rs b/src/app/data_harvester/network.rs index b4d32c29..9a40d5f7 100644 --- a/src/app/data_harvester/network.rs +++ b/src/app/data_harvester/network.rs @@ -1,7 +1,8 @@ +use std::time::Instant; + use futures::StreamExt; use heim::net; use heim::units::information::byte; -use std::time::Instant; use sysinfo::{NetworkExt, System, SystemExt}; #[derive(Default, Clone, Debug)] diff --git a/src/app/data_harvester/processes.rs b/src/app/data_harvester/processes.rs index 9a2bc548..7b56f32c 100644 --- a/src/app/data_harvester/processes.rs +++ b/src/app/data_harvester/processes.rs @@ -1,10 +1,13 @@ -use crate::utils::error; use std::{ - collections::{hash_map::RandomState, HashMap}, - process::Command, - time::Instant, + collections::{hash_map::RandomState, HashMap}, + process::Command, + time::Instant, }; + use sysinfo::{ProcessExt, ProcessorExt, System, SystemExt}; + +use crate::utils::error; + #[derive(Clone)] pub enum ProcessSorting { CPU, diff --git a/src/app/data_harvester/temperature.rs b/src/app/data_harvester/temperature.rs index 52500047..66d47e1e 100644 --- a/src/app/data_harvester/temperature.rs +++ b/src/app/data_harvester/temperature.rs @@ -1,6 +1,7 @@ +use std::cmp::Ordering; + use futures::StreamExt; use heim::units::thermodynamic_temperature; -use std::cmp::Ordering; use sysinfo::{ComponentExt, System, SystemExt}; #[derive(Default, Debug, Clone)] diff --git a/src/app/process_killer.rs b/src/app/process_killer.rs index 85b5b402..c2712874 100644 --- a/src/app/process_killer.rs +++ b/src/app/process_killer.rs @@ -1,17 +1,18 @@ -/// This file is meant to house (OS specific) implementations on how to kill processes. -use crate::utils::error::BottomError; use std::process::Command; // Copied from SO: https://stackoverflow.com/a/55231715 #[cfg(target_os = "windows")] use winapi::{ - shared::{minwindef::DWORD, ntdef::HANDLE}, - um::{ - processthreadsapi::{OpenProcess, TerminateProcess}, - winnt::{PROCESS_QUERY_INFORMATION, PROCESS_TERMINATE}, + shared::{minwindef::DWORD, ntdef::HANDLE}, + um::{ + processthreadsapi::{OpenProcess, TerminateProcess}, + winnt::{PROCESS_QUERY_INFORMATION, PROCESS_TERMINATE}, }, }; +/// This file is meant to house (OS specific) implementations on how to kill processes. +use crate::utils::error::BottomError; + #[cfg(target_os = "windows")] struct Process(HANDLE); diff --git a/src/canvas.rs b/src/canvas.rs index 38070a5e..69d51039 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -1,28 +1,30 @@ -use crate::{ - app::{self, data_harvester::processes::ProcessHarvest, WidgetPosition}, - constants::*, - data_conversion::{ConvertedCpuData, ConvertedProcessData}, - utils::error, -}; use std::cmp::max; use std::collections::HashMap; + use tui::{ - backend, - layout::{Alignment, Constraint, Direction, Layout, Rect}, - style::{Color, Style}, - terminal::Frame, - widgets::{Axis, Block, Borders, Chart, Dataset, Marker, Paragraph, Row, Table, Text, Widget}, - Terminal, + backend, + layout::{Alignment, Constraint, Direction, Layout, Rect}, + style::{Color, Style}, + Terminal, + terminal::Frame, + widgets::{Axis, Block, Borders, Chart, Dataset, Marker, Paragraph, Row, Table, Text, Widget}, }; use unicode_segmentation::UnicodeSegmentation; use unicode_width::UnicodeWidthStr; -mod canvas_colours; use canvas_colours::*; - -mod drawing_utils; use drawing_utils::*; +use crate::{ + app::{self, data_harvester::processes::ProcessHarvest, WidgetPosition}, + constants::*, + data_conversion::{ConvertedCpuData, ConvertedProcessData}, + utils::error, +}; + +mod canvas_colours; +mod drawing_utils; + // Headers const CPU_LEGEND_HEADER: [&str; 2] = ["CPU", "Use%"]; const CPU_SELECT_LEGEND_HEADER: [&str; 2] = ["CPU", "Show (Space)"]; diff --git a/src/canvas/canvas_colours.rs b/src/canvas/canvas_colours.rs index 949a90c5..27cc228f 100644 --- a/src/canvas/canvas_colours.rs +++ b/src/canvas/canvas_colours.rs @@ -1,9 +1,11 @@ -mod colour_utils; -use colour_utils::*; use tui::style::{Color, Modifier, Style}; +use colour_utils::*; + use crate::{constants::*, utils::error}; +mod colour_utils; + pub struct CanvasColours { pub currently_selected_text_colour: Color, pub currently_selected_bg_colour: Color, diff --git a/src/canvas/canvas_colours/colour_utils.rs b/src/canvas/canvas_colours/colour_utils.rs index c7e32a23..c7e2a1ae 100644 --- a/src/canvas/canvas_colours/colour_utils.rs +++ b/src/canvas/canvas_colours/colour_utils.rs @@ -1,7 +1,9 @@ -use crate::utils::{error, gen_util::*}; use std::collections::HashMap; + use tui::style::{Color, Style}; +use crate::utils::{error, gen_util::*}; + const GOLDEN_RATIO: f32 = 0.618_034; // Approx, good enough for use (also Clippy gets mad if it's too long) pub const STANDARD_FIRST_COLOUR: Color = Color::LightMagenta; pub const STANDARD_SECOND_COLOUR: Color = Color::LightYellow; diff --git a/src/data_conversion.rs b/src/data_conversion.rs index bbd51ee5..c1dc2a17 100644 --- a/src/data_conversion.rs +++ b/src/data_conversion.rs @@ -1,18 +1,20 @@ //! This mainly concerns converting collected data into things that the canvas //! can actually handle. -use crate::{ - app::{ - data_farmer, - data_harvester::{self, processes::ProcessHarvest}, - App, - }, - constants, - utils::gen_util::{get_exact_byte_values, get_simple_byte_values}, -}; -use constants::*; use std::collections::HashMap; +use constants::*; + +use crate::{ + app::{ + App, + data_farmer, + data_harvester::{self, processes::ProcessHarvest}, + }, + constants, + utils::gen_util::{get_exact_byte_values, get_simple_byte_values}, +}; + #[derive(Default, Debug)] pub struct ConvertedNetworkData { pub rx: Vec<(f64, f64)>, diff --git a/src/main.rs b/src/main.rs index 47a63229..4e5ffc2b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,26 +1,13 @@ #![warn(rust_2018_idioms)] -#[macro_use] -extern crate log; #[macro_use] extern crate clap; #[macro_use] +extern crate futures; +#[macro_use] extern crate lazy_static; #[macro_use] -extern crate futures; - -use serde::Deserialize; - -use crossterm::{ - event::{ - poll, read, DisableMouseCapture, EnableMouseCapture, Event as CEvent, KeyCode, KeyEvent, - KeyModifiers, MouseEvent, - }, - execute, - style::Print, - terminal::LeaveAlternateScreen, - terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen}, -}; +extern crate log; use std::{ boxed::Box, @@ -30,8 +17,28 @@ use std::{ thread, time::{Duration, Instant}, }; + +use crossterm::{ + event::{ + DisableMouseCapture, EnableMouseCapture, Event as CEvent, KeyCode, KeyEvent, KeyModifiers, MouseEvent, + poll, read, + }, + execute, + style::Print, + terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen}, + terminal::LeaveAlternateScreen, +}; +use serde::Deserialize; use tui::{backend::CrosstermBackend, Terminal}; +use app::{ + App, + data_harvester::{self, processes::ProcessSorting}, +}; +use constants::*; +use data_conversion::*; +use utils::error::{self, BottomError}; + pub mod app; mod utils { pub mod error; @@ -42,14 +49,6 @@ mod canvas; mod constants; mod data_conversion; -use app::{ - data_harvester::{self, processes::ProcessSorting}, - App, -}; -use constants::*; -use data_conversion::*; -use utils::error::{self, BottomError}; - enum Event { KeyInput(I), MouseInput(J), diff --git a/tests/arg_rate_tests.rs b/tests/arg_rate_tests.rs index 206dbf50..35afb4d2 100644 --- a/tests/arg_rate_tests.rs +++ b/tests/arg_rate_tests.rs @@ -1,6 +1,7 @@ +use std::process::Command; + use assert_cmd::prelude::*; use predicates::prelude::*; -use std::process::Command; // These tests are mostly here just to ensure that invalid results will be caught when passing arguments... From 520af2b68f550b45c64aaefc4004e4ddd5688b92 Mon Sep 17 00:00:00 2001 From: ClementTsang Date: Fri, 28 Feb 2020 22:27:29 -0500 Subject: [PATCH 07/11] Updated rustfmt to remove nightly-only features (for now) --- rustfmt.toml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/rustfmt.toml b/rustfmt.toml index c7c801a9..5e1a41b9 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -3,11 +3,7 @@ max_width = 100 newline_style = "Unix" reorder_imports = true fn_args_layout = "Compressed" -empty_item_single_line = false hard_tabs = true -merge_imports = true merge_derives = true reorder_modules = true -reorder_impl_items = true tab_spaces = 4 -format_strings = true From 75a19344207d52dd445487747998ff4065540f2e Mon Sep 17 00:00:00 2001 From: ClementTsang Date: Fri, 28 Feb 2020 22:27:35 -0500 Subject: [PATCH 08/11] rustfmt --- src/app.rs | 2 +- src/app/data_farmer.rs | 2 +- src/app/data_harvester/processes.rs | 6 +++--- src/app/process_killer.rs | 8 ++++---- src/canvas.rs | 20 ++++++++++---------- src/data_conversion.rs | 12 ++++++------ src/main.rs | 8 ++++---- 7 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/app.rs b/src/app.rs index ad5f9c5d..f7de26f0 100644 --- a/src/app.rs +++ b/src/app.rs @@ -8,8 +8,8 @@ use data_harvester::{processes, temperature}; use crate::{canvas, constants, utils::error::Result}; -pub mod data_harvester; pub mod data_farmer; +pub mod data_harvester; mod process_killer; const MAX_SEARCH_LENGTH: usize = 200; diff --git a/src/app/data_farmer.rs b/src/app/data_farmer.rs index c32a62d3..6552a8ec 100644 --- a/src/app/data_farmer.rs +++ b/src/app/data_farmer.rs @@ -15,7 +15,7 @@ use std::time::Instant; use std::vec::Vec; -use crate::data_harvester::{cpu, Data, disks, mem, network, processes, temperature}; +use crate::data_harvester::{cpu, disks, mem, network, processes, temperature, Data}; pub type TimeOffset = f64; pub type Value = f64; diff --git a/src/app/data_harvester/processes.rs b/src/app/data_harvester/processes.rs index 7b56f32c..027781eb 100644 --- a/src/app/data_harvester/processes.rs +++ b/src/app/data_harvester/processes.rs @@ -1,7 +1,7 @@ use std::{ - collections::{hash_map::RandomState, HashMap}, - process::Command, - time::Instant, + collections::{hash_map::RandomState, HashMap}, + process::Command, + time::Instant, }; use sysinfo::{ProcessExt, ProcessorExt, System, SystemExt}; diff --git a/src/app/process_killer.rs b/src/app/process_killer.rs index c2712874..d2089aad 100644 --- a/src/app/process_killer.rs +++ b/src/app/process_killer.rs @@ -3,10 +3,10 @@ use std::process::Command; // Copied from SO: https://stackoverflow.com/a/55231715 #[cfg(target_os = "windows")] use winapi::{ - shared::{minwindef::DWORD, ntdef::HANDLE}, - um::{ - processthreadsapi::{OpenProcess, TerminateProcess}, - winnt::{PROCESS_QUERY_INFORMATION, PROCESS_TERMINATE}, + shared::{minwindef::DWORD, ntdef::HANDLE}, + um::{ + processthreadsapi::{OpenProcess, TerminateProcess}, + winnt::{PROCESS_QUERY_INFORMATION, PROCESS_TERMINATE}, }, }; diff --git a/src/canvas.rs b/src/canvas.rs index 69d51039..7b543bb0 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -2,12 +2,12 @@ use std::cmp::max; use std::collections::HashMap; use tui::{ - backend, - layout::{Alignment, Constraint, Direction, Layout, Rect}, - style::{Color, Style}, - Terminal, - terminal::Frame, - widgets::{Axis, Block, Borders, Chart, Dataset, Marker, Paragraph, Row, Table, Text, Widget}, + backend, + layout::{Alignment, Constraint, Direction, Layout, Rect}, + style::{Color, Style}, + terminal::Frame, + widgets::{Axis, Block, Borders, Chart, Dataset, Marker, Paragraph, Row, Table, Text, Widget}, + Terminal, }; use unicode_segmentation::UnicodeSegmentation; use unicode_width::UnicodeWidthStr; @@ -16,10 +16,10 @@ use canvas_colours::*; use drawing_utils::*; use crate::{ - app::{self, data_harvester::processes::ProcessHarvest, WidgetPosition}, - constants::*, - data_conversion::{ConvertedCpuData, ConvertedProcessData}, - utils::error, + app::{self, data_harvester::processes::ProcessHarvest, WidgetPosition}, + constants::*, + data_conversion::{ConvertedCpuData, ConvertedProcessData}, + utils::error, }; mod canvas_colours; diff --git a/src/data_conversion.rs b/src/data_conversion.rs index c1dc2a17..9302eae2 100644 --- a/src/data_conversion.rs +++ b/src/data_conversion.rs @@ -6,13 +6,13 @@ use std::collections::HashMap; use constants::*; use crate::{ - app::{ - App, - data_farmer, - data_harvester::{self, processes::ProcessHarvest}, + app::{ + data_farmer, + data_harvester::{self, processes::ProcessHarvest}, + App, }, - constants, - utils::gen_util::{get_exact_byte_values, get_simple_byte_values}, + constants, + utils::gen_util::{get_exact_byte_values, get_simple_byte_values}, }; #[derive(Default, Debug)] diff --git a/src/main.rs b/src/main.rs index 4e5ffc2b..a4ddad26 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,20 +20,20 @@ use std::{ use crossterm::{ event::{ - DisableMouseCapture, EnableMouseCapture, Event as CEvent, KeyCode, KeyEvent, KeyModifiers, MouseEvent, - poll, read, + poll, read, DisableMouseCapture, EnableMouseCapture, Event as CEvent, KeyCode, KeyEvent, + KeyModifiers, MouseEvent, }, execute, style::Print, - terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen}, terminal::LeaveAlternateScreen, + terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen}, }; use serde::Deserialize; use tui::{backend::CrosstermBackend, Terminal}; use app::{ - App, data_harvester::{self, processes::ProcessSorting}, + App, }; use constants::*; use data_conversion::*; From eb159a45c469ad6d95c3e11ee35e8514e3fb4fbc Mon Sep 17 00:00:00 2001 From: ClementTsang Date: Fri, 28 Feb 2020 22:31:11 -0500 Subject: [PATCH 09/11] [skip travis] Update .gitignore to ignore .idea --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4a453e53..82f38bf0 100644 --- a/.gitignore +++ b/.gitignore @@ -15,5 +15,6 @@ Cargo.lock rust-unmangle *.svg *.data +.idea/ sample_configs/testing.toml From c715133b4d313ac631b224c526535955c34422cf Mon Sep 17 00:00:00 2001 From: ClementTsang Date: Fri, 28 Feb 2020 22:39:26 -0500 Subject: [PATCH 10/11] Some more suggestions based on clion. Mostly removing brackets. --- src/app.rs | 2 +- src/canvas.rs | 28 ++++++++++++++-------------- src/main.rs | 14 +++++++------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/app.rs b/src/app.rs index f7de26f0..e23938ac 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1032,7 +1032,7 @@ impl App { pub fn kill_highlighted_process(&mut self) -> Result<()> { // Technically unnecessary but this is a good check... if let WidgetPosition::Process = self.current_widget_selected { - if let Some(current_selected_processes) = &(self.to_delete_process_list) { + if let Some(current_selected_processes) = &self.to_delete_process_list { for pid in ¤t_selected_processes.1 { process_killer::kill_process_given_pid(*pid)?; } diff --git a/src/canvas.rs b/src/canvas.rs index 7b543bb0..64d325fe 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -622,12 +622,12 @@ impl Painter { fn draw_cpu_legend( &self, f: &mut Frame<'_, B>, app_state: &mut app::App, draw_loc: Rect, ) { - let cpu_data: &[ConvertedCpuData] = &(app_state.canvas_data.cpu_data); + let cpu_data: &[ConvertedCpuData] = &app_state.canvas_data.cpu_data; let num_rows = max(0, i64::from(draw_loc.height) - 5) as u64; let start_position = get_start_position( num_rows, - &(app_state.app_scroll_positions.scroll_direction), + &app_state.app_scroll_positions.scroll_direction, &mut app_state .app_scroll_positions .cpu_scroll_state @@ -768,8 +768,8 @@ impl Painter { fn draw_memory_graph( &self, f: &mut Frame<'_, B>, app_state: &app::App, draw_loc: Rect, ) { - let mem_data: &[(f64, f64)] = &(app_state.canvas_data.mem_data); - let swap_data: &[(f64, f64)] = &(app_state.canvas_data.swap_data); + let mem_data: &[(f64, f64)] = &app_state.canvas_data.mem_data; + let swap_data: &[(f64, f64)] = &app_state.canvas_data.swap_data; let x_axis: Axis<'_, String> = Axis::default().bounds([0.0, TIME_STARTS_FROM as f64]); @@ -841,8 +841,8 @@ impl Painter { fn draw_network_graph( &self, f: &mut Frame<'_, B>, app_state: &app::App, draw_loc: Rect, ) { - let network_data_rx: &[(f64, f64)] = &(app_state.canvas_data.network_data_rx); - let network_data_tx: &[(f64, f64)] = &(app_state.canvas_data.network_data_tx); + let network_data_rx: &[(f64, f64)] = &app_state.canvas_data.network_data_rx; + let network_data_tx: &[(f64, f64)] = &app_state.canvas_data.network_data_tx; let x_axis: Axis<'_, String> = Axis::default().bounds([0.0, 60_000.0]); let y_axis: Axis<'_, &str> = Axis::default() @@ -940,7 +940,7 @@ impl Painter { // Calculate widths let width_ratios: Vec = vec![0.25, 0.25, 0.25, 0.25]; - let lens: &Vec = &NETWORK_HEADERS_LENS; + let lens: &[usize] = &NETWORK_HEADERS_LENS; let width = f64::from(draw_loc.width); let variable_intrinsic_results = @@ -969,12 +969,12 @@ impl Painter { fn draw_temp_table( &self, f: &mut Frame<'_, B>, app_state: &mut app::App, draw_loc: Rect, ) { - let temp_sensor_data: &[Vec] = &(app_state.canvas_data.temp_sensor_data); + let temp_sensor_data: &[Vec] = &app_state.canvas_data.temp_sensor_data; let num_rows = max(0, i64::from(draw_loc.height) - 5) as u64; let start_position = get_start_position( num_rows, - &(app_state.app_scroll_positions.scroll_direction), + &app_state.app_scroll_positions.scroll_direction, &mut app_state .app_scroll_positions .temp_scroll_state @@ -986,7 +986,7 @@ impl Painter { app_state.is_resized, ); - let sliced_vec = &(temp_sensor_data[start_position as usize..]); + let sliced_vec = &temp_sensor_data[start_position as usize..]; let mut temp_row_counter: i64 = 0; let temperature_rows = sliced_vec.iter().map(|temp_row| { @@ -1066,11 +1066,11 @@ impl Painter { fn draw_disk_table( &self, f: &mut Frame<'_, B>, app_state: &mut app::App, draw_loc: Rect, ) { - let disk_data: &[Vec] = &(app_state.canvas_data.disk_data); + let disk_data: &[Vec] = &app_state.canvas_data.disk_data; let num_rows = max(0, i64::from(draw_loc.height) - 5) as u64; let start_position = get_start_position( num_rows, - &(app_state.app_scroll_positions.scroll_direction), + &app_state.app_scroll_positions.scroll_direction, &mut app_state .app_scroll_positions .disk_scroll_state @@ -1352,7 +1352,7 @@ impl Painter { let position = get_start_position( num_rows, - &(app_state.app_scroll_positions.scroll_direction), + &app_state.app_scroll_positions.scroll_direction, &mut app_state .app_scroll_positions .process_scroll_state @@ -1371,7 +1371,7 @@ impl Painter { position }; - let sliced_vec = &(process_data[start_position as usize..]); + let sliced_vec = &process_data[start_position as usize..]; let mut process_counter: i64 = 0; // Draw! diff --git a/src/main.rs b/src/main.rs index a4ddad26..18061db6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -494,20 +494,20 @@ fn get_temperature_option( } else if let Some(flags) = &config.flags { if let Some(temp_type) = &flags.temperature_type { // Give lowest priority to config. - match temp_type.as_str() { + return match temp_type.as_str() { "fahrenheit" | "f" => { - return Ok(data_harvester::temperature::TemperatureType::Fahrenheit); + Ok(data_harvester::temperature::TemperatureType::Fahrenheit) } "kelvin" | "k" => { - return Ok(data_harvester::temperature::TemperatureType::Kelvin); + Ok(data_harvester::temperature::TemperatureType::Kelvin) } "celsius" | "c" => { - return Ok(data_harvester::temperature::TemperatureType::Celsius); + Ok(data_harvester::temperature::TemperatureType::Celsius) } _ => { - return Err(BottomError::ConfigError( + Err(BottomError::ConfigError( "Invalid temperature type. Please have the value be of the form ".to_string() - )); + )) } } } @@ -713,7 +713,7 @@ fn generate_config_colours(config: &Config, painter: &mut canvas::Painter) -> er painter.colours.set_avg_cpu_colour(avg_cpu_color)?; } - if let Some(cpu_core_colors) = &(colours.cpu_core_colors) { + if let Some(cpu_core_colors) = &colours.cpu_core_colors { painter.colours.set_cpu_colours(cpu_core_colors)?; } From b9911028190190f6fe0a7905107cddf1d910a216 Mon Sep 17 00:00:00 2001 From: Clement Tsang <34804052+ClementTsang@users.noreply.github.com> Date: Sat, 29 Feb 2020 19:37:49 -0500 Subject: [PATCH 11/11] [skip travis] Add "avoid merge conflicts" --- .github/pull_request_template.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 0f4b7955..d25908ef 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -29,6 +29,7 @@ _Please ensure all are ticked (and actually done):_ - [ ] Code has been self-reviewed - [ ] Code has been tested and no new breakage is introduced - [ ] Documentation has been added/updated if needed +- [ ] No merge conflicts arise from the change ## Other information