Skip to content

Commit

Permalink
simplify to_cell to return a Cow
Browse files Browse the repository at this point in the history
  • Loading branch information
ClementTsang committed May 6, 2024
1 parent 6d012db commit 287e8e4
Show file tree
Hide file tree
Showing 10 changed files with 83 additions and 100 deletions.
4 changes: 2 additions & 2 deletions src/canvas/components/data_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ impl<DataType: DataToCell<H>, H: ColumnHeader, S: SortType, C: DataTableColumn<H

#[cfg(test)]
mod test {
use std::num::NonZeroU16;
use std::{borrow::Cow, num::NonZeroU16};

use super::*;

Expand All @@ -164,7 +164,7 @@ mod test {
impl DataToCell<&'static str> for TestType {
fn to_cell(
&self, _column: &&'static str, _calculated_width: NonZeroU16,
) -> Option<tui::text::Text<'_>> {
) -> Option<Cow<'static, str>> {
None
}

Expand Down
9 changes: 5 additions & 4 deletions src/canvas/components/data_table/data_type.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::num::NonZeroU16;
use std::{borrow::Cow, num::NonZeroU16};

use tui::{text::Text, widgets::Row};
use tui::widgets::Row;

use super::{ColumnHeader, DataTableColumn};
use crate::canvas::Painter;
Expand All @@ -9,8 +9,9 @@ pub trait DataToCell<H>
where
H: ColumnHeader,
{
/// Given data, a column, and its corresponding width, return what should be displayed in the [`DataTable`](super::DataTable).
fn to_cell(&self, column: &H, calculated_width: NonZeroU16) -> Option<Text<'_>>;
/// Given data, a column, and its corresponding width, return the string in the cell that will
/// be displayed in the [`DataTable`](super::DataTable).
fn to_cell(&self, column: &H, calculated_width: NonZeroU16) -> Option<Cow<'static, str>>;

/// Apply styling to the generated [`Row`] of cells.
///
Expand Down
5 changes: 4 additions & 1 deletion src/canvas/components/data_table/draw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use crate::{
app::layout_manager::BottomWidget,
canvas::Painter,
constants::{SIDE_BORDERS, TABLE_GAP_HEIGHT_LIMIT},
utils::strings::truncate_to_text,
};

pub enum SelectionState {
Expand Down Expand Up @@ -225,7 +226,9 @@ where
.iter()
.zip(&self.state.calculated_widths)
.filter_map(|(column, &width)| {
data_row.to_cell(column.inner(), width)
data_row
.to_cell(column.inner(), width)
.map(|content| truncate_to_text(&content, width.get()))
}),
);

Expand Down
6 changes: 3 additions & 3 deletions src/canvas/components/data_table/sortable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,8 +345,6 @@ where

#[cfg(test)]
mod test {
use tui::text::Text;

use super::*;

#[derive(Clone, PartialEq, Eq, Debug)]
Expand All @@ -361,7 +359,9 @@ mod test {
}

impl DataToCell<ColumnType> for TestType {
fn to_cell(&self, _column: &ColumnType, _calculated_width: NonZeroU16) -> Option<Text<'_>> {
fn to_cell(
&self, _column: &ColumnType, _calculated_width: NonZeroU16,
) -> Option<Cow<'static, str>> {
None
}

Expand Down
16 changes: 5 additions & 11 deletions src/utils/strings.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,20 @@
use std::num::NonZeroUsize;

use tui::{
style::Style,
text::{Line, Span, Text},
};
use tui::text::Text;
use unicode_segmentation::UnicodeSegmentation;
use unicode_width::UnicodeWidthStr;

/// Truncates text if it is too long, and adds an ellipsis at the end if needed.
///
/// TODO: Maybe cache results from this function for some cases? e.g. columns
#[inline]
pub fn truncate_to_text<'a, U: Into<usize>>(content: &str, width: U) -> Text<'a> {
Text {
lines: vec![Line::from(vec![Span::raw(truncate_str(content, width))])],
style: Style::default(),
alignment: None,
}
Text::raw(truncate_str(content, width))
}

/// Returns the width of a str `s`. This takes into account some things like
/// joiners when calculating width.
#[inline]
pub fn str_width(s: &str) -> usize {
UnicodeSegmentation::graphemes(s, true)
.map(|g| {
Expand Down Expand Up @@ -107,8 +102,7 @@ fn greedy_ascii_add(content: &str, width: NonZeroUsize) -> (String, AsciiIterati
/// we will use this function for fine... hopefully.
///
/// TODO: Maybe fuzz this function?
/// TODO: Maybe release this as a lib? Testing against Fish's script [here](https://github.com/ridiculousfish/widecharwidth)
/// might be useful.
/// TODO: Maybe release this as a lib? Testing against Fish's script [here](https://github.com/ridiculousfish/widecharwidth) might be useful.
#[inline]
fn truncate_str<U: Into<usize>>(content: &str, width: U) -> String {
let width = width.into();
Expand Down
21 changes: 8 additions & 13 deletions src/widgets/cpu_graph.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{borrow::Cow, num::NonZeroU16, time::Instant};

use concat_string::concat_string;
use tui::{style::Style, text::Text, widgets::Row};
use tui::{style::Style, widgets::Row};

use crate::{
app::AppConfigFields,
Expand All @@ -16,7 +16,6 @@ use crate::{
data_collection::cpu::CpuDataType,
data_conversion::CpuWidgetData,
options::config::cpu::CpuDefault,
utils::strings::truncate_to_text,
};

#[derive(Default)]
Expand Down Expand Up @@ -81,7 +80,9 @@ impl CpuWidgetTableData {
}

impl DataToCell<CpuWidgetColumn> for CpuWidgetTableData {
fn to_cell(&self, column: &CpuWidgetColumn, calculated_width: NonZeroU16) -> Option<Text<'_>> {
fn to_cell(
&self, column: &CpuWidgetColumn, calculated_width: NonZeroU16,
) -> Option<Cow<'static, str>> {
const CPU_TRUNCATE_BREAKPOINT: u16 = 5;

let calculated_width = calculated_width.get();
Expand All @@ -107,25 +108,19 @@ impl DataToCell<CpuWidgetColumn> for CpuWidgetTableData {
} else {
match column {
CpuWidgetColumn::CPU => match data_type {
CpuDataType::Avg => Some(truncate_to_text("AVG", calculated_width)),
CpuDataType::Avg => Some("AVG".into()),
CpuDataType::Cpu(index) => {
let index_str = index.to_string();
let text = if calculated_width < CPU_TRUNCATE_BREAKPOINT {
truncate_to_text(&index_str, calculated_width)
index_str.into()
} else {
truncate_to_text(
&concat_string!("CPU", index_str),
calculated_width,
)
concat_string!("CPU", index_str).into()
};

Some(text)
}
},
CpuWidgetColumn::Use => Some(truncate_to_text(
&format!("{:.0}%", last_entry.round()),
calculated_width,
)),
CpuWidgetColumn::Use => Some(format!("{:.0}%", last_entry.round()).into()),
}
}
}
Expand Down
33 changes: 13 additions & 20 deletions src/widgets/disk_table.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use std::{borrow::Cow, cmp::max, num::NonZeroU16};

use tui::text::Text;

use crate::{
app::AppConfigFields,
canvas::{
Expand All @@ -11,9 +9,7 @@ use crate::{
},
styling::CanvasStyling,
},
utils::{
data_prefixes::get_decimal_bytes, general::sort_partial_fn, strings::truncate_to_text,
},
utils::{data_prefixes::get_decimal_bytes, general::sort_partial_fn},
};

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -129,22 +125,19 @@ impl ColumnHeader for DiskWidgetColumn {
}

impl DataToCell<DiskWidgetColumn> for DiskWidgetData {
fn to_cell(&self, column: &DiskWidgetColumn, calculated_width: NonZeroU16) -> Option<Text<'_>> {
let calculated_width = calculated_width.get();
fn to_cell(
&self, column: &DiskWidgetColumn, _calculated_width: NonZeroU16,
) -> Option<Cow<'static, str>> {
let text = match column {
DiskWidgetColumn::Disk => truncate_to_text(&self.name, calculated_width),
DiskWidgetColumn::Mount => truncate_to_text(&self.mount_point, calculated_width),
DiskWidgetColumn::Used => truncate_to_text(&self.used_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::IoRead => truncate_to_text(&self.io_read, calculated_width),
DiskWidgetColumn::IoWrite => truncate_to_text(&self.io_write, calculated_width),
DiskWidgetColumn::Disk => self.name.clone(),
DiskWidgetColumn::Mount => self.mount_point.clone(),
DiskWidgetColumn::Used => self.used_space(),
DiskWidgetColumn::Free => self.free_space(),
DiskWidgetColumn::UsedPercent => self.used_percent_string(),
DiskWidgetColumn::FreePercent => self.free_percent_string(),
DiskWidgetColumn::Total => self.total_space(),
DiskWidgetColumn::IoRead => self.io_read.clone(),
DiskWidgetColumn::IoWrite => self.io_write.clone(),
};

Some(text)
Expand Down
59 changes: 28 additions & 31 deletions src/widgets/process_table/proc_widget_data.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use std::{
borrow::Cow,
cmp::{max, Ordering},
fmt::Display,
num::NonZeroU16,
time::Duration,
};

use concat_string::concat_string;
use tui::{text::Text, widgets::Row};
use tui::widgets::Row;

use super::proc_widget_column::ProcColumn;
use crate::{
Expand All @@ -16,7 +17,6 @@ use crate::{
},
data_collection::processes::ProcessHarvest,
data_conversion::{binary_byte_string, dec_bytes_per_second_string, dec_bytes_string},
utils::strings::truncate_to_text,
Pid,
};

Expand Down Expand Up @@ -301,40 +301,37 @@ impl ProcWidgetData {
}

impl DataToCell<ProcColumn> for ProcWidgetData {
fn to_cell(&self, column: &ProcColumn, calculated_width: NonZeroU16) -> Option<Text<'_>> {
fn to_cell(
&self, column: &ProcColumn, calculated_width: NonZeroU16,
) -> Option<Cow<'static, str>> {
let calculated_width = calculated_width.get();

// TODO: Optimize the string allocations here...
// TODO: Also maybe just pull in the to_string call but add a variable for the differences.
Some(truncate_to_text(
&match column {
ProcColumn::CpuPercent => {
format!("{:.1}%", self.cpu_usage_percent)
Some(match column {
ProcColumn::CpuPercent => format!("{:.1}%", self.cpu_usage_percent).into(),
ProcColumn::MemoryVal | ProcColumn::MemoryPercent => self.mem_usage.to_string().into(),
ProcColumn::Pid => self.pid.to_string().into(),
ProcColumn::Count => self.num_similar.to_string().into(),
ProcColumn::Name | ProcColumn::Command => self.id.to_prefixed_string().into(),
ProcColumn::ReadPerSecond => dec_bytes_per_second_string(self.rps).into(),
ProcColumn::WritePerSecond => dec_bytes_per_second_string(self.wps).into(),
ProcColumn::TotalRead => dec_bytes_string(self.total_read).into(),
ProcColumn::TotalWrite => dec_bytes_string(self.total_write).into(),
ProcColumn::State => {
if calculated_width < 8 {
self.process_char.to_string().into()
} else {
self.process_state.clone().into()
}
ProcColumn::MemoryVal | ProcColumn::MemoryPercent => self.mem_usage.to_string(),
ProcColumn::Pid => self.pid.to_string(),
ProcColumn::Count => self.num_similar.to_string(),
ProcColumn::Name | ProcColumn::Command => self.id.to_prefixed_string(),
ProcColumn::ReadPerSecond => dec_bytes_per_second_string(self.rps),
ProcColumn::WritePerSecond => dec_bytes_per_second_string(self.wps),
ProcColumn::TotalRead => dec_bytes_string(self.total_read),
ProcColumn::TotalWrite => dec_bytes_string(self.total_write),
ProcColumn::State => {
if calculated_width < 8 {
self.process_char.to_string()
} else {
self.process_state.clone()
}
}
ProcColumn::User => self.user.clone(),
ProcColumn::Time => format_time(self.time),
#[cfg(feature = "gpu")]
ProcColumn::GpuMem | ProcColumn::GpuMemPercent => self.gpu_mem_usage.to_string(),
#[cfg(feature = "gpu")]
ProcColumn::GpuUtilPercent => format!("{:.1}%", self.gpu_usage),
},
calculated_width,
))
}
ProcColumn::User => self.user.clone().into(),
ProcColumn::Time => format_time(self.time).into(),
#[cfg(feature = "gpu")]
ProcColumn::GpuMem | ProcColumn::GpuMemPercent => self.gpu_mem_usage.to_string().into(),
#[cfg(feature = "gpu")]
ProcColumn::GpuUtilPercent => format!("{:.1}%", self.gpu_usage).into(),
})
}

#[inline(always)]
Expand Down
19 changes: 9 additions & 10 deletions src/widgets/process_table/sort_table.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
use std::{borrow::Cow, num::NonZeroU16};

use tui::text::Text;

use crate::{
canvas::components::data_table::{ColumnHeader, DataTableColumn, DataToCell},
utils::strings::truncate_to_text,
};
use crate::canvas::components::data_table::{ColumnHeader, DataTableColumn, DataToCell};

pub struct SortTableColumn;

Expand All @@ -16,8 +11,10 @@ impl ColumnHeader for SortTableColumn {
}

impl DataToCell<SortTableColumn> for &'static str {
fn to_cell(&self, _column: &SortTableColumn, calculated_width: NonZeroU16) -> Option<Text<'_>> {
Some(truncate_to_text(self, calculated_width.get()))
fn to_cell(
&self, _column: &SortTableColumn, _calculated_width: NonZeroU16,
) -> Option<Cow<'static, str>> {
Some(Cow::Borrowed(self))
}

fn column_widths<C: DataTableColumn<SortTableColumn>>(data: &[Self], _columns: &[C]) -> Vec<u16>
Expand All @@ -29,8 +26,10 @@ impl DataToCell<SortTableColumn> for &'static str {
}

impl DataToCell<SortTableColumn> for Cow<'static, str> {
fn to_cell(&self, _column: &SortTableColumn, calculated_width: NonZeroU16) -> Option<Text<'_>> {
Some(truncate_to_text(self, calculated_width.get()))
fn to_cell(
&self, _column: &SortTableColumn, _calculated_width: NonZeroU16,
) -> Option<Cow<'static, str>> {
Some(self.clone())
}

fn column_widths<C: DataTableColumn<SortTableColumn>>(data: &[Self], _columns: &[C]) -> Vec<u16>
Expand Down
11 changes: 6 additions & 5 deletions src/widgets/temperature_table.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::{borrow::Cow, cmp::max, num::NonZeroU16};

use concat_string::concat_string;
use tui::text::Text;

use crate::{
app::AppConfigFields,
Expand All @@ -13,7 +12,7 @@ use crate::{
styling::CanvasStyling,
},
data_collection::temperature::TemperatureType,
utils::{general::sort_partial_fn, strings::truncate_to_text},
utils::general::sort_partial_fn,
};

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -54,10 +53,12 @@ impl TempWidgetData {
}

impl DataToCell<TempWidgetColumn> for TempWidgetData {
fn to_cell(&self, column: &TempWidgetColumn, calculated_width: NonZeroU16) -> Option<Text<'_>> {
fn to_cell(
&self, column: &TempWidgetColumn, _calculated_width: NonZeroU16,
) -> Option<Cow<'static, str>> {
Some(match column {
TempWidgetColumn::Sensor => truncate_to_text(&self.sensor, calculated_width.get()),
TempWidgetColumn::Temp => truncate_to_text(&self.temperature(), calculated_width.get()),
TempWidgetColumn::Sensor => self.sensor.clone(),
TempWidgetColumn::Temp => self.temperature(),
})
}

Expand Down

0 comments on commit 287e8e4

Please sign in to comment.