mirror of
https://github.com/ClementTsang/bottom.git
synced 2024-11-03 21:04:38 +03:00
change: add scrolling to help menu
This commit is contained in:
parent
99fe0a1844
commit
863e780f2f
20
CHANGELOG.md
20
CHANGELOG.md
@ -27,12 +27,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- `"processes"`
|
||||
- `"temperature"`
|
||||
|
||||
- Removed an (undocumented) feature in allowing modifying total RX/TX colours. This is mainly due to the legend change.
|
||||
|
||||
- Updated error messages to be a bit more consistent/helpful.
|
||||
|
||||
- [#117](https://github.com/ClementTsang/bottom/issues/117): Update tui to 0.9:
|
||||
|
||||
- Removed an (undocumented) feature in allowing modifying total RX/TX colours. This is mainly due to the legend change.
|
||||
|
||||
- Use custom legend-hiding to stop hiding legends for memory and network widgets.
|
||||
|
||||
- In addition, changed to using only legends within the graph for network, as well as redesigned the legend.
|
||||
@ -40,9 +38,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- Allow for option to hide the header gap on tables via `--hide_table_gap` or `hide_table_gap = true`.
|
||||
|
||||
- Switch to stateful widget style for tables.
|
||||
- [#126](https://github.com/ClementTsang/bottom/pull/126): Updated error messages to be a bit more consistent/helpful.
|
||||
|
||||
- Switch to using tui-rs' new built in linear interpolation rather than doing it manually.
|
||||
- Redesigned help menu to allow for scrolling.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@ -51,9 +49,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Fixed bug where a single empty row as a layout would crash without a proper warning.
|
||||
The behaviour now errors out with a more helpful message.
|
||||
|
||||
### Other
|
||||
### Development changes
|
||||
|
||||
- Updated tests and added config testing.
|
||||
- Switch to stateful widget style for tables.
|
||||
|
||||
- Switch to using tui-rs' new built in linear interpolation rather than doing it manually.
|
||||
|
||||
- Updated arg tests and added config testing.
|
||||
|
||||
- More refactoring.
|
||||
|
||||
## [0.3.0] - 2020-04-07
|
||||
|
||||
|
21
README.md
21
README.md
@ -7,6 +7,8 @@
|
||||
|
||||
A cross-platform graphical process/system monitor with a customizable interface and a multitude of features. Supports Linux, macOS, and Windows. Inspired by both [gtop](https://github.com/aksakalli/gtop) and [gotop](https://github.com/cjbassi/gotop).
|
||||
|
||||
<!--TODO: Update recording for 0.4-->
|
||||
|
||||
![Quick demo recording showing off searching, maximizing, and process killing.](assets/summary_and_search.gif) _Theme based on [gruvbox](https://github.com/morhetz/gruvbox) (see [sample config](./sample_configs/demo_config.toml))._ Recorded on version 0.2.0.
|
||||
|
||||
**Note**: This documentation is relevant to version 0.4.0 and may refer to in-development features, especially if you are reading this on the master branch. Please refer to [release branch](https://github.com/ClementTsang/bottom/tree/release/README.md) or [crates.io](https://crates.io/crates/bottom) for the most up-to-date _release_ documentation.
|
||||
@ -163,19 +165,19 @@ Run using `btm`.
|
||||
|
||||
| | |
|
||||
| -------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
|
||||
| `q`, `Ctrl-c` | Quit bottom |
|
||||
| `q`, `Ctrl-c` | Quit |
|
||||
| `Esc` | Close dialog windows, search, widgets, or exit maximized mode |
|
||||
| `Ctrl-r` | Reset display and any collected data |
|
||||
| `f` | Freeze/unfreeze updating with new data |
|
||||
| `Ctrl`-arrow key<br>`Shift`-arrow key<br>`H/J/K/L` | Move to a different widget (on macOS some keybindings may conflict) |
|
||||
| `Up`,`k` | Scroll up in tables |
|
||||
| `Down`, `j` | Scroll down in tables |
|
||||
| `Up`,`k` | Scroll up |
|
||||
| `Down`, `j` | Scroll down |
|
||||
| `?` | Open help menu |
|
||||
| `gg`, `Home` | Jump to the first entry of a table |
|
||||
| `Shift-g`, `End` | Jump to the last entry of a table |
|
||||
| `Enter` | Maximize widget |
|
||||
| `+` | Zoom in on a chart |
|
||||
| `-` | Zoom out on a chart |
|
||||
| `gg`, `Home` | Jump to the first entry |
|
||||
| `Shift-g`, `End` | Jump to the last entry |
|
||||
| `Enter` | Maximize the currently selected widget |
|
||||
| `+` | Zoom in on chart (decrease time range) |
|
||||
| `-` | Zoom out on chart (increase time range) |
|
||||
| `=` | Reset zoom |
|
||||
| Mouse scroll | Table: Scrolls through the list<br>Chart: Zooms in or out by scrolling up or down respectively |
|
||||
|
||||
@ -207,6 +209,9 @@ Run using `btm`.
|
||||
| `Esc` | Close the search widget (retains the filter) |
|
||||
| `Ctrl-a` | Skip to the start of the search query |
|
||||
| `Ctrl-e` | Skip to the end of the search query |
|
||||
| `Ctrl-u` | Clear the current search query |
|
||||
| `Backspace` | Delete the character behind the cursor |
|
||||
| `Delete` | Delete the character at the cursor |
|
||||
| `Alt-c`/`F1` | Toggle matching case |
|
||||
| `Alt-w`/`F2` | Toggle matching the entire word |
|
||||
| `Alt-r`/`F3` | Toggle using regex |
|
||||
|
103
src/app.rs
103
src/app.rs
@ -64,18 +64,15 @@ pub enum AppHelpCategory {
|
||||
Search,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct AppHelpDialogState {
|
||||
pub is_showing_help: bool,
|
||||
pub current_category: AppHelpCategory,
|
||||
}
|
||||
|
||||
impl Default for AppHelpDialogState {
|
||||
fn default() -> Self {
|
||||
AppHelpDialogState {
|
||||
is_showing_help: false,
|
||||
current_category: AppHelpCategory::General,
|
||||
}
|
||||
}
|
||||
pub scroll_state: ParagraphScrollState,
|
||||
pub general_index: u16,
|
||||
pub cpu_index: u16,
|
||||
pub process_index: u16,
|
||||
pub search_index: u16,
|
||||
pub battery_index: u16,
|
||||
}
|
||||
|
||||
/// AppConfigFields is meant to cover basic fields that would normally be set
|
||||
@ -481,6 +478,12 @@ impl BatteryState {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ParagraphScrollState {
|
||||
pub current_scroll_index: u16,
|
||||
pub max_scroll_index: u16,
|
||||
}
|
||||
|
||||
#[derive(TypedBuilder)]
|
||||
pub struct App {
|
||||
#[builder(default = false, setter(skip))]
|
||||
@ -517,7 +520,7 @@ pub struct App {
|
||||
pub is_expanded: bool,
|
||||
|
||||
#[builder(default = false, setter(skip))]
|
||||
pub is_resized: bool,
|
||||
pub is_force_redraw: bool,
|
||||
|
||||
pub cpu_state: CpuState,
|
||||
pub mem_state: MemState,
|
||||
@ -581,11 +584,11 @@ impl App {
|
||||
self.reset_multi_tap_keys();
|
||||
if self.is_in_dialog() {
|
||||
self.help_dialog_state.is_showing_help = false;
|
||||
self.help_dialog_state.current_category = AppHelpCategory::General;
|
||||
self.delete_dialog_state.is_showing_dd = false;
|
||||
self.delete_dialog_state.is_on_yes = false;
|
||||
self.to_delete_process_list = None;
|
||||
self.dd_err = None;
|
||||
self.is_force_redraw = true;
|
||||
} else if self.is_filtering_or_searching() {
|
||||
match self.current_widget.widget_type {
|
||||
BottomWidgetType::Cpu => {
|
||||
@ -603,7 +606,7 @@ impl App {
|
||||
cpu_widget_state.scroll_state.current_scroll_position = new_position;
|
||||
cpu_widget_state.scroll_state.previous_scroll_position = 0;
|
||||
}
|
||||
self.is_resized = true;
|
||||
self.is_force_redraw = true;
|
||||
}
|
||||
}
|
||||
BottomWidgetType::CpuLegend => {
|
||||
@ -621,7 +624,7 @@ impl App {
|
||||
cpu_widget_state.scroll_state.current_scroll_position = new_position;
|
||||
cpu_widget_state.scroll_state.previous_scroll_position = 0;
|
||||
}
|
||||
self.is_resized = true;
|
||||
self.is_force_redraw = true;
|
||||
}
|
||||
}
|
||||
BottomWidgetType::Proc => {
|
||||
@ -636,7 +639,7 @@ impl App {
|
||||
.search_state
|
||||
.is_enabled = false;
|
||||
}
|
||||
self.is_resized = true;
|
||||
self.is_force_redraw = true;
|
||||
}
|
||||
}
|
||||
BottomWidgetType::ProcSearch => {
|
||||
@ -652,14 +655,14 @@ impl App {
|
||||
.is_enabled = false;
|
||||
self.move_widget_selection_up();
|
||||
}
|
||||
self.is_resized = true;
|
||||
self.is_force_redraw = true;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else if self.is_expanded {
|
||||
self.is_expanded = false;
|
||||
self.is_resized = true;
|
||||
self.is_force_redraw = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -974,7 +977,7 @@ impl App {
|
||||
BottomWidgetType::ProcSearch => {}
|
||||
_ => {
|
||||
self.is_expanded = true;
|
||||
self.is_resized = true;
|
||||
self.is_force_redraw = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1098,13 +1101,19 @@ impl App {
|
||||
pub fn on_up_key(&mut self) {
|
||||
if !self.is_in_dialog() {
|
||||
self.decrement_position_count();
|
||||
} else if self.help_dialog_state.is_showing_help {
|
||||
self.help_scroll_up();
|
||||
}
|
||||
self.reset_multi_tap_keys();
|
||||
}
|
||||
|
||||
pub fn on_down_key(&mut self) {
|
||||
if !self.is_in_dialog() {
|
||||
self.increment_position_count();
|
||||
} else if self.help_dialog_state.is_showing_help {
|
||||
self.help_scroll_down();
|
||||
}
|
||||
self.reset_multi_tap_keys();
|
||||
}
|
||||
|
||||
pub fn on_left_key(&mut self) {
|
||||
@ -1428,10 +1437,16 @@ impl App {
|
||||
}
|
||||
self.handle_char(caught_char);
|
||||
} else if self.help_dialog_state.is_showing_help {
|
||||
// TODO: Seems weird that we have it like this; it would be better to make this
|
||||
// more obvious that we are separating dialog logic and normal logic IMO.
|
||||
// This is even more so as most logic already checks for dialog state.
|
||||
match caught_char {
|
||||
'1' => self.help_dialog_state.current_category = AppHelpCategory::General,
|
||||
'2' => self.help_dialog_state.current_category = AppHelpCategory::Process,
|
||||
'3' => self.help_dialog_state.current_category = AppHelpCategory::Search,
|
||||
'1' => self.help_scroll_to_or_max(self.help_dialog_state.general_index),
|
||||
'2' => self.help_scroll_to_or_max(self.help_dialog_state.cpu_index),
|
||||
'3' => self.help_scroll_to_or_max(self.help_dialog_state.process_index),
|
||||
'4' => self.help_scroll_to_or_max(self.help_dialog_state.search_index),
|
||||
'5' => self.help_scroll_to_or_max(self.help_dialog_state.battery_index),
|
||||
'j' | 'k' | 'g' | 'G' => self.handle_char(caught_char),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@ -1478,8 +1493,8 @@ impl App {
|
||||
}
|
||||
}
|
||||
'G' => self.skip_to_last(),
|
||||
'k' => self.decrement_position_count(),
|
||||
'j' => self.increment_position_count(),
|
||||
'k' => self.on_up_key(),
|
||||
'j' => self.on_down_key(),
|
||||
'f' => {
|
||||
self.is_frozen = !self.is_frozen;
|
||||
if self.is_frozen {
|
||||
@ -1584,6 +1599,7 @@ impl App {
|
||||
}
|
||||
'?' => {
|
||||
self.help_dialog_state.is_showing_help = true;
|
||||
self.is_force_redraw = true;
|
||||
}
|
||||
'H' => self.move_widget_selection_left(),
|
||||
'L' => self.move_widget_selection_right(),
|
||||
@ -2019,6 +2035,8 @@ impl App {
|
||||
_ => {}
|
||||
}
|
||||
self.reset_multi_tap_keys();
|
||||
} else {
|
||||
self.help_dialog_state.scroll_state.current_scroll_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2093,6 +2111,12 @@ impl App {
|
||||
_ => {}
|
||||
}
|
||||
self.reset_multi_tap_keys();
|
||||
} else {
|
||||
self.help_dialog_state.scroll_state.current_scroll_index = self
|
||||
.help_dialog_state
|
||||
.scroll_state
|
||||
.max_scroll_index
|
||||
.saturating_sub(1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2105,7 +2129,6 @@ impl App {
|
||||
BottomWidgetType::CpuLegend => self.change_cpu_table_position(-1),
|
||||
_ => {}
|
||||
}
|
||||
self.reset_multi_tap_keys();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2118,7 +2141,6 @@ impl App {
|
||||
BottomWidgetType::CpuLegend => self.change_cpu_table_position(1),
|
||||
_ => {}
|
||||
}
|
||||
self.reset_multi_tap_keys();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2228,8 +2250,33 @@ impl App {
|
||||
}
|
||||
}
|
||||
|
||||
fn help_scroll_up(&mut self) {
|
||||
if self.help_dialog_state.scroll_state.current_scroll_index > 0 {
|
||||
self.help_dialog_state.scroll_state.current_scroll_index -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn help_scroll_down(&mut self) {
|
||||
if self.help_dialog_state.scroll_state.current_scroll_index + 1
|
||||
< self.help_dialog_state.scroll_state.max_scroll_index
|
||||
{
|
||||
self.help_dialog_state.scroll_state.current_scroll_index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn help_scroll_to_or_max(&mut self, new_position: u16) {
|
||||
if new_position < self.help_dialog_state.scroll_state.max_scroll_index {
|
||||
self.help_dialog_state.scroll_state.current_scroll_index = new_position;
|
||||
} else {
|
||||
self.help_dialog_state.scroll_state.current_scroll_index =
|
||||
self.help_dialog_state.scroll_state.max_scroll_index - 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_scroll_up(&mut self) {
|
||||
if self.current_widget.widget_type.is_widget_graph() {
|
||||
if self.help_dialog_state.is_showing_help {
|
||||
self.help_scroll_up();
|
||||
} else if self.current_widget.widget_type.is_widget_graph() {
|
||||
self.zoom_in();
|
||||
} else if self.current_widget.widget_type.is_widget_table() {
|
||||
self.decrement_position_count();
|
||||
@ -2237,7 +2284,9 @@ impl App {
|
||||
}
|
||||
|
||||
pub fn handle_scroll_down(&mut self) {
|
||||
if self.current_widget.widget_type.is_widget_graph() {
|
||||
if self.help_dialog_state.is_showing_help {
|
||||
self.help_scroll_down();
|
||||
} else if self.current_widget.widget_type.is_widget_graph() {
|
||||
self.zoom_out();
|
||||
} else if self.current_widget.widget_type.is_widget_table() {
|
||||
self.increment_position_count();
|
||||
|
128
src/canvas.rs
128
src/canvas.rs
@ -59,9 +59,7 @@ pub struct Painter {
|
||||
pub colours: CanvasColours,
|
||||
height: u16,
|
||||
width: u16,
|
||||
styled_general_help_text: Vec<Text<'static>>,
|
||||
styled_process_help_text: Vec<Text<'static>>,
|
||||
styled_search_help_text: Vec<Text<'static>>,
|
||||
styled_help_text: Vec<Text<'static>>,
|
||||
is_mac_os: bool,
|
||||
row_constraints: Vec<Constraint>,
|
||||
col_constraints: Vec<Vec<Constraint>>,
|
||||
@ -145,9 +143,7 @@ impl Painter {
|
||||
colours: CanvasColours::default(),
|
||||
height: 0,
|
||||
width: 0,
|
||||
styled_general_help_text: Vec::new(),
|
||||
styled_process_help_text: Vec::new(),
|
||||
styled_search_help_text: Vec::new(),
|
||||
styled_help_text: Vec::new(),
|
||||
is_mac_os: false,
|
||||
row_constraints,
|
||||
col_constraints,
|
||||
@ -164,44 +160,79 @@ impl Painter {
|
||||
pub fn complete_painter_init(&mut self) {
|
||||
self.is_mac_os = cfg!(target_os = "macos");
|
||||
|
||||
if GENERAL_HELP_TEXT.len() > 1 {
|
||||
self.styled_general_help_text.push(Text::Styled(
|
||||
GENERAL_HELP_TEXT[0].into(),
|
||||
self.colours.table_header_style,
|
||||
));
|
||||
self.styled_general_help_text.extend(
|
||||
GENERAL_HELP_TEXT[1..]
|
||||
.iter()
|
||||
.map(|&text| Text::Styled(text.into(), self.colours.text_style))
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
}
|
||||
// Init help text:
|
||||
// ToC
|
||||
self.styled_help_text.extend(
|
||||
HELP_CONTENTS_TEXT
|
||||
.iter()
|
||||
.map(|&text| Text::Styled(text.into(), self.colours.text_style))
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
|
||||
if PROCESS_HELP_TEXT.len() > 1 {
|
||||
self.styled_process_help_text.push(Text::Styled(
|
||||
PROCESS_HELP_TEXT[0].into(),
|
||||
self.colours.table_header_style,
|
||||
));
|
||||
self.styled_process_help_text.extend(
|
||||
PROCESS_HELP_TEXT[1..]
|
||||
.iter()
|
||||
.map(|&text| Text::Styled(text.into(), self.colours.text_style))
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
}
|
||||
// General
|
||||
self.styled_help_text.push(Text::Raw("\n\n".into()));
|
||||
self.styled_help_text.push(Text::Styled(
|
||||
GENERAL_HELP_TEXT[0].into(),
|
||||
self.colours.table_header_style,
|
||||
));
|
||||
self.styled_help_text.extend(
|
||||
GENERAL_HELP_TEXT[1..]
|
||||
.iter()
|
||||
.map(|&text| Text::Styled(text.into(), self.colours.text_style))
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
|
||||
if SEARCH_HELP_TEXT.len() > 1 {
|
||||
self.styled_search_help_text.push(Text::Styled(
|
||||
SEARCH_HELP_TEXT[0].into(),
|
||||
self.colours.table_header_style,
|
||||
));
|
||||
self.styled_search_help_text.extend(
|
||||
SEARCH_HELP_TEXT[1..]
|
||||
.iter()
|
||||
.map(|&text| Text::Styled(text.into(), self.colours.text_style))
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
}
|
||||
// CPU
|
||||
self.styled_help_text.push(Text::Raw("\n\n".into()));
|
||||
self.styled_help_text.push(Text::Styled(
|
||||
CPU_HELP_TEXT[0].into(),
|
||||
self.colours.table_header_style,
|
||||
));
|
||||
self.styled_help_text.extend(
|
||||
CPU_HELP_TEXT[1..]
|
||||
.iter()
|
||||
.map(|&text| Text::Styled(text.into(), self.colours.text_style))
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
|
||||
// Proc
|
||||
self.styled_help_text.push(Text::Raw("\n\n".into()));
|
||||
self.styled_help_text.push(Text::Styled(
|
||||
PROCESS_HELP_TEXT[0].into(),
|
||||
self.colours.table_header_style,
|
||||
));
|
||||
self.styled_help_text.extend(
|
||||
PROCESS_HELP_TEXT[1..]
|
||||
.iter()
|
||||
.map(|&text| Text::Styled(text.into(), self.colours.text_style))
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
|
||||
// Proc Search
|
||||
self.styled_help_text.push(Text::Raw("\n\n".into()));
|
||||
self.styled_help_text.push(Text::Styled(
|
||||
SEARCH_HELP_TEXT[0].into(),
|
||||
self.colours.table_header_style,
|
||||
));
|
||||
self.styled_help_text.extend(
|
||||
SEARCH_HELP_TEXT[1..]
|
||||
.iter()
|
||||
.map(|&text| Text::Styled(text.into(), self.colours.text_style))
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
|
||||
// Battery
|
||||
self.styled_help_text.push(Text::Raw("\n\n".into()));
|
||||
self.styled_help_text.push(Text::Styled(
|
||||
BATTERY_HELP_TEXT[0].into(),
|
||||
self.colours.table_header_style,
|
||||
));
|
||||
self.styled_help_text.extend(
|
||||
BATTERY_HELP_TEXT[1..]
|
||||
.iter()
|
||||
.map(|&text| Text::Styled(text.into(), self.colours.text_style))
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: [FEATURE] Auto-resizing dialog sizes.
|
||||
@ -214,11 +245,10 @@ impl Painter {
|
||||
let current_height = terminal_size.height;
|
||||
let current_width = terminal_size.width;
|
||||
|
||||
if self.height == 0 && self.width == 0 {
|
||||
self.height = current_height;
|
||||
self.width = current_width;
|
||||
} else if self.height != current_height || self.width != current_width {
|
||||
app_state.is_resized = true;
|
||||
if (self.height == 0 && self.width == 0)
|
||||
|| (self.height != current_height || self.width != current_width)
|
||||
{
|
||||
app_state.is_force_redraw = true;
|
||||
self.height = current_height;
|
||||
self.width = current_width;
|
||||
}
|
||||
@ -434,7 +464,7 @@ impl Painter {
|
||||
}
|
||||
} else {
|
||||
// Draws using the passed in (or default) layout. NOT basic so far.
|
||||
if self.derived_widget_draw_locs.is_empty() || app_state.is_resized {
|
||||
if self.derived_widget_draw_locs.is_empty() || app_state.is_force_redraw {
|
||||
let row_draw_locs = Layout::default()
|
||||
.margin(0)
|
||||
.constraints(self.row_constraints.as_ref())
|
||||
@ -531,7 +561,7 @@ impl Painter {
|
||||
}
|
||||
})?;
|
||||
|
||||
app_state.is_resized = false;
|
||||
app_state.is_force_redraw = false;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
0
src/canvas/dialogs/filter_dialog.rs
Normal file
0
src/canvas/dialogs/filter_dialog.rs
Normal file
@ -1,4 +1,5 @@
|
||||
use std::cmp::max;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use tui::{
|
||||
backend::Backend,
|
||||
@ -7,12 +8,9 @@ use tui::{
|
||||
widgets::{Block, Borders, Paragraph},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
app::{App, AppHelpCategory},
|
||||
canvas::Painter,
|
||||
};
|
||||
use crate::{app::App, canvas::Painter, constants};
|
||||
|
||||
const HELP_BASE: &str = " Help ── 1: General ─── 2: Processes ─── 3: Search ─── Esc to close ";
|
||||
const HELP_BASE: &str = " Help ── Esc to close ";
|
||||
|
||||
pub trait HelpDialog {
|
||||
fn draw_help_dialog<B: Backend>(
|
||||
@ -28,31 +26,121 @@ impl HelpDialog for Painter {
|
||||
0,
|
||||
draw_loc.width as i32 - HELP_BASE.chars().count() as i32 - 2,
|
||||
);
|
||||
let help_title = format!(
|
||||
" Help ─{}─ 1: General ─── 2: Processes ─── 3: Search ─── Esc to close ",
|
||||
"─".repeat(repeat_num as usize)
|
||||
);
|
||||
let help_title = format!(" Help ─{}─ Esc to close ", "─".repeat(repeat_num as usize));
|
||||
|
||||
if app_state.is_force_redraw {
|
||||
// We must also recalculate how many lines are wrapping to properly get scrolling to work on
|
||||
// small terminal sizes... oh joy.
|
||||
|
||||
// TODO: Make this more automated and easier to add.
|
||||
|
||||
let mut overflow_buffer = 0;
|
||||
let paragraph_width = draw_loc.width - 2;
|
||||
constants::HELP_CONTENTS_TEXT.iter().for_each(|text_line| {
|
||||
overflow_buffer +=
|
||||
UnicodeWidthStr::width(*text_line).saturating_sub(1) as u16 / paragraph_width;
|
||||
});
|
||||
|
||||
// General
|
||||
app_state.help_dialog_state.general_index =
|
||||
constants::HELP_CONTENTS_TEXT.len() as u16 + 1 + overflow_buffer;
|
||||
constants::GENERAL_HELP_TEXT.iter().for_each(|text_line| {
|
||||
overflow_buffer +=
|
||||
UnicodeWidthStr::width(*text_line).saturating_sub(1) as u16 / paragraph_width;
|
||||
});
|
||||
|
||||
// CPU
|
||||
app_state.help_dialog_state.cpu_index =
|
||||
(constants::HELP_CONTENTS_TEXT.len() + constants::GENERAL_HELP_TEXT.len()) as u16
|
||||
+ 2
|
||||
+ overflow_buffer;
|
||||
constants::CPU_HELP_TEXT.iter().for_each(|text_line| {
|
||||
overflow_buffer +=
|
||||
UnicodeWidthStr::width(*text_line).saturating_sub(1) as u16 / paragraph_width;
|
||||
});
|
||||
|
||||
// Processes
|
||||
app_state.help_dialog_state.process_index = (constants::HELP_CONTENTS_TEXT.len()
|
||||
+ constants::GENERAL_HELP_TEXT.len()
|
||||
+ constants::CPU_HELP_TEXT.len())
|
||||
as u16
|
||||
+ 3
|
||||
+ overflow_buffer;
|
||||
constants::PROCESS_HELP_TEXT.iter().for_each(|text_line| {
|
||||
overflow_buffer +=
|
||||
UnicodeWidthStr::width(*text_line).saturating_sub(1) as u16 / paragraph_width;
|
||||
});
|
||||
|
||||
// Search
|
||||
app_state.help_dialog_state.search_index = (constants::HELP_CONTENTS_TEXT.len()
|
||||
+ constants::GENERAL_HELP_TEXT.len()
|
||||
+ constants::CPU_HELP_TEXT.len()
|
||||
+ constants::PROCESS_HELP_TEXT.len())
|
||||
as u16
|
||||
+ 4
|
||||
+ overflow_buffer;
|
||||
constants::SEARCH_HELP_TEXT.iter().for_each(|text_line| {
|
||||
overflow_buffer +=
|
||||
UnicodeWidthStr::width(*text_line).saturating_sub(1) as u16 / paragraph_width;
|
||||
});
|
||||
|
||||
// Battery
|
||||
app_state.help_dialog_state.battery_index = (constants::HELP_CONTENTS_TEXT.len()
|
||||
+ constants::GENERAL_HELP_TEXT.len()
|
||||
+ constants::CPU_HELP_TEXT.len()
|
||||
+ constants::PROCESS_HELP_TEXT.len()
|
||||
+ constants::SEARCH_HELP_TEXT.len())
|
||||
as u16
|
||||
+ 5
|
||||
+ overflow_buffer;
|
||||
constants::BATTERY_HELP_TEXT.iter().for_each(|text_line| {
|
||||
overflow_buffer +=
|
||||
UnicodeWidthStr::width(*text_line).saturating_sub(1) as u16 / paragraph_width;
|
||||
});
|
||||
|
||||
app_state.help_dialog_state.scroll_state.max_scroll_index =
|
||||
(self.styled_help_text.len() as u16
|
||||
+ (constants::NUM_CATEGORIES - 3)
|
||||
+ overflow_buffer)
|
||||
.saturating_sub(draw_loc.height);
|
||||
|
||||
// Fix if over-scrolled
|
||||
if app_state
|
||||
.help_dialog_state
|
||||
.scroll_state
|
||||
.current_scroll_index
|
||||
>= app_state.help_dialog_state.scroll_state.max_scroll_index
|
||||
{
|
||||
app_state
|
||||
.help_dialog_state
|
||||
.scroll_state
|
||||
.current_scroll_index = app_state
|
||||
.help_dialog_state
|
||||
.scroll_state
|
||||
.max_scroll_index
|
||||
.saturating_sub(1);
|
||||
}
|
||||
}
|
||||
|
||||
f.render_widget(
|
||||
Paragraph::new(
|
||||
match app_state.help_dialog_state.current_category {
|
||||
AppHelpCategory::General => &self.styled_general_help_text,
|
||||
AppHelpCategory::Process => &self.styled_process_help_text,
|
||||
AppHelpCategory::Search => &self.styled_search_help_text,
|
||||
}
|
||||
.iter(),
|
||||
)
|
||||
.block(
|
||||
Block::default()
|
||||
.title(&help_title)
|
||||
.title_style(self.colours.border_style)
|
||||
.style(self.colours.border_style)
|
||||
.borders(Borders::ALL)
|
||||
.border_style(self.colours.border_style),
|
||||
)
|
||||
.style(self.colours.text_style)
|
||||
.alignment(Alignment::Left)
|
||||
.wrap(true),
|
||||
Paragraph::new(self.styled_help_text.iter())
|
||||
.block(
|
||||
Block::default()
|
||||
.title(&help_title)
|
||||
.title_style(self.colours.border_style)
|
||||
.style(self.colours.border_style)
|
||||
.borders(Borders::ALL)
|
||||
.border_style(self.colours.border_style),
|
||||
)
|
||||
.style(self.colours.text_style)
|
||||
.alignment(Alignment::Left)
|
||||
.wrap(true)
|
||||
.scroll(
|
||||
app_state
|
||||
.help_dialog_state
|
||||
.scroll_state
|
||||
.current_scroll_index,
|
||||
),
|
||||
draw_loc,
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::app;
|
||||
use itertools::izip;
|
||||
|
||||
// TODO: Reverse intrinsic?
|
||||
/// A somewhat jury-rigged solution to simulate a variable intrinsic layout for
|
||||
/// table widths. Note that this will do one main pass to try to properly
|
||||
/// allocate widths. This will thus potentially cut off latter elements
|
||||
@ -77,9 +78,9 @@ pub fn get_variable_intrinsic_widths(
|
||||
|
||||
pub fn get_search_start_position(
|
||||
num_columns: usize, cursor_direction: &app::CursorDirection, cursor_bar: &mut usize,
|
||||
current_cursor_position: usize, is_resized: bool,
|
||||
current_cursor_position: usize, is_force_redraw: bool,
|
||||
) -> usize {
|
||||
if is_resized {
|
||||
if is_force_redraw {
|
||||
*cursor_bar = 0;
|
||||
}
|
||||
|
||||
@ -117,9 +118,9 @@ pub fn get_search_start_position(
|
||||
|
||||
pub fn get_start_position(
|
||||
num_rows: u64, scroll_direction: &app::ScrollDirection, scroll_position_bar: &mut u64,
|
||||
currently_selected_position: u64, is_resized: bool,
|
||||
currently_selected_position: u64, is_force_redraw: bool,
|
||||
) -> u64 {
|
||||
if is_resized {
|
||||
if is_force_redraw {
|
||||
*scroll_position_bar = 0;
|
||||
}
|
||||
|
||||
|
@ -224,7 +224,7 @@ impl CpuGraphWidget for Painter {
|
||||
&cpu_widget_state.scroll_state.scroll_direction,
|
||||
&mut cpu_widget_state.scroll_state.previous_scroll_position,
|
||||
cpu_widget_state.scroll_state.current_scroll_position,
|
||||
app_state.is_resized,
|
||||
app_state.is_force_redraw,
|
||||
);
|
||||
let is_on_widget = widget_id == app_state.current_widget.widget_id;
|
||||
|
||||
|
@ -45,7 +45,7 @@ impl DiskTableWidget for Painter {
|
||||
&disk_widget_state.scroll_state.scroll_direction,
|
||||
&mut disk_widget_state.scroll_state.previous_scroll_position,
|
||||
disk_widget_state.scroll_state.current_scroll_position,
|
||||
app_state.is_resized,
|
||||
app_state.is_force_redraw,
|
||||
);
|
||||
let is_on_widget = app_state.current_widget.widget_id == widget_id;
|
||||
let disk_table_state = &mut disk_widget_state.scroll_state.table_state;
|
||||
|
@ -91,7 +91,7 @@ impl ProcessTableWidget for Painter {
|
||||
&proc_widget_state.scroll_state.scroll_direction,
|
||||
&mut proc_widget_state.scroll_state.previous_scroll_position,
|
||||
proc_widget_state.scroll_state.current_scroll_position,
|
||||
app_state.is_resized,
|
||||
app_state.is_force_redraw,
|
||||
);
|
||||
|
||||
// Sanity check
|
||||
@ -370,7 +370,7 @@ impl ProcessTableWidget for Painter {
|
||||
.search_state
|
||||
.cursor_bar,
|
||||
current_cursor_position,
|
||||
app_state.is_resized,
|
||||
app_state.is_force_redraw,
|
||||
);
|
||||
|
||||
let query = proc_widget_state.get_current_search_query().as_str();
|
||||
|
@ -46,7 +46,7 @@ impl TempTableWidget for Painter {
|
||||
&temp_widget_state.scroll_state.scroll_direction,
|
||||
&mut temp_widget_state.scroll_state.previous_scroll_position,
|
||||
temp_widget_state.scroll_state.current_scroll_position,
|
||||
app_state.is_resized,
|
||||
app_state.is_force_redraw,
|
||||
);
|
||||
let is_on_widget = widget_id == app_state.current_widget.widget_id;
|
||||
let temp_table_state = &mut temp_widget_state.scroll_state.table_state;
|
||||
|
@ -36,52 +36,76 @@ lazy_static! {
|
||||
}
|
||||
|
||||
// Help text
|
||||
pub const NUM_CATEGORIES: u16 = 6;
|
||||
|
||||
pub const HELP_CONTENTS_TEXT: [&str; 6] = [
|
||||
"Press the corresponding numbers to jump to the section, or scroll:\n",
|
||||
"1 - General bindings\n",
|
||||
"2 - CPU bindings\n",
|
||||
"3 - Process bindings\n",
|
||||
"4 - Process search bindings\n",
|
||||
"5 - Battery bindings",
|
||||
];
|
||||
|
||||
pub const GENERAL_HELP_TEXT: [&str; 18] = [
|
||||
"General Keybindings\n\n",
|
||||
"q, Ctrl-c Quit bottom\n",
|
||||
"Esc Close filters, dialog boxes, etc.\n",
|
||||
"Ctrl-r Reset all data\n",
|
||||
"f Freeze display\n",
|
||||
"Ctrl-Arrow Change your selected widget\n",
|
||||
"Shift-Arrow Change your selected widget\n",
|
||||
"H/J/K/L Change your selected widget up/down/left/right\n",
|
||||
"Up, k Move cursor up\n",
|
||||
"Down, j Move cursor down\n",
|
||||
"? Open the help screen\n",
|
||||
"gg Skip to the first entry of a list\n",
|
||||
"G Skip to the last entry of a list\n",
|
||||
"1 - General bindings\n",
|
||||
"q, Ctrl-c Quit\n",
|
||||
"Esc Close dialog windows, search, widgets, or exit maximized mode\n",
|
||||
"Ctrl-r Reset display and any collected data\n",
|
||||
"f Freeze/unfreeze updating with new data\n",
|
||||
"Ctrl-Arrow \n",
|
||||
"Shift-Arrow Move to a different widget\n",
|
||||
"H/J/K/L \n",
|
||||
"Up, k Scroll up\n",
|
||||
"Down, j Scroll down\n",
|
||||
"? Open help menu\n",
|
||||
"gg Jump to the first entry\n",
|
||||
"G Jump to the last entry\n",
|
||||
"Enter Maximize the currently selected widget\n",
|
||||
"/ Filter out graph lines (only CPU at the moment)\n",
|
||||
"+ Zoom in (decrease time range)\n",
|
||||
"- Zoom out (increase time range)\n",
|
||||
"+ Zoom in on chart (decrease time range)\n",
|
||||
"- Zoom out on chart (increase time range)\n",
|
||||
"= Reset zoom\n",
|
||||
"Mouse scroll Scroll through the tables or zoom in/out of charts by scrolling up/down",
|
||||
];
|
||||
|
||||
pub const CPU_HELP_TEXT: [&str; 4] = [
|
||||
"2 - CPU bindings\n",
|
||||
"/ Open filtering for showing certain CPU cores\n",
|
||||
"Space Toggle enabled/disabled cores\n",
|
||||
"Esc Exit filtering mode",
|
||||
];
|
||||
|
||||
pub const PROCESS_HELP_TEXT: [&str; 8] = [
|
||||
"Process Keybindings\n\n",
|
||||
"dd, Delete Kill the highlighted process\n",
|
||||
"c Sort by CPU usage\n",
|
||||
"3 - Process bindings\n",
|
||||
"dd Kill the selected process\n",
|
||||
"c Sort by memory usage, press again to reverse sorting order\n",
|
||||
"m Sort by memory usage\n",
|
||||
"p Sort by PID\n",
|
||||
"n Sort by process name\n",
|
||||
"Tab Group together processes with the same name\n",
|
||||
"Ctrl-f, / Open up the search widget\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",
|
||||
"Tab Group/un-group processes with the same name\n",
|
||||
"Ctrl-f, / Open process search widget",
|
||||
];
|
||||
|
||||
pub const SEARCH_HELP_TEXT: [&str; 13] = [
|
||||
"Search Keybindings\n\n",
|
||||
"Tab Toggle between searching for PID and name.\n",
|
||||
"Esc Close search widget\n",
|
||||
"Ctrl-a Skip to the start of search widget\n",
|
||||
"Ctrl-e Skip to the end of search widget\n",
|
||||
"4 - Process search bindings\n",
|
||||
"Tab Toggle between searching for PID and name\n",
|
||||
"Esc Close the search widget (retains the filter)\n",
|
||||
"Ctrl-a Skip to the start of the search query\n",
|
||||
"Ctrl-e Skip to the end of the search query\n",
|
||||
"Ctrl-u Clear the current search query\n",
|
||||
"Backspace Delete the character behind the cursor\n",
|
||||
"Delete Delete the character at the cursor\n",
|
||||
"Alt-c/F1 Toggle matching case\n",
|
||||
"Alt-w/F2 Toggle matching the entire word\n",
|
||||
"Alt-r/F3 Toggle using regex\n",
|
||||
"Left Move cursor left\n",
|
||||
"Right Move cursor right\n",
|
||||
"Alt-c/F1 Toggle whether to ignore case\n",
|
||||
"Alt-w/F2 Toggle whether to match the whole word\n",
|
||||
"Alt-r/F3 Toggle whether to use regex\n",
|
||||
"Right Move cursor right",
|
||||
];
|
||||
|
||||
pub const BATTERY_HELP_TEXT: [&str; 3] = [
|
||||
"5 - Battery bindings\n",
|
||||
"Left Go to previous battery\n",
|
||||
"Right Go to next battery",
|
||||
];
|
||||
|
||||
// Config and flags
|
||||
|
22
src/main.rs
22
src/main.rs
@ -114,17 +114,6 @@ fn main() -> error::Result<()> {
|
||||
painter.colours.generate_remaining_cpu_colours();
|
||||
painter.complete_painter_init();
|
||||
|
||||
// Set up up tui and crossterm
|
||||
let mut stdout_val = stdout();
|
||||
execute!(stdout_val, EnterAlternateScreen, EnableMouseCapture)?;
|
||||
enable_raw_mode()?;
|
||||
|
||||
let mut terminal = Terminal::new(CrosstermBackend::new(stdout_val))?;
|
||||
terminal.hide_cursor()?;
|
||||
|
||||
// Set panic hook
|
||||
panic::set_hook(Box::new(|info| panic_hook(info)));
|
||||
|
||||
// Set up input handling
|
||||
let (tx, rx) = mpsc::channel();
|
||||
create_input_thread(tx.clone());
|
||||
@ -151,6 +140,17 @@ fn main() -> error::Result<()> {
|
||||
app.used_widgets.clone(),
|
||||
);
|
||||
|
||||
// Set up up tui and crossterm
|
||||
let mut stdout_val = stdout();
|
||||
execute!(stdout_val, EnterAlternateScreen, EnableMouseCapture)?;
|
||||
enable_raw_mode()?;
|
||||
|
||||
let mut terminal = Terminal::new(CrosstermBackend::new(stdout_val))?;
|
||||
terminal.hide_cursor()?;
|
||||
|
||||
// Set panic hook
|
||||
panic::set_hook(Box::new(|info| panic_hook(info)));
|
||||
|
||||
let mut first_run = true;
|
||||
loop {
|
||||
if let Ok(recv) = rx.recv_timeout(Duration::from_millis(TICK_RATE_IN_MILLISECONDS)) {
|
||||
|
Loading…
Reference in New Issue
Block a user