feature: Allow toggling advanced kill menu (#408)

Allows toggling the advanced kill menu via --advanced_kill or advanced_kill=true.
This commit is contained in:
Clement Tsang 2021-02-15 22:23:22 -05:00 committed by GitHub
parent fb7b1226fd
commit e437b14922
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 398 additions and 356 deletions

15
.vscode/settings.json vendored
View File

@ -1,6 +1,9 @@
{ {
"cSpell.words": [ "cSpell.words": [
"ABRT",
"ALRM",
"Artem", "Artem",
"CHLD",
"COPR", "COPR",
"Condvar", "Condvar",
"DWORD", "DWORD",
@ -8,10 +11,12 @@
"EINVAL", "EINVAL",
"EPERM", "EPERM",
"ESRCH", "ESRCH",
"Erlend",
"Fini", "Fini",
"GIBI", "GIBI",
"GIBIBYTE", "GIBIBYTE",
"GIGA", "GIGA",
"Hamberg",
"KIBI", "KIBI",
"Lukas", "Lukas",
"MEBI", "MEBI",
@ -25,15 +30,25 @@
"PKGBUILDs", "PKGBUILDs",
"Polishchuk", "Polishchuk",
"Qudsi", "Qudsi",
"RTMAX",
"RTMIN",
"Rysavy", "Rysavy",
"SEGV",
"SIGTERM", "SIGTERM",
"STKFLT",
"TEBI", "TEBI",
"TERA", "TERA",
"TSTP",
"TTIN",
"TTOU",
"Tebibytes", "Tebibytes",
"Toolset", "Toolset",
"Ungrouped", "Ungrouped",
"VTALRM",
"WASD", "WASD",
"Wojnarowski", "Wojnarowski",
"XCPU",
"XFSZ",
"aarch", "aarch",
"andys", "andys",
"armhf", "armhf",

View File

@ -247,37 +247,38 @@ Run using `btm`.
Use `btm --help` for more information. Use `btm --help` for more information.
``` ```
--advanced_kill Shows more options when killing a process on Unix-like systems.
--autohide_time Temporarily shows the time scale in graphs. --autohide_time Temporarily shows the time scale in graphs.
-b, --basic Hides graphs and uses a more basic look. -b, --basic Hides graphs and uses a more basic look.
--battery Shows the battery widget. --battery Shows the battery widget.
-S, --case_sensitive Enables case sensitivity by default. -S, --case_sensitive Enables case sensitivity by default.
-c, --celsius Sets the temperature type to Celsius. -c, --celsius Sets the temperature type to Celsius.
--color <COLOR SCHEME> Use a color scheme, use --help for supported values. --color <COLOR SCHEME> Use a color scheme, use --help for supported values.
--process_command Show processes as their commands by default. -C, --config <CONFIG PATH> Sets the location of the config file.
-C, --config <CONFIG PATH> Sets the location of the config file. -u, --current_usage Sets process CPU% to be based on current CPU%.
-u, --current_usage Sets process CPU% to be based on current CPU%. -t, --default_time_value <MS> Default time value for graphs in ms.
-t, --default_time_value <MS> Default time value for graphs in ms.
--default_widget_count <INT> Sets the n'th selected widget type as the default. --default_widget_count <INT> Sets the n'th selected widget type as the default.
--default_widget_type <WIDGET TYPE> Sets which widget type to use as the default widget. --default_widget_type <WIDGET TYPE> Sets the default widget type, use --help for more info.
--disable_click Disables mouse clicks. --disable_click Disables mouse clicks.
-m, --dot_marker Uses a dot marker for graphs. -m, --dot_marker Uses a dot marker for graphs.
-f, --fahrenheit Sets the temperature type to Fahrenheit. -f, --fahrenheit Sets the temperature type to Fahrenheit.
-g, --group Groups processes with the same name by default. -g, --group Groups processes with the same name by default.
-h, --help Prints help information. Use --help for more info. -h, --help Prints help information. Use --help for more info.
-a, --hide_avg_cpu Hides the average CPU usage. -a, --hide_avg_cpu Hides the average CPU usage.
--hide_table_gap Hides the spacing between table headers and entries. --hide_table_gap Hides the spacing between table headers and entries.
--hide_time Completely hides the time scaling. --hide_time Completely hides the time scaling.
-k, --kelvin Sets the temperature type to Kelvin. -k, --kelvin Sets the temperature type to Kelvin.
-l, --left_legend Puts the CPU chart legend to the left side. -l, --left_legend Puts the CPU chart legend to the left side.
--mem_as_value Defaults to showing process memory usage by value. --mem_as_value Defaults to showing process memory usage by value.
-r, --rate <MS> Sets a refresh rate in ms. --process_command Show processes as their commands by default.
-R, --regex Enables regex by default. -r, --rate <MS> Sets a refresh rate in ms.
--show_table_scroll_position Shows the scroll position tracker in table widgets -R, --regex Enables regex by default.
-d, --time_delta <MS> The amount in ms changed upon zooming. --show_table_scroll_position Shows the scroll position tracker in table widgets.
-T, --tree Defaults to showing the process widget in tree mode. -d, --time_delta <MS> 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. --use_old_network_legend DEPRECATED - uses the older network legend.
-V, --version Prints version information. -V, --version Prints version information.
-W, --whole_word Enables whole-word matching by default. -W, --whole_word Enables whole-word matching by default.
``` ```
### Keybindings ### Keybindings
@ -564,7 +565,7 @@ 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): These are the following supported flag config values, which correspond to the flag of the same name described in [Flags](#flags):
| Field | Type | Functionality | | Field | Type | Functionality |
| ---------------------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------- | | ---------------------------- | ---------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
| `hide_avg_cpu` | Boolean | Hides the average CPU usage. | | `hide_avg_cpu` | Boolean | Hides the average CPU usage. |
| `dot_marker` | Boolean | Uses a dot marker for graphs. | | `dot_marker` | Boolean | Uses a dot marker for graphs. |
| `left_legend` | Boolean | Puts the CPU chart legend to the left side. | | `left_legend` | Boolean | Puts the CPU chart legend to the left side. |
@ -588,6 +589,7 @@ These are the following supported flag config values, which correspond to the fl
| `tree` | Boolean | Defaults to showing the process widget in tree mode. | | `tree` | Boolean | Defaults to showing the process widget in tree mode. |
| `show_table_scroll_position` | Boolean | Shows the scroll position tracker in table widgets. | | `show_table_scroll_position` | Boolean | Shows the scroll position tracker in table widgets. |
| `process_command` | Boolean | Show processes as their commands by default. | | `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 #### Theming

View File

@ -54,6 +54,7 @@ pub struct AppConfigFields {
pub disable_click: bool, pub disable_click: bool,
pub no_write: bool, pub no_write: bool,
pub show_table_scroll_position: bool, pub show_table_scroll_position: bool,
pub is_advanced_kill: bool,
} }
/// For filtering out information /// For filtering out information
@ -858,7 +859,13 @@ impl App {
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
self.on_right_key(); self.on_right_key();
#[cfg(target_family = "unix")] #[cfg(target_family = "unix")]
{
if self.app_config_fields.is_advanced_kill {
self.on_left_key(); self.on_left_key();
} else {
self.on_right_key();
}
}
return; return;
} }
self.reset_multi_tap_keys(); self.reset_multi_tap_keys();
@ -874,7 +881,13 @@ impl App {
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
self.on_left_key(); self.on_left_key();
#[cfg(target_family = "unix")] #[cfg(target_family = "unix")]
{
if self.app_config_fields.is_advanced_kill {
self.on_right_key(); self.on_right_key();
} else {
self.on_left_key();
}
}
return; return;
} }
self.reset_multi_tap_keys(); self.reset_multi_tap_keys();
@ -884,20 +897,6 @@ impl App {
if self.is_config_open { if self.is_config_open {
} else if !self.is_in_dialog() { } else 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);
// debug!(
// "Current column index <: {}",
// proc_widget_state.current_column_index
// );
// }
}
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
@ -943,6 +942,7 @@ impl App {
} else if self.delete_dialog_state.is_showing_dd { } else if self.delete_dialog_state.is_showing_dd {
#[cfg(target_family = "unix")] #[cfg(target_family = "unix")]
{ {
if self.app_config_fields.is_advanced_kill {
match self.delete_dialog_state.selected_signal { match self.delete_dialog_state.selected_signal {
KillSignal::KILL(prev_signal) => { KillSignal::KILL(prev_signal) => {
self.delete_dialog_state.selected_signal = match prev_signal - 1 { self.delete_dialog_state.selected_signal = match prev_signal - 1 {
@ -952,8 +952,11 @@ impl App {
signal => KillSignal::KILL(signal), signal => KillSignal::KILL(signal),
}; };
} }
KillSignal::CANCEL => (), KillSignal::CANCEL => {}
}; };
} else {
self.delete_dialog_state.selected_signal = KillSignal::default();
}
} }
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
{ {
@ -966,22 +969,6 @@ impl App {
if self.is_config_open { if self.is_config_open {
} else if !self.is_in_dialog() { } else 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.columns.get_enabled_columns()
// {
// proc_widget_state.current_column_index += 1;
// }
// debug!(
// "Current column index >: {}",
// proc_widget_state.current_column_index
// );
// }
}
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
@ -1031,6 +1018,7 @@ impl App {
} else if self.delete_dialog_state.is_showing_dd { } else if self.delete_dialog_state.is_showing_dd {
#[cfg(target_family = "unix")] #[cfg(target_family = "unix")]
{ {
if self.app_config_fields.is_advanced_kill {
let new_signal = match self.delete_dialog_state.selected_signal { let new_signal = match self.delete_dialog_state.selected_signal {
KillSignal::CANCEL => 1, KillSignal::CANCEL => 1,
// 32+33 are skipped // 32+33 are skipped
@ -1042,6 +1030,9 @@ impl App {
KillSignal::KILL(signal) => signal + 1, KillSignal::KILL(signal) => signal + 1,
}; };
self.delete_dialog_state.selected_signal = KillSignal::KILL(new_signal); self.delete_dialog_state.selected_signal = KillSignal::KILL(new_signal);
} else {
self.delete_dialog_state.selected_signal = KillSignal::CANCEL;
}
} }
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
{ {

View File

@ -381,15 +381,15 @@ impl Painter {
} else { } else {
terminal_width * 50 / 100 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; 7
} } else {
#[cfg(target_os = "windows")] 22
{ };
text_height = 7;
}
// let (text_width, text_height) = if let Some(dd_text) = &dd_text { // let (text_width, text_height) = if let Some(dd_text) = &dd_text {
// let width = if current_width < 100 { // let width = if current_width < 100 {
// current_width * 90 / 100 // current_width * 90 / 100

View File

@ -67,10 +67,10 @@ impl KillDialog for Painter {
None None
} }
#[cfg(target_os = "windows")]
fn draw_dd_confirm_buttons<B: Backend>( fn draw_dd_confirm_buttons<B: Backend>(
&self, f: &mut Frame<'_, B>, button_draw_loc: &Rect, app_state: &mut App, &self, f: &mut Frame<'_, B>, button_draw_loc: &Rect, app_state: &mut App,
) { ) {
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 { let (yes_button, no_button) = match app_state.delete_dialog_state.selected_signal {
KillSignal::KILL(_) => ( KillSignal::KILL(_) => (
Span::styled("Yes", self.colours.currently_selected_text_style), Span::styled("Yes", self.colours.currently_selected_text_style),
@ -125,12 +125,9 @@ impl KillDialog for Painter {
), ),
]; ];
} }
} } else {
#[cfg(target_family = "unix")] #[cfg(target_family = "unix")]
fn draw_dd_confirm_buttons<B: Backend>( {
&self, f: &mut Frame<'_, B>, button_draw_loc: &Rect, app_state: &mut App,
) {
let signal_text; let signal_text;
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
{ {
@ -277,8 +274,8 @@ impl KillDialog for Painter {
}; };
let scroll_offset: usize = app_state.delete_dialog_state.scroll_pos; let scroll_offset: usize = app_state.delete_dialog_state.scroll_pos;
let mut buttons = signal_text let mut buttons = signal_text[scroll_offset + 1
[scroll_offset + 1..min((layout.len() as usize) + scroll_offset, signal_text.len())] ..min((layout.len() as usize) + scroll_offset, signal_text.len())]
.iter() .iter()
.map(|text| Span::raw(*text)) .map(|text| Span::raw(*text))
.collect::<Vec<Span<'_>>>(); .collect::<Vec<Span<'_>>>();
@ -306,6 +303,8 @@ impl KillDialog for Painter {
f.render_widget(Paragraph::new(btn).alignment(Alignment::Left), pos); f.render_widget(Paragraph::new(btn).alignment(Alignment::Left), pos);
} }
} }
}
}
fn draw_dd_dialog<B: Backend>( fn draw_dd_dialog<B: Backend>(
&self, f: &mut Frame<'_, B>, dd_text: Option<Text<'_>>, app_state: &mut App, draw_loc: Rect, &self, f: &mut Frame<'_, B>, dd_text: Option<Text<'_>>, app_state: &mut App, draw_loc: Rect,
@ -356,15 +355,13 @@ impl KillDialog for Painter {
draw_loc, draw_loc,
); );
let btn_height; let btn_height =
#[cfg(target_family = "unix")] if cfg!(target_os = "windows") || !app_state.app_config_fields.is_advanced_kill {
{ 3
btn_height = 20; } else {
} 20
#[cfg(target_os = "windows")] };
{
btn_height = 3;
}
// Now draw buttons if needed... // Now draw buttons if needed...
let split_draw_loc = Layout::default() let split_draw_loc = Layout::default()
.direction(Direction::Vertical) .direction(Direction::Vertical)

View File

@ -106,6 +106,7 @@ rather than total CPU usage.\n\n",
"\ "\
Disables mouse clicks from interacting with the program.\n\n", Disables mouse clicks from interacting with the program.\n\n",
); );
let dot_marker = Arg::with_name("dot_marker") let dot_marker = Arg::with_name("dot_marker")
.short("m") .short("m")
.long("dot_marker") .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 Uses a dot marker for graphs as opposed to the default braille
marker.\n\n", marker.\n\n",
); );
let group = Arg::with_name("group") // FIXME: Rename this to something like "group_process", would be "breaking" though. let group = Arg::with_name("group") // FIXME: Rename this to something like "group_process", would be "breaking" though.
.short("g") .short("g")
.long("group") .long("group")
@ -123,6 +125,7 @@ marker.\n\n",
"\ "\
Groups processes with the same name by default.\n\n", Groups processes with the same name by default.\n\n",
); );
let hide_avg_cpu = Arg::with_name("hide_avg_cpu") let hide_avg_cpu = Arg::with_name("hide_avg_cpu")
.short("a") .short("a")
.long("hide_avg_cpu") .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", Hides the average CPU usage from being shown.\n\n",
); );
let hide_table_gap = Arg::with_name("hide_table_gap") let hide_table_gap = Arg::with_name("hide_table_gap")
.long("hide_table_gap") .long("hide_table_gap")
.help("Hides the spacing between table headers and entries.") .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", Hides the spacing between table headers and entries.\n\n",
); );
let hide_time = Arg::with_name("hide_time") let hide_time = Arg::with_name("hide_time")
.long("hide_time") .long("hide_time")
.help("Completely hides the time scaling.") .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", Completely hides the time scaling from being shown.\n\n",
); );
let process_command = Arg::with_name("process_command") let process_command = Arg::with_name("process_command")
.long("process_command") .long("process_command")
.help("Show processes as their commands by default.") .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. Show processes as their commands by default in the process widget.
", ",
); );
let left_legend = Arg::with_name("left_legend") let left_legend = Arg::with_name("left_legend")
.short("l") .short("l")
.long("left_legend") .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", Puts the CPU chart legend to the left side rather than the right side.\n\n",
); );
// let no_write = Arg::with_name("no_write") // let no_write = Arg::with_name("no_write")
// .long("no_write") // .long("no_write")
// .help("Disables writing to the config file.") // .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.", // Disables config changes in-app from writing to the config file.",
// ); // );
let regex = Arg::with_name("regex") let regex = Arg::with_name("regex")
.short("R") .short("R")
.long("regex") .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", 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") let show_table_scroll_position = Arg::with_name("show_table_scroll_position")
.long("show_table_scroll_position") .long("show_table_scroll_position")
.help("Shows the scroll position tracker in table widgets.") .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", 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") let use_old_network_legend = Arg::with_name("use_old_network_legend")
.long("use_old_network_legend") .long("use_old_network_legend")
.help("DEPRECATED - uses the older 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. DEPRECATED - uses the older (pre-0.4) network widget legend.
This display is not tested anymore and could be broken.\n\n\n", This display is not tested anymore and could be broken.\n\n\n",
); );
let whole_word = Arg::with_name("whole_word") let whole_word = Arg::with_name("whole_word")
.short("W") .short("W")
.long("whole_word") .long("whole_word")
@ -396,6 +416,7 @@ Defaults to showing the process widget in tree mode.\n\n",
.arg(hide_time) .arg(hide_time)
.arg(show_table_scroll_position) .arg(show_table_scroll_position)
.arg(left_legend) .arg(left_legend)
.arg(advanced_kill)
// .arg(no_write) // .arg(no_write)
.arg(rate) .arg(rate)
.arg(regex) .arg(regex)

View File

@ -154,6 +154,9 @@ pub struct ConfigFlags {
#[builder(default, setter(strip_option))] #[builder(default, setter(strip_option))]
pub process_command: Option<bool>, pub process_command: Option<bool>,
#[builder(default, setter(strip_option))]
pub advanced_kill: Option<bool>,
} }
#[derive(Clone, Default, Debug, Deserialize, Serialize)] #[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 show_memory_as_values = get_mem_as_value(matches, config);
let is_default_tree = get_is_default_tree(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_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 row in &widget_layout.rows {
for col in &row.children { for col in &row.children {
@ -399,6 +403,7 @@ pub fn build_app(
// no_write: get_no_write(matches, config), // no_write: get_no_write(matches, config),
no_write: false, no_write: false,
show_table_scroll_position: get_show_table_scroll_position(matches, config), show_table_scroll_position: get_show_table_scroll_position(matches, config),
is_advanced_kill,
}; };
let used_widgets = UsedWidgets { let used_widgets = UsedWidgets {
@ -1015,3 +1020,14 @@ fn get_is_default_process_command(matches: &clap::ArgMatches<'static>, config: &
} }
false 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
}