diff --git a/.vscode/settings.json b/.vscode/settings.json index 9a10ba3f..e8c56d7e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,9 @@ { "cSpell.words": [ + "ABRT", + "ALRM", "Artem", + "CHLD", "COPR", "Condvar", "DWORD", @@ -8,10 +11,12 @@ "EINVAL", "EPERM", "ESRCH", + "Erlend", "Fini", "GIBI", "GIBIBYTE", "GIGA", + "Hamberg", "KIBI", "Lukas", "MEBI", @@ -25,15 +30,25 @@ "PKGBUILDs", "Polishchuk", "Qudsi", + "RTMAX", + "RTMIN", "Rysavy", + "SEGV", "SIGTERM", + "STKFLT", "TEBI", "TERA", + "TSTP", + "TTIN", + "TTOU", "Tebibytes", "Toolset", "Ungrouped", + "VTALRM", "WASD", "Wojnarowski", + "XCPU", + "XFSZ", "aarch", "andys", "armhf", diff --git a/README.md b/README.md index 9cd80753..9078bfd5 100644 --- a/README.md +++ b/README.md @@ -247,37 +247,38 @@ Run using `btm`. Use `btm --help` for more information. ``` - --autohide_time Temporarily shows the time scale in graphs. - -b, --basic Hides graphs and uses a more basic look. - --battery Shows the battery widget. - -S, --case_sensitive Enables case sensitivity by default. - -c, --celsius Sets the temperature type to Celsius. - --color Use a color scheme, use --help for supported values. - --process_command Show processes as their commands by default. - -C, --config Sets the location of the config file. - -u, --current_usage Sets process CPU% to be based on current CPU%. - -t, --default_time_value Default time value for graphs in ms. - --default_widget_count Sets the n'th selected widget type as the default. - --default_widget_type Sets which widget type to use as the default widget. - --disable_click Disables mouse clicks. - -m, --dot_marker Uses a dot marker for graphs. - -f, --fahrenheit Sets the temperature type to Fahrenheit. - -g, --group Groups processes with the same name by default. - -h, --help Prints help information. Use --help for more info. - -a, --hide_avg_cpu Hides the average CPU usage. - --hide_table_gap Hides the spacing between table headers and entries. - --hide_time Completely hides the time scaling. - -k, --kelvin Sets the temperature type to Kelvin. - -l, --left_legend Puts the CPU chart legend to the left side. - --mem_as_value Defaults to showing process memory usage by value. - -r, --rate Sets a refresh rate in ms. - -R, --regex Enables regex by default. - --show_table_scroll_position Shows the scroll position tracker in table widgets - -d, --time_delta The amount in ms changed upon zooming. - -T, --tree Defaults to showing the process widget in tree mode. - --use_old_network_legend DEPRECATED - uses the older network legend. - -V, --version Prints version information. - -W, --whole_word Enables whole-word matching by default. + --advanced_kill Shows more options when killing a process on Unix-like systems. + --autohide_time Temporarily shows the time scale in graphs. +-b, --basic Hides graphs and uses a more basic look. + --battery Shows the battery widget. +-S, --case_sensitive Enables case sensitivity by default. +-c, --celsius Sets the temperature type to Celsius. + --color Use a color scheme, use --help for supported values. +-C, --config Sets the location of the config file. +-u, --current_usage Sets process CPU% to be based on current CPU%. +-t, --default_time_value Default time value for graphs in ms. + --default_widget_count Sets the n'th selected widget type as the default. + --default_widget_type Sets the default widget type, use --help for more info. + --disable_click Disables mouse clicks. +-m, --dot_marker Uses a dot marker for graphs. +-f, --fahrenheit Sets the temperature type to Fahrenheit. +-g, --group Groups processes with the same name by default. +-h, --help Prints help information. Use --help for more info. +-a, --hide_avg_cpu Hides the average CPU usage. + --hide_table_gap Hides the spacing between table headers and entries. + --hide_time Completely hides the time scaling. +-k, --kelvin Sets the temperature type to Kelvin. +-l, --left_legend Puts the CPU chart legend to the left side. + --mem_as_value Defaults to showing process memory usage by value. + --process_command Show processes as their commands by default. +-r, --rate Sets a refresh rate in ms. +-R, --regex Enables regex by default. + --show_table_scroll_position Shows the scroll position tracker in table widgets. +-d, --time_delta The amount in ms changed upon zooming. +-T, --tree Defaults to showing the process widget in tree mode. + --use_old_network_legend DEPRECATED - uses the older network legend. +-V, --version Prints version information. +-W, --whole_word Enables whole-word matching by default. ``` ### Keybindings @@ -563,31 +564,32 @@ The following options can be set under `[flags]` to achieve the same effect as p These are the following supported flag config values, which correspond to the flag of the same name described in [Flags](#flags): -| Field | Type | Functionality | -| ---------------------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------- | -| `hide_avg_cpu` | Boolean | Hides the average CPU usage. | -| `dot_marker` | Boolean | Uses a dot marker for graphs. | -| `left_legend` | Boolean | Puts the CPU chart legend to the left side. | -| `current_usage` | Boolean | Sets process CPU% to be based on current CPU%. | -| `group_processes` | Boolean | Groups processes with the same name by default. | -| `case_sensitive` | Boolean | Enables case sensitivity by default. | -| `whole_word` | Boolean | Enables whole-word matching by default. | -| `regex` | Boolean | Enables regex by default. | -| `basic` | Boolean | Hides graphs and uses a more basic look. | -| `use_old_network_legend` | Boolean | DEPRECATED - uses the older network legend. | -| `battery` | Boolean | Shows the battery widget. | -| `rate` | Unsigned Int (represents milliseconds) | Sets a refresh rate in ms. | -| `default_time_value` | Unsigned Int (represents milliseconds) | Default time value for graphs in ms. | -| `time_delta` | Unsigned Int (represents milliseconds) | The amount in ms changed upon zooming. | -| `temperature_type` | String (one of ["k", "f", "c", "kelvin", "fahrenheit", "celsius"]) | Sets the temperature unit type. | -| `default_widget_type` | String (one of ["cpu", "proc", "net", "temp", "mem", "disk"], same as layout options) | Sets the default widget type, use --help for more info. | -| `default_widget_count` | Unsigned Int (represents which `default_widget_type`) | Sets the n'th selected widget type as the default. | -| `disable_click` | Boolean | Disables mouse clicks. | -| `color` | String (one of ["default", "default-light", "gruvbox", "gruvbox-light", "nord", "nord-light"]) | Use a color scheme, use --help for supported values. | -| `mem_as_value` | Boolean | Defaults to showing process memory usage by value. | -| `tree` | Boolean | Defaults to showing the process widget in tree mode. | -| `show_table_scroll_position` | Boolean | Shows the scroll position tracker in table widgets. | -| `process_command` | Boolean | Show processes as their commands by default. | +| Field | Type | Functionality | +| ---------------------------- | ---------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | +| `hide_avg_cpu` | Boolean | Hides the average CPU usage. | +| `dot_marker` | Boolean | Uses a dot marker for graphs. | +| `left_legend` | Boolean | Puts the CPU chart legend to the left side. | +| `current_usage` | Boolean | Sets process CPU% to be based on current CPU%. | +| `group_processes` | Boolean | Groups processes with the same name by default. | +| `case_sensitive` | Boolean | Enables case sensitivity by default. | +| `whole_word` | Boolean | Enables whole-word matching by default. | +| `regex` | Boolean | Enables regex by default. | +| `basic` | Boolean | Hides graphs and uses a more basic look. | +| `use_old_network_legend` | Boolean | DEPRECATED - uses the older network legend. | +| `battery` | Boolean | Shows the battery widget. | +| `rate` | Unsigned Int (represents milliseconds) | Sets a refresh rate in ms. | +| `default_time_value` | Unsigned Int (represents milliseconds) | Default time value for graphs in ms. | +| `time_delta` | Unsigned Int (represents milliseconds) | The amount in ms changed upon zooming. | +| `temperature_type` | String (one of ["k", "f", "c", "kelvin", "fahrenheit", "celsius"]) | Sets the temperature unit type. | +| `default_widget_type` | String (one of ["cpu", "proc", "net", "temp", "mem", "disk"], same as layout options) | Sets the default widget type, use --help for more info. | +| `default_widget_count` | Unsigned Int (represents which `default_widget_type`) | Sets the n'th selected widget type as the default. | +| `disable_click` | Boolean | Disables mouse clicks. | +| `color` | String (one of ["default", "default-light", "gruvbox", "gruvbox-light", "nord", "nord-light"]) | Use a color scheme, use --help for supported values. | +| `mem_as_value` | Boolean | Defaults to showing process memory usage by value. | +| `tree` | Boolean | Defaults to showing the process widget in tree mode. | +| `show_table_scroll_position` | Boolean | Shows the scroll position tracker in table widgets. | +| `process_command` | Boolean | Show processes as their commands by default. | +| `advanced_kill` | Boolean | Shows more options when killing a process on Unix-like systems. | #### Theming diff --git a/src/app.rs b/src/app.rs index 41f7af68..b10570b8 100644 --- a/src/app.rs +++ b/src/app.rs @@ -54,6 +54,7 @@ pub struct AppConfigFields { pub disable_click: bool, pub no_write: bool, pub show_table_scroll_position: bool, + pub is_advanced_kill: bool, } /// For filtering out information @@ -858,7 +859,13 @@ impl App { #[cfg(target_os = "windows")] self.on_right_key(); #[cfg(target_family = "unix")] - self.on_left_key(); + { + if self.app_config_fields.is_advanced_kill { + self.on_left_key(); + } else { + self.on_right_key(); + } + } return; } self.reset_multi_tap_keys(); @@ -874,7 +881,13 @@ impl App { #[cfg(target_os = "windows")] self.on_left_key(); #[cfg(target_family = "unix")] - self.on_right_key(); + { + if self.app_config_fields.is_advanced_kill { + self.on_right_key(); + } else { + self.on_left_key(); + } + } return; } self.reset_multi_tap_keys(); @@ -884,20 +897,6 @@ impl App { if self.is_config_open { } else if !self.is_in_dialog() { 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); - - // debug!( - // "Current column index <: {}", - // proc_widget_state.current_column_index - // ); - // } - } BottomWidgetType::ProcSearch => { let is_in_search_widget = self.is_in_search_widget(); if let Some(proc_widget_state) = self @@ -943,17 +942,21 @@ impl App { } else if self.delete_dialog_state.is_showing_dd { #[cfg(target_family = "unix")] { - match self.delete_dialog_state.selected_signal { - KillSignal::KILL(prev_signal) => { - self.delete_dialog_state.selected_signal = match prev_signal - 1 { - 0 => KillSignal::CANCEL, - // 32+33 are skipped - 33 => KillSignal::KILL(31), - signal => KillSignal::KILL(signal), - }; - } - KillSignal::CANCEL => (), - }; + if self.app_config_fields.is_advanced_kill { + match self.delete_dialog_state.selected_signal { + KillSignal::KILL(prev_signal) => { + self.delete_dialog_state.selected_signal = match prev_signal - 1 { + 0 => KillSignal::CANCEL, + // 32+33 are skipped + 33 => KillSignal::KILL(31), + signal => KillSignal::KILL(signal), + }; + } + KillSignal::CANCEL => {} + }; + } else { + self.delete_dialog_state.selected_signal = KillSignal::default(); + } } #[cfg(target_os = "windows")] { @@ -966,22 +969,6 @@ impl App { if self.is_config_open { } else if !self.is_in_dialog() { 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.columns.get_enabled_columns() - // { - // proc_widget_state.current_column_index += 1; - // } - // debug!( - // "Current column index >: {}", - // proc_widget_state.current_column_index - // ); - // } - } BottomWidgetType::ProcSearch => { let is_in_search_widget = self.is_in_search_widget(); if let Some(proc_widget_state) = self @@ -1031,17 +1018,21 @@ impl App { } else if self.delete_dialog_state.is_showing_dd { #[cfg(target_family = "unix")] { - let new_signal = match self.delete_dialog_state.selected_signal { - KillSignal::CANCEL => 1, - // 32+33 are skipped - #[cfg(target_os = "linux")] - KillSignal::KILL(31) => 34, - #[cfg(target_os = "macos")] - KillSignal::KILL(31) => 31, - KillSignal::KILL(64) => 64, - KillSignal::KILL(signal) => signal + 1, - }; - self.delete_dialog_state.selected_signal = KillSignal::KILL(new_signal); + if self.app_config_fields.is_advanced_kill { + let new_signal = match self.delete_dialog_state.selected_signal { + KillSignal::CANCEL => 1, + // 32+33 are skipped + #[cfg(target_os = "linux")] + KillSignal::KILL(31) => 34, + #[cfg(target_os = "macos")] + KillSignal::KILL(31) => 31, + KillSignal::KILL(64) => 64, + KillSignal::KILL(signal) => signal + 1, + }; + self.delete_dialog_state.selected_signal = KillSignal::KILL(new_signal); + } else { + self.delete_dialog_state.selected_signal = KillSignal::CANCEL; + } } #[cfg(target_os = "windows")] { diff --git a/src/canvas.rs b/src/canvas.rs index e96dfd18..2e669d46 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -381,15 +381,15 @@ impl Painter { } else { terminal_width * 50 / 100 }; - let text_height; - #[cfg(target_family = "unix")] + + let text_height = if cfg!(target_os = "windows") + || !app_state.app_config_fields.is_advanced_kill { - text_height = 22; - } - #[cfg(target_os = "windows")] - { - text_height = 7; - } + 7 + } else { + 22 + }; + // let (text_width, text_height) = if let Some(dd_text) = &dd_text { // let width = if current_width < 100 { // current_width * 90 / 100 diff --git a/src/canvas/dialogs/dd_dialog.rs b/src/canvas/dialogs/dd_dialog.rs index 794abe1b..cd9029c8 100644 --- a/src/canvas/dialogs/dd_dialog.rs +++ b/src/canvas/dialogs/dd_dialog.rs @@ -67,243 +67,242 @@ impl KillDialog for Painter { None } - #[cfg(target_os = "windows")] fn draw_dd_confirm_buttons( &self, f: &mut Frame<'_, B>, button_draw_loc: &Rect, app_state: &mut App, ) { - let (yes_button, no_button) = match app_state.delete_dialog_state.selected_signal { - KillSignal::KILL(_) => ( - Span::styled("Yes", self.colours.currently_selected_text_style), - Span::raw("No"), - ), - KillSignal::CANCEL => ( - Span::raw("Yes"), - Span::styled("No", self.colours.currently_selected_text_style), - ), - }; - - let button_layout = Layout::default() - .direction(Direction::Horizontal) - .constraints( - [ - Constraint::Percentage(35), - Constraint::Percentage(30), - Constraint::Percentage(35), - ] - .as_ref(), - ) - .split(*button_draw_loc); - - f.render_widget( - Paragraph::new(yes_button) - .block(Block::default()) - .alignment(Alignment::Right), - button_layout[0], - ); - f.render_widget( - Paragraph::new(no_button) - .block(Block::default()) - .alignment(Alignment::Left), - button_layout[2], - ); - - if app_state.should_get_widget_bounds() { - app_state.delete_dialog_state.button_positions = vec![ - ( - button_layout[2].x, - button_layout[2].y, - button_layout[2].x + button_layout[2].width, - button_layout[2].y + button_layout[2].height, - 0, + if cfg!(target_os = "windows") || !app_state.app_config_fields.is_advanced_kill { + let (yes_button, no_button) = match app_state.delete_dialog_state.selected_signal { + KillSignal::KILL(_) => ( + Span::styled("Yes", self.colours.currently_selected_text_style), + Span::raw("No"), ), - ( - button_layout[0].x, - button_layout[0].y, - button_layout[0].x + button_layout[0].width, - button_layout[0].y + button_layout[0].height, - 1, + KillSignal::CANCEL => ( + Span::raw("Yes"), + Span::styled("No", self.colours.currently_selected_text_style), ), - ]; - } - } + }; - #[cfg(target_family = "unix")] - fn draw_dd_confirm_buttons( - &self, f: &mut Frame<'_, B>, button_draw_loc: &Rect, app_state: &mut App, - ) { - let signal_text; - #[cfg(target_os = "linux")] - { - signal_text = vec![ - "0: Cancel", - "1: HUP", - "2: INT", - "3: QUIT", - "4: ILL", - "5: TRAP", - "6: ABRT", - "7: BUS", - "8: FPE", - "9: KILL", - "10: USR1", - "11: SEGV", - "12: USR2", - "13: PIPE", - "14: ALRM", - "15: TERM", - "16: STKFLT", - "17: CHLD", - "18: CONT", - "19: STOP", - "20: TSTP", - "21: TTIN", - "22: TTOU", - "23: URG", - "24: XCPU", - "25: XFSZ", - "26: VTALRM", - "27: PROF", - "28: WINCH", - "29: IO", - "30: PWR", - "31: SYS", - "34: RTMIN", - "35: RTMIN+1", - "36: RTMIN+2", - "37: RTMIN+3", - "38: RTMIN+4", - "39: RTMIN+5", - "40: RTMIN+6", - "41: RTMIN+7", - "42: RTMIN+8", - "43: RTMIN+9", - "44: RTMIN+10", - "45: RTMIN+11", - "46: RTMIN+12", - "47: RTMIN+13", - "48: RTMIN+14", - "49: RTMIN+15", - "50: RTMAX-14", - "51: RTMAX-13", - "52: RTMAX-12", - "53: RTMAX-11", - "54: RTMAX-10", - "55: RTMAX-9", - "56: RTMAX-8", - "57: RTMAX-7", - "58: RTMAX-6", - "59: RTMAX-5", - "60: RTMAX-4", - "61: RTMAX-3", - "62: RTMAX-2", - "63: RTMAX-1", - "64: RTMAX", - ]; - } - #[cfg(target_os = "macos")] - { - signal_text = vec![ - "0: Cancel", - "1: HUP", - "2: INT", - "3: QUIT", - "4: ILL", - "5: TRAP", - "6: ABRT", - "7: EMT", - "8: FPE", - "9: KILL", - "10: BUS", - "11: SEGV", - "12: SYS", - "13: PIPE", - "14: ALRM", - "15: TERM", - "16: URG", - "17: STOP", - "18: TSTP", - "19: CONT", - "20: CHLD", - "21: TTIN", - "22: TTOU", - "23: IO", - "24: XCPU", - "25: XFSZ", - "26: VTALRM", - "27: PROF", - "28: WINCH", - "29: INFO", - "30: USR1", - "31: USR2", - ]; - } - - let button_rect = Layout::default() - .direction(Direction::Horizontal) - .margin(1) - .constraints( - [ - Constraint::Length((button_draw_loc.width - 14) / 2), - Constraint::Min(0), - Constraint::Length((button_draw_loc.width - 14) / 2), - ] - .as_ref(), - ) - .split(*button_draw_loc)[1]; - - let mut selected = match app_state.delete_dialog_state.selected_signal { - KillSignal::CANCEL => 0, - KillSignal::KILL(signal) => signal, - }; - // 32+33 are skipped - if selected > 31 { - selected -= 2; - } - - let layout = Layout::default() - .direction(Direction::Vertical) - .constraints(vec![Constraint::Min(1); button_rect.height as usize]) - .split(button_rect); - - let prev_offset: usize = app_state.delete_dialog_state.scroll_pos; - app_state.delete_dialog_state.scroll_pos = if selected == 0 { - 0 - } else if selected < prev_offset + 1 { - selected - 1 - } else if selected > prev_offset + (layout.len() as usize) - 1 { - selected - (layout.len() as usize) + 1 - } else { - prev_offset - }; - let scroll_offset: usize = app_state.delete_dialog_state.scroll_pos; - - let mut buttons = signal_text - [scroll_offset + 1..min((layout.len() as usize) + scroll_offset, signal_text.len())] - .iter() - .map(|text| Span::raw(*text)) - .collect::>>(); - buttons.insert(0, Span::raw(signal_text[0])); - buttons[selected - scroll_offset] = Span::styled( - signal_text[selected], - self.colours.currently_selected_text_style, - ); - - app_state.delete_dialog_state.button_positions = layout - .iter() - .enumerate() - .map(|(i, pos)| { - ( - pos.x, - pos.y, - pos.x + pos.width - 1, - pos.y + pos.height - 1, - if i == 0 { 0 } else { scroll_offset } + i, + let button_layout = Layout::default() + .direction(Direction::Horizontal) + .constraints( + [ + Constraint::Percentage(35), + Constraint::Percentage(30), + Constraint::Percentage(35), + ] + .as_ref(), ) - }) - .collect::>(); + .split(*button_draw_loc); - for (btn, pos) in buttons.into_iter().zip(layout.into_iter()) { - f.render_widget(Paragraph::new(btn).alignment(Alignment::Left), pos); + f.render_widget( + Paragraph::new(yes_button) + .block(Block::default()) + .alignment(Alignment::Right), + button_layout[0], + ); + f.render_widget( + Paragraph::new(no_button) + .block(Block::default()) + .alignment(Alignment::Left), + button_layout[2], + ); + + if app_state.should_get_widget_bounds() { + app_state.delete_dialog_state.button_positions = vec![ + ( + button_layout[2].x, + button_layout[2].y, + button_layout[2].x + button_layout[2].width, + button_layout[2].y + button_layout[2].height, + 0, + ), + ( + button_layout[0].x, + button_layout[0].y, + button_layout[0].x + button_layout[0].width, + button_layout[0].y + button_layout[0].height, + 1, + ), + ]; + } + } else { + #[cfg(target_family = "unix")] + { + let signal_text; + #[cfg(target_os = "linux")] + { + signal_text = vec![ + "0: Cancel", + "1: HUP", + "2: INT", + "3: QUIT", + "4: ILL", + "5: TRAP", + "6: ABRT", + "7: BUS", + "8: FPE", + "9: KILL", + "10: USR1", + "11: SEGV", + "12: USR2", + "13: PIPE", + "14: ALRM", + "15: TERM", + "16: STKFLT", + "17: CHLD", + "18: CONT", + "19: STOP", + "20: TSTP", + "21: TTIN", + "22: TTOU", + "23: URG", + "24: XCPU", + "25: XFSZ", + "26: VTALRM", + "27: PROF", + "28: WINCH", + "29: IO", + "30: PWR", + "31: SYS", + "34: RTMIN", + "35: RTMIN+1", + "36: RTMIN+2", + "37: RTMIN+3", + "38: RTMIN+4", + "39: RTMIN+5", + "40: RTMIN+6", + "41: RTMIN+7", + "42: RTMIN+8", + "43: RTMIN+9", + "44: RTMIN+10", + "45: RTMIN+11", + "46: RTMIN+12", + "47: RTMIN+13", + "48: RTMIN+14", + "49: RTMIN+15", + "50: RTMAX-14", + "51: RTMAX-13", + "52: RTMAX-12", + "53: RTMAX-11", + "54: RTMAX-10", + "55: RTMAX-9", + "56: RTMAX-8", + "57: RTMAX-7", + "58: RTMAX-6", + "59: RTMAX-5", + "60: RTMAX-4", + "61: RTMAX-3", + "62: RTMAX-2", + "63: RTMAX-1", + "64: RTMAX", + ]; + } + #[cfg(target_os = "macos")] + { + signal_text = vec![ + "0: Cancel", + "1: HUP", + "2: INT", + "3: QUIT", + "4: ILL", + "5: TRAP", + "6: ABRT", + "7: EMT", + "8: FPE", + "9: KILL", + "10: BUS", + "11: SEGV", + "12: SYS", + "13: PIPE", + "14: ALRM", + "15: TERM", + "16: URG", + "17: STOP", + "18: TSTP", + "19: CONT", + "20: CHLD", + "21: TTIN", + "22: TTOU", + "23: IO", + "24: XCPU", + "25: XFSZ", + "26: VTALRM", + "27: PROF", + "28: WINCH", + "29: INFO", + "30: USR1", + "31: USR2", + ]; + } + + let button_rect = Layout::default() + .direction(Direction::Horizontal) + .margin(1) + .constraints( + [ + Constraint::Length((button_draw_loc.width - 14) / 2), + Constraint::Min(0), + Constraint::Length((button_draw_loc.width - 14) / 2), + ] + .as_ref(), + ) + .split(*button_draw_loc)[1]; + + let mut selected = match app_state.delete_dialog_state.selected_signal { + KillSignal::CANCEL => 0, + KillSignal::KILL(signal) => signal, + }; + // 32+33 are skipped + if selected > 31 { + selected -= 2; + } + + let layout = Layout::default() + .direction(Direction::Vertical) + .constraints(vec![Constraint::Min(1); button_rect.height as usize]) + .split(button_rect); + + let prev_offset: usize = app_state.delete_dialog_state.scroll_pos; + app_state.delete_dialog_state.scroll_pos = if selected == 0 { + 0 + } else if selected < prev_offset + 1 { + selected - 1 + } else if selected > prev_offset + (layout.len() as usize) - 1 { + selected - (layout.len() as usize) + 1 + } else { + prev_offset + }; + let scroll_offset: usize = app_state.delete_dialog_state.scroll_pos; + + let mut buttons = signal_text[scroll_offset + 1 + ..min((layout.len() as usize) + scroll_offset, signal_text.len())] + .iter() + .map(|text| Span::raw(*text)) + .collect::>>(); + buttons.insert(0, Span::raw(signal_text[0])); + buttons[selected - scroll_offset] = Span::styled( + signal_text[selected], + self.colours.currently_selected_text_style, + ); + + app_state.delete_dialog_state.button_positions = layout + .iter() + .enumerate() + .map(|(i, pos)| { + ( + pos.x, + pos.y, + pos.x + pos.width - 1, + pos.y + pos.height - 1, + if i == 0 { 0 } else { scroll_offset } + i, + ) + }) + .collect::>(); + + for (btn, pos) in buttons.into_iter().zip(layout.into_iter()) { + f.render_widget(Paragraph::new(btn).alignment(Alignment::Left), pos); + } + } } } @@ -356,15 +355,13 @@ impl KillDialog for Painter { draw_loc, ); - let btn_height; - #[cfg(target_family = "unix")] - { - btn_height = 20; - } - #[cfg(target_os = "windows")] - { - btn_height = 3; - } + let btn_height = + if cfg!(target_os = "windows") || !app_state.app_config_fields.is_advanced_kill { + 3 + } else { + 20 + }; + // Now draw buttons if needed... let split_draw_loc = Layout::default() .direction(Direction::Vertical) diff --git a/src/clap.rs b/src/clap.rs index 4218a854..de1b5448 100644 --- a/src/clap.rs +++ b/src/clap.rs @@ -106,6 +106,7 @@ rather than total CPU usage.\n\n", "\ Disables mouse clicks from interacting with the program.\n\n", ); + let dot_marker = Arg::with_name("dot_marker") .short("m") .long("dot_marker") @@ -115,6 +116,7 @@ Disables mouse clicks from interacting with the program.\n\n", Uses a dot marker for graphs as opposed to the default braille marker.\n\n", ); + let group = Arg::with_name("group") // FIXME: Rename this to something like "group_process", would be "breaking" though. .short("g") .long("group") @@ -123,6 +125,7 @@ marker.\n\n", "\ Groups processes with the same name by default.\n\n", ); + let hide_avg_cpu = Arg::with_name("hide_avg_cpu") .short("a") .long("hide_avg_cpu") @@ -131,6 +134,7 @@ Groups processes with the same name by default.\n\n", "\ Hides the average CPU usage from being shown.\n\n", ); + let hide_table_gap = Arg::with_name("hide_table_gap") .long("hide_table_gap") .help("Hides the spacing between table headers and entries.") @@ -138,6 +142,7 @@ Hides the average CPU usage from being shown.\n\n", "\ Hides the spacing between table headers and entries.\n\n", ); + let hide_time = Arg::with_name("hide_time") .long("hide_time") .help("Completely hides the time scaling.") @@ -145,6 +150,7 @@ Hides the spacing between table headers and entries.\n\n", "\ Completely hides the time scaling from being shown.\n\n", ); + let process_command = Arg::with_name("process_command") .long("process_command") .help("Show processes as their commands by default.") @@ -153,6 +159,7 @@ Completely hides the time scaling from being shown.\n\n", Show processes as their commands by default in the process widget. ", ); + let left_legend = Arg::with_name("left_legend") .short("l") .long("left_legend") @@ -161,6 +168,7 @@ Completely hides the time scaling from being shown.\n\n", "\ Puts the CPU chart legend to the left side rather than the right side.\n\n", ); + // let no_write = Arg::with_name("no_write") // .long("no_write") // .help("Disables writing to the config file.") @@ -168,6 +176,7 @@ Puts the CPU chart legend to the left side rather than the right side.\n\n", // "\ // Disables config changes in-app from writing to the config file.", // ); + let regex = Arg::with_name("regex") .short("R") .long("regex") @@ -176,6 +185,15 @@ Puts the CPU chart legend to the left side rather than the right side.\n\n", "\ When searching for a process, enables regex by default.\n\n", ); + + let advanced_kill = Arg::with_name("advanced_kill") + .long("advanced_kill") + .help("Shows more options when killing a process on Unix-like systems.") + .long_help( + "\ +Shows more options when killing a process on Unix-like systems.\n\n", + ); + let show_table_scroll_position = Arg::with_name("show_table_scroll_position") .long("show_table_scroll_position") .help("Shows the scroll position tracker in table widgets.") @@ -183,6 +201,7 @@ When searching for a process, enables regex by default.\n\n", "\ Shows the list scroll position tracker in the widget title for table widgets.\n\n", ); + let use_old_network_legend = Arg::with_name("use_old_network_legend") .long("use_old_network_legend") .help("DEPRECATED - uses the older network legend.") @@ -191,6 +210,7 @@ When searching for a process, enables regex by default.\n\n", DEPRECATED - uses the older (pre-0.4) network widget legend. This display is not tested anymore and could be broken.\n\n\n", ); + let whole_word = Arg::with_name("whole_word") .short("W") .long("whole_word") @@ -396,6 +416,7 @@ Defaults to showing the process widget in tree mode.\n\n", .arg(hide_time) .arg(show_table_scroll_position) .arg(left_legend) + .arg(advanced_kill) // .arg(no_write) .arg(rate) .arg(regex) diff --git a/src/options.rs b/src/options.rs index 999a8cf1..badc32b8 100644 --- a/src/options.rs +++ b/src/options.rs @@ -154,6 +154,9 @@ pub struct ConfigFlags { #[builder(default, setter(strip_option))] pub process_command: Option, + + #[builder(default, setter(strip_option))] + pub advanced_kill: Option, } #[derive(Clone, Default, Debug, Deserialize, Serialize)] @@ -260,6 +263,7 @@ pub fn build_app( let show_memory_as_values = get_mem_as_value(matches, config); let is_default_tree = get_is_default_tree(matches, config); let is_default_command = get_is_default_process_command(matches, config); + let is_advanced_kill = get_is_using_advanced_kill(matches, config); for row in &widget_layout.rows { for col in &row.children { @@ -399,6 +403,7 @@ pub fn build_app( // no_write: get_no_write(matches, config), no_write: false, show_table_scroll_position: get_show_table_scroll_position(matches, config), + is_advanced_kill, }; let used_widgets = UsedWidgets { @@ -1015,3 +1020,14 @@ fn get_is_default_process_command(matches: &clap::ArgMatches<'static>, config: & } false } + +fn get_is_using_advanced_kill(matches: &clap::ArgMatches<'static>, config: &Config) -> bool { + if matches.is_present("advanced_kill") { + return true; + } else if let Some(flags) = &config.flags { + if let Some(advanced_kill) = flags.advanced_kill { + return advanced_kill; + } + } + false +}