feature: add full command to process widget
This PR adds the ability to toggle between the process name and process path. Currently, this uses `P` as the modifier key. Currently, the longer command names are dealt with by forcefully changing the width of the columns, but this can be handled in a more graceful manner IMO.
This commit is contained in:
parent
d2129056e3
commit
30bdaa6073
|
@ -8,12 +8,15 @@
|
||||||
"Nonexhaustive",
|
"Nonexhaustive",
|
||||||
"Qudsi",
|
"Qudsi",
|
||||||
"Tebibytes",
|
"Tebibytes",
|
||||||
|
"Ungrouped",
|
||||||
"Wojnarowski",
|
"Wojnarowski",
|
||||||
"andys",
|
"andys",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
"curr",
|
"curr",
|
||||||
|
"czvf",
|
||||||
"gotop",
|
"gotop",
|
||||||
"gtop",
|
"gtop",
|
||||||
|
"haase",
|
||||||
"heim",
|
"heim",
|
||||||
"hjkl",
|
"hjkl",
|
||||||
"markdownlint",
|
"markdownlint",
|
||||||
|
|
|
@ -1340,9 +1340,9 @@ checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tui"
|
name = "tui"
|
||||||
version = "0.9.4"
|
version = "0.9.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c25eac88406f384894aa6db56ac0378c767254ee5829824ce5b0fc8fd24d5778"
|
checksum = "9533d39bef0ae8f510e8a99d78702e68d1bbf0b98a78ec9740509d287010ae1e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"cassowary",
|
"cassowary",
|
||||||
|
|
20
README.md
20
README.md
|
@ -206,15 +206,16 @@ Run using `btm`.
|
||||||
|
|
||||||
#### Process bindings
|
#### Process bindings
|
||||||
|
|
||||||
| | |
|
| | |
|
||||||
| ------------- | ---------------------------------------------------------- |
|
| ------------- | ------------------------------------------------------------- |
|
||||||
| `dd` | Kill the selected process |
|
| `dd` | Kill the selected process |
|
||||||
| `c` | Sort by CPU usage, press again to reverse sorting order |
|
| `c` | Sort by CPU usage, press again to reverse sorting order |
|
||||||
| `m` | Sort by memory usage, press again to reverse sorting order |
|
| `m` | Sort by memory usage, press again to reverse sorting order |
|
||||||
| `p` | Sort by PID name, press again to reverse sorting order |
|
| `p` | Sort by PID name, press again to reverse sorting order |
|
||||||
| `n` | Sort by process name, press again to reverse sorting order |
|
| `n` | Sort by process name, press again to reverse sorting order |
|
||||||
| `Tab` | Group/un-group processes with the same name |
|
| `Tab` | Group/un-group processes with the same name |
|
||||||
| `Ctrl-f`, `/` | Open process search widget |
|
| `Ctrl-f`, `/` | Open process search widget |
|
||||||
|
| `P` | Toggle between showing the full path or just the process name |
|
||||||
|
|
||||||
#### Process search bindings
|
#### Process search bindings
|
||||||
|
|
||||||
|
@ -551,6 +552,7 @@ Thanks to all contributors ([emoji key](https://allcontributors.org/docs/en/emoj
|
||||||
|
|
||||||
<!-- markdownlint-enable -->
|
<!-- markdownlint-enable -->
|
||||||
<!-- prettier-ignore-end -->
|
<!-- prettier-ignore-end -->
|
||||||
|
|
||||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||||
|
|
||||||
## Thanks
|
## Thanks
|
||||||
|
|
104
src/app.rs
104
src/app.rs
|
@ -149,8 +149,7 @@ impl App {
|
||||||
BottomWidgetType::Proc => {
|
BottomWidgetType::Proc => {
|
||||||
if let Some(current_proc_state) = self
|
if let Some(current_proc_state) = self
|
||||||
.proc_state
|
.proc_state
|
||||||
.widget_states
|
.get_mut_widget_state(self.current_widget.widget_id)
|
||||||
.get_mut(&self.current_widget.widget_id)
|
|
||||||
{
|
{
|
||||||
if current_proc_state.is_search_enabled() {
|
if current_proc_state.is_search_enabled() {
|
||||||
current_proc_state
|
current_proc_state
|
||||||
|
@ -164,8 +163,7 @@ impl App {
|
||||||
BottomWidgetType::ProcSearch => {
|
BottomWidgetType::ProcSearch => {
|
||||||
if let Some(current_proc_state) = self
|
if let Some(current_proc_state) = self
|
||||||
.proc_state
|
.proc_state
|
||||||
.widget_states
|
.get_mut_widget_state(self.current_widget.widget_id - 1)
|
||||||
.get_mut(&(self.current_widget.widget_id - 1))
|
|
||||||
{
|
{
|
||||||
if current_proc_state.is_search_enabled() {
|
if current_proc_state.is_search_enabled() {
|
||||||
current_proc_state
|
current_proc_state
|
||||||
|
@ -243,8 +241,7 @@ impl App {
|
||||||
BottomWidgetType::Cpu => {
|
BottomWidgetType::Cpu => {
|
||||||
if let Some(cpu_widget_state) = self
|
if let Some(cpu_widget_state) = self
|
||||||
.cpu_state
|
.cpu_state
|
||||||
.widget_states
|
.get_mut_widget_state(self.current_widget.widget_id)
|
||||||
.get_mut(&self.current_widget.widget_id)
|
|
||||||
{
|
{
|
||||||
cpu_widget_state.is_multi_graph_mode =
|
cpu_widget_state.is_multi_graph_mode =
|
||||||
!cpu_widget_state.is_multi_graph_mode;
|
!cpu_widget_state.is_multi_graph_mode;
|
||||||
|
@ -253,8 +250,7 @@ impl App {
|
||||||
BottomWidgetType::Proc => {
|
BottomWidgetType::Proc => {
|
||||||
if let Some(proc_widget_state) = self
|
if let Some(proc_widget_state) = self
|
||||||
.proc_state
|
.proc_state
|
||||||
.widget_states
|
.get_mut_widget_state(self.current_widget.widget_id)
|
||||||
.get_mut(&self.current_widget.widget_id)
|
|
||||||
{
|
{
|
||||||
// Toggles process widget grouping state
|
// Toggles process widget grouping state
|
||||||
proc_widget_state.is_grouped = !(proc_widget_state.is_grouped);
|
proc_widget_state.is_grouped = !(proc_widget_state.is_grouped);
|
||||||
|
@ -285,8 +281,7 @@ impl App {
|
||||||
// Toggle on
|
// Toggle on
|
||||||
if let Some(proc_widget_state) = self
|
if let Some(proc_widget_state) = self
|
||||||
.proc_state
|
.proc_state
|
||||||
.widget_states
|
.get_mut_widget_state(self.current_widget.widget_id)
|
||||||
.get_mut(&self.current_widget.widget_id)
|
|
||||||
{
|
{
|
||||||
proc_widget_state
|
proc_widget_state
|
||||||
.process_search_state
|
.process_search_state
|
||||||
|
@ -500,12 +495,20 @@ impl App {
|
||||||
pub fn on_left_key(&mut self) {
|
pub fn on_left_key(&mut self) {
|
||||||
if !self.is_in_dialog() {
|
if !self.is_in_dialog() {
|
||||||
match self.current_widget.widget_type {
|
match self.current_widget.widget_type {
|
||||||
|
BottomWidgetType::Proc => {
|
||||||
|
if let Some(proc_widget_state) = self
|
||||||
|
.proc_state
|
||||||
|
.get_mut_widget_state(self.current_widget.widget_id)
|
||||||
|
{
|
||||||
|
proc_widget_state.current_column_index =
|
||||||
|
proc_widget_state.current_column_index.saturating_sub(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
BottomWidgetType::ProcSearch => {
|
BottomWidgetType::ProcSearch => {
|
||||||
let is_in_search_widget = self.is_in_search_widget();
|
let is_in_search_widget = self.is_in_search_widget();
|
||||||
if let Some(proc_widget_state) = self
|
if let Some(proc_widget_state) = self
|
||||||
.proc_state
|
.proc_state
|
||||||
.widget_states
|
.get_mut_widget_state(self.current_widget.widget_id - 1)
|
||||||
.get_mut(&(self.current_widget.widget_id - 1))
|
|
||||||
{
|
{
|
||||||
if is_in_search_widget {
|
if is_in_search_widget {
|
||||||
let prev_cursor = proc_widget_state.get_cursor_position();
|
let prev_cursor = proc_widget_state.get_cursor_position();
|
||||||
|
@ -533,8 +536,7 @@ impl App {
|
||||||
if !self.canvas_data.battery_data.is_empty() {
|
if !self.canvas_data.battery_data.is_empty() {
|
||||||
if let Some(battery_widget_state) = self
|
if let Some(battery_widget_state) = self
|
||||||
.battery_state
|
.battery_state
|
||||||
.widget_states
|
.get_mut_widget_state(self.current_widget.widget_id)
|
||||||
.get_mut(&self.current_widget.widget_id)
|
|
||||||
{
|
{
|
||||||
if battery_widget_state.currently_selected_battery_index > 0 {
|
if battery_widget_state.currently_selected_battery_index > 0 {
|
||||||
battery_widget_state.currently_selected_battery_index -= 1;
|
battery_widget_state.currently_selected_battery_index -= 1;
|
||||||
|
@ -552,12 +554,21 @@ impl App {
|
||||||
pub fn on_right_key(&mut self) {
|
pub fn on_right_key(&mut self) {
|
||||||
if !self.is_in_dialog() {
|
if !self.is_in_dialog() {
|
||||||
match self.current_widget.widget_type {
|
match self.current_widget.widget_type {
|
||||||
|
BottomWidgetType::Proc => {
|
||||||
|
if let Some(proc_widget_state) = self
|
||||||
|
.proc_state
|
||||||
|
.get_mut_widget_state(self.current_widget.widget_id)
|
||||||
|
{
|
||||||
|
if proc_widget_state.current_column_index < proc_widget_state.num_columns {
|
||||||
|
proc_widget_state.current_column_index += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BottomWidgetType::ProcSearch => {
|
BottomWidgetType::ProcSearch => {
|
||||||
let is_in_search_widget = self.is_in_search_widget();
|
let is_in_search_widget = self.is_in_search_widget();
|
||||||
if let Some(proc_widget_state) = self
|
if let Some(proc_widget_state) = self
|
||||||
.proc_state
|
.proc_state
|
||||||
.widget_states
|
.get_mut_widget_state(self.current_widget.widget_id - 1)
|
||||||
.get_mut(&(self.current_widget.widget_id - 1))
|
|
||||||
{
|
{
|
||||||
if is_in_search_widget {
|
if is_in_search_widget {
|
||||||
let prev_cursor = proc_widget_state.get_cursor_position();
|
let prev_cursor = proc_widget_state.get_cursor_position();
|
||||||
|
@ -586,8 +597,7 @@ impl App {
|
||||||
let battery_count = self.canvas_data.battery_data.len();
|
let battery_count = self.canvas_data.battery_data.len();
|
||||||
if let Some(battery_widget_state) = self
|
if let Some(battery_widget_state) = self
|
||||||
.battery_state
|
.battery_state
|
||||||
.widget_states
|
.get_mut_widget_state(self.current_widget.widget_id)
|
||||||
.get_mut(&self.current_widget.widget_id)
|
|
||||||
{
|
{
|
||||||
if battery_widget_state.currently_selected_battery_index
|
if battery_widget_state.currently_selected_battery_index
|
||||||
< battery_count - 1
|
< battery_count - 1
|
||||||
|
@ -887,8 +897,7 @@ impl App {
|
||||||
if let BottomWidgetType::Proc = self.current_widget.widget_type {
|
if let BottomWidgetType::Proc = self.current_widget.widget_type {
|
||||||
if let Some(proc_widget_state) = self
|
if let Some(proc_widget_state) = self
|
||||||
.proc_state
|
.proc_state
|
||||||
.widget_states
|
.get_mut_widget_state(self.current_widget.widget_id)
|
||||||
.get_mut(&self.current_widget.widget_id)
|
|
||||||
{
|
{
|
||||||
match proc_widget_state.process_sorting_type {
|
match proc_widget_state.process_sorting_type {
|
||||||
processes::ProcessSorting::CPU => {
|
processes::ProcessSorting::CPU => {
|
||||||
|
@ -911,8 +920,7 @@ impl App {
|
||||||
if let BottomWidgetType::Proc = self.current_widget.widget_type {
|
if let BottomWidgetType::Proc = self.current_widget.widget_type {
|
||||||
if let Some(proc_widget_state) = self
|
if let Some(proc_widget_state) = self
|
||||||
.proc_state
|
.proc_state
|
||||||
.widget_states
|
.get_mut_widget_state(self.current_widget.widget_id)
|
||||||
.get_mut(&self.current_widget.widget_id)
|
|
||||||
{
|
{
|
||||||
match proc_widget_state.process_sorting_type {
|
match proc_widget_state.process_sorting_type {
|
||||||
processes::ProcessSorting::MEM => {
|
processes::ProcessSorting::MEM => {
|
||||||
|
@ -934,8 +942,7 @@ impl App {
|
||||||
if let BottomWidgetType::Proc = self.current_widget.widget_type {
|
if let BottomWidgetType::Proc = self.current_widget.widget_type {
|
||||||
if let Some(proc_widget_state) = self
|
if let Some(proc_widget_state) = self
|
||||||
.proc_state
|
.proc_state
|
||||||
.widget_states
|
.get_mut_widget_state(self.current_widget.widget_id)
|
||||||
.get_mut(&self.current_widget.widget_id)
|
|
||||||
{
|
{
|
||||||
// Skip if grouped
|
// Skip if grouped
|
||||||
if !proc_widget_state.is_grouped {
|
if !proc_widget_state.is_grouped {
|
||||||
|
@ -956,21 +963,32 @@ impl App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
'P' => {
|
||||||
|
if let BottomWidgetType::Proc = self.current_widget.widget_type {
|
||||||
|
if let Some(proc_widget_state) = self
|
||||||
|
.proc_state
|
||||||
|
.get_mut_widget_state(self.current_widget.widget_id)
|
||||||
|
{
|
||||||
|
proc_widget_state.is_using_full_path =
|
||||||
|
!proc_widget_state.is_using_full_path;
|
||||||
|
self.proc_state.force_update = Some(self.current_widget.widget_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
'n' => {
|
'n' => {
|
||||||
if let BottomWidgetType::Proc = self.current_widget.widget_type {
|
if let BottomWidgetType::Proc = self.current_widget.widget_type {
|
||||||
if let Some(proc_widget_state) = self
|
if let Some(proc_widget_state) = self
|
||||||
.proc_state
|
.proc_state
|
||||||
.widget_states
|
.get_mut_widget_state(self.current_widget.widget_id)
|
||||||
.get_mut(&self.current_widget.widget_id)
|
|
||||||
{
|
{
|
||||||
match proc_widget_state.process_sorting_type {
|
match proc_widget_state.process_sorting_type {
|
||||||
processes::ProcessSorting::NAME => {
|
processes::ProcessSorting::IDENTIFIER => {
|
||||||
proc_widget_state.process_sorting_reverse =
|
proc_widget_state.process_sorting_reverse =
|
||||||
!proc_widget_state.process_sorting_reverse
|
!proc_widget_state.process_sorting_reverse
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
proc_widget_state.process_sorting_type =
|
proc_widget_state.process_sorting_type =
|
||||||
processes::ProcessSorting::NAME;
|
processes::ProcessSorting::IDENTIFIER;
|
||||||
proc_widget_state.process_sorting_reverse = false;
|
proc_widget_state.process_sorting_reverse = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1371,8 +1389,7 @@ impl App {
|
||||||
if let Some(new_widget) = self.widget_map.get(&new_widget_id) {
|
if let Some(new_widget) = self.widget_map.get(&new_widget_id) {
|
||||||
if let Some(proc_widget_state) = self
|
if let Some(proc_widget_state) = self
|
||||||
.proc_state
|
.proc_state
|
||||||
.widget_states
|
.get_widget_state(self.current_widget.widget_id)
|
||||||
.get(&self.current_widget.widget_id)
|
|
||||||
{
|
{
|
||||||
if proc_widget_state.is_search_enabled() {
|
if proc_widget_state.is_search_enabled() {
|
||||||
self.current_widget = new_widget.clone();
|
self.current_widget = new_widget.clone();
|
||||||
|
@ -1393,8 +1410,7 @@ impl App {
|
||||||
BottomWidgetType::Proc => {
|
BottomWidgetType::Proc => {
|
||||||
if let Some(proc_widget_state) = self
|
if let Some(proc_widget_state) = self
|
||||||
.proc_state
|
.proc_state
|
||||||
.widget_states
|
.get_mut_widget_state(self.current_widget.widget_id)
|
||||||
.get_mut(&self.current_widget.widget_id)
|
|
||||||
{
|
{
|
||||||
proc_widget_state.scroll_state.current_scroll_position = 0;
|
proc_widget_state.scroll_state.current_scroll_position = 0;
|
||||||
proc_widget_state.scroll_state.scroll_direction = ScrollDirection::UP;
|
proc_widget_state.scroll_state.scroll_direction = ScrollDirection::UP;
|
||||||
|
@ -1403,8 +1419,7 @@ impl App {
|
||||||
BottomWidgetType::Temp => {
|
BottomWidgetType::Temp => {
|
||||||
if let Some(temp_widget_state) = self
|
if let Some(temp_widget_state) = self
|
||||||
.temp_state
|
.temp_state
|
||||||
.widget_states
|
.get_mut_widget_state(self.current_widget.widget_id)
|
||||||
.get_mut(&self.current_widget.widget_id)
|
|
||||||
{
|
{
|
||||||
temp_widget_state.scroll_state.current_scroll_position = 0;
|
temp_widget_state.scroll_state.current_scroll_position = 0;
|
||||||
temp_widget_state.scroll_state.scroll_direction = ScrollDirection::UP;
|
temp_widget_state.scroll_state.scroll_direction = ScrollDirection::UP;
|
||||||
|
@ -1413,8 +1428,7 @@ impl App {
|
||||||
BottomWidgetType::Disk => {
|
BottomWidgetType::Disk => {
|
||||||
if let Some(disk_widget_state) = self
|
if let Some(disk_widget_state) = self
|
||||||
.disk_state
|
.disk_state
|
||||||
.widget_states
|
.get_mut_widget_state(self.current_widget.widget_id)
|
||||||
.get_mut(&self.current_widget.widget_id)
|
|
||||||
{
|
{
|
||||||
disk_widget_state.scroll_state.current_scroll_position = 0;
|
disk_widget_state.scroll_state.current_scroll_position = 0;
|
||||||
disk_widget_state.scroll_state.scroll_direction = ScrollDirection::UP;
|
disk_widget_state.scroll_state.scroll_direction = ScrollDirection::UP;
|
||||||
|
@ -1423,8 +1437,7 @@ impl App {
|
||||||
BottomWidgetType::CpuLegend => {
|
BottomWidgetType::CpuLegend => {
|
||||||
if let Some(cpu_widget_state) = self
|
if let Some(cpu_widget_state) = self
|
||||||
.cpu_state
|
.cpu_state
|
||||||
.widget_states
|
.get_mut_widget_state(self.current_widget.widget_id - 1)
|
||||||
.get_mut(&(self.current_widget.widget_id - 1))
|
|
||||||
{
|
{
|
||||||
cpu_widget_state.scroll_state.current_scroll_position = 0;
|
cpu_widget_state.scroll_state.current_scroll_position = 0;
|
||||||
cpu_widget_state.scroll_state.scroll_direction = ScrollDirection::UP;
|
cpu_widget_state.scroll_state.scroll_direction = ScrollDirection::UP;
|
||||||
|
@ -1445,8 +1458,7 @@ impl App {
|
||||||
BottomWidgetType::Proc => {
|
BottomWidgetType::Proc => {
|
||||||
if let Some(proc_widget_state) = self
|
if let Some(proc_widget_state) = self
|
||||||
.proc_state
|
.proc_state
|
||||||
.widget_states
|
.get_mut_widget_state(self.current_widget.widget_id)
|
||||||
.get_mut(&self.current_widget.widget_id)
|
|
||||||
{
|
{
|
||||||
if let Some(finalized_process_data) = self
|
if let Some(finalized_process_data) = self
|
||||||
.canvas_data
|
.canvas_data
|
||||||
|
@ -1465,8 +1477,7 @@ impl App {
|
||||||
BottomWidgetType::Temp => {
|
BottomWidgetType::Temp => {
|
||||||
if let Some(temp_widget_state) = self
|
if let Some(temp_widget_state) = self
|
||||||
.temp_state
|
.temp_state
|
||||||
.widget_states
|
.get_mut_widget_state(self.current_widget.widget_id)
|
||||||
.get_mut(&self.current_widget.widget_id)
|
|
||||||
{
|
{
|
||||||
if !self.canvas_data.temp_sensor_data.is_empty() {
|
if !self.canvas_data.temp_sensor_data.is_empty() {
|
||||||
temp_widget_state.scroll_state.current_scroll_position =
|
temp_widget_state.scroll_state.current_scroll_position =
|
||||||
|
@ -1478,8 +1489,7 @@ impl App {
|
||||||
BottomWidgetType::Disk => {
|
BottomWidgetType::Disk => {
|
||||||
if let Some(disk_widget_state) = self
|
if let Some(disk_widget_state) = self
|
||||||
.disk_state
|
.disk_state
|
||||||
.widget_states
|
.get_mut_widget_state(self.current_widget.widget_id)
|
||||||
.get_mut(&self.current_widget.widget_id)
|
|
||||||
{
|
{
|
||||||
if !self.canvas_data.disk_data.is_empty() {
|
if !self.canvas_data.disk_data.is_empty() {
|
||||||
disk_widget_state.scroll_state.current_scroll_position =
|
disk_widget_state.scroll_state.current_scroll_position =
|
||||||
|
@ -1491,8 +1501,7 @@ impl App {
|
||||||
BottomWidgetType::CpuLegend => {
|
BottomWidgetType::CpuLegend => {
|
||||||
if let Some(cpu_widget_state) = self
|
if let Some(cpu_widget_state) = self
|
||||||
.cpu_state
|
.cpu_state
|
||||||
.widget_states
|
.get_mut_widget_state(self.current_widget.widget_id - 1)
|
||||||
.get_mut(&(self.current_widget.widget_id - 1))
|
|
||||||
{
|
{
|
||||||
let cap = self.canvas_data.cpu_data.len();
|
let cap = self.canvas_data.cpu_data.len();
|
||||||
if cap > 0 {
|
if cap > 0 {
|
||||||
|
@ -1564,8 +1573,7 @@ impl App {
|
||||||
fn change_process_position(&mut self, num_to_change_by: i64) {
|
fn change_process_position(&mut self, num_to_change_by: i64) {
|
||||||
if let Some(proc_widget_state) = self
|
if let Some(proc_widget_state) = self
|
||||||
.proc_state
|
.proc_state
|
||||||
.widget_states
|
.get_mut_widget_state(self.current_widget.widget_id)
|
||||||
.get_mut(&self.current_widget.widget_id)
|
|
||||||
{
|
{
|
||||||
let current_posn = proc_widget_state.scroll_state.current_scroll_position;
|
let current_posn = proc_widget_state.scroll_state.current_scroll_position;
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ pub enum ProcessSorting {
|
||||||
CPU,
|
CPU,
|
||||||
MEM,
|
MEM,
|
||||||
PID,
|
PID,
|
||||||
NAME,
|
IDENTIFIER,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ProcessSorting {
|
impl Default for ProcessSorting {
|
||||||
|
@ -32,6 +32,7 @@ pub struct ProcessHarvest {
|
||||||
pub cpu_usage_percent: f64,
|
pub cpu_usage_percent: f64,
|
||||||
pub mem_usage_percent: f64,
|
pub mem_usage_percent: f64,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
pub path: String,
|
||||||
pub read_bytes_per_sec: u64,
|
pub read_bytes_per_sec: u64,
|
||||||
pub write_bytes_per_sec: u64,
|
pub write_bytes_per_sec: u64,
|
||||||
pub total_read_bytes: u64,
|
pub total_read_bytes: u64,
|
||||||
|
@ -46,6 +47,7 @@ pub struct PrevProcDetails {
|
||||||
pub total_write_bytes: u64,
|
pub total_write_bytes: u64,
|
||||||
pub cpu_time: f64,
|
pub cpu_time: f64,
|
||||||
pub proc_stat_path: PathBuf,
|
pub proc_stat_path: PathBuf,
|
||||||
|
pub proc_exe_path: PathBuf,
|
||||||
pub proc_io_path: PathBuf,
|
pub proc_io_path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,6 +56,7 @@ impl PrevProcDetails {
|
||||||
let pid_string = pid.to_string();
|
let pid_string = pid.to_string();
|
||||||
PrevProcDetails {
|
PrevProcDetails {
|
||||||
proc_io_path: PathBuf::from(format!("/proc/{}/io", pid_string)),
|
proc_io_path: PathBuf::from(format!("/proc/{}/io", pid_string)),
|
||||||
|
proc_exe_path: PathBuf::from(format!("/proc/{}/exe", pid_string)),
|
||||||
proc_stat_path: PathBuf::from(format!("/proc/{}/stat", pid_string)),
|
proc_stat_path: PathBuf::from(format!("/proc/{}/stat", pid_string)),
|
||||||
..PrevProcDetails::default()
|
..PrevProcDetails::default()
|
||||||
}
|
}
|
||||||
|
@ -174,7 +177,9 @@ fn get_linux_cpu_usage(
|
||||||
// Based heavily on https://stackoverflow.com/a/23376195 and https://stackoverflow.com/a/1424556
|
// Based heavily on https://stackoverflow.com/a/23376195 and https://stackoverflow.com/a/1424556
|
||||||
let after_proc_val = get_process_cpu_stats(&proc_stats);
|
let after_proc_val = get_process_cpu_stats(&proc_stats);
|
||||||
|
|
||||||
if use_current_cpu_total {
|
if cpu_usage == 0.0 {
|
||||||
|
Ok((0_f64, after_proc_val))
|
||||||
|
} else if use_current_cpu_total {
|
||||||
Ok((
|
Ok((
|
||||||
(after_proc_val - before_proc_val) / cpu_usage * 100_f64,
|
(after_proc_val - before_proc_val) / cpu_usage * 100_f64,
|
||||||
after_proc_val,
|
after_proc_val,
|
||||||
|
@ -194,17 +199,18 @@ fn convert_ps<S: core::hash::BuildHasher>(
|
||||||
new_pid_stats: &mut HashMap<u32, PrevProcDetails, S>, use_current_cpu_total: bool,
|
new_pid_stats: &mut HashMap<u32, PrevProcDetails, S>, use_current_cpu_total: bool,
|
||||||
time_difference_in_secs: u64,
|
time_difference_in_secs: u64,
|
||||||
) -> std::io::Result<ProcessHarvest> {
|
) -> std::io::Result<ProcessHarvest> {
|
||||||
let pid = (&process[..11])
|
let pid = (&process[..10])
|
||||||
.trim()
|
.trim()
|
||||||
.to_string()
|
.to_string()
|
||||||
.parse::<u32>()
|
.parse::<u32>()
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
let name = (&process[11..61]).trim().to_string();
|
let name = (&process[11..111]).trim().to_string();
|
||||||
let mem_usage_percent = (&process[62..])
|
let mem_usage_percent = (&process[112..116])
|
||||||
.trim()
|
.trim()
|
||||||
.to_string()
|
.to_string()
|
||||||
.parse::<f64>()
|
.parse::<f64>()
|
||||||
.unwrap_or(0_f64);
|
.unwrap_or(0_f64);
|
||||||
|
let path = (&process[117..]).trim().to_string();
|
||||||
|
|
||||||
let mut new_pid_stat = if let Some(prev_proc_stats) = prev_pid_stats.remove(&pid) {
|
let mut new_pid_stat = if let Some(prev_proc_stats) = prev_pid_stats.remove(&pid) {
|
||||||
prev_proc_stats
|
prev_proc_stats
|
||||||
|
@ -265,9 +271,11 @@ fn convert_ps<S: core::hash::BuildHasher>(
|
||||||
|
|
||||||
new_pid_stats.insert(pid, new_pid_stat);
|
new_pid_stats.insert(pid, new_pid_stat);
|
||||||
|
|
||||||
|
// TODO: Is there a way to re-use these stats so I don't have to do so many syscalls?
|
||||||
Ok(ProcessHarvest {
|
Ok(ProcessHarvest {
|
||||||
pid,
|
pid,
|
||||||
name,
|
name,
|
||||||
|
path,
|
||||||
mem_usage_percent,
|
mem_usage_percent,
|
||||||
cpu_usage_percent,
|
cpu_usage_percent,
|
||||||
total_read_bytes,
|
total_read_bytes,
|
||||||
|
@ -286,7 +294,7 @@ pub fn linux_get_processes_list(
|
||||||
time_difference_in_secs: u64,
|
time_difference_in_secs: u64,
|
||||||
) -> crate::utils::error::Result<Vec<ProcessHarvest>> {
|
) -> crate::utils::error::Result<Vec<ProcessHarvest>> {
|
||||||
let ps_result = Command::new("ps")
|
let ps_result = Command::new("ps")
|
||||||
.args(&["-axo", "pid:10,comm:50,%mem:5", "--noheader"])
|
.args(&["-axo", "pid:10,comm:100,%mem:5,args:100", "--noheader"])
|
||||||
.output()?;
|
.output()?;
|
||||||
let ps_stdout = String::from_utf8_lossy(&ps_result.stdout);
|
let ps_stdout = String::from_utf8_lossy(&ps_result.stdout);
|
||||||
let split_string = ps_stdout.split('\n');
|
let split_string = ps_stdout.split('\n');
|
||||||
|
@ -356,13 +364,21 @@ pub fn windows_macos_get_processes_list(
|
||||||
} else {
|
} else {
|
||||||
process_val.name().to_string()
|
process_val.name().to_string()
|
||||||
};
|
};
|
||||||
|
let path = {
|
||||||
|
let path = process_val.cmd().join(" ");
|
||||||
|
if path.is_empty() {
|
||||||
|
name.to_string()
|
||||||
|
} else {
|
||||||
|
path
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let pcu = if cfg!(target_os = "windows") {
|
let pcu = if cfg!(target_os = "windows") || num_cpus == 0.0 {
|
||||||
process_val.cpu_usage() as f64
|
process_val.cpu_usage() as f64
|
||||||
} else {
|
} else {
|
||||||
process_val.cpu_usage() as f64 / num_cpus
|
process_val.cpu_usage() as f64 / num_cpus
|
||||||
};
|
};
|
||||||
let process_cpu_usage = if use_current_cpu_total {
|
let process_cpu_usage = if use_current_cpu_total && cpu_usage > 0.0 {
|
||||||
pcu / cpu_usage
|
pcu / cpu_usage
|
||||||
} else {
|
} else {
|
||||||
pcu
|
pcu
|
||||||
|
@ -373,6 +389,7 @@ pub fn windows_macos_get_processes_list(
|
||||||
process_vector.push(ProcessHarvest {
|
process_vector.push(ProcessHarvest {
|
||||||
pid: process_val.pid() as u32,
|
pid: process_val.pid() as u32,
|
||||||
name,
|
name,
|
||||||
|
path,
|
||||||
mem_usage_percent: if mem_total_kb > 0 {
|
mem_usage_percent: if mem_total_kb > 0 {
|
||||||
process_val.memory() as f64 * 100.0 / mem_total_kb as f64
|
process_val.memory() as f64 * 100.0 / mem_total_kb as f64
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -147,6 +147,9 @@ pub struct ProcWidgetState {
|
||||||
pub scroll_state: AppScrollWidgetState,
|
pub scroll_state: AppScrollWidgetState,
|
||||||
pub process_sorting_type: processes::ProcessSorting,
|
pub process_sorting_type: processes::ProcessSorting,
|
||||||
pub process_sorting_reverse: bool,
|
pub process_sorting_reverse: bool,
|
||||||
|
pub is_using_full_path: bool,
|
||||||
|
pub current_column_index: usize,
|
||||||
|
pub num_columns: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProcWidgetState {
|
impl ProcWidgetState {
|
||||||
|
@ -171,6 +174,9 @@ impl ProcWidgetState {
|
||||||
scroll_state: AppScrollWidgetState::default(),
|
scroll_state: AppScrollWidgetState::default(),
|
||||||
process_sorting_type: processes::ProcessSorting::CPU,
|
process_sorting_type: processes::ProcessSorting::CPU,
|
||||||
process_sorting_reverse: true,
|
process_sorting_reverse: true,
|
||||||
|
is_using_full_path: false,
|
||||||
|
current_column_index: 0,
|
||||||
|
num_columns: 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,6 +269,14 @@ impl ProcState {
|
||||||
force_update_all: false,
|
force_update_all: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_mut_widget_state(&mut self, widget_id: u64) -> Option<&mut ProcWidgetState> {
|
||||||
|
self.widget_states.get_mut(&widget_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_widget_state(&self, widget_id: u64) -> Option<&ProcWidgetState> {
|
||||||
|
self.widget_states.get(&widget_id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct NetWidgetState {
|
pub struct NetWidgetState {
|
||||||
|
@ -291,6 +305,14 @@ impl NetState {
|
||||||
widget_states,
|
widget_states,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_mut_widget_state(&mut self, widget_id: u64) -> Option<&mut NetWidgetState> {
|
||||||
|
self.widget_states.get_mut(&widget_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_widget_state(&self, widget_id: u64) -> Option<&NetWidgetState> {
|
||||||
|
self.widget_states.get(&widget_id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CpuWidgetState {
|
pub struct CpuWidgetState {
|
||||||
|
@ -325,6 +347,14 @@ impl CpuState {
|
||||||
widget_states,
|
widget_states,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_mut_widget_state(&mut self, widget_id: u64) -> Option<&mut CpuWidgetState> {
|
||||||
|
self.widget_states.get_mut(&widget_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_widget_state(&self, widget_id: u64) -> Option<&CpuWidgetState> {
|
||||||
|
self.widget_states.get(&widget_id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MemWidgetState {
|
pub struct MemWidgetState {
|
||||||
|
@ -353,6 +383,14 @@ impl MemState {
|
||||||
widget_states,
|
widget_states,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_mut_widget_state(&mut self, widget_id: u64) -> Option<&mut MemWidgetState> {
|
||||||
|
self.widget_states.get_mut(&widget_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_widget_state(&self, widget_id: u64) -> Option<&MemWidgetState> {
|
||||||
|
self.widget_states.get(&widget_id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TempWidgetState {
|
pub struct TempWidgetState {
|
||||||
|
@ -375,6 +413,14 @@ impl TempState {
|
||||||
pub fn init(widget_states: HashMap<u64, TempWidgetState>) -> Self {
|
pub fn init(widget_states: HashMap<u64, TempWidgetState>) -> Self {
|
||||||
TempState { widget_states }
|
TempState { widget_states }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_mut_widget_state(&mut self, widget_id: u64) -> Option<&mut TempWidgetState> {
|
||||||
|
self.widget_states.get_mut(&widget_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_widget_state(&self, widget_id: u64) -> Option<&TempWidgetState> {
|
||||||
|
self.widget_states.get(&widget_id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DiskWidgetState {
|
pub struct DiskWidgetState {
|
||||||
|
@ -397,6 +443,14 @@ impl DiskState {
|
||||||
pub fn init(widget_states: HashMap<u64, DiskWidgetState>) -> Self {
|
pub fn init(widget_states: HashMap<u64, DiskWidgetState>) -> Self {
|
||||||
DiskState { widget_states }
|
DiskState { widget_states }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_mut_widget_state(&mut self, widget_id: u64) -> Option<&mut DiskWidgetState> {
|
||||||
|
self.widget_states.get_mut(&widget_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_widget_state(&self, widget_id: u64) -> Option<&DiskWidgetState> {
|
||||||
|
self.widget_states.get(&widget_id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub struct BasicTableWidgetState {
|
pub struct BasicTableWidgetState {
|
||||||
// Since this is intended (currently) to only be used for ONE widget, that's
|
// Since this is intended (currently) to only be used for ONE widget, that's
|
||||||
|
@ -420,6 +474,14 @@ impl BatteryState {
|
||||||
pub fn init(widget_states: HashMap<u64, BatteryWidgetState>) -> Self {
|
pub fn init(widget_states: HashMap<u64, BatteryWidgetState>) -> Self {
|
||||||
BatteryState { widget_states }
|
BatteryState { widget_states }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_mut_widget_state(&mut self, widget_id: u64) -> Option<&mut BatteryWidgetState> {
|
||||||
|
self.widget_states.get_mut(&widget_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_widget_state(&self, widget_id: u64) -> Option<&BatteryWidgetState> {
|
||||||
|
self.widget_states.get(&widget_id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
|
@ -40,8 +40,6 @@ pub struct DisplayableData {
|
||||||
pub temp_sensor_data: Vec<Vec<String>>,
|
pub temp_sensor_data: Vec<Vec<String>>,
|
||||||
// Not the final value
|
// Not the final value
|
||||||
pub process_data: Vec<ConvertedProcessData>,
|
pub process_data: Vec<ConvertedProcessData>,
|
||||||
// Not the final value
|
|
||||||
pub grouped_process_data: Vec<ConvertedProcessData>,
|
|
||||||
// What's actually displayed
|
// What's actually displayed
|
||||||
pub finalized_process_data_map: HashMap<u64, Vec<ConvertedProcessData>>,
|
pub finalized_process_data_map: HashMap<u64, Vec<ConvertedProcessData>>,
|
||||||
pub mem_label: String,
|
pub mem_label: String,
|
||||||
|
|
|
@ -28,20 +28,19 @@ impl KillDialog for Painter {
|
||||||
if app_state.is_grouped(app_state.current_widget.widget_id) {
|
if app_state.is_grouped(app_state.current_widget.widget_id) {
|
||||||
if to_kill_processes.1.len() != 1 {
|
if to_kill_processes.1.len() != 1 {
|
||||||
Text::raw(format!(
|
Text::raw(format!(
|
||||||
"\nKill {} processes with the name {}?",
|
"\nKill {} processes with the name \"{}\"?",
|
||||||
to_kill_processes.1.len(),
|
to_kill_processes.1.len(),
|
||||||
to_kill_processes.0
|
to_kill_processes.0
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
Text::raw(format!(
|
Text::raw(format!(
|
||||||
"\nKill {} process with the name {}?",
|
"\nKill 1 process with the name \"{}\"?",
|
||||||
to_kill_processes.1.len(),
|
|
||||||
to_kill_processes.0
|
to_kill_processes.0
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Text::raw(format!(
|
Text::raw(format!(
|
||||||
"\nKill process {} with PID {}?",
|
"\nKill process \"{}\" with PID {}?",
|
||||||
to_kill_processes.0, first_pid
|
to_kill_processes.0, first_pid
|
||||||
))
|
))
|
||||||
},
|
},
|
||||||
|
|
|
@ -31,7 +31,7 @@ impl HelpDialog for Painter {
|
||||||
// small terminal sizes... oh joy.
|
// small terminal sizes... oh joy.
|
||||||
|
|
||||||
let mut overflow_buffer = 0;
|
let mut overflow_buffer = 0;
|
||||||
let paragraph_width = draw_loc.width - 2;
|
let paragraph_width = std::cmp::max(draw_loc.width.saturating_sub(2), 1);
|
||||||
let mut prev_section_len = 0;
|
let mut prev_section_len = 0;
|
||||||
|
|
||||||
constants::HELP_TEXT
|
constants::HELP_TEXT
|
||||||
|
|
|
@ -133,13 +133,17 @@ impl ProcessTableWidget for Painter {
|
||||||
});
|
});
|
||||||
|
|
||||||
use app::data_harvester::processes::ProcessSorting;
|
use app::data_harvester::processes::ProcessSorting;
|
||||||
let mut pid_or_name = if proc_widget_state.is_grouped {
|
let mut pid_or_count = if proc_widget_state.is_grouped {
|
||||||
"Count"
|
"Count"
|
||||||
} else {
|
} else {
|
||||||
"PID(p)"
|
"PID(p)"
|
||||||
}
|
}
|
||||||
.to_string();
|
.to_string();
|
||||||
let mut name = "Name(n)".to_string();
|
let mut identifier = if proc_widget_state.is_using_full_path {
|
||||||
|
"Command(n)".to_string()
|
||||||
|
} else {
|
||||||
|
"Name(n)".to_string()
|
||||||
|
};
|
||||||
let mut cpu = "CPU%(c)".to_string();
|
let mut cpu = "CPU%(c)".to_string();
|
||||||
let mut mem = "Mem%(m)".to_string();
|
let mut mem = "Mem%(m)".to_string();
|
||||||
let rps = "R/s".to_string();
|
let rps = "R/s".to_string();
|
||||||
|
@ -157,14 +161,15 @@ impl ProcessTableWidget for Painter {
|
||||||
match proc_widget_state.process_sorting_type {
|
match proc_widget_state.process_sorting_type {
|
||||||
ProcessSorting::CPU => cpu += &direction_val,
|
ProcessSorting::CPU => cpu += &direction_val,
|
||||||
ProcessSorting::MEM => mem += &direction_val,
|
ProcessSorting::MEM => mem += &direction_val,
|
||||||
ProcessSorting::PID => pid_or_name += &direction_val,
|
ProcessSorting::PID => pid_or_count += &direction_val,
|
||||||
ProcessSorting::NAME => name += &direction_val,
|
ProcessSorting::IDENTIFIER => identifier += &direction_val,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: Gonna have to figure out how to do left/right GUI notation.
|
||||||
let process_headers = if proc_widget_state.is_grouped {
|
let process_headers = if proc_widget_state.is_grouped {
|
||||||
vec![
|
vec![
|
||||||
pid_or_name,
|
pid_or_count,
|
||||||
name,
|
identifier,
|
||||||
cpu,
|
cpu,
|
||||||
mem,
|
mem,
|
||||||
rps,
|
rps,
|
||||||
|
@ -174,8 +179,8 @@ impl ProcessTableWidget for Painter {
|
||||||
]
|
]
|
||||||
} else {
|
} else {
|
||||||
vec![
|
vec![
|
||||||
pid_or_name,
|
pid_or_count,
|
||||||
name,
|
identifier,
|
||||||
cpu,
|
cpu,
|
||||||
mem,
|
mem,
|
||||||
rps,
|
rps,
|
||||||
|
@ -185,6 +190,7 @@ impl ProcessTableWidget for Painter {
|
||||||
process_state,
|
process_state,
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
proc_widget_state.num_columns = process_headers.len();
|
||||||
let process_headers_lens: Vec<usize> = process_headers
|
let process_headers_lens: Vec<usize> = process_headers
|
||||||
.iter()
|
.iter()
|
||||||
.map(|entry| entry.len())
|
.map(|entry| entry.len())
|
||||||
|
@ -192,8 +198,16 @@ impl ProcessTableWidget for Painter {
|
||||||
|
|
||||||
// Calculate widths
|
// Calculate widths
|
||||||
let width = f64::from(draw_loc.width);
|
let width = f64::from(draw_loc.width);
|
||||||
|
|
||||||
|
// TODO: This is a ugly work-around for now.
|
||||||
let width_ratios = if proc_widget_state.is_grouped {
|
let width_ratios = if proc_widget_state.is_grouped {
|
||||||
vec![0.1, 0.2, 0.1, 0.1, 0.1, 0.1, 0.15, 0.15]
|
if proc_widget_state.is_using_full_path {
|
||||||
|
vec![0.1, 0.7, 0.05, 0.05, 0.025, 0.025, 0.025, 0.025]
|
||||||
|
} else {
|
||||||
|
vec![0.1, 0.2, 0.1, 0.1, 0.1, 0.1, 0.15, 0.15]
|
||||||
|
}
|
||||||
|
} else if proc_widget_state.is_using_full_path {
|
||||||
|
vec![0.1, 0.7, 0.05, 0.05, 0.02, 0.02, 0.02, 0.02, 0.02]
|
||||||
} else {
|
} else {
|
||||||
vec![0.1, 0.2, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]
|
vec![0.1, 0.2, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]
|
||||||
};
|
};
|
||||||
|
|
|
@ -79,7 +79,7 @@ pub const CPU_HELP_TEXT: [&str; 2] = [
|
||||||
"Mouse scroll Scrolling over an CPU core/average shows only that entry on the chart",
|
"Mouse scroll Scrolling over an CPU core/average shows only that entry on the chart",
|
||||||
];
|
];
|
||||||
|
|
||||||
pub const PROCESS_HELP_TEXT: [&str; 8] = [
|
pub const PROCESS_HELP_TEXT: [&str; 9] = [
|
||||||
"3 - Process widget\n",
|
"3 - Process widget\n",
|
||||||
"dd Kill the selected process\n",
|
"dd Kill the selected process\n",
|
||||||
"c Sort by CPU usage, press again to reverse sorting order\n",
|
"c Sort by CPU usage, press again to reverse sorting order\n",
|
||||||
|
@ -87,7 +87,8 @@ pub const PROCESS_HELP_TEXT: [&str; 8] = [
|
||||||
"p Sort by PID name, press again to reverse sorting order\n",
|
"p Sort by PID name, press again to reverse sorting order\n",
|
||||||
"n Sort by process name, press again to reverse sorting order\n",
|
"n Sort by process name, press again to reverse sorting order\n",
|
||||||
"Tab Group/un-group processes with the same name\n",
|
"Tab Group/un-group processes with the same name\n",
|
||||||
"Ctrl-f, / Open process search widget",
|
"Ctrl-f, / Open process search widget\n",
|
||||||
|
"P Toggle between showing the full path or just the process name",
|
||||||
];
|
];
|
||||||
|
|
||||||
pub const SEARCH_HELP_TEXT: [&str; 43] = [
|
pub const SEARCH_HELP_TEXT: [&str; 43] = [
|
||||||
|
|
|
@ -359,99 +359,122 @@ pub fn convert_network_data_points(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum ProcessGroupingType {
|
||||||
|
Grouped,
|
||||||
|
Ungrouped,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum ProcessNamingType {
|
||||||
|
Name,
|
||||||
|
Path,
|
||||||
|
}
|
||||||
|
|
||||||
pub fn convert_process_data(
|
pub fn convert_process_data(
|
||||||
current_data: &data_farmer::DataCollection,
|
current_data: &data_farmer::DataCollection, grouping_type: ProcessGroupingType,
|
||||||
) -> (Vec<ConvertedProcessData>, Vec<ConvertedProcessData>) {
|
name_type: ProcessNamingType,
|
||||||
let mut single_list = Vec::new();
|
) -> Vec<ConvertedProcessData> {
|
||||||
|
match grouping_type {
|
||||||
|
ProcessGroupingType::Ungrouped => current_data
|
||||||
|
.process_harvest
|
||||||
|
.iter()
|
||||||
|
.map(|process| {
|
||||||
|
let converted_rps = get_exact_byte_values(process.read_bytes_per_sec, false);
|
||||||
|
let converted_wps = get_exact_byte_values(process.write_bytes_per_sec, false);
|
||||||
|
let converted_total_read = get_exact_byte_values(process.total_read_bytes, false);
|
||||||
|
let converted_total_write = get_exact_byte_values(process.total_write_bytes, false);
|
||||||
|
|
||||||
// cpu, mem, pids
|
let read_per_sec = format!("{:.*}{}/s", 0, converted_rps.0, converted_rps.1);
|
||||||
let mut grouped_hashmap: HashMap<String, SingleProcessData> = std::collections::HashMap::new();
|
let write_per_sec = format!("{:.*}{}/s", 0, converted_wps.0, converted_wps.1);
|
||||||
|
let total_read =
|
||||||
|
format!("{:.*}{}", 0, converted_total_read.0, converted_total_read.1);
|
||||||
|
let total_write = format!(
|
||||||
|
"{:.*}{}",
|
||||||
|
0, converted_total_write.0, converted_total_write.1
|
||||||
|
);
|
||||||
|
|
||||||
// Go through every single process in the list... and build a hashmap + single list
|
ConvertedProcessData {
|
||||||
for process in &(current_data).process_harvest {
|
pid: process.pid,
|
||||||
let entry = grouped_hashmap
|
name: match name_type {
|
||||||
.entry(process.name.clone())
|
ProcessNamingType::Name => process.name.to_string(),
|
||||||
.or_insert(SingleProcessData {
|
ProcessNamingType::Path => process.path.to_string(),
|
||||||
pid: process.pid,
|
},
|
||||||
..SingleProcessData::default()
|
cpu_usage: process.cpu_usage_percent,
|
||||||
|
mem_usage: process.mem_usage_percent,
|
||||||
|
group_pids: vec![process.pid],
|
||||||
|
read_per_sec,
|
||||||
|
write_per_sec,
|
||||||
|
total_read,
|
||||||
|
total_write,
|
||||||
|
rps_f64: process.read_bytes_per_sec as f64,
|
||||||
|
wps_f64: process.write_bytes_per_sec as f64,
|
||||||
|
tr_f64: process.total_read_bytes as f64,
|
||||||
|
tw_f64: process.total_write_bytes as f64,
|
||||||
|
process_states: process.process_state.to_owned(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
ProcessGroupingType::Grouped => {
|
||||||
|
let mut grouped_hashmap: HashMap<String, SingleProcessData> =
|
||||||
|
std::collections::HashMap::new();
|
||||||
|
|
||||||
|
current_data.process_harvest.iter().for_each(|process| {
|
||||||
|
let entry = grouped_hashmap
|
||||||
|
.entry(match name_type {
|
||||||
|
ProcessNamingType::Name => process.name.to_string(),
|
||||||
|
ProcessNamingType::Path => process.path.to_string(),
|
||||||
|
})
|
||||||
|
.or_insert(SingleProcessData {
|
||||||
|
pid: process.pid,
|
||||||
|
..SingleProcessData::default()
|
||||||
|
});
|
||||||
|
|
||||||
|
(*entry).cpu_usage += process.cpu_usage_percent;
|
||||||
|
(*entry).mem_usage += process.mem_usage_percent;
|
||||||
|
(*entry).group_pids.push(process.pid);
|
||||||
|
(*entry).read_per_sec += process.read_bytes_per_sec;
|
||||||
|
(*entry).write_per_sec += process.write_bytes_per_sec;
|
||||||
|
(*entry).total_read += process.total_read_bytes;
|
||||||
|
(*entry).total_write += process.total_write_bytes;
|
||||||
});
|
});
|
||||||
|
|
||||||
(*entry).cpu_usage += process.cpu_usage_percent;
|
grouped_hashmap
|
||||||
(*entry).mem_usage += process.mem_usage_percent;
|
.iter()
|
||||||
(*entry).group_pids.push(process.pid);
|
.map(|(identifier, process_details)| {
|
||||||
(*entry).read_per_sec += process.read_bytes_per_sec;
|
let p = process_details.clone();
|
||||||
(*entry).write_per_sec += process.write_bytes_per_sec;
|
let converted_rps = get_exact_byte_values(p.read_per_sec, false);
|
||||||
(*entry).total_read += process.total_read_bytes;
|
let converted_wps = get_exact_byte_values(p.write_per_sec, false);
|
||||||
(*entry).total_write += process.total_write_bytes;
|
let converted_total_read = get_exact_byte_values(p.total_read, false);
|
||||||
|
let converted_total_write = get_exact_byte_values(p.total_write, false);
|
||||||
|
|
||||||
let converted_rps = get_exact_byte_values(process.read_bytes_per_sec, false);
|
let read_per_sec = format!("{:.*}{}/s", 0, converted_rps.0, converted_rps.1);
|
||||||
let converted_wps = get_exact_byte_values(process.write_bytes_per_sec, false);
|
let write_per_sec = format!("{:.*}{}/s", 0, converted_wps.0, converted_wps.1);
|
||||||
let converted_total_read = get_exact_byte_values(process.total_read_bytes, false);
|
let total_read =
|
||||||
let converted_total_write = get_exact_byte_values(process.total_write_bytes, false);
|
format!("{:.*}{}", 0, converted_total_read.0, converted_total_read.1);
|
||||||
|
let total_write = format!(
|
||||||
|
"{:.*}{}",
|
||||||
|
0, converted_total_write.0, converted_total_write.1
|
||||||
|
);
|
||||||
|
|
||||||
let read_per_sec = format!("{:.*}{}/s", 0, converted_rps.0, converted_rps.1);
|
ConvertedProcessData {
|
||||||
let write_per_sec = format!("{:.*}{}/s", 0, converted_wps.0, converted_wps.1);
|
pid: p.pid,
|
||||||
let total_read = format!("{:.*}{}", 0, converted_total_read.0, converted_total_read.1);
|
name: identifier.to_string(),
|
||||||
let total_write = format!(
|
cpu_usage: p.cpu_usage,
|
||||||
"{:.*}{}",
|
mem_usage: p.mem_usage,
|
||||||
0, converted_total_write.0, converted_total_write.1
|
group_pids: p.group_pids,
|
||||||
);
|
read_per_sec,
|
||||||
|
write_per_sec,
|
||||||
single_list.push(ConvertedProcessData {
|
total_read,
|
||||||
pid: process.pid,
|
total_write,
|
||||||
name: process.name.to_string(),
|
rps_f64: p.read_per_sec as f64,
|
||||||
cpu_usage: process.cpu_usage_percent,
|
wps_f64: p.write_per_sec as f64,
|
||||||
mem_usage: process.mem_usage_percent,
|
tr_f64: p.total_read as f64,
|
||||||
group_pids: vec![process.pid],
|
tw_f64: p.total_write as f64,
|
||||||
read_per_sec,
|
process_states: p.process_state,
|
||||||
write_per_sec,
|
}
|
||||||
total_read,
|
})
|
||||||
total_write,
|
.collect::<Vec<_>>()
|
||||||
rps_f64: process.read_bytes_per_sec as f64,
|
}
|
||||||
wps_f64: process.write_bytes_per_sec as f64,
|
|
||||||
tr_f64: process.total_read_bytes as f64,
|
|
||||||
tw_f64: process.total_write_bytes as f64,
|
|
||||||
process_states: process.process_state.to_owned(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let grouped_list: Vec<ConvertedProcessData> = grouped_hashmap
|
|
||||||
.iter()
|
|
||||||
.map(|(name, process_details)| {
|
|
||||||
let p = process_details.clone();
|
|
||||||
let converted_rps = get_exact_byte_values(p.read_per_sec, false);
|
|
||||||
let converted_wps = get_exact_byte_values(p.write_per_sec, false);
|
|
||||||
let converted_total_read = get_exact_byte_values(p.total_read, false);
|
|
||||||
let converted_total_write = get_exact_byte_values(p.total_write, false);
|
|
||||||
|
|
||||||
let read_per_sec = format!("{:.*}{}/s", 0, converted_rps.0, converted_rps.1);
|
|
||||||
let write_per_sec = format!("{:.*}{}/s", 0, converted_wps.0, converted_wps.1);
|
|
||||||
let total_read = format!("{:.*}{}", 0, converted_total_read.0, converted_total_read.1);
|
|
||||||
let total_write = format!(
|
|
||||||
"{:.*}{}",
|
|
||||||
0, converted_total_write.0, converted_total_write.1
|
|
||||||
);
|
|
||||||
|
|
||||||
ConvertedProcessData {
|
|
||||||
pid: p.pid,
|
|
||||||
name: name.to_string(),
|
|
||||||
cpu_usage: p.cpu_usage,
|
|
||||||
mem_usage: p.mem_usage,
|
|
||||||
group_pids: p.group_pids,
|
|
||||||
read_per_sec,
|
|
||||||
write_per_sec,
|
|
||||||
total_read,
|
|
||||||
total_write,
|
|
||||||
rps_f64: p.read_per_sec as f64,
|
|
||||||
wps_f64: p.write_per_sec as f64,
|
|
||||||
tr_f64: p.total_read as f64,
|
|
||||||
tw_f64: p.total_write as f64,
|
|
||||||
process_states: p.process_state,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
(single_list, grouped_list)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn convert_battery_harvest(
|
pub fn convert_battery_harvest(
|
||||||
|
|
68
src/main.rs
68
src/main.rs
|
@ -225,9 +225,6 @@ fn main() -> error::Result<()> {
|
||||||
|
|
||||||
// Processes
|
// Processes
|
||||||
if app.used_widgets.use_proc {
|
if app.used_widgets.use_proc {
|
||||||
let (single, grouped) = convert_process_data(&app.data_collection);
|
|
||||||
app.canvas_data.process_data = single;
|
|
||||||
app.canvas_data.grouped_process_data = grouped;
|
|
||||||
update_all_process_lists(&mut app);
|
update_all_process_lists(&mut app);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -582,44 +579,45 @@ fn update_final_process_list(app: &mut App, widget_id: u64) {
|
||||||
.is_invalid_or_blank_search(),
|
.is_invalid_or_blank_search(),
|
||||||
None => false,
|
None => false,
|
||||||
};
|
};
|
||||||
|
let is_grouped = app.is_grouped(widget_id);
|
||||||
|
|
||||||
|
if let Some(proc_widget_state) = app.proc_state.get_mut_widget_state(widget_id) {
|
||||||
|
app.canvas_data.process_data = convert_process_data(
|
||||||
|
&app.data_collection,
|
||||||
|
if is_grouped {
|
||||||
|
ProcessGroupingType::Grouped
|
||||||
|
} else {
|
||||||
|
ProcessGroupingType::Ungrouped
|
||||||
|
},
|
||||||
|
if proc_widget_state.is_using_full_path {
|
||||||
|
ProcessNamingType::Path
|
||||||
|
} else {
|
||||||
|
ProcessNamingType::Name
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let process_filter = app.get_process_filter(widget_id);
|
let process_filter = app.get_process_filter(widget_id);
|
||||||
let filtered_process_data: Vec<ConvertedProcessData> = if app.is_grouped(widget_id) {
|
let filtered_process_data: Vec<ConvertedProcessData> = app
|
||||||
app.canvas_data
|
.canvas_data
|
||||||
.grouped_process_data
|
.process_data
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|process| {
|
.filter(|process| {
|
||||||
if is_invalid_or_blank {
|
if !is_invalid_or_blank {
|
||||||
true
|
if let Some(process_filter) = process_filter {
|
||||||
} else if let Some(process_filter) = process_filter {
|
process_filter.check(&process)
|
||||||
process_filter.check(process)
|
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
})
|
} else {
|
||||||
.cloned()
|
true
|
||||||
.collect::<Vec<_>>()
|
}
|
||||||
} else {
|
})
|
||||||
app.canvas_data
|
.cloned()
|
||||||
.process_data
|
.collect::<Vec<_>>();
|
||||||
.iter()
|
|
||||||
.filter(|process| {
|
|
||||||
if !is_invalid_or_blank {
|
|
||||||
if let Some(process_filter) = process_filter {
|
|
||||||
process_filter.check(&process)
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.cloned()
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Quick fix for tab updating the table headers
|
// Quick fix for tab updating the table headers
|
||||||
if let Some(proc_widget_state) = app.proc_state.widget_states.get_mut(&widget_id) {
|
if let Some(proc_widget_state) = app.proc_state.get_mut_widget_state(widget_id) {
|
||||||
if let data_harvester::processes::ProcessSorting::PID =
|
if let data_harvester::processes::ProcessSorting::PID =
|
||||||
proc_widget_state.process_sorting_type
|
proc_widget_state.process_sorting_type
|
||||||
{
|
{
|
||||||
|
@ -672,7 +670,7 @@ fn sort_process_data(
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ProcessSorting::NAME => {
|
ProcessSorting::IDENTIFIER => {
|
||||||
// Don't repeat if false...
|
// Don't repeat if false...
|
||||||
if proc_widget_state.process_sorting_reverse {
|
if proc_widget_state.process_sorting_reverse {
|
||||||
to_sort_vec.sort_by(|a, b| {
|
to_sort_vec.sort_by(|a, b| {
|
||||||
|
|
|
@ -357,8 +357,6 @@ fn get_temperature(
|
||||||
|
|
||||||
/// Yes, this function gets whether to show average CPU (true) or not (false)
|
/// Yes, this function gets whether to show average CPU (true) or not (false)
|
||||||
fn get_show_average_cpu(matches: &clap::ArgMatches<'static>, config: &Config) -> bool {
|
fn get_show_average_cpu(matches: &clap::ArgMatches<'static>, config: &Config) -> bool {
|
||||||
// FIXME: Update the demo config file and default config files! Need to remove
|
|
||||||
// old options and change to hide_avg_cpu option.
|
|
||||||
if matches.is_present("HIDE_AVG_CPU") {
|
if matches.is_present("HIDE_AVG_CPU") {
|
||||||
return false;
|
return false;
|
||||||
} else if let Some(flags) = &config.flags {
|
} else if let Some(flags) = &config.flags {
|
||||||
|
|
Loading…
Reference in New Issue