feature: split usage into usage percentage and value (#950)
Denotes both usage and usage percentage. This also redoes the calculation for percentage to be based on the sum of avail + used, rather than on total, as otherwise we get potentially confusing percentages.
This commit is contained in:
parent
d7e9fd6be0
commit
a56e7f6cc9
10
CHANGELOG.md
10
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/),
|
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).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [0.7.1] - ???
|
||||||
|
|
||||||
|
## Bug Fixes
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- [#950](https://github.com/ClementTsang/bottom/pull/950): Split usage into usage percentage and value.
|
||||||
|
|
||||||
## [0.7.0] - 2022-12-31
|
## [0.7.0] - 2022-12-31
|
||||||
|
|
||||||
## Bug Fixes
|
## Bug Fixes
|
||||||
|
|
|
@ -204,7 +204,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bottom"
|
name = "bottom"
|
||||||
version = "0.7.0"
|
version = "0.7.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"assert_cmd",
|
"assert_cmd",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "bottom"
|
name = "bottom"
|
||||||
version = "0.7.0"
|
version = "0.7.1"
|
||||||
authors = ["Clement Tsang <cjhtsang@uwaterloo.ca>"]
|
authors = ["Clement Tsang <cjhtsang@uwaterloo.ca>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
repository = "https://github.com/ClementTsang/bottom"
|
repository = "https://github.com/ClementTsang/bottom"
|
||||||
|
|
|
@ -138,7 +138,7 @@ cargo install bottom
|
||||||
|
|
||||||
### Arch Linux
|
### Arch Linux
|
||||||
|
|
||||||
There is an official package that can be installed with `pacman`:
|
There is an [official package](https://archlinux.org/packages/community/x86_64/bottom/) that can be installed with `pacman`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo pacman -Syu bottom
|
sudo pacman -Syu bottom
|
||||||
|
|
12
src/app.rs
12
src/app.rs
|
@ -379,9 +379,9 @@ impl App {
|
||||||
.get_mut(&self.current_widget.widget_id)
|
.get_mut(&self.current_widget.widget_id)
|
||||||
{
|
{
|
||||||
proc_widget_state.toggle_mem_percentage();
|
proc_widget_state.toggle_mem_percentage();
|
||||||
proc_widget_state.force_data_update();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1219,6 +1219,12 @@ impl App {
|
||||||
{
|
{
|
||||||
proc_widget_state.select_column(ProcWidget::PID_OR_COUNT);
|
proc_widget_state.select_column(ProcWidget::PID_OR_COUNT);
|
||||||
}
|
}
|
||||||
|
} else if let Some(disk) = self
|
||||||
|
.disk_state
|
||||||
|
.get_mut_widget_state(self.current_widget.widget_id)
|
||||||
|
{
|
||||||
|
disk.table.set_sort_index(5);
|
||||||
|
disk.force_data_update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'P' => {
|
'P' => {
|
||||||
|
@ -1302,7 +1308,7 @@ impl App {
|
||||||
.disk_state
|
.disk_state
|
||||||
.get_mut_widget_state(self.current_widget.widget_id)
|
.get_mut_widget_state(self.current_widget.widget_id)
|
||||||
{
|
{
|
||||||
disk.table.set_sort_index(5);
|
disk.table.set_sort_index(6);
|
||||||
disk.force_data_update();
|
disk.force_data_update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1311,7 +1317,7 @@ impl App {
|
||||||
.disk_state
|
.disk_state
|
||||||
.get_mut_widget_state(self.current_widget.widget_id)
|
.get_mut_widget_state(self.current_widget.widget_id)
|
||||||
{
|
{
|
||||||
disk.table.set_sort_index(6);
|
disk.table.set_sort_index(7);
|
||||||
disk.force_data_update();
|
disk.force_data_update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,12 +90,18 @@ impl ConvertedData {
|
||||||
.iter()
|
.iter()
|
||||||
.zip(&data.io_labels)
|
.zip(&data.io_labels)
|
||||||
.for_each(|(disk, (io_read, io_write))| {
|
.for_each(|(disk, (io_read, io_write))| {
|
||||||
|
let summed_total_bytes = match (disk.used_space, disk.free_space) {
|
||||||
|
(Some(used), Some(free)) => Some(used + free),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
self.disk_data.push(DiskWidgetData {
|
self.disk_data.push(DiskWidgetData {
|
||||||
name: KString::from_ref(&disk.name),
|
name: KString::from_ref(&disk.name),
|
||||||
mount_point: KString::from_ref(&disk.mount_point),
|
mount_point: KString::from_ref(&disk.mount_point),
|
||||||
free_bytes: disk.free_space,
|
free_bytes: disk.free_space,
|
||||||
used_bytes: disk.used_space,
|
used_bytes: disk.used_space,
|
||||||
total_bytes: disk.total_space,
|
total_bytes: disk.total_space,
|
||||||
|
summed_total_bytes,
|
||||||
io_read: io_read.into(),
|
io_read: io_read.into(),
|
||||||
io_write: io_write.into(),
|
io_write: io_write.into(),
|
||||||
});
|
});
|
||||||
|
|
|
@ -20,20 +20,12 @@ pub struct DiskWidgetData {
|
||||||
pub free_bytes: Option<u64>,
|
pub free_bytes: Option<u64>,
|
||||||
pub used_bytes: Option<u64>,
|
pub used_bytes: Option<u64>,
|
||||||
pub total_bytes: Option<u64>,
|
pub total_bytes: Option<u64>,
|
||||||
|
pub summed_total_bytes: Option<u64>,
|
||||||
pub io_read: KString,
|
pub io_read: KString,
|
||||||
pub io_write: KString,
|
pub io_write: KString,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DiskWidgetData {
|
impl DiskWidgetData {
|
||||||
pub fn free_space(&self) -> KString {
|
|
||||||
if let Some(free_bytes) = self.free_bytes {
|
|
||||||
let converted_free_space = get_decimal_bytes(free_bytes);
|
|
||||||
format!("{:.*}{}", 0, converted_free_space.0, converted_free_space.1).into()
|
|
||||||
} else {
|
|
||||||
"N/A".into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn total_space(&self) -> KString {
|
pub fn total_space(&self) -> KString {
|
||||||
if let Some(total_bytes) = self.total_bytes {
|
if let Some(total_bytes) = self.total_bytes {
|
||||||
let converted_total_space = get_decimal_bytes(total_bytes);
|
let converted_total_space = get_decimal_bytes(total_bytes);
|
||||||
|
@ -47,13 +39,57 @@ impl DiskWidgetData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn usage(&self) -> KString {
|
pub fn free_space(&self) -> KString {
|
||||||
if let (Some(used_bytes), Some(total_bytes)) = (self.used_bytes, self.total_bytes) {
|
if let Some(free_bytes) = self.free_bytes {
|
||||||
format!("{:.0}%", used_bytes as f64 / total_bytes as f64 * 100_f64).into()
|
let converted_free_space = get_decimal_bytes(free_bytes);
|
||||||
|
format!("{:.*}{}", 0, converted_free_space.0, converted_free_space.1).into()
|
||||||
} else {
|
} else {
|
||||||
"N/A".into()
|
"N/A".into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn used_space(&self) -> KString {
|
||||||
|
if let Some(used_bytes) = self.used_bytes {
|
||||||
|
let converted_free_space = get_decimal_bytes(used_bytes);
|
||||||
|
format!("{:.*}{}", 0, converted_free_space.0, converted_free_space.1).into()
|
||||||
|
} else {
|
||||||
|
"N/A".into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn free_percent(&self) -> Option<f64> {
|
||||||
|
if let (Some(free_bytes), Some(summed_total_bytes)) =
|
||||||
|
(self.free_bytes, self.summed_total_bytes)
|
||||||
|
{
|
||||||
|
Some(free_bytes as f64 / summed_total_bytes as f64 * 100_f64)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn free_percent_string(&self) -> KString {
|
||||||
|
match self.free_percent() {
|
||||||
|
Some(val) => format!("{:.1}%", val).into(),
|
||||||
|
None => "N/A".into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn used_percent(&self) -> Option<f64> {
|
||||||
|
if let (Some(used_bytes), Some(summed_total_bytes)) =
|
||||||
|
(self.used_bytes, self.summed_total_bytes)
|
||||||
|
{
|
||||||
|
Some(used_bytes as f64 / summed_total_bytes as f64 * 100_f64)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn used_percent_string(&self) -> KString {
|
||||||
|
match self.used_percent() {
|
||||||
|
Some(val) => format!("{:.1}%", val).into(),
|
||||||
|
None => "N/A".into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum DiskWidgetColumn {
|
pub enum DiskWidgetColumn {
|
||||||
|
@ -62,6 +98,8 @@ pub enum DiskWidgetColumn {
|
||||||
Used,
|
Used,
|
||||||
Free,
|
Free,
|
||||||
Total,
|
Total,
|
||||||
|
UsedPercent,
|
||||||
|
FreePercent,
|
||||||
IoRead,
|
IoRead,
|
||||||
IoWrite,
|
IoWrite,
|
||||||
}
|
}
|
||||||
|
@ -73,6 +111,8 @@ impl ColumnHeader for DiskWidgetColumn {
|
||||||
DiskWidgetColumn::Mount => "Mount(m)",
|
DiskWidgetColumn::Mount => "Mount(m)",
|
||||||
DiskWidgetColumn::Used => "Used(u)",
|
DiskWidgetColumn::Used => "Used(u)",
|
||||||
DiskWidgetColumn::Free => "Free(n)",
|
DiskWidgetColumn::Free => "Free(n)",
|
||||||
|
DiskWidgetColumn::UsedPercent => "Used%(p)",
|
||||||
|
DiskWidgetColumn::FreePercent => "Free%",
|
||||||
DiskWidgetColumn::Total => "Total(t)",
|
DiskWidgetColumn::Total => "Total(t)",
|
||||||
DiskWidgetColumn::IoRead => "R/s(r)",
|
DiskWidgetColumn::IoRead => "R/s(r)",
|
||||||
DiskWidgetColumn::IoWrite => "W/s(w)",
|
DiskWidgetColumn::IoWrite => "W/s(w)",
|
||||||
|
@ -86,8 +126,14 @@ impl DataToCell<DiskWidgetColumn> for DiskWidgetData {
|
||||||
let text = match column {
|
let text = match column {
|
||||||
DiskWidgetColumn::Disk => truncate_to_text(&self.name, calculated_width),
|
DiskWidgetColumn::Disk => truncate_to_text(&self.name, calculated_width),
|
||||||
DiskWidgetColumn::Mount => truncate_to_text(&self.mount_point, calculated_width),
|
DiskWidgetColumn::Mount => truncate_to_text(&self.mount_point, calculated_width),
|
||||||
DiskWidgetColumn::Used => truncate_to_text(&self.usage(), calculated_width),
|
DiskWidgetColumn::Used => truncate_to_text(&self.used_space(), calculated_width),
|
||||||
DiskWidgetColumn::Free => truncate_to_text(&self.free_space(), calculated_width),
|
DiskWidgetColumn::Free => truncate_to_text(&self.free_space(), calculated_width),
|
||||||
|
DiskWidgetColumn::UsedPercent => {
|
||||||
|
truncate_to_text(&self.used_percent_string(), calculated_width)
|
||||||
|
}
|
||||||
|
DiskWidgetColumn::FreePercent => {
|
||||||
|
truncate_to_text(&self.free_percent_string(), calculated_width)
|
||||||
|
}
|
||||||
DiskWidgetColumn::Total => truncate_to_text(&self.total_space(), calculated_width),
|
DiskWidgetColumn::Total => truncate_to_text(&self.total_space(), calculated_width),
|
||||||
DiskWidgetColumn::IoRead => truncate_to_text(&self.io_read, calculated_width),
|
DiskWidgetColumn::IoRead => truncate_to_text(&self.io_read, calculated_width),
|
||||||
DiskWidgetColumn::IoWrite => truncate_to_text(&self.io_write, calculated_width),
|
DiskWidgetColumn::IoWrite => truncate_to_text(&self.io_write, calculated_width),
|
||||||
|
@ -132,9 +178,19 @@ impl SortsRow for DiskWidgetColumn {
|
||||||
DiskWidgetColumn::Used => {
|
DiskWidgetColumn::Used => {
|
||||||
data.sort_by(|a, b| sort_partial_fn(descending)(&a.used_bytes, &b.used_bytes));
|
data.sort_by(|a, b| sort_partial_fn(descending)(&a.used_bytes, &b.used_bytes));
|
||||||
}
|
}
|
||||||
|
DiskWidgetColumn::UsedPercent => {
|
||||||
|
data.sort_by(|a, b| {
|
||||||
|
sort_partial_fn(descending)(&a.used_percent(), &b.used_percent())
|
||||||
|
});
|
||||||
|
}
|
||||||
DiskWidgetColumn::Free => {
|
DiskWidgetColumn::Free => {
|
||||||
data.sort_by(|a, b| sort_partial_fn(descending)(&a.free_bytes, &b.free_bytes));
|
data.sort_by(|a, b| sort_partial_fn(descending)(&a.free_bytes, &b.free_bytes));
|
||||||
}
|
}
|
||||||
|
DiskWidgetColumn::FreePercent => {
|
||||||
|
data.sort_by(|a, b| {
|
||||||
|
sort_partial_fn(descending)(&a.free_percent(), &b.free_percent())
|
||||||
|
});
|
||||||
|
}
|
||||||
DiskWidgetColumn::Total => {
|
DiskWidgetColumn::Total => {
|
||||||
data.sort_by(|a, b| sort_partial_fn(descending)(&a.total_bytes, &b.total_bytes));
|
data.sort_by(|a, b| sort_partial_fn(descending)(&a.total_bytes, &b.total_bytes));
|
||||||
}
|
}
|
||||||
|
@ -156,6 +212,7 @@ impl DiskTableWidget {
|
||||||
SortColumn::hard(DiskWidgetColumn::Used, 8).default_descending(),
|
SortColumn::hard(DiskWidgetColumn::Used, 8).default_descending(),
|
||||||
SortColumn::hard(DiskWidgetColumn::Free, 8).default_descending(),
|
SortColumn::hard(DiskWidgetColumn::Free, 8).default_descending(),
|
||||||
SortColumn::hard(DiskWidgetColumn::Total, 9).default_descending(),
|
SortColumn::hard(DiskWidgetColumn::Total, 9).default_descending(),
|
||||||
|
SortColumn::hard(DiskWidgetColumn::UsedPercent, 9).default_descending(),
|
||||||
SortColumn::hard(DiskWidgetColumn::IoRead, 10).default_descending(),
|
SortColumn::hard(DiskWidgetColumn::IoRead, 10).default_descending(),
|
||||||
SortColumn::hard(DiskWidgetColumn::IoWrite, 11).default_descending(),
|
SortColumn::hard(DiskWidgetColumn::IoWrite, 11).default_descending(),
|
||||||
];
|
];
|
||||||
|
|
Loading…
Reference in New Issue