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",

114
README.md
View File

@ -247,37 +247,38 @@ Run using `btm`.
Use `btm --help` for more information. Use `btm --help` for more information.
``` ```
--autohide_time Temporarily shows the time scale in graphs. --advanced_kill Shows more options when killing a process on Unix-like systems.
-b, --basic Hides graphs and uses a more basic look. --autohide_time Temporarily shows the time scale in graphs.
--battery Shows the battery widget. -b, --basic Hides graphs and uses a more basic look.
-S, --case_sensitive Enables case sensitivity by default. --battery Shows the battery widget.
-c, --celsius Sets the temperature type to Celsius. -S, --case_sensitive Enables case sensitivity by default.
--color <COLOR SCHEME> Use a color scheme, use --help for supported values. -c, --celsius Sets the temperature type to Celsius.
--process_command Show processes as their commands by default. --color <COLOR SCHEME> Use a color scheme, use --help for supported values.
-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.
--use_old_network_legend DEPRECATED - uses the older network legend. -T, --tree Defaults to showing the process widget in tree mode.
-V, --version Prints version information. --use_old_network_legend DEPRECATED - uses the older network legend.
-W, --whole_word Enables whole-word matching by default. -V, --version Prints version information.
-W, --whole_word Enables whole-word matching by default.
``` ```
### Keybindings ### 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): 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. |
| `current_usage` | Boolean | Sets process CPU% to be based on current CPU%. | | `current_usage` | Boolean | Sets process CPU% to be based on current CPU%. |
| `group_processes` | Boolean | Groups processes with the same name by default. | | `group_processes` | Boolean | Groups processes with the same name by default. |
| `case_sensitive` | Boolean | Enables case sensitivity by default. | | `case_sensitive` | Boolean | Enables case sensitivity by default. |
| `whole_word` | Boolean | Enables whole-word matching by default. | | `whole_word` | Boolean | Enables whole-word matching by default. |
| `regex` | Boolean | Enables regex by default. | | `regex` | Boolean | Enables regex by default. |
| `basic` | Boolean | Hides graphs and uses a more basic look. | | `basic` | Boolean | Hides graphs and uses a more basic look. |
| `use_old_network_legend` | Boolean | DEPRECATED - uses the older network legend. | | `use_old_network_legend` | Boolean | DEPRECATED - uses the older network legend. |
| `battery` | Boolean | Shows the battery widget. | | `battery` | Boolean | Shows the battery widget. |
| `rate` | Unsigned Int (represents milliseconds) | Sets a refresh rate in ms. | | `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. | | `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. | | `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. | | `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_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. | | `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. | | `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. | | `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. | | `mem_as_value` | Boolean | Defaults to showing process memory usage by value. |
| `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")]
self.on_left_key(); {
if self.app_config_fields.is_advanced_kill {
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")]
self.on_right_key(); {
if self.app_config_fields.is_advanced_kill {
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,17 +942,21 @@ 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")]
{ {
match self.delete_dialog_state.selected_signal { if self.app_config_fields.is_advanced_kill {
KillSignal::KILL(prev_signal) => { match self.delete_dialog_state.selected_signal {
self.delete_dialog_state.selected_signal = match prev_signal - 1 { KillSignal::KILL(prev_signal) => {
0 => KillSignal::CANCEL, self.delete_dialog_state.selected_signal = match prev_signal - 1 {
// 32+33 are skipped 0 => KillSignal::CANCEL,
33 => KillSignal::KILL(31), // 32+33 are skipped
signal => KillSignal::KILL(signal), 33 => KillSignal::KILL(31),
}; 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,17 +1018,21 @@ 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")]
{ {
let new_signal = match self.delete_dialog_state.selected_signal { if self.app_config_fields.is_advanced_kill {
KillSignal::CANCEL => 1, let new_signal = match self.delete_dialog_state.selected_signal {
// 32+33 are skipped KillSignal::CANCEL => 1,
#[cfg(target_os = "linux")] // 32+33 are skipped
KillSignal::KILL(31) => 34, #[cfg(target_os = "linux")]
#[cfg(target_os = "macos")] KillSignal::KILL(31) => 34,
KillSignal::KILL(31) => 31, #[cfg(target_os = "macos")]
KillSignal::KILL(64) => 64, KillSignal::KILL(31) => 31,
KillSignal::KILL(signal) => signal + 1, KillSignal::KILL(64) => 64,
}; 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,243 +67,242 @@ 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,
) { ) {
let (yes_button, no_button) = match app_state.delete_dialog_state.selected_signal { if cfg!(target_os = "windows") || !app_state.app_config_fields.is_advanced_kill {
KillSignal::KILL(_) => ( let (yes_button, no_button) = match app_state.delete_dialog_state.selected_signal {
Span::styled("Yes", self.colours.currently_selected_text_style), KillSignal::KILL(_) => (
Span::raw("No"), 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,
), ),
( KillSignal::CANCEL => (
button_layout[0].x, Span::raw("Yes"),
button_layout[0].y, Span::styled("No", self.colours.currently_selected_text_style),
button_layout[0].x + button_layout[0].width,
button_layout[0].y + button_layout[0].height,
1,
), ),
]; };
}
}
#[cfg(target_family = "unix")] let button_layout = Layout::default()
fn draw_dd_confirm_buttons<B: Backend>( .direction(Direction::Horizontal)
&self, f: &mut Frame<'_, B>, button_draw_loc: &Rect, app_state: &mut App, .constraints(
) { [
let signal_text; Constraint::Percentage(35),
#[cfg(target_os = "linux")] Constraint::Percentage(30),
{ Constraint::Percentage(35),
signal_text = vec![ ]
"0: Cancel", .as_ref(),
"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::<Vec<Span<'_>>>();
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,
) )
}) .split(*button_draw_loc);
.collect::<Vec<(u16, u16, u16, u16, usize)>>();
for (btn, pos) in buttons.into_iter().zip(layout.into_iter()) { f.render_widget(
f.render_widget(Paragraph::new(btn).alignment(Alignment::Left), pos); 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::<Vec<Span<'_>>>();
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::<Vec<(u16, u16, u16, u16, usize)>>();
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, 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
}