summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClement Tsang <34804052+ClementTsang@users.noreply.github.com>2020-11-28 15:37:06 -0500
committerGitHub <noreply@github.com>2020-11-28 15:37:06 -0500
commit3260ff4663baed9b2186ee130306dc71e5d521fd (patch)
treedd0ce4b737bede4b643fa0d1680e0b9ff9852747
parenta9c1197075d7897cc3066657820eb321434eb0c0 (diff)
feature: Add scroll indicator to keep track of table position in widgets. (#333)
Adds the option to enable an "out of" indicator for scrollable table widgets (using --show_table_scroll_position).
-rw-r--r--.github/workflows/deployment.yml2
-rw-r--r--CHANGELOG.md10
-rw-r--r--README.md52
-rw-r--r--src/app.rs1
-rw-r--r--src/app/layout_manager.rs4
-rw-r--r--src/canvas/widgets/disk_table.rs56
-rw-r--r--src/canvas/widgets/process_table.rs62
-rw-r--r--src/canvas/widgets/temp_table.rs59
-rw-r--r--src/clap.rs8
-rw-r--r--src/options.rs15
10 files changed, 214 insertions, 55 deletions
diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml
index d6dbb4b1..2ea2bd25 100644
--- a/.github/workflows/deployment.yml
+++ b/.github/workflows/deployment.yml
@@ -203,6 +203,8 @@ jobs:
run: |
strip target/${{ matrix.triple.target }}/release/btm
+ # TODO: Strip ARM
+
- name: Bundle release and completion (Windows)
if: matrix.triple.os == 'windows-2019'
shell: bash
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cf257620..a5b0cebb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [0.6.0] - Unreleased
+
+## Features
+
+- [#333](https://github.com/ClementTsang/bottom/pull/333): Adds an "out of" indicator that can be enabled using `--show_table_scroll_position` to help keep track of scrolled position.
+
+## Changes
+
+## Bug Fixes
+
## [0.5.3] - 2020-11-26
## Bug Fixes
diff --git a/README.md b/README.md
index 3c3533cb..2b8ffe00 100644
--- a/README.md
+++ b/README.md
@@ -238,6 +238,7 @@ Use `btm --help` for more information.
--mem_as_value Defaults to showing process memory usage by value.
-r, --rate <MS> 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 <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.
@@ -528,31 +529,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 |
-| ------------------------ | ------------------------------------------------------------------------------------- |
-| `hide_avg_cpu` | Boolean |
-| `dot_marker` | Boolean |
-| `left_legend` | Boolean |
-| `current_usage` | Boolean |
-| `group_processes` | Boolean |
-| `case_sensitive` | Boolean |
-| `whole_word` | Boolean |
-| `regex` | Boolean |
-| `show_disabled_data` | Boolean |
-| `basic` | Boolean |
-| `hide_table_count` | Boolean |
-| `use_old_network_legend` | Boolean |
-| `battery` | Boolean |
-| `rate` | Unsigned Int (represents milliseconds) |
-| `default_time_value` | Unsigned Int (represents milliseconds) |
-| `time_delta` | Unsigned Int (represents milliseconds) |
-| `temperature_type` | String (one of ["k", "f", "c", "kelvin", "fahrenheit", "celsius"]) |
-| `default_widget_type` | String (one of ["cpu", "proc", "net", "temp", "mem", "disk"], same as layout options) |
-| `default_widget_count` | Unsigned Int (represents which `default_widget_type`) |
-| `disable_click` | Boolean |
-| `color` | String (one of ["default", "default-light", "gruvbox", "gruvbox-light"]) |
-| `mem_as_value` | Boolean |
-| `tree` | Boolean |
+| Field | Type |
+| ---------------------------- | ------------------------------------------------------------------------------------- |
+| `hide_avg_cpu` | Boolean |
+| `dot_marker` | Boolean |
+| `left_legend` | Boolean |
+| `current_usage` | Boolean |
+| `group_processes` | Boolean |
+| `case_sensitive` | Boolean |
+| `whole_word` | Boolean |
+| `regex` | Boolean |
+| `show_disabled_data` | Boolean |
+| `basic` | Boolean |
+| `hide_table_count` | Boolean |
+| `use_old_network_legend` | Boolean |
+| `battery` | Boolean |
+| `rate` | Unsigned Int (represents milliseconds) |
+| `default_time_value` | Unsigned Int (represents milliseconds) |
+| `time_delta` | Unsigned Int (represents milliseconds) |
+| `temperature_type` | String (one of ["k", "f", "c", "kelvin", "fahrenheit", "celsius"]) |
+| `default_widget_type` | String (one of ["cpu", "proc", "net", "temp", "mem", "disk"], same as layout options) |
+| `default_widget_count` | Unsigned Int (represents which `default_widget_type`) |
+| `disable_click` | Boolean |
+| `color` | String (one of ["default", "default-light", "gruvbox", "gruvbox-light"]) |
+| `mem_as_value` | Boolean |
+| `tree` | Boolean |
+| `show_table_scroll_position` | Boolean |
#### Theming
diff --git a/src/app.rs b/src/app.rs
index 1d2d3a50..d66ce89c 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -48,6 +48,7 @@ pub struct AppConfigFields {
pub table_gap: u16,
pub disable_click: bool,
pub no_write: bool,
+ pub show_table_scroll_position: bool,
}
/// For filtering out information
diff --git a/src/app/layout_manager.rs b/src/app/layout_manager.rs
index c856c42d..05e73822 100644
--- a/src/app/layout_manager.rs
+++ b/src/app/layout_manager.rs
@@ -868,11 +868,11 @@ pub struct BottomWidget {
#[builder(default = None)]
pub parent_reflector: Option<(WidgetDirection, u64)>,
- /// Top left corner when drawn, for mouse click detection
+ /// Top left corner when drawn, for mouse click detection. (x, y)
#[builder(default = None)]
pub top_left_corner: Option<(u16, u16)>,
- /// Bottom right corner when drawn, for mouse click detection
+ /// Bottom right corner when drawn, for mouse click detection. (x, y)
#[builder(default = None)]
pub bottom_right_corner: Option<(u16, u16)>,
}
diff --git a/src/canvas/widgets/disk_table.rs b/src/canvas/widgets/disk_table.rs
index 0fee787a..14cb4f60 100644
--- a/src/canvas/widgets/disk_table.rs
+++ b/src/canvas/widgets/disk_table.rs
@@ -42,7 +42,6 @@ impl DiskTableWidget for Painter {
) {
let recalculate_column_widths = app_state.should_get_widget_bounds();
if let Some(disk_widget_state) = app_state.disk_state.widget_states.get_mut(&widget_id) {
- let disk_data: &mut [Vec<String>] = &mut app_state.canvas_data.disk_data;
let table_gap = if draw_loc.height < TABLE_GAP_HEIGHT_LIMIT {
0
} else {
@@ -65,7 +64,7 @@ impl DiskTableWidget for Painter {
.current_scroll_position
.saturating_sub(start_position),
));
- let sliced_vec = &disk_data[start_position..];
+ let sliced_vec = &app_state.canvas_data.disk_data[start_position..];
// Calculate widths
let hard_widths = [None, None, Some(4), Some(6), Some(6), Some(7), Some(7)];
@@ -154,7 +153,6 @@ impl DiskTableWidget for Painter {
Row::Data(truncated_data)
});
- // TODO: This seems to be bugged? The selected text style gets "stuck"? I think this gets fixed with tui 0.10?
let (border_style, highlight_style) = if is_on_widget {
(
self.colours.highlighted_border_style,
@@ -164,22 +162,62 @@ impl DiskTableWidget for Painter {
(self.colours.border_style, self.colours.text_style)
};
+ let title_base = if app_state.app_config_fields.show_table_scroll_position {
+ let title_string = format!(
+ " Disk ({} of {}) ",
+ disk_widget_state
+ .scroll_state
+ .current_scroll_position
+ .saturating_add(1),
+ app_state.canvas_data.disk_data.len()
+ );
+
+ if title_string.len() <= draw_loc.width as usize {
+ title_string
+ } else {
+ " Disk ".to_string()
+ }
+ } else {
+ " Disk ".to_string()
+ };
+
let title = if app_state.is_expanded {
- const TITLE_BASE: &str = " Disk ── Esc to go back ";
+ const ESCAPE_ENDING: &str = "── Esc to go back ";
+
+ let (chosen_title_base, expanded_title_base) = {
+ let temp_title_base = format!("{}{}", title_base, ESCAPE_ENDING);
+
+ if temp_title_base.len() > draw_loc.width as usize {
+ (
+ " Disk ".to_string(),
+ format!("{}{}", " Disk ".to_string(), ESCAPE_ENDING),
+ )
+ } else {
+ (title_base, temp_title_base)
+ }
+ };
+
Spans::from(vec![
- Span::styled(" Disk ", self.colours.widget_title_style),
+ Span::styled(chosen_title_base, self.colours.widget_title_style),
Span::styled(
format!(
"─{}─ Esc to go back ",
- "─".repeat(usize::from(draw_loc.width).saturating_sub(
- UnicodeSegmentation::graphemes(TITLE_BASE, true).count() + 2
- ))
+ "─".repeat(
+ usize::from(draw_loc.width).saturating_sub(
+ UnicodeSegmentation::graphemes(
+ expanded_title_base.as_str(),
+ true
+ )
+ .count()
+ + 2
+ )
+ )
),
border_style,
),
])
} else {
- Spans::from(Span::styled(" Disk ", self.colours.widget_title_style))
+ Spans::from(Span::styled(title_base, self.colours.widget_title_style))
};
let disk_block = if draw_border {
diff --git a/src/canvas/widgets/process_table.rs b/src/canvas/widgets/process_table.rs
index e9e9ec40..338118b4 100644
--- a/src/canvas/widgets/process_table.rs
+++ b/src/canvas/widgets/process_table.rs
@@ -207,6 +207,33 @@ impl ProcessTableWidget for Painter {
(self.colours.border_style, self.colours.text_style)
};
+ let title_base = if app_state.app_config_fields.show_table_scroll_position {
+ if let Some(finalized_process_data) = app_state
+ .canvas_data
+ .finalized_process_data_map
+ .get(&widget_id)
+ {
+ let title = format!(
+ " Processes ({} of {}) ",
+ proc_widget_state
+ .scroll_state
+ .current_scroll_position
+ .saturating_add(1),
+ finalized_process_data.len()
+ );
+
+ if title.len() <= draw_loc.width as usize {
+ title
+ } else {
+ " Processes ".to_string()
+ }
+ } else {
+ " Processes ".to_string()
+ }
+ } else {
+ " Processes ".to_string()
+ };
+
let title = if app_state.is_expanded
&& !proc_widget_state
.process_search_state
@@ -214,21 +241,42 @@ impl ProcessTableWidget for Painter {
.is_enabled
&& !proc_widget_state.is_sort_open
{
- const TITLE_BASE: &str = " Processes ── Esc to go back ";
+ const ESCAPE_ENDING: &str = "── Esc to go back ";
+
+ let (chosen_title_base, expanded_title_base) = {
+ let temp_title_base = format!("{}{}", title_base, ESCAPE_ENDING);
+
+ if temp_title_base.len() > draw_loc.width as usize {
+ (
+ " Processes ".to_string(),
+ format!("{}{}", " Processes ".to_string(), ESCAPE_ENDING),
+ )
+ } else {
+ (title_base, temp_title_base)
+ }
+ };
+
Spans::from(vec![
- Span::styled(" Processes ", self.colours.widget_title_style),
+ Span::styled(chosen_title_base, self.colours.widget_title_style),
Span::styled(
format!(
"─{}─ Esc to go back ",
- "─".repeat(usize::from(draw_loc.width).saturating_sub(
- UnicodeSegmentation::graphemes(TITLE_BASE, true).count() + 2
- ))
+ "─".repeat(
+ usize::from(draw_loc.width).saturating_sub(
+ UnicodeSegmentation::graphemes(
+ expanded_title_base.as_str(),
+ true
+ )
+ .count()
+ + 2
+ )
+ )
),
border_style,
),
])
} else {
- Spans::from(Span::styled(" Processes ", self.colours.widget_title_style))
+ Spans::from(Span::styled(title_base, self.colours.widget_title_style))
};
let process_block = if draw_border {
@@ -281,6 +329,7 @@ impl ProcessTableWidget for Painter {
disabled,
)
});
+
let proc_table_state = &mut proc_widget_state.scroll_state.table_state;
proc_table_state.select(Some(
proc_widget_state
@@ -434,7 +483,6 @@ impl ProcessTableWidget for Painter {
}
});
- // FIXME: gotop's "x out of y" thing is really nice to help keep track of the scroll position. Add to everything?
f.render_stateful_widget(
Table::new(process_headers.iter(), process_rows)
.block(process_block)
diff --git a/src/canvas/widgets/temp_table.rs b/src/canvas/widgets/temp_table.rs
index 07b5d730..f4e6a9c1 100644
--- a/src/canvas/widgets/temp_table.rs
+++ b/src/canvas/widgets/temp_table.rs
@@ -42,8 +42,6 @@ impl TempTableWidget for Painter {
) {
let recalculate_column_widths = app_state.should_get_widget_bounds();
if let Some(temp_widget_state) = app_state.temp_state.widget_states.get_mut(&widget_id) {
- let temp_sensor_data: &mut [Vec<String>] = &mut app_state.canvas_data.temp_sensor_data;
-
let table_gap = if draw_loc.height < TABLE_GAP_HEIGHT_LIMIT {
0
} else {
@@ -66,7 +64,7 @@ impl TempTableWidget for Painter {
.current_scroll_position
.saturating_sub(start_position),
));
- let sliced_vec = &temp_sensor_data[start_position..];
+ let sliced_vec = &app_state.canvas_data.temp_sensor_data[start_position..];
// Calculate widths
let hard_widths = [None, None];
@@ -153,25 +151,62 @@ impl TempTableWidget for Painter {
(self.colours.border_style, self.colours.text_style)
};
+ let title_base = if app_state.app_config_fields.show_table_scroll_position {
+ let title_string = format!(
+ " Temperatures ({} of {}) ",
+ temp_widget_state
+ .scroll_state
+ .current_scroll_position
+ .saturating_add(1),
+ app_state.canvas_data.temp_sensor_data.len()
+ );
+
+ if title_string.len() <= draw_loc.width as usize {
+ title_string
+ } else {
+ " Temperatures ".to_string()
+ }
+ } else {
+ " Temperatures ".to_string()
+ };
+
let title = if app_state.is_expanded {
- const TITLE_BASE: &str = " Temperatures ── Esc to go back ";
+ const ESCAPE_ENDING: &str = "── Esc to go back ";
+
+ let (chosen_title_base, expanded_title_base) = {
+ let temp_title_base = format!("{}{}", title_base, ESCAPE_ENDING);
+
+ if temp_title_base.len() > draw_loc.width as usize {
+ (
+ " Temperatures ".to_string(),
+ format!("{}{}", " Temperatures ".to_string(), ESCAPE_ENDING),
+ )
+ } else {
+ (title_base, temp_title_base)
+ }
+ };
+
Spans::from(vec![
- Span::styled(" Temperatures ", self.colours.widget_title_style),
+ Span::styled(chosen_title_base, self.colours.widget_title_style),
Span::styled(
format!(
"─{}─ Esc to go back ",
- "─".repeat(usize::from(draw_loc.width).saturating_sub(
- UnicodeSegmentation::graphemes(TITLE_BASE, true).count() + 2
- ))
+ "─".repeat(
+ usize::from(draw_loc.width).saturating_sub(
+ UnicodeSegmentation::graphemes(
+ expanded_title_base.as_str(),
+ true
+ )
+ .count()
+ + 2
+ )
+ )
),
border_style,
),
])
} else {
- Spans::from(Span::styled(
- " Temperatures ",
- self.colours.widget_title_style,
- ))
+ Spans::from(Span::styled(title_base, self.colours.widget_title_style))
};
let temp_block = if draw_border {
diff --git a/src/clap.rs b/src/clap.rs
index f4b9222b..50939f5a 100644
--- a/src/clap.rs
+++ b/src/clap.rs
@@ -135,6 +135,13 @@ Hides the spacing between table headers and entries.\n\n",
"\
Completely hides the time scaling from being shown.\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")
+ .long_help(
+ "\
+ Shows the list scroll position tracker in the widget title for table widgets.\n\n",
+ );
let left_legend = Arg::with_name("left_legend")
.short("l")
.long("left_legend")
@@ -366,6 +373,7 @@ Defaults to showing the process widget in tree mode.\n\n",
.arg(hide_avg_cpu)
.arg(hide_table_gap)
.arg(hide_time)
+ .arg(show_table_scroll_position)
.arg(left_legend)
// .arg(no_write)
.arg(rate)
diff --git a/src/options.rs b/src/options.rs
index 53ccd223..cfdeca88 100644
--- a/src/options.rs
+++ b/src/options.rs
@@ -147,6 +147,9 @@ pub struct ConfigFlags {
#[builder(default, setter(strip_option))]
pub tree: Option<bool>,
+
+ #[builder(default, setter(strip_option))]
+ show_table_scroll_position: Option<bool>,
}
#[derive(Clone, Default, Debug, Deserialize, Serialize)]
@@ -388,6 +391,7 @@ pub fn build_app(
disable_click: get_disable_click(matches, config),
// no_write: get_no_write(matches, config),
no_write: false,
+ show_table_scroll_position: get_show_table_scroll_position(matches, config),
};
let used_widgets = UsedWidgets {
@@ -972,3 +976,14 @@ fn get_is_default_tree(matches: &clap::ArgMatches<'static>, config: &Config) ->
}
false
}
+
+fn get_show_table_scroll_position(matches: &clap::ArgMatches<'static>, config: &Config) -> bool {
+ if matches.is_present("show_table_scroll_position") {
+ return true;
+ } else if let Some(flags) = &config.flags {
+ if let Some(show_table_scroll_position) = flags.show_table_scroll_position {
+ return show_table_scroll_position;
+ }
+ }
+ false
+}