deps: Update dependencies, drop MSRV

Update dependencies to most recent versions if applicable. Refactor to deal with breaking changes. Drop MSRV due to dependency issues, just support stable and later.
This commit is contained in:
Clement Tsang 2020-08-11 17:22:39 -07:00 committed by GitHub
parent 17552c50cf
commit d0cc6078df
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 408 additions and 376 deletions

View file

@ -1,7 +1,5 @@
language: rust language: rust
rust: rust:
# MSRV; though I only want to test if it builds.
- 1.40.0
- stable - stable
- beta - beta
os: os:
@ -13,8 +11,6 @@ jobs:
exclude: exclude:
- if: tag IS present - if: tag IS present
rust: beta rust: beta
- if: tag IS present
rust: 1.40.0
branches: branches:
only: only:
- master - master
@ -34,15 +30,9 @@ before_script:
- rustup target add $TARGET - rustup target add $TARGET
- rustup component add clippy - rustup component add clippy
script: script:
- | - cargo clippy -- -D clippy::all
if [[ $TRAVIS_RUST_VERSION != "1.40.0" ]]; then
cargo clippy -- -D clippy::all
fi
- cargo build --verbose --target $TARGET - cargo build --verbose --target $TARGET
- | - cargo test --verbose --target $TARGET
if [[ $TRAVIS_RUST_VERSION != "1.40.0" ]]; then
cargo test --verbose --target $TARGET;
fi
- cargo install --path . --target $TARGET --locked --force - cargo install --path . --target $TARGET --locked --force
before_cache: before_cache:

View file

@ -13,6 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [179](https://github.com/ClementTsang/bottom/pull/179): Show full command/process path as an option. - [179](https://github.com/ClementTsang/bottom/pull/179): Show full command/process path as an option.
### Changes
- Changed to just support stable (and newer) Rust, due to library incompatibilities.
## [0.4.5] - 2020-07-08 ## [0.4.5] - 2020-07-08
- No changes here, just an uptick for Crates.io using the wrong Cargo.lock. - No changes here, just an uptick for Crates.io using the wrong Cargo.lock.

View file

@ -36,7 +36,7 @@ For reports/suggestions that don't fit the definition of a feature or bug, try t
If you want to help contribute by submitting a PR, by all means, I'm open! In regards to the development process: If you want to help contribute by submitting a PR, by all means, I'm open! In regards to the development process:
- I develop primarily using _stable_ Rust. That is, whatever is the most up-to-date stable version you can get via running - I develop primarily using _stable_ Rust. That is, whatever is the most up-to-date stable version you can get via running
`rustup update stable`. However, as of writing, I do support a MSRV of 1.40.0. `rustup update stable`.
- Note that `cargo test` will fail on anything lower than 1.43.0 due to it using a then-introduced env variable. - Note that `cargo test` will fail on anything lower than 1.43.0 due to it using a then-introduced env variable.

39
Cargo.lock generated
View file

@ -135,6 +135,7 @@ dependencies = [
"assert_cmd", "assert_cmd",
"backtrace", "backtrace",
"battery", "battery",
"cargo-husky",
"chrono", "chrono",
"clap", "clap",
"crossterm", "crossterm",
@ -157,6 +158,12 @@ dependencies = [
"winapi 0.3.8", "winapi 0.3.8",
] ]
[[package]]
name = "cargo-husky"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b02b629252fe8ef6460461409564e2c21d0c8e77e0944f3d189ff06c4e932ad"
[[package]] [[package]]
name = "cassowary" name = "cassowary"
version = "0.3.0" version = "0.3.0"
@ -177,9 +184,9 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]] [[package]]
name = "chrono" name = "chrono"
version = "0.4.11" version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" checksum = "c74d84029116787153e02106bf53e66828452a4b325cc8652b788b5967c0a0b6"
dependencies = [ dependencies = [
"num-integer", "num-integer",
"num-traits", "num-traits",
@ -188,9 +195,9 @@ dependencies = [
[[package]] [[package]]
name = "clap" name = "clap"
version = "2.33.1" version = "2.33.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" checksum = "10040cdf04294b565d9e0319955430099ec3813a64c952b86a41200ad714ae48"
dependencies = [ dependencies = [
"ansi_term", "ansi_term",
"atty", "atty",
@ -348,21 +355,19 @@ checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
[[package]] [[package]]
name = "dirs" name = "dirs"
version = "2.0.2" version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" checksum = "142995ed02755914747cc6ca76fc7e4583cd18578746716d0508ea6ed558b9ff"
dependencies = [ dependencies = [
"cfg-if",
"dirs-sys", "dirs-sys",
] ]
[[package]] [[package]]
name = "dirs-sys" name = "dirs-sys"
version = "0.3.4" version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a"
dependencies = [ dependencies = [
"cfg-if",
"libc", "libc",
"redox_users", "redox_users",
"winapi 0.3.8", "winapi 0.3.8",
@ -1273,9 +1278,9 @@ dependencies = [
[[package]] [[package]]
name = "sysinfo" name = "sysinfo"
version = "0.14.2" version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70bbf8e10fc10b83e71bc19f4374ce17209d45c7c4c99b5067ac554aba3bfd08" checksum = "f597c00e6548b9ddd54c11b8e8534fc11223f28509d57e021f01797b50ca5ca1"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"doc-comment", "doc-comment",
@ -1340,24 +1345,22 @@ checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41"
[[package]] [[package]]
name = "tui" name = "tui"
version = "0.9.5" version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9533d39bef0ae8f510e8a99d78702e68d1bbf0b98a78ec9740509d287010ae1e" checksum = "a977b0bb2e2033a6fef950f218f13622c3c34e59754b704ce3492dedab1dfe95"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"cassowary", "cassowary",
"crossterm", "crossterm",
"either",
"itertools",
"unicode-segmentation", "unicode-segmentation",
"unicode-width", "unicode-width",
] ]
[[package]] [[package]]
name = "typed-builder" name = "typed-builder"
version = "0.6.0" version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85fc4459191c621a53ef6c6ca5642e6e0e5ccc61f3e5b8ad6b6ab5317f0200fb" checksum = "d942c3f63d40f62b3fece2ab34a5bfc0d427ef148010fa732f5d56da0ac6d6ec"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",

View file

@ -23,22 +23,22 @@ codegen-units = 1
[dependencies] [dependencies]
battery = "0.7.5" battery = "0.7.5"
crossterm = "0.17" crossterm = "0.17"
chrono = "0.4.11" chrono = "0.4.13"
clap = "2.33.1" clap = "2.33.2"
dirs = "2.0.2" dirs = "3.0.1"
futures = "0.3.5" futures = "0.3.5"
heim = "0.0.10" heim = "0.0.10"
itertools = "0.9.0" itertools = "0.9.0"
regex = "1.3" regex = "1.3"
sysinfo = "0.14.2" sysinfo = "0.15.0"
toml = "0.5.6" toml = "0.5.6"
typed-builder = "0.6.0" typed-builder = "0.7.0"
lazy_static = "1.4.0" lazy_static = "1.4.0"
backtrace = "0.3" backtrace = "0.3"
serde = {version = "1.0", features = ["derive"] } serde = {version = "1.0", features = ["derive"] }
unicode-segmentation = "1.6.0" unicode-segmentation = "1.6.0"
unicode-width = "0.1.7" unicode-width = "0.1.7"
tui = {version = "0.9", features = ["crossterm"], default-features = false } tui = {version = "0.10.0", features = ["crossterm"], default-features = false }
# For debugging only... # For debugging only...
fern = "0.6.0" fern = "0.6.0"
@ -50,6 +50,7 @@ winapi = "0.3.8"
[dev-dependencies] [dev-dependencies]
assert_cmd = "1.0" assert_cmd = "1.0"
predicates = "1" predicates = "1"
cargo-husky = "1"
[package.metadata.deb] [package.metadata.deb]
section = "utils" section = "utils"

View file

@ -13,7 +13,7 @@ A cross-platform graphical process/system monitor with a customizable interface
## Table of Contents ## Table of Contents
- [Installation](#installation) - [Installation](#installation)
- [Manual](#manual) - [Manually](#manually)
- [Cargo](#cargo) - [Cargo](#cargo)
- [AUR](#aur) - [AUR](#aur)
- [Debian (and Debian-based)](#debian) - [Debian (and Debian-based)](#debian)
@ -59,9 +59,9 @@ Note that bottom is:
As such, support beyond that is not guaranteed. As such, support beyond that is not guaranteed.
### Manual ### [Manually]
There are a few ways to go about doing this. Note that the MSRV is 1.40.0. For example: There are a few ways to go about doing this manually. If you do so, please build using the current stable release of Rust. For example:
```bash ```bash
# If required, update Rust on the stable channel # If required, update Rust on the stable channel
@ -84,6 +84,9 @@ cargo install --path .
### Cargo ### Cargo
```bash ```bash
# If required, update Rust on the stable channel
rustup update stable
cargo install bottom cargo install bottom
# OR, --locked may be required due to how cargo install works # OR, --locked may be required due to how cargo install works

View file

@ -4,7 +4,7 @@ use std::collections::HashMap;
use tui::{ use tui::{
backend::Backend, backend::Backend,
layout::{Constraint, Direction, Layout, Rect}, layout::{Constraint, Direction, Layout, Rect},
widgets::Text, text::{Span, Spans},
Frame, Terminal, Frame, Terminal,
}; };
@ -55,7 +55,7 @@ pub struct Painter {
pub colours: CanvasColours, pub colours: CanvasColours,
height: u16, height: u16,
width: u16, width: u16,
styled_help_text: Vec<Text<'static>>, styled_help_text: Vec<Spans<'static>>,
is_mac_os: bool, is_mac_os: bool,
row_constraints: Vec<Constraint>, row_constraints: Vec<Constraint>,
col_constraints: Vec<Vec<Constraint>>, col_constraints: Vec<Vec<Constraint>>,
@ -139,14 +139,14 @@ impl Painter {
colours: CanvasColours::default(), colours: CanvasColours::default(),
height: 0, height: 0,
width: 0, width: 0,
styled_help_text: Vec::new(), styled_help_text: Vec::default(),
is_mac_os: false, is_mac_os: false,
row_constraints, row_constraints,
col_constraints, col_constraints,
col_row_constraints, col_row_constraints,
layout_constraints, layout_constraints,
widget_layout, widget_layout,
derived_widget_draw_locs: Vec::new(), derived_widget_draw_locs: Vec::default(),
table_height_offset: 4 + table_gap, table_height_offset: 4 + table_gap,
} }
} }
@ -155,34 +155,35 @@ impl Painter {
/// This is to set some remaining styles and text. /// This is to set some remaining styles and text.
pub fn complete_painter_init(&mut self) { pub fn complete_painter_init(&mut self) {
self.is_mac_os = cfg!(target_os = "macos"); self.is_mac_os = cfg!(target_os = "macos");
let mut styled_help_spans = Vec::new();
// Init help text: // Init help text:
(*HELP_TEXT).iter().enumerate().for_each(|(itx, section)| { (*HELP_TEXT).iter().enumerate().for_each(|(itx, section)| {
if itx == 0 { if itx == 0 {
self.styled_help_text.extend( styled_help_spans.extend(
section section
.iter() .iter()
.map(|&text| Text::Styled(text.into(), self.colours.text_style)) .map(|&text| Span::styled(text, self.colours.text_style))
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
); );
} else { } else {
// Not required check but it runs only a few times... so whatever ig, prevents me from // Not required check but it runs only a few times... so whatever ig, prevents me from
// being dumb and leaving a help text section only one line long. // being dumb and leaving a help text section only one line long.
if section.len() > 1 { if section.len() > 1 {
self.styled_help_text.push(Text::Raw("\n\n".into())); styled_help_spans.push(Span::from("\n\n"));
self.styled_help_text.push(Text::Styled( styled_help_spans
section[0].into(), .push(Span::styled(section[0], self.colours.table_header_style));
self.colours.table_header_style, styled_help_spans.extend(
));
self.styled_help_text.extend(
section[1..] section[1..]
.iter() .iter()
.map(|&text| Text::Styled(text.into(), self.colours.text_style)) .map(|&text| Span::styled(text, self.colours.text_style))
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
); );
} }
} }
}); });
self.styled_help_text = styled_help_spans.into_iter().map(Spans::from).collect();
} }
pub fn draw_data<B: Backend>( pub fn draw_data<B: Backend>(

View file

@ -85,7 +85,7 @@ impl CanvasColours {
} }
pub fn set_table_header_colour(&mut self, colour: &str) -> error::Result<()> { pub fn set_table_header_colour(&mut self, colour: &str) -> error::Result<()> {
self.table_header_style = get_style_from_config(colour)?.modifier(Modifier::BOLD); self.table_header_style = get_style_from_config(colour)?.add_modifier(Modifier::BOLD);
Ok(()) Ok(())
} }

View file

@ -2,7 +2,8 @@ use tui::{
backend::Backend, backend::Backend,
layout::{Alignment, Rect}, layout::{Alignment, Rect},
terminal::Frame, terminal::Frame,
widgets::{Block, Borders, Paragraph, Text}, text::{Span, Spans, Text},
widgets::{Block, Borders, Paragraph, Wrap},
}; };
use crate::{app::App, canvas::Painter}; use crate::{app::App, canvas::Painter};
@ -24,60 +25,67 @@ impl KillDialog for Painter {
) -> bool { ) -> bool {
if let Some(to_kill_processes) = app_state.get_to_delete_processes() { if let Some(to_kill_processes) = app_state.get_to_delete_processes() {
if let Some(first_pid) = to_kill_processes.1.first() { if let Some(first_pid) = to_kill_processes.1.first() {
let dd_text = vec![ let dd_text = Text::from(vec![
Spans::from(vec![]),
Spans::from(vec![
if app_state.is_grouped(app_state.current_widget.widget_id) { if app_state.is_grouped(app_state.current_widget.widget_id) {
if to_kill_processes.1.len() != 1 { if to_kill_processes.1.len() != 1 {
Text::raw(format!( Span::from(format!(
"\nKill {} processes with the name \"{}\"?", "\nKill {} processes with the name \"{}\"?",
to_kill_processes.1.len(), to_kill_processes.1.len(),
to_kill_processes.0 to_kill_processes.0
)) ))
} else { } else {
Text::raw(format!( Span::from(format!(
"\nKill 1 process with the name \"{}\"?", "\nKill 1 process with the name \"{}\"?",
to_kill_processes.0 to_kill_processes.0
)) ))
} }
} else { } else {
Text::raw(format!( Span::from(format!(
"\nKill process \"{}\" with PID {}?", "\nKill process \"{}\" with PID {}?",
to_kill_processes.0, first_pid to_kill_processes.0, first_pid
)) ))
}, },
Text::raw("\n\n"), ]),
Spans::from(vec![]),
Spans::from(vec![
if app_state.delete_dialog_state.is_on_yes { if app_state.delete_dialog_state.is_on_yes {
Text::styled("Yes", self.colours.currently_selected_text_style) Span::styled("Yes", self.colours.currently_selected_text_style)
} else { } else {
Text::raw("Yes") Span::from("Yes")
}, },
Text::raw(" "), Span::from(" "),
if app_state.delete_dialog_state.is_on_yes { if app_state.delete_dialog_state.is_on_yes {
Text::raw("No") Span::from("No")
} else { } else {
Text::styled("No", self.colours.currently_selected_text_style) Span::styled("No", self.colours.currently_selected_text_style)
}, },
]; ]),
]);
let dd_title = format!( let dd_title = Span::styled(
format!(
" Confirm Kill Process ─{}─ Esc to close ", " Confirm Kill Process ─{}─ Esc to close ",
"".repeat( "".repeat(
usize::from(draw_loc.width).saturating_sub(DD_BASE.chars().count() + 2) usize::from(draw_loc.width).saturating_sub(DD_BASE.chars().count() + 2)
) )
),
self.colours.border_style,
); );
f.render_widget( f.render_widget(
Paragraph::new(dd_text.iter()) Paragraph::new(dd_text)
.block( .block(
Block::default() Block::default()
.title(&dd_title) .title(dd_title)
.title_style(self.colours.border_style)
.style(self.colours.border_style) .style(self.colours.border_style)
.borders(Borders::ALL) .borders(Borders::ALL)
.border_style(self.colours.border_style), .border_style(self.colours.border_style),
) )
.style(self.colours.text_style) .style(self.colours.text_style)
.alignment(Alignment::Center) .alignment(Alignment::Center)
.wrap(true), .wrap(Wrap { trim: true }),
draw_loc, draw_loc,
); );
@ -92,31 +100,33 @@ impl KillDialog for Painter {
} }
fn draw_dd_error_dialog<B: Backend>(&self, f: &mut Frame<'_, B>, dd_err: &str, draw_loc: Rect) { fn draw_dd_error_dialog<B: Backend>(&self, f: &mut Frame<'_, B>, dd_err: &str, draw_loc: Rect) {
let dd_text = [Text::raw(format!( let dd_text = Span::from(format!(
"\nFailure to properly kill the process - {}", "\nFailure to properly kill the process - {}",
dd_err dd_err
))]; ));
let error_title = format!( let error_title = Span::styled(
format!(
" Error ─{}─ Esc to close ", " Error ─{}─ Esc to close ",
"".repeat( "".repeat(
usize::from(draw_loc.width).saturating_sub(DD_ERROR_BASE.chars().count() + 2) usize::from(draw_loc.width).saturating_sub(DD_ERROR_BASE.chars().count() + 2)
) )
),
self.colours.border_style,
); );
f.render_widget( f.render_widget(
Paragraph::new(dd_text.iter()) Paragraph::new(dd_text)
.block( .block(
Block::default() Block::default()
.title(&error_title) .title(error_title)
.title_style(self.colours.border_style)
.style(self.colours.border_style) .style(self.colours.border_style)
.borders(Borders::ALL) .borders(Borders::ALL)
.border_style(self.colours.border_style), .border_style(self.colours.border_style),
) )
.style(self.colours.text_style) .style(self.colours.text_style)
.alignment(Alignment::Center) .alignment(Alignment::Center)
.wrap(true), .wrap(Wrap { trim: true }),
draw_loc, draw_loc,
); );
} }

View file

@ -4,7 +4,8 @@ use tui::{
backend::Backend, backend::Backend,
layout::{Alignment, Rect}, layout::{Alignment, Rect},
terminal::Frame, terminal::Frame,
widgets::{Block, Borders, Paragraph}, text::Span,
widgets::{Block, Borders, Paragraph, Wrap},
}; };
use crate::{app::App, canvas::Painter, constants}; use crate::{app::App, canvas::Painter, constants};
@ -21,9 +22,14 @@ impl HelpDialog for Painter {
fn draw_help_dialog<B: Backend>( fn draw_help_dialog<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, &self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect,
) { ) {
let help_title = format!( let help_title = Span::styled(
format!(
" Help ─{}─ Esc to close ", " Help ─{}─ Esc to close ",
"".repeat(usize::from(draw_loc.width).saturating_sub(HELP_BASE.chars().count() + 2)) "".repeat(
usize::from(draw_loc.width).saturating_sub(HELP_BASE.chars().count() + 2)
)
),
self.colours.border_style,
); );
if app_state.is_force_redraw { if app_state.is_force_redraw {
@ -89,24 +95,24 @@ impl HelpDialog for Painter {
} }
f.render_widget( f.render_widget(
Paragraph::new(self.styled_help_text.iter()) Paragraph::new(self.styled_help_text.clone())
.block( .block(
Block::default() Block::default()
.title(&help_title) .title(help_title)
.title_style(self.colours.border_style)
.style(self.colours.border_style) .style(self.colours.border_style)
.borders(Borders::ALL) .borders(Borders::ALL)
.border_style(self.colours.border_style), .border_style(self.colours.border_style),
) )
.style(self.colours.text_style) .style(self.colours.text_style)
.alignment(Alignment::Left) .alignment(Alignment::Left)
.wrap(true) .wrap(Wrap { trim: true })
.scroll( .scroll((
app_state app_state
.help_dialog_state .help_dialog_state
.scroll_state .scroll_state
.current_scroll_index, .current_scroll_index,
), 0,
)),
draw_loc, draw_loc,
); );
} }

View file

@ -10,7 +10,8 @@ use tui::{
backend::Backend, backend::Backend,
layout::{Constraint, Layout, Rect}, layout::{Constraint, Layout, Rect},
terminal::Frame, terminal::Frame,
widgets::{Block, Paragraph, Text}, text::{Span, Spans},
widgets::{Block, Paragraph},
}; };
pub trait BasicTableArrows { pub trait BasicTableArrows {
@ -58,9 +59,12 @@ impl BasicTableArrows for Painter {
usize::from(draw_loc.width).saturating_sub(6 + left_name.len() + right_name.len()); usize::from(draw_loc.width).saturating_sub(6 + left_name.len() + right_name.len());
let arrow_text = vec![ let arrow_text = vec![
Text::Styled(format!("\n{}", left_name).into(), self.colours.text_style), Spans::from(Span::from(String::default())),
Text::Raw(" ".repeat(num_spaces).into()), Spans::from(vec![
Text::Styled(format!("{}", right_name).into(), self.colours.text_style), Span::styled(format!("{}", left_name), self.colours.text_style),
Span::from(" ".repeat(num_spaces)),
Span::styled(format!("{}", right_name), self.colours.text_style),
]),
]; ];
let margined_draw_loc = Layout::default() let margined_draw_loc = Layout::default()
@ -69,7 +73,7 @@ impl BasicTableArrows for Painter {
.split(draw_loc); .split(draw_loc);
f.render_widget( f.render_widget(
Paragraph::new(arrow_text.iter()).block(Block::default()), Paragraph::new(arrow_text).block(Block::default()),
margined_draw_loc[0], margined_draw_loc[0],
); );
} }

View file

@ -8,7 +8,8 @@ use tui::{
backend::Backend, backend::Backend,
layout::{Constraint, Rect}, layout::{Constraint, Rect},
terminal::Frame, terminal::Frame,
widgets::{Block, Borders, Paragraph, Row, Table, Tabs, Text}, text::{Span, Spans},
widgets::{Block, Borders, Paragraph, Row, Table, Tabs},
}; };
pub trait BatteryDisplayWidget { pub trait BatteryDisplayWidget {
@ -27,32 +28,31 @@ impl BatteryDisplayWidget for Painter {
app_state.battery_state.widget_states.get_mut(&widget_id) app_state.battery_state.widget_states.get_mut(&widget_id)
{ {
let is_on_widget = widget_id == app_state.current_widget.widget_id; let is_on_widget = widget_id == app_state.current_widget.widget_id;
let title = if app_state.is_expanded {
const TITLE_BASE: &str = " Battery ── Esc to go back ";
format!(
" Battery ─{}─ Esc to go back ",
"".repeat(
usize::from(draw_loc.width).saturating_sub(TITLE_BASE.chars().count() + 2)
)
)
} else {
" Battery ".to_string()
};
let border_and_title_style = if is_on_widget { let border_and_title_style = if is_on_widget {
self.colours.highlighted_border_style self.colours.highlighted_border_style
} else { } else {
self.colours.border_style self.colours.border_style
}; };
let title = if app_state.is_expanded {
const TITLE_BASE: &str = " Battery ── Esc to go back ";
Span::styled(
format!(
" Battery ─{}─ Esc to go back ",
"".repeat(
usize::from(draw_loc.width)
.saturating_sub(TITLE_BASE.chars().count() + 2)
)
),
border_and_title_style,
)
} else {
Span::styled(" Battery ".to_string(), self.colours.widget_title_style)
};
let battery_block = if draw_border { let battery_block = if draw_border {
Block::default() Block::default()
.title(&title) .title(title)
.title_style(if app_state.is_expanded {
border_and_title_style
} else {
self.colours.widget_title_style
})
.borders(Borders::ALL) .borders(Borders::ALL)
.border_style(border_and_title_style) .border_style(border_and_title_style)
} else if is_on_widget { } else if is_on_widget {
@ -63,6 +63,23 @@ impl BatteryDisplayWidget for Painter {
Block::default().borders(Borders::NONE) Block::default().borders(Borders::NONE)
}; };
f.render_widget(
Tabs::new(
(app_state
.canvas_data
.battery_data
.iter()
.map(|battery| Spans::from(battery.battery_name.clone())))
.collect::<Vec<_>>(),
)
.block(battery_block.clone())
.divider(tui::symbols::line::VERTICAL)
.style(self.colours.text_style)
.highlight_style(self.colours.currently_selected_text_style)
.select(battery_widget_state.currently_selected_battery_index),
draw_loc,
);
if let Some(battery_details) = app_state if let Some(battery_details) = app_state
.canvas_data .canvas_data
.battery_data .battery_data
@ -117,44 +134,21 @@ impl BatteryDisplayWidget for Painter {
// Draw // Draw
f.render_widget( f.render_widget(
Table::new([""].iter(), battery_rows) Table::new([""].iter(), battery_rows)
.block(battery_block) .block(battery_block.clone())
.header_style(self.colours.table_header_style) .header_style(self.colours.table_header_style)
.widths([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref()), .widths([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref()),
draw_loc, draw_loc,
); );
} else { } else {
f.render_widget( f.render_widget(
Paragraph::new( Paragraph::new(Spans::from(Span::styled(
[Text::Styled( "No data found for this battery",
"No data found for this battery".into(),
self.colours.text_style, self.colours.text_style,
)] )))
.iter(),
)
.block(battery_block), .block(battery_block),
draw_loc, draw_loc,
); );
} }
// if app_state.canvas_data.battery_data.len() > 1 {
f.render_widget(
Tabs::default()
.block(battery_block)
.titles(
(app_state
.canvas_data
.battery_data
.iter()
.map(|battery| &battery.battery_name))
.collect::<Vec<_>>()
.as_ref(),
)
.divider(tui::symbols::line::VERTICAL)
.style(self.colours.text_style)
.highlight_style(self.colours.currently_selected_text_style)
.select(battery_widget_state.currently_selected_battery_index),
draw_loc,
);
// }
} }
} }
} }

View file

@ -11,7 +11,8 @@ use tui::{
backend::Backend, backend::Backend,
layout::{Constraint, Direction, Layout, Rect}, layout::{Constraint, Direction, Layout, Rect},
terminal::Frame, terminal::Frame,
widgets::{Block, Paragraph, Text}, text::{Span, Spans},
widgets::{Block, Paragraph},
}; };
pub trait CpuBasicWidget { pub trait CpuBasicWidget {
@ -76,10 +77,10 @@ impl CpuBasicWidget for Painter {
let num_bars = calculate_basic_use_bars(use_percentage, bar_length); let num_bars = calculate_basic_use_bars(use_percentage, bar_length);
format!( format!(
"{:3}[{}{}{:3.0}%]\n", "{:3}[{}{}{:3.0}%]",
if app_state.app_config_fields.show_average_cpu { if app_state.app_config_fields.show_average_cpu {
if cpu_index == 0 { if cpu_index == 0 {
"AVG".to_string() " AVG".to_string()
} else { } else {
(cpu_index - 1).to_string() (cpu_index - 1).to_string()
} }
@ -106,13 +107,13 @@ impl CpuBasicWidget for Painter {
); );
row_counter -= how_many_cpus; row_counter -= how_many_cpus;
let end_index = min(start_index + how_many_cpus, num_cpus); let end_index = min(start_index + how_many_cpus, num_cpus);
let cpu_column: Vec<Text<'_>> = (start_index..end_index) let cpu_column = (start_index..end_index)
.map(|cpu_index| { .map(|cpu_index| {
Text::Styled( Spans::from(Span {
(&cpu_bars[cpu_index]).into(), content: (&cpu_bars[cpu_index]).into(),
self.colours.cpu_colour_styles style: self.colours.cpu_colour_styles
[cpu_index % self.colours.cpu_colour_styles.len()], [cpu_index % self.colours.cpu_colour_styles.len()],
) })
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -125,7 +126,7 @@ impl CpuBasicWidget for Painter {
.split(*chunk); .split(*chunk);
f.render_widget( f.render_widget(
Paragraph::new(cpu_column.iter()).block(Block::default()), Paragraph::new(cpu_column).block(Block::default()),
margined_loc[0], margined_loc[0],
); );
} }

View file

@ -17,6 +17,7 @@ use tui::{
layout::{Constraint, Direction, Layout, Rect}, layout::{Constraint, Direction, Layout, Rect},
symbols::Marker, symbols::Marker,
terminal::Frame, terminal::Frame,
text::Span,
widgets::{Axis, Block, Borders, Chart, Dataset, Row, Table}, widgets::{Axis, Block, Borders, Chart, Dataset, Row, Table},
}; };
@ -103,9 +104,12 @@ impl CpuGraphWidget for Painter {
if let Some(cpu_widget_state) = app_state.cpu_state.widget_states.get_mut(&widget_id) { if let Some(cpu_widget_state) = app_state.cpu_state.widget_states.get_mut(&widget_id) {
let cpu_data: &mut [ConvertedCpuData] = &mut app_state.canvas_data.cpu_data; let cpu_data: &mut [ConvertedCpuData] = &mut app_state.canvas_data.cpu_data;
let display_time_labels = [ let display_time_labels = vec![
Span::styled(
format!("{}s", cpu_widget_state.current_display_time / 1000), format!("{}s", cpu_widget_state.current_display_time / 1000),
"0s".to_string(), self.colours.graph_style,
),
Span::styled("0s".to_string(), self.colours.graph_style),
]; ];
let x_axis = if app_state.app_config_fields.hide_time let x_axis = if app_state.app_config_fields.hide_time
@ -120,8 +124,7 @@ impl CpuGraphWidget for Painter {
Axis::default() Axis::default()
.bounds([-(cpu_widget_state.current_display_time as f64), 0.0]) .bounds([-(cpu_widget_state.current_display_time as f64), 0.0])
.style(self.colours.graph_style) .style(self.colours.graph_style)
.labels_style(self.colours.graph_style) .labels(display_time_labels)
.labels(&display_time_labels)
} else { } else {
cpu_widget_state.autohide_timer = None; cpu_widget_state.autohide_timer = None;
Axis::default().bounds([-(cpu_widget_state.current_display_time as f64), 0.0]) Axis::default().bounds([-(cpu_widget_state.current_display_time as f64), 0.0])
@ -132,16 +135,17 @@ impl CpuGraphWidget for Painter {
Axis::default() Axis::default()
.bounds([-(cpu_widget_state.current_display_time as f64), 0.0]) .bounds([-(cpu_widget_state.current_display_time as f64), 0.0])
.style(self.colours.graph_style) .style(self.colours.graph_style)
.labels_style(self.colours.graph_style) .labels(display_time_labels)
.labels(&display_time_labels)
}; };
// Note this is offset as otherwise the 0 value is not drawn! // Note this is offset as otherwise the 0 value is not drawn!
let y_axis = Axis::default() let y_axis = Axis::default()
.style(self.colours.graph_style) .style(self.colours.graph_style)
.labels_style(self.colours.graph_style)
.bounds([-0.5, 100.5]) .bounds([-0.5, 100.5])
.labels(&["0%", "100%"]); .labels(vec![
Span::styled("0%", self.colours.graph_style),
Span::styled("100%", self.colours.graph_style),
]);
let use_dot = app_state.app_config_fields.use_dot; let use_dot = app_state.app_config_fields.use_dot;
let show_avg_cpu = app_state.app_config_fields.show_average_cpu; let show_avg_cpu = app_state.app_config_fields.show_average_cpu;
@ -189,30 +193,28 @@ impl CpuGraphWidget for Painter {
vec![] vec![]
}; };
let title = " CPU ".to_string();
let border_style = if app_state.current_widget.widget_id == widget_id { let border_style = if app_state.current_widget.widget_id == widget_id {
self.colours.highlighted_border_style self.colours.highlighted_border_style
} else { } else {
self.colours.border_style self.colours.border_style
}; };
let title = if app_state.is_expanded {
Span::styled(" CPU ".to_string(), border_style)
} else {
Span::styled(" CPU ".to_string(), self.colours.widget_title_style)
};
f.render_widget( f.render_widget(
Chart::default() Chart::new(dataset_vector)
.block( .block(
Block::default() Block::default()
.title(&title) .title(title)
.title_style(if app_state.is_expanded {
border_style
} else {
self.colours.widget_title_style
})
.borders(Borders::ALL) .borders(Borders::ALL)
.border_style(border_style), .border_style(border_style),
) )
.x_axis(x_axis) .x_axis(x_axis)
.y_axis(y_axis) .y_axis(y_axis),
.datasets(&dataset_vector),
draw_loc, draw_loc,
); );
} }
@ -296,7 +298,6 @@ impl CpuGraphWidget for Painter {
Table::new(CPU_LEGEND_HEADER.iter(), cpu_rows) Table::new(CPU_LEGEND_HEADER.iter(), cpu_rows)
.block( .block(
Block::default() Block::default()
.title_style(border_and_title_style)
.borders(Borders::ALL) .borders(Borders::ALL)
.border_style(border_and_title_style), .border_style(border_and_title_style),
) )

View file

@ -4,6 +4,7 @@ use tui::{
backend::Backend, backend::Backend,
layout::{Constraint, Direction, Layout, Rect}, layout::{Constraint, Direction, Layout, Rect},
terminal::Frame, terminal::Frame,
text::Span,
widgets::{Block, Borders, Row, Table}, widgets::{Block, Borders, Row, Table},
}; };
@ -67,20 +68,6 @@ impl DiskTableWidget for Painter {
get_variable_intrinsic_widths(width as u16, &width_ratios, &DISK_HEADERS_LENS); get_variable_intrinsic_widths(width as u16, &width_ratios, &DISK_HEADERS_LENS);
let intrinsic_widths = &variable_intrinsic_results.0[0..variable_intrinsic_results.1]; let intrinsic_widths = &variable_intrinsic_results.0[0..variable_intrinsic_results.1];
let title = if app_state.is_expanded {
const TITLE_BASE: &str = " Disk ── Esc to go back ";
format!(
" Disk ─{}─ Esc to go back ",
"".repeat(
usize::from(draw_loc.width).saturating_sub(TITLE_BASE.chars().count() + 2)
)
)
} else if app_state.app_config_fields.use_basic_mode {
String::new()
} else {
" Disk ".to_string()
};
let (border_and_title_style, highlight_style) = if is_on_widget { let (border_and_title_style, highlight_style) = if is_on_widget {
( (
self.colours.highlighted_border_style, self.colours.highlighted_border_style,
@ -90,14 +77,27 @@ impl DiskTableWidget for Painter {
(self.colours.border_style, self.colours.text_style) (self.colours.border_style, self.colours.text_style)
}; };
let title = if app_state.is_expanded {
const TITLE_BASE: &str = " Disk ── Esc to go back ";
Span::styled(
format!(
" Disk ─{}─ Esc to go back ",
"".repeat(
usize::from(draw_loc.width)
.saturating_sub(TITLE_BASE.chars().count() + 2)
)
),
border_and_title_style,
)
} else if app_state.app_config_fields.use_basic_mode {
Span::from(String::new())
} else {
Span::styled(" Disk ".to_string(), self.colours.widget_title_style)
};
let disk_block = if draw_border { let disk_block = if draw_border {
Block::default() Block::default()
.title(&title) .title(title)
.title_style(if app_state.is_expanded {
border_and_title_style
} else {
self.colours.widget_title_style
})
.borders(Borders::ALL) .borders(Borders::ALL)
.border_style(border_and_title_style) .border_style(border_and_title_style)
} else if is_on_widget { } else if is_on_widget {

View file

@ -8,7 +8,8 @@ use tui::{
backend::Backend, backend::Backend,
layout::{Constraint, Layout, Rect}, layout::{Constraint, Layout, Rect},
terminal::Frame, terminal::Frame,
widgets::{Block, Paragraph, Text}, text::{Span, Spans},
widgets::{Block, Paragraph},
}; };
pub trait MemBasicWidget { pub trait MemBasicWidget {
@ -65,13 +66,13 @@ impl MemBasicWidget for Painter {
swap_use_percentage.round(), swap_use_percentage.round(),
); );
let mem_text: Vec<Text<'_>> = vec![ let mem_text = vec![
Text::Styled(mem_label.into(), self.colours.ram_style), Spans::from(Span::styled(mem_label, self.colours.ram_style)),
Text::Styled(swap_label.into(), self.colours.swap_style), Spans::from(Span::styled(swap_label, self.colours.swap_style)),
]; ];
f.render_widget( f.render_widget(
Paragraph::new(mem_text.iter()).block(Block::default()), Paragraph::new(mem_text).block(Block::default()),
margined_loc[0], margined_loc[0],
); );
} }

View file

@ -5,6 +5,7 @@ use tui::{
layout::{Constraint, Rect}, layout::{Constraint, Rect},
symbols::Marker, symbols::Marker,
terminal::Frame, terminal::Frame,
text::Span,
widgets::{Axis, Block, Borders, Chart, Dataset}, widgets::{Axis, Block, Borders, Chart, Dataset},
}; };
@ -22,9 +23,12 @@ impl MemGraphWidget for Painter {
let mem_data: &[(f64, f64)] = &app_state.canvas_data.mem_data; let mem_data: &[(f64, f64)] = &app_state.canvas_data.mem_data;
let swap_data: &[(f64, f64)] = &app_state.canvas_data.swap_data; let swap_data: &[(f64, f64)] = &app_state.canvas_data.swap_data;
let display_time_labels = [ let display_time_labels = vec![
Span::styled(
format!("{}s", mem_widget_state.current_display_time / 1000), format!("{}s", mem_widget_state.current_display_time / 1000),
"0s".to_string(), self.colours.graph_style,
),
Span::styled("0s".to_string(), self.colours.graph_style),
]; ];
let x_axis = if app_state.app_config_fields.hide_time let x_axis = if app_state.app_config_fields.hide_time
|| (app_state.app_config_fields.autohide_time || (app_state.app_config_fields.autohide_time
@ -38,8 +42,7 @@ impl MemGraphWidget for Painter {
Axis::default() Axis::default()
.bounds([-(mem_widget_state.current_display_time as f64), 0.0]) .bounds([-(mem_widget_state.current_display_time as f64), 0.0])
.style(self.colours.graph_style) .style(self.colours.graph_style)
.labels_style(self.colours.graph_style) .labels(display_time_labels)
.labels(&display_time_labels)
} else { } else {
mem_widget_state.autohide_timer = None; mem_widget_state.autohide_timer = None;
Axis::default().bounds([-(mem_widget_state.current_display_time as f64), 0.0]) Axis::default().bounds([-(mem_widget_state.current_display_time as f64), 0.0])
@ -50,16 +53,17 @@ impl MemGraphWidget for Painter {
Axis::default() Axis::default()
.bounds([-(mem_widget_state.current_display_time as f64), 0.0]) .bounds([-(mem_widget_state.current_display_time as f64), 0.0])
.style(self.colours.graph_style) .style(self.colours.graph_style)
.labels_style(self.colours.graph_style) .labels(display_time_labels)
.labels(&display_time_labels)
}; };
// Offset as the zero value isn't drawn otherwise... // Offset as the zero value isn't drawn otherwise...
let y_axis: Axis<'_, &str> = Axis::default() let y_axis = Axis::default()
.style(self.colours.graph_style) .style(self.colours.graph_style)
.labels_style(self.colours.graph_style)
.bounds([-0.5, 100.5]) .bounds([-0.5, 100.5])
.labels(&["0%", "100%"]); .labels(vec![
Span::styled("0%", self.colours.graph_style),
Span::styled("100%", self.colours.graph_style),
]);
let mut mem_canvas_vec: Vec<Dataset<'_>> = vec![]; let mut mem_canvas_vec: Vec<Dataset<'_>> = vec![];
@ -91,26 +95,25 @@ impl MemGraphWidget for Painter {
let title = if app_state.is_expanded { let title = if app_state.is_expanded {
const TITLE_BASE: &str = " Memory ── Esc to go back "; const TITLE_BASE: &str = " Memory ── Esc to go back ";
Span::styled(
format!( format!(
" Memory ─{}─ Esc to go back ", " Memory ─{}─ Esc to go back ",
"".repeat( "".repeat(
usize::from(draw_loc.width).saturating_sub(TITLE_BASE.chars().count() + 2) usize::from(draw_loc.width)
.saturating_sub(TITLE_BASE.chars().count() + 2)
) )
),
self.colours.highlighted_border_style,
) )
} else { } else {
" Memory ".to_string() Span::styled(" Memory ".to_string(), self.colours.widget_title_style)
}; };
f.render_widget( f.render_widget(
Chart::default() Chart::new(mem_canvas_vec)
.block( .block(
Block::default() Block::default()
.title(&title) .title(title)
.title_style(if app_state.is_expanded {
self.colours.highlighted_border_style
} else {
self.colours.widget_title_style
})
.borders(Borders::ALL) .borders(Borders::ALL)
.border_style(if app_state.current_widget.widget_id == widget_id { .border_style(if app_state.current_widget.widget_id == widget_id {
self.colours.highlighted_border_style self.colours.highlighted_border_style
@ -120,7 +123,6 @@ impl MemGraphWidget for Painter {
) )
.x_axis(x_axis) .x_axis(x_axis)
.y_axis(y_axis) .y_axis(y_axis)
.datasets(&mem_canvas_vec)
.hidden_legend_constraints((Constraint::Ratio(3, 4), Constraint::Ratio(3, 4))), .hidden_legend_constraints((Constraint::Ratio(3, 4), Constraint::Ratio(3, 4))),
draw_loc, draw_loc,
); );

View file

@ -4,7 +4,8 @@ use tui::{
backend::Backend, backend::Backend,
layout::{Constraint, Direction, Layout, Rect}, layout::{Constraint, Direction, Layout, Rect},
terminal::Frame, terminal::Frame,
widgets::{Block, Paragraph, Text}, text::{Span, Spans},
widgets::{Block, Paragraph},
}; };
pub trait NetworkBasicWidget { pub trait NetworkBasicWidget {
@ -49,22 +50,19 @@ impl NetworkBasicWidget for Painter {
let total_tx_label = format!("Total TX: {}", &app_state.canvas_data.total_tx_display); let total_tx_label = format!("Total TX: {}", &app_state.canvas_data.total_tx_display);
let net_text = vec![ let net_text = vec![
Text::Styled(rx_label.into(), self.colours.rx_style), Spans::from(Span::styled(rx_label, self.colours.rx_style)),
Text::Styled(tx_label.into(), self.colours.tx_style), Spans::from(Span::styled(tx_label, self.colours.tx_style)),
]; ];
let total_net_text = vec![ let total_net_text = vec![
Text::Styled(total_rx_label.into(), self.colours.total_rx_style), Spans::from(Span::styled(total_rx_label, self.colours.total_rx_style)),
Text::Styled(total_tx_label.into(), self.colours.total_tx_style), Spans::from(Span::styled(total_tx_label, self.colours.total_tx_style)),
]; ];
f.render_widget( f.render_widget(Paragraph::new(net_text).block(Block::default()), net_loc[0]);
Paragraph::new(net_text.iter()).block(Block::default()),
net_loc[0],
);
f.render_widget( f.render_widget(
Paragraph::new(total_net_text.iter()).block(Block::default()), Paragraph::new(total_net_text).block(Block::default()),
total_loc[0], total_loc[0],
); );
} }

View file

@ -12,6 +12,7 @@ use tui::{
layout::{Constraint, Direction, Layout, Rect}, layout::{Constraint, Direction, Layout, Rect},
symbols::Marker, symbols::Marker,
terminal::Frame, terminal::Frame,
text::Span,
widgets::{Axis, Block, Borders, Chart, Dataset, Row, Table}, widgets::{Axis, Block, Borders, Chart, Dataset, Row, Table},
}; };
@ -71,9 +72,12 @@ impl NetworkGraphWidget for Painter {
let network_data_rx: &[(f64, f64)] = &app_state.canvas_data.network_data_rx; let network_data_rx: &[(f64, f64)] = &app_state.canvas_data.network_data_rx;
let network_data_tx: &[(f64, f64)] = &app_state.canvas_data.network_data_tx; let network_data_tx: &[(f64, f64)] = &app_state.canvas_data.network_data_tx;
let display_time_labels = [ let display_time_labels = vec![
Span::styled(
format!("{}s", network_widget_state.current_display_time / 1000), format!("{}s", network_widget_state.current_display_time / 1000),
"0s".to_string(), self.colours.graph_style,
),
Span::styled("0s".to_string(), self.colours.graph_style),
]; ];
let x_axis = if app_state.app_config_fields.hide_time let x_axis = if app_state.app_config_fields.hide_time
|| (app_state.app_config_fields.autohide_time || (app_state.app_config_fields.autohide_time
@ -87,8 +91,7 @@ impl NetworkGraphWidget for Painter {
Axis::default() Axis::default()
.bounds([-(network_widget_state.current_display_time as f64), 0.0]) .bounds([-(network_widget_state.current_display_time as f64), 0.0])
.style(self.colours.graph_style) .style(self.colours.graph_style)
.labels_style(self.colours.graph_style) .labels(display_time_labels)
.labels(&display_time_labels)
} else { } else {
network_widget_state.autohide_timer = None; network_widget_state.autohide_timer = None;
Axis::default() Axis::default()
@ -100,27 +103,35 @@ impl NetworkGraphWidget for Painter {
Axis::default() Axis::default()
.bounds([-(network_widget_state.current_display_time as f64), 0.0]) .bounds([-(network_widget_state.current_display_time as f64), 0.0])
.style(self.colours.graph_style) .style(self.colours.graph_style)
.labels_style(self.colours.graph_style) .labels(display_time_labels)
.labels(&display_time_labels)
}; };
// 0 is offset. // 0 is offset.
let y_axis: Axis<'_, &str> = Axis::default() let y_axis_labels = vec![
Span::styled("0B", self.colours.graph_style),
Span::styled("1KiB", self.colours.graph_style),
Span::styled("1MiB", self.colours.graph_style),
Span::styled("1GiB", self.colours.graph_style),
];
let y_axis = Axis::default()
.style(self.colours.graph_style) .style(self.colours.graph_style)
.labels_style(self.colours.graph_style)
.bounds([-0.5, 30_f64]) .bounds([-0.5, 30_f64])
.labels(&["0B", "1KiB", "1MiB", "1GiB"]); .labels(y_axis_labels);
let title = if app_state.is_expanded { let title = if app_state.is_expanded {
const TITLE_BASE: &str = " Network ── Esc to go back "; const TITLE_BASE: &str = " Network ── Esc to go back ";
Span::styled(
format!( format!(
" Network ─{}─ Esc to go back ", " Network ─{}─ Esc to go back ",
"".repeat( "".repeat(
usize::from(draw_loc.width).saturating_sub(TITLE_BASE.chars().count() + 2) usize::from(draw_loc.width)
.saturating_sub(TITLE_BASE.chars().count() + 2)
) )
),
self.colours.highlighted_border_style,
) )
} else { } else {
" Network ".to_string() Span::styled(" Network ".to_string(), self.colours.widget_title_style)
}; };
let legend_constraints = if hide_legend { let legend_constraints = if hide_legend {
@ -209,15 +220,10 @@ impl NetworkGraphWidget for Painter {
}; };
f.render_widget( f.render_widget(
Chart::default() Chart::new(dataset)
.block( .block(
Block::default() Block::default()
.title(&title) .title(title)
.title_style(if app_state.is_expanded {
self.colours.highlighted_border_style
} else {
self.colours.widget_title_style
})
.borders(Borders::ALL) .borders(Borders::ALL)
.border_style(if app_state.current_widget.widget_id == widget_id { .border_style(if app_state.current_widget.widget_id == widget_id {
self.colours.highlighted_border_style self.colours.highlighted_border_style
@ -227,7 +233,6 @@ impl NetworkGraphWidget for Painter {
) )
.x_axis(x_axis) .x_axis(x_axis)
.y_axis(y_axis) .y_axis(y_axis)
.datasets(&dataset)
.hidden_legend_constraints(legend_constraints), .hidden_legend_constraints(legend_constraints),
draw_loc, draw_loc,
); );

View file

@ -13,7 +13,8 @@ use tui::{
backend::Backend, backend::Backend,
layout::{Alignment, Constraint, Direction, Layout, Rect}, layout::{Alignment, Constraint, Direction, Layout, Rect},
terminal::Frame, terminal::Frame,
widgets::{Block, Borders, Paragraph, Row, Table, Text}, text::{Span, Spans},
widgets::{Block, Borders, Paragraph, Row, Table, Wrap},
}; };
use unicode_segmentation::{GraphemeIndices, UnicodeSegmentation}; use unicode_segmentation::{GraphemeIndices, UnicodeSegmentation};
@ -202,12 +203,12 @@ impl ProcessTableWidget for Painter {
// TODO: This is a ugly work-around for now. // TODO: This is a ugly work-around for now.
let width_ratios = if proc_widget_state.is_grouped { let width_ratios = if proc_widget_state.is_grouped {
if proc_widget_state.is_using_full_path { if proc_widget_state.is_using_full_path {
vec![0.1, 0.7, 0.05, 0.05, 0.025, 0.025, 0.025, 0.025] vec![0.05, 0.7, 0.05, 0.05, 0.0375, 0.0375, 0.0375, 0.0375]
} else { } else {
vec![0.1, 0.2, 0.1, 0.1, 0.1, 0.1, 0.15, 0.15] vec![0.1, 0.2, 0.1, 0.1, 0.1, 0.1, 0.15, 0.15]
} }
} else if proc_widget_state.is_using_full_path { } else if proc_widget_state.is_using_full_path {
vec![0.1, 0.7, 0.05, 0.05, 0.02, 0.02, 0.02, 0.02, 0.02] vec![0.05, 0.7, 0.05, 0.05, 0.03, 0.03, 0.03, 0.03]
} else { } else {
vec![0.1, 0.2, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1] vec![0.1, 0.2, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]
}; };
@ -219,28 +220,6 @@ impl ProcessTableWidget for Painter {
let intrinsic_widths = let intrinsic_widths =
&(variable_intrinsic_results.0)[0..variable_intrinsic_results.1]; &(variable_intrinsic_results.0)[0..variable_intrinsic_results.1];
let title = if draw_border {
if app_state.is_expanded
&& !proc_widget_state
.process_search_state
.search_state
.is_enabled
{
const TITLE_BASE: &str = " Processes ── Esc to go back ";
format!(
" Processes ─{}─ Esc to go back ",
"".repeat(
usize::from(draw_loc.width)
.saturating_sub(TITLE_BASE.chars().count() + 2)
)
)
} else {
" Processes ".to_string()
}
} else {
String::default()
};
let (border_and_title_style, highlight_style) = if is_on_widget { let (border_and_title_style, highlight_style) = if is_on_widget {
( (
self.colours.highlighted_border_style, self.colours.highlighted_border_style,
@ -250,14 +229,34 @@ impl ProcessTableWidget for Painter {
(self.colours.border_style, self.colours.text_style) (self.colours.border_style, self.colours.text_style)
}; };
let title = if draw_border {
if app_state.is_expanded
&& !proc_widget_state
.process_search_state
.search_state
.is_enabled
{
const TITLE_BASE: &str = " Processes ── Esc to go back ";
Span::styled(
format!(
" Processes ─{}─ Esc to go back ",
"".repeat(
usize::from(draw_loc.width)
.saturating_sub(TITLE_BASE.chars().count() + 2)
)
),
border_and_title_style,
)
} else {
Span::styled(" Processes ".to_string(), self.colours.widget_title_style)
}
} else {
Span::from(String::default())
};
let process_block = if draw_border { let process_block = if draw_border {
Block::default() Block::default()
.title(&title) .title(title)
.title_style(if app_state.is_expanded {
border_and_title_style
} else {
self.colours.widget_title_style
})
.borders(Borders::ALL) .borders(Borders::ALL)
.border_style(border_and_title_style) .border_style(border_and_title_style)
} else if is_on_widget { } else if is_on_widget {
@ -304,7 +303,7 @@ impl ProcessTableWidget for Painter {
is_on_widget: bool, grapheme_indices: GraphemeIndices<'a>, start_position: usize, is_on_widget: bool, grapheme_indices: GraphemeIndices<'a>, start_position: usize,
cursor_position: usize, query: &str, currently_selected_text_style: tui::style::Style, cursor_position: usize, query: &str, currently_selected_text_style: tui::style::Style,
text_style: tui::style::Style, text_style: tui::style::Style,
) -> Vec<Text<'a>> { ) -> Vec<Span<'a>> {
let mut current_grapheme_posn = 0; let mut current_grapheme_posn = 0;
if is_on_widget { if is_on_widget {
@ -316,9 +315,9 @@ impl ProcessTableWidget for Painter {
None None
} else { } else {
let styled = if grapheme.0 == cursor_position { let styled = if grapheme.0 == cursor_position {
Text::styled(grapheme.1, currently_selected_text_style) Span::styled(grapheme.1, currently_selected_text_style)
} else { } else {
Text::styled(grapheme.1, text_style) Span::styled(grapheme.1, text_style)
}; };
Some(styled) Some(styled)
} }
@ -326,20 +325,21 @@ impl ProcessTableWidget for Painter {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
if cursor_position >= query.len() { if cursor_position >= query.len() {
res.push(Text::styled(" ", currently_selected_text_style)) res.push(Span::styled(" ", currently_selected_text_style))
} }
res res
} else { } else {
// This is easier - we just need to get a range of graphemes, rather than // This is easier - we just need to get a range of graphemes, rather than
// dealing with possibly inserting a cursor (as none is shown!) // dealing with possibly inserting a cursor (as none is shown!)
grapheme_indices grapheme_indices
.filter_map(|grapheme| { .filter_map(|grapheme| {
current_grapheme_posn += UnicodeWidthStr::width(grapheme.1); current_grapheme_posn += UnicodeWidthStr::width(grapheme.1);
if current_grapheme_posn <= start_position { if current_grapheme_posn <= start_position {
None None
} else { } else {
let styled = Text::styled(grapheme.1, text_style); let styled = Span::styled(grapheme.1, text_style);
Some(styled) Some(styled)
} }
}) })
@ -372,17 +372,10 @@ impl ProcessTableWidget for Painter {
app_state.is_force_redraw, app_state.is_force_redraw,
); );
let mut search_text = vec![Text::styled(
search_title,
if is_on_widget {
self.colours.table_header_style
} else {
self.colours.text_style
},
)];
let query = proc_widget_state.get_current_search_query().as_str(); let query = proc_widget_state.get_current_search_query().as_str();
let grapheme_indices = UnicodeSegmentation::grapheme_indices(query, true); let grapheme_indices = UnicodeSegmentation::grapheme_indices(query, true);
let query_with_cursor: Vec<Text<'_>> = build_query(
let query_with_cursor = build_query(
is_on_widget, is_on_widget,
grapheme_indices, grapheme_indices,
start_position, start_position,
@ -392,6 +385,19 @@ impl ProcessTableWidget for Painter {
self.colours.text_style, self.colours.text_style,
); );
let mut search_text = vec![Spans::from({
let mut search_vec = vec![Span::styled(
search_title,
if is_on_widget {
self.colours.table_header_style
} else {
self.colours.text_style
},
)];
search_vec.extend(query_with_cursor);
search_vec
})];
// Text options shamelessly stolen from VS Code. // Text options shamelessly stolen from VS Code.
let case_style = if !proc_widget_state.process_search_state.is_ignoring_case { let case_style = if !proc_widget_state.process_search_state.is_ignoring_case {
self.colours.currently_selected_text_style self.colours.currently_selected_text_style
@ -417,28 +423,24 @@ impl ProcessTableWidget for Painter {
self.colours.text_style self.colours.text_style
}; };
let option_text = vec![ let option_text = Spans::from(vec![
Text::raw("\n"), Span::styled(
Text::styled(
format!("Case({})", if self.is_mac_os { "F1" } else { "Alt+C" }), format!("Case({})", if self.is_mac_os { "F1" } else { "Alt+C" }),
case_style, case_style,
), ),
Text::raw(" "), Span::from(" "),
Text::styled( Span::styled(
format!("Whole({})", if self.is_mac_os { "F2" } else { "Alt+W" }), format!("Whole({})", if self.is_mac_os { "F2" } else { "Alt+W" }),
whole_word_style, whole_word_style,
), ),
Text::raw(" "), Span::from(" "),
Text::styled( Span::styled(
format!("Regex({})", if self.is_mac_os { "F3" } else { "Alt+R" }), format!("Regex({})", if self.is_mac_os { "F3" } else { "Alt+R" }),
regex_style, regex_style,
), ),
]; ]);
search_text.extend(query_with_cursor); search_text.push(Spans::from(Span::styled(
search_text.push(Text::styled(
format!(
"\n{}",
if let Some(err) = &proc_widget_state if let Some(err) = &proc_widget_state
.process_search_state .process_search_state
.search_state .search_state
@ -447,11 +449,10 @@ impl ProcessTableWidget for Painter {
err.as_str() err.as_str()
} else { } else {
"" ""
} },
),
self.colours.invalid_query_style, self.colours.invalid_query_style,
)); )));
search_text.extend(option_text); search_text.push(option_text);
let current_border_style = if proc_widget_state let current_border_style = if proc_widget_state
.process_search_state .process_search_state
@ -470,15 +471,17 @@ impl ProcessTableWidget for Painter {
let repeat_num = let repeat_num =
usize::from(draw_loc.width).saturating_sub(TITLE_BASE.chars().count() + 2); usize::from(draw_loc.width).saturating_sub(TITLE_BASE.chars().count() + 2);
format!("{} Esc to close ", "".repeat(repeat_num)) Span::styled(
format!("{} Esc to close ", "".repeat(repeat_num)),
current_border_style,
)
} else { } else {
String::new() Span::from(String::new())
}; };
let process_search_block = if draw_border { let process_search_block = if draw_border {
Block::default() Block::default()
.title(&title) .title(title)
.title_style(current_border_style)
.borders(Borders::ALL) .borders(Borders::ALL)
.border_style(current_border_style) .border_style(current_border_style)
} else if is_on_widget { } else if is_on_widget {
@ -496,11 +499,11 @@ impl ProcessTableWidget for Painter {
.split(draw_loc); .split(draw_loc);
f.render_widget( f.render_widget(
Paragraph::new(search_text.iter()) Paragraph::new(search_text)
.block(process_search_block) .block(process_search_block)
.style(self.colours.text_style) .style(self.colours.text_style)
.alignment(Alignment::Left) .alignment(Alignment::Left)
.wrap(false), .wrap(Wrap { trim: false }),
margined_draw_loc[0], margined_draw_loc[0],
); );
} }

View file

@ -5,6 +5,7 @@ use tui::{
backend::Backend, backend::Backend,
layout::{Constraint, Direction, Layout, Rect}, layout::{Constraint, Direction, Layout, Rect},
terminal::Frame, terminal::Frame,
text::Span,
widgets::{Block, Borders, Row, Table}, widgets::{Block, Borders, Row, Table},
}; };
@ -67,20 +68,6 @@ impl TempTableWidget for Painter {
get_variable_intrinsic_widths(width as u16, &width_ratios, &TEMP_HEADERS_LENS); get_variable_intrinsic_widths(width as u16, &width_ratios, &TEMP_HEADERS_LENS);
let intrinsic_widths = &(variable_intrinsic_results.0)[0..variable_intrinsic_results.1]; let intrinsic_widths = &(variable_intrinsic_results.0)[0..variable_intrinsic_results.1];
let title = if app_state.is_expanded {
const TITLE_BASE: &str = " Temperatures ── Esc to go back ";
format!(
" Temperatures ─{}─ Esc to go back ",
"".repeat(
usize::from(draw_loc.width).saturating_sub(TITLE_BASE.chars().count() + 2)
)
)
} else if app_state.app_config_fields.use_basic_mode {
String::new()
} else {
" Temperatures ".to_string()
};
let (border_and_title_style, highlight_style) = if is_on_widget { let (border_and_title_style, highlight_style) = if is_on_widget {
( (
self.colours.highlighted_border_style, self.colours.highlighted_border_style,
@ -90,14 +77,30 @@ impl TempTableWidget for Painter {
(self.colours.border_style, self.colours.text_style) (self.colours.border_style, self.colours.text_style)
}; };
let title = if app_state.is_expanded {
const TITLE_BASE: &str = " Temperatures ── Esc to go back ";
Span::styled(
format!(
" Temperatures ─{}─ Esc to go back ",
"".repeat(
usize::from(draw_loc.width)
.saturating_sub(TITLE_BASE.chars().count() + 2)
)
),
border_and_title_style,
)
} else if app_state.app_config_fields.use_basic_mode {
Span::from(String::new())
} else {
Span::styled(
" Temperatures ".to_string(),
self.colours.widget_title_style,
)
};
let temp_block = if draw_border { let temp_block = if draw_border {
Block::default() Block::default()
.title(&title) .title(title)
.title_style(if app_state.is_expanded {
border_and_title_style
} else {
self.colours.widget_title_style
})
.borders(Borders::ALL) .borders(Borders::ALL)
.border_style(border_and_title_style) .border_style(border_and_title_style)
} else if is_on_widget { } else if is_on_widget {

View file

@ -365,6 +365,8 @@ fn create_config(flag_config_location: Option<&str>) -> error::Result<Config> {
} }
} else if let Some(home_path) = dirs::home_dir() { } else if let Some(home_path) = dirs::home_dir() {
let mut path = home_path; let mut path = home_path;
// TODO: This should not be done like this IMO... it should be based on the defaults set by dirs rather than home_dir
// This WILL cause breaking changes on macOS though, warning!
path.push(DEFAULT_UNIX_CONFIG_FILE_PATH); path.push(DEFAULT_UNIX_CONFIG_FILE_PATH);
path.into_os_string() path.into_os_string()
} else { } else {