mirror of
https://github.com/ClementTsang/bottom
synced 2024-11-23 04:33:10 +00:00
Added colour options to config; updated sample config to reflect this; updated README
This commit is contained in:
parent
238e0c88e0
commit
2123becb81
5 changed files with 486 additions and 176 deletions
23
README.md
23
README.md
|
@ -92,17 +92,32 @@ Run using `btm`.
|
||||||
|
|
||||||
- `-R`, `--regex` will default to using regex.
|
- `-R`, `--regex` will default to using regex.
|
||||||
|
|
||||||
- `-C`, `--config` takes in a file path leading to a TOML file, where one can set flags to execute by default.
|
- `-C`, `--config` takes in a file path leading to a TOML file.
|
||||||
|
|
||||||
- Options are generally the same as the long names as other flags (ie: `case_sensitive = true`).
|
One use of a config file is to set flags to execute by default.
|
||||||
- For temperature type, use `temperature_type = <kelvin|k|celsius|c|fahrenheit|f>`.
|
|
||||||
- See the [sample config](./sample_config.toml) for an example.
|
- Options are generally the same as the long names as other flags (ex: `case_sensitive = true`).
|
||||||
|
- For temperature type, use `temperature_type = "<kelvin|k|celsius|c|fahrenheit|f>"`.
|
||||||
|
|
||||||
|
Another use is to set colours (by default they're somewhat randomly generated). The following labels are customizable with a hex colour code strings:
|
||||||
|
|
||||||
|
- Table header colours (`table_header_color="#ffffff"`).
|
||||||
|
- Every CPU core colour as an array (`cpu_core_colors=["#ffffff", "#000000", "#111111"]`). bottom will look at 216 (let's be realistic here) colours at most, and in order. If not enough colours are provided, then the rest will be pseudo-randomly generated.
|
||||||
|
- RAM and SWAP colours (`ram_color="#ffffff"`, `swap_color="#111111"`).
|
||||||
|
- RX and TX colours (`rx_color="#ffffff"`, `tx_color="#111111"`).
|
||||||
|
- General widget border colour (`border_color="#ffffff"`).
|
||||||
|
- Current widget border colour (`highlighted_border_color="#ffffff"`).
|
||||||
|
- Text colour (`text_color="#ffffff"`).
|
||||||
|
- Cursor colour (`cursor_color="#ffffff"`).
|
||||||
|
- Current selected scroll entry colour (`scroll_entry_text_color="#282828"`, `scroll_entry_bg_color="#458588"`).
|
||||||
|
|
||||||
bottom will check specific locations by default for a config file.
|
bottom will check specific locations by default for a config file.
|
||||||
|
|
||||||
- For Unix-based systems: `~/.config/btm/btm.toml`.
|
- For Unix-based systems: `~/.config/btm/btm.toml`.
|
||||||
- For Windows: TBD.
|
- For Windows: TBD.
|
||||||
|
|
||||||
|
See the [sample config](./sample_config.toml) for an example.
|
||||||
|
|
||||||
### Keybindings
|
### Keybindings
|
||||||
|
|
||||||
#### General
|
#### General
|
||||||
|
|
|
@ -1,10 +1,26 @@
|
||||||
|
[flags]
|
||||||
avg_cpu = true
|
avg_cpu = true
|
||||||
dot_marker = true
|
dot_marker = true
|
||||||
temperature_type = "kelvin"
|
temperature_type = "k"
|
||||||
rate = 2000
|
rate = 1000
|
||||||
left_legend = false
|
left_legend = true
|
||||||
current_usage = false
|
current_usage = false
|
||||||
group_processes = true
|
group_processes = false
|
||||||
case_sensitive = true
|
case_sensitive = true
|
||||||
whole_word = true
|
whole_word = true
|
||||||
regex = true
|
regex = true
|
||||||
|
|
||||||
|
[colors]
|
||||||
|
# Based on gruvbox: https://github.com/morhetz/gruvbox
|
||||||
|
table_header_color="#458588"
|
||||||
|
cpu_core_colors=["#cc241d", "#98971a", "#d79921", "#458588", "#b16286", "#689d6a", "#fb4934", "#b8bb26", "#fabd2f", "#83a598"]
|
||||||
|
ram_color="#fb4934"
|
||||||
|
swap_color="#fabd2f"
|
||||||
|
rx_color="#458588"
|
||||||
|
tx_color="#689d6a"
|
||||||
|
border_color="#ebdbb2"
|
||||||
|
highlighted_border_color="#fe8019"
|
||||||
|
text_color="#ebdbb2"
|
||||||
|
cursor_color="#8ec07c"
|
||||||
|
scroll_entry_text_color="#282828"
|
||||||
|
scroll_entry_bg_color="#458588"
|
|
@ -711,7 +711,7 @@ impl App {
|
||||||
WidgetPosition::Process => self.change_process_position(-1),
|
WidgetPosition::Process => self.change_process_position(-1),
|
||||||
WidgetPosition::Temp => self.change_temp_position(-1),
|
WidgetPosition::Temp => self.change_temp_position(-1),
|
||||||
WidgetPosition::Disk => self.change_disk_position(-1),
|
WidgetPosition::Disk => self.change_disk_position(-1),
|
||||||
WidgetPosition::Cpu => self.change_cpu_table_position(-1), // TODO: Temporary, may change if we add scaling
|
WidgetPosition::Cpu => self.change_cpu_table_position(-1), // TODO: [PO?] Temporary, may change if we add scaling
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
self.scroll_direction = ScrollDirection::UP;
|
self.scroll_direction = ScrollDirection::UP;
|
||||||
|
@ -725,7 +725,7 @@ impl App {
|
||||||
WidgetPosition::Process => self.change_process_position(1),
|
WidgetPosition::Process => self.change_process_position(1),
|
||||||
WidgetPosition::Temp => self.change_temp_position(1),
|
WidgetPosition::Temp => self.change_temp_position(1),
|
||||||
WidgetPosition::Disk => self.change_disk_position(1),
|
WidgetPosition::Disk => self.change_disk_position(1),
|
||||||
WidgetPosition::Cpu => self.change_cpu_table_position(1), // TODO: Temporary, may change if we add scaling
|
WidgetPosition::Cpu => self.change_cpu_table_position(1), // TODO: [PO?] Temporary, may change if we add scaling
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
self.scroll_direction = ScrollDirection::DOWN;
|
self.scroll_direction = ScrollDirection::DOWN;
|
||||||
|
|
426
src/canvas.rs
426
src/canvas.rs
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
app::{self, data_harvester::processes::ProcessHarvest},
|
app::{self, data_harvester::processes::ProcessHarvest},
|
||||||
constants,
|
constants::*,
|
||||||
data_conversion::{ConvertedCpuData, ConvertedProcessData},
|
data_conversion::{ConvertedCpuData, ConvertedProcessData},
|
||||||
utils::{error, gen_util::*},
|
utils::{error, gen_util::*},
|
||||||
};
|
};
|
||||||
|
@ -15,11 +15,8 @@ use tui::{
|
||||||
Terminal,
|
Terminal,
|
||||||
};
|
};
|
||||||
|
|
||||||
const TEXT_COLOUR: Color = Color::Gray;
|
const STANDARD_FIRST_COLOUR: Color = Color::Rgb(150, 106, 253);
|
||||||
const GRAPH_COLOUR: Color = Color::Gray;
|
const STANDARD_SECOND_COLOUR: Color = Color::LightYellow;
|
||||||
const BORDER_STYLE_COLOUR: Color = Color::Gray;
|
|
||||||
const HIGHLIGHTED_BORDER_STYLE_COLOUR: Color = Color::LightBlue;
|
|
||||||
const TABLE_HEADER_COLOUR: Color = Color::LightBlue;
|
|
||||||
const GOLDEN_RATIO: f32 = 0.618_034; // Approx, good enough for use (also Clippy gets mad if it's too long)
|
const GOLDEN_RATIO: f32 = 0.618_034; // Approx, good enough for use (also Clippy gets mad if it's too long)
|
||||||
|
|
||||||
// Headers
|
// Headers
|
||||||
|
@ -58,10 +55,6 @@ lazy_static! {
|
||||||
Text::raw("Use Alt-r to toggle regex.\n"),
|
Text::raw("Use Alt-r to toggle regex.\n"),
|
||||||
Text::raw("\nFor startup flags, type in \"btm -h\".")
|
Text::raw("\nFor startup flags, type in \"btm -h\".")
|
||||||
];
|
];
|
||||||
static ref COLOUR_LIST: Vec<Color> = gen_n_colours(constants::NUM_COLOURS);
|
|
||||||
static ref CANVAS_BORDER_STYLE: Style = Style::default().fg(BORDER_STYLE_COLOUR);
|
|
||||||
static ref CANVAS_HIGHLIGHTED_BORDER_STYLE: Style =
|
|
||||||
Style::default().fg(HIGHLIGHTED_BORDER_STYLE_COLOUR);
|
|
||||||
static ref DISK_HEADERS_LENS: Vec<usize> = DISK_HEADERS
|
static ref DISK_HEADERS_LENS: Vec<usize> = DISK_HEADERS
|
||||||
.iter()
|
.iter()
|
||||||
.map(|entry| max(FORCE_MIN_THRESHOLD, entry.len()))
|
.map(|entry| max(FORCE_MIN_THRESHOLD, entry.len()))
|
||||||
|
@ -98,8 +91,8 @@ pub struct DisplayableData {
|
||||||
pub network_data_tx: Vec<(f64, f64)>,
|
pub network_data_tx: Vec<(f64, f64)>,
|
||||||
pub disk_data: Vec<Vec<String>>,
|
pub disk_data: Vec<Vec<String>>,
|
||||||
pub temp_sensor_data: Vec<Vec<String>>,
|
pub temp_sensor_data: Vec<Vec<String>>,
|
||||||
pub process_data: HashMap<u32, ProcessHarvest>, // Not final
|
pub process_data: HashMap<u32, ProcessHarvest>, // Not the final value
|
||||||
pub grouped_process_data: Vec<ConvertedProcessData>, // Not final
|
pub grouped_process_data: Vec<ConvertedProcessData>, // Not the final value
|
||||||
pub finalized_process_data: Vec<ConvertedProcessData>, // What's actually displayed
|
pub finalized_process_data: Vec<ConvertedProcessData>, // What's actually displayed
|
||||||
pub mem_label: String,
|
pub mem_label: String,
|
||||||
pub swap_label: String,
|
pub swap_label: String,
|
||||||
|
@ -108,8 +101,8 @@ pub struct DisplayableData {
|
||||||
pub cpu_data: Vec<ConvertedCpuData>,
|
pub cpu_data: Vec<ConvertedCpuData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates random colours.
|
/// Generates random colours. Strategy found from
|
||||||
/// Strategy found from https://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/
|
/// https://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/
|
||||||
fn gen_n_colours(num_to_gen: i32) -> Vec<Color> {
|
fn gen_n_colours(num_to_gen: i32) -> Vec<Color> {
|
||||||
fn gen_hsv(h: f32) -> f32 {
|
fn gen_hsv(h: f32) -> f32 {
|
||||||
let new_val = h + GOLDEN_RATIO;
|
let new_val = h + GOLDEN_RATIO;
|
||||||
|
@ -146,7 +139,7 @@ fn gen_n_colours(num_to_gen: i32) -> Vec<Color> {
|
||||||
];
|
];
|
||||||
|
|
||||||
let mut h: f32 = 0.4; // We don't need random colours... right?
|
let mut h: f32 = 0.4; // We don't need random colours... right?
|
||||||
for _i in 0..num_to_gen {
|
for _i in 0..(num_to_gen - 6) {
|
||||||
h = gen_hsv(h);
|
h = gen_hsv(h);
|
||||||
let result = hsv_to_rgb(h, 0.5, 0.95);
|
let result = hsv_to_rgb(h, 0.5, 0.95);
|
||||||
colour_vec.push(Color::Rgb(result.0, result.1, result.2));
|
colour_vec.push(Color::Rgb(result.0, result.1, result.2));
|
||||||
|
@ -155,9 +148,31 @@ fn gen_n_colours(num_to_gen: i32) -> Vec<Color> {
|
||||||
colour_vec
|
colour_vec
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn convert_hex_to_color(hex: &str) -> error::Result<Color> {
|
||||||
|
fn convert_hex_to_rgb(hex: &str) -> error::Result<(u8, u8, u8)> {
|
||||||
|
if hex.len() == 7 && &hex[0..1] == "#" {
|
||||||
|
let r = u8::from_str_radix(&hex[1..3], 16)?;
|
||||||
|
let g = u8::from_str_radix(&hex[3..5], 16)?;
|
||||||
|
let b = u8::from_str_radix(&hex[5..7], 16)?;
|
||||||
|
|
||||||
|
return Ok((r, g, b));
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(error::BottomError::GenericError {
|
||||||
|
message: format!(
|
||||||
|
"Colour hex {} is not of valid length. It must be a 7 character string of the form \"#112233\".",
|
||||||
|
hex
|
||||||
|
),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let rgb = convert_hex_to_rgb(hex)?;
|
||||||
|
Ok(Color::Rgb(rgb.0, rgb.1, rgb.2))
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
/// Handles the canvas' state.
|
/// Handles the canvas' state. TODO: [OPT] implement this.
|
||||||
pub struct Painter {
|
pub struct Painter {
|
||||||
height: f64,
|
height: f64,
|
||||||
width: f64,
|
width: f64,
|
||||||
|
@ -169,6 +184,118 @@ pub struct Painter {
|
||||||
bottom_chunks: Vec<Rect>,
|
bottom_chunks: Vec<Rect>,
|
||||||
cpu_chunk: Vec<Rect>,
|
cpu_chunk: Vec<Rect>,
|
||||||
network_chunk: Vec<Rect>,
|
network_chunk: Vec<Rect>,
|
||||||
|
pub colours: CanvasColours,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CanvasColours {
|
||||||
|
text_colour: Color,
|
||||||
|
scroll_text_colour: Color,
|
||||||
|
scroll_bg_colour: Color,
|
||||||
|
scroll_entry_style: Style,
|
||||||
|
border_colour: Color,
|
||||||
|
highlighted_border_colour: Color,
|
||||||
|
table_header_colour: Color,
|
||||||
|
ram_colour: Color,
|
||||||
|
swap_colour: Color,
|
||||||
|
rx_colour: Color,
|
||||||
|
tx_colour: Color,
|
||||||
|
cpu_colours: Vec<Color>,
|
||||||
|
cursor_colour: Color,
|
||||||
|
border_style: Style,
|
||||||
|
highlighted_border_style: Style,
|
||||||
|
text_style: Style,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for CanvasColours {
|
||||||
|
fn default() -> Self {
|
||||||
|
CanvasColours {
|
||||||
|
text_colour: Color::Gray,
|
||||||
|
scroll_text_colour: Color::Black,
|
||||||
|
scroll_bg_colour: Color::Cyan,
|
||||||
|
scroll_entry_style: Style::default().fg(Color::Black).bg(Color::Cyan),
|
||||||
|
border_colour: Color::Gray,
|
||||||
|
highlighted_border_colour: Color::LightBlue,
|
||||||
|
table_header_colour: Color::LightBlue,
|
||||||
|
ram_colour: STANDARD_FIRST_COLOUR,
|
||||||
|
swap_colour: STANDARD_SECOND_COLOUR,
|
||||||
|
rx_colour: STANDARD_FIRST_COLOUR,
|
||||||
|
tx_colour: STANDARD_SECOND_COLOUR,
|
||||||
|
cpu_colours: Vec::new(),
|
||||||
|
cursor_colour: Color::Cyan,
|
||||||
|
border_style: Style::default().fg(Color::Gray),
|
||||||
|
highlighted_border_style: Style::default().fg(Color::LightBlue),
|
||||||
|
text_style: Style::default().fg(Color::Gray),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CanvasColours {
|
||||||
|
pub fn set_text_colour(&mut self, hex: &str) -> error::Result<()> {
|
||||||
|
self.text_colour = convert_hex_to_color(hex)?;
|
||||||
|
self.text_style = Style::default().fg(self.text_colour);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn set_border_colour(&mut self, hex: &str) -> error::Result<()> {
|
||||||
|
self.border_colour = convert_hex_to_color(hex)?;
|
||||||
|
self.border_style = Style::default().fg(self.border_colour);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn set_highlighted_border_colour(&mut self, hex: &str) -> error::Result<()> {
|
||||||
|
self.highlighted_border_colour = convert_hex_to_color(hex)?;
|
||||||
|
self.highlighted_border_style = Style::default().fg(self.highlighted_border_colour);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn set_table_header_colour(&mut self, hex: &str) -> error::Result<()> {
|
||||||
|
self.table_header_colour = convert_hex_to_color(hex)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn set_ram_colour(&mut self, hex: &str) -> error::Result<()> {
|
||||||
|
self.ram_colour = convert_hex_to_color(hex)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn set_swap_colour(&mut self, hex: &str) -> error::Result<()> {
|
||||||
|
self.swap_colour = convert_hex_to_color(hex)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn set_rx_colour(&mut self, hex: &str) -> error::Result<()> {
|
||||||
|
self.rx_colour = convert_hex_to_color(hex)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn set_tx_colour(&mut self, hex: &str) -> error::Result<()> {
|
||||||
|
self.tx_colour = convert_hex_to_color(hex)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn set_cpu_colours(&mut self, hex_colours: &Vec<String>) -> error::Result<()> {
|
||||||
|
let max_amount = std::cmp::min(hex_colours.len(), NUM_COLOURS as usize);
|
||||||
|
for i in 0..max_amount {
|
||||||
|
self.cpu_colours
|
||||||
|
.push(convert_hex_to_color(&hex_colours[i])?);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn generate_remaining_cpu_colours(&mut self) {
|
||||||
|
let remaining_num_colours = NUM_COLOURS - self.cpu_colours.len() as i32;
|
||||||
|
self.cpu_colours
|
||||||
|
.extend(gen_n_colours(remaining_num_colours));
|
||||||
|
}
|
||||||
|
pub fn set_cursor_colour(&mut self, hex: &str) -> error::Result<()> {
|
||||||
|
self.cursor_colour = convert_hex_to_color(hex)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn set_scroll_entry_text_color(&mut self, hex: &str) -> error::Result<()> {
|
||||||
|
self.scroll_text_colour = convert_hex_to_color(hex)?;
|
||||||
|
self.scroll_entry_style = Style::default()
|
||||||
|
.fg(self.scroll_text_colour)
|
||||||
|
.bg(self.scroll_bg_colour);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn set_scroll_entry_bg_color(&mut self, hex: &str) -> error::Result<()> {
|
||||||
|
self.scroll_bg_colour = convert_hex_to_color(hex)?;
|
||||||
|
self.scroll_entry_style = Style::default()
|
||||||
|
.fg(self.scroll_text_colour)
|
||||||
|
.bg(self.scroll_bg_colour);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Painter {
|
impl Painter {
|
||||||
|
@ -208,10 +335,12 @@ impl Painter {
|
||||||
Paragraph::new(HELP_TEXT.iter())
|
Paragraph::new(HELP_TEXT.iter())
|
||||||
.block(
|
.block(
|
||||||
Block::default()
|
Block::default()
|
||||||
.title("Help (Press Esc to close)")
|
.title(" Help (Press Esc to close) ")
|
||||||
|
.title_style(self.colours.text_style)
|
||||||
|
.style(self.colours.border_style)
|
||||||
.borders(Borders::ALL),
|
.borders(Borders::ALL),
|
||||||
)
|
)
|
||||||
.style(Style::default().fg(Color::Gray))
|
.style(Style::default().fg(self.colours.text_colour))
|
||||||
.alignment(Alignment::Left)
|
.alignment(Alignment::Left)
|
||||||
.wrap(true)
|
.wrap(true)
|
||||||
.render(&mut f, middle_dialog_chunk[1]);
|
.render(&mut f, middle_dialog_chunk[1]);
|
||||||
|
@ -251,10 +380,12 @@ impl Painter {
|
||||||
Paragraph::new(dd_text.iter())
|
Paragraph::new(dd_text.iter())
|
||||||
.block(
|
.block(
|
||||||
Block::default()
|
Block::default()
|
||||||
.title("Kill Process Error (Press Esc to close)")
|
.title(" Kill Process Error (Press Esc to close) ")
|
||||||
|
.title_style(self.colours.text_style)
|
||||||
|
.style(self.colours.border_style)
|
||||||
.borders(Borders::ALL),
|
.borders(Borders::ALL),
|
||||||
)
|
)
|
||||||
.style(Style::default().fg(Color::Gray))
|
.style(Style::default().fg(self.colours.text_colour))
|
||||||
.alignment(Alignment::Center)
|
.alignment(Alignment::Center)
|
||||||
.wrap(true)
|
.wrap(true)
|
||||||
.render(&mut f, middle_dialog_chunk[1]);
|
.render(&mut f, middle_dialog_chunk[1]);
|
||||||
|
@ -279,10 +410,12 @@ impl Painter {
|
||||||
Paragraph::new(dd_text.iter())
|
Paragraph::new(dd_text.iter())
|
||||||
.block(
|
.block(
|
||||||
Block::default()
|
Block::default()
|
||||||
.title("Kill Process Confirmation (Press Esc to close)")
|
.title(" Kill Process Confirmation (Press Esc to close) ")
|
||||||
|
.title_style(self.colours.text_style)
|
||||||
|
.style(self.colours.border_style)
|
||||||
.borders(Borders::ALL),
|
.borders(Borders::ALL),
|
||||||
)
|
)
|
||||||
.style(Style::default().fg(Color::Gray))
|
.style(Style::default().fg(self.colours.text_colour))
|
||||||
.alignment(Alignment::Center)
|
.alignment(Alignment::Center)
|
||||||
.wrap(true)
|
.wrap(true)
|
||||||
.render(&mut f, middle_dialog_chunk[1]);
|
.render(&mut f, middle_dialog_chunk[1]);
|
||||||
|
@ -423,11 +556,10 @@ impl Painter {
|
||||||
let cpu_data: &[ConvertedCpuData] = &app_state.canvas_data.cpu_data;
|
let cpu_data: &[ConvertedCpuData] = &app_state.canvas_data.cpu_data;
|
||||||
|
|
||||||
// CPU usage graph
|
// CPU usage graph
|
||||||
let x_axis: Axis<String> = Axis::default()
|
let x_axis: Axis<String> = Axis::default().bounds([0.0, TIME_STARTS_FROM as f64]);
|
||||||
.style(Style::default().fg(GRAPH_COLOUR))
|
|
||||||
.bounds([0.0, constants::TIME_STARTS_FROM as f64]);
|
|
||||||
let y_axis = Axis::default()
|
let y_axis = Axis::default()
|
||||||
.style(Style::default().fg(GRAPH_COLOUR))
|
.style(self.colours.text_style)
|
||||||
|
.labels_style(self.colours.text_style)
|
||||||
.bounds([-0.5, 100.5])
|
.bounds([-0.5, 100.5])
|
||||||
.labels(&["0%", "100%"]);
|
.labels(&["0%", "100%"]);
|
||||||
|
|
||||||
|
@ -436,7 +568,7 @@ impl Painter {
|
||||||
|
|
||||||
for (i, cpu) in cpu_data.iter().enumerate() {
|
for (i, cpu) in cpu_data.iter().enumerate() {
|
||||||
cpu_entries_vec.push((
|
cpu_entries_vec.push((
|
||||||
Style::default().fg(COLOUR_LIST[(i) % COLOUR_LIST.len()]),
|
Style::default().fg(self.colours.cpu_colours[(i) % self.colours.cpu_colours.len()]),
|
||||||
cpu.cpu_data
|
cpu.cpu_data
|
||||||
.iter()
|
.iter()
|
||||||
.map(<(f64, f64)>::from)
|
.map(<(f64, f64)>::from)
|
||||||
|
@ -447,7 +579,7 @@ impl Painter {
|
||||||
if app_state.show_average_cpu {
|
if app_state.show_average_cpu {
|
||||||
if let Some(avg_cpu_entry) = cpu_data.first() {
|
if let Some(avg_cpu_entry) = cpu_data.first() {
|
||||||
cpu_entries_vec.push((
|
cpu_entries_vec.push((
|
||||||
Style::default().fg(COLOUR_LIST[0]),
|
Style::default().fg(self.colours.cpu_colours[0]),
|
||||||
avg_cpu_entry
|
avg_cpu_entry
|
||||||
.cpu_data
|
.cpu_data
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -473,11 +605,12 @@ impl Painter {
|
||||||
Chart::default()
|
Chart::default()
|
||||||
.block(
|
.block(
|
||||||
Block::default()
|
Block::default()
|
||||||
.title("CPU")
|
.title(" CPU ")
|
||||||
|
.title_style(self.colours.text_style)
|
||||||
.borders(Borders::ALL)
|
.borders(Borders::ALL)
|
||||||
.border_style(match app_state.current_widget_selected {
|
.border_style(match app_state.current_widget_selected {
|
||||||
app::WidgetPosition::Cpu => *CANVAS_HIGHLIGHTED_BORDER_STYLE,
|
app::WidgetPosition::Cpu => self.colours.highlighted_border_style,
|
||||||
_ => *CANVAS_BORDER_STYLE,
|
_ => self.colours.border_style,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.x_axis(x_axis)
|
.x_axis(x_axis)
|
||||||
|
@ -525,15 +658,18 @@ impl Painter {
|
||||||
== app_state.currently_selected_cpu_table_position - start_position
|
== app_state.currently_selected_cpu_table_position - start_position
|
||||||
{
|
{
|
||||||
cpu_row_counter = -1;
|
cpu_row_counter = -1;
|
||||||
Style::default().fg(Color::Black).bg(Color::Cyan)
|
self.colours.scroll_entry_style
|
||||||
} else {
|
} else {
|
||||||
if cpu_row_counter >= 0 {
|
if cpu_row_counter >= 0 {
|
||||||
cpu_row_counter += 1;
|
cpu_row_counter += 1;
|
||||||
}
|
}
|
||||||
Style::default().fg(COLOUR_LIST[itx % COLOUR_LIST.len()])
|
Style::default()
|
||||||
|
.fg(self.colours.cpu_colours
|
||||||
|
[itx % self.colours.cpu_colours.len()])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => Style::default().fg(COLOUR_LIST[itx % COLOUR_LIST.len()]),
|
_ => Style::default()
|
||||||
|
.fg(self.colours.cpu_colours[itx % self.colours.cpu_colours.len()]),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
@ -549,11 +685,11 @@ impl Painter {
|
||||||
Table::new(CPU_LEGEND_HEADER.iter(), cpu_rows)
|
Table::new(CPU_LEGEND_HEADER.iter(), cpu_rows)
|
||||||
.block(Block::default().borders(Borders::ALL).border_style(
|
.block(Block::default().borders(Borders::ALL).border_style(
|
||||||
match app_state.current_widget_selected {
|
match app_state.current_widget_selected {
|
||||||
app::WidgetPosition::Cpu => *CANVAS_HIGHLIGHTED_BORDER_STYLE,
|
app::WidgetPosition::Cpu => self.colours.highlighted_border_style,
|
||||||
_ => *CANVAS_BORDER_STYLE,
|
_ => self.colours.border_style,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
.header_style(Style::default().fg(TABLE_HEADER_COLOUR))
|
.header_style(Style::default().fg(self.colours.table_header_colour))
|
||||||
.widths(
|
.widths(
|
||||||
&(intrinsic_widths
|
&(intrinsic_widths
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -569,13 +705,12 @@ impl 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 x_axis: Axis<String> = Axis::default()
|
let x_axis: Axis<String> = Axis::default().bounds([0.0, TIME_STARTS_FROM as f64]);
|
||||||
.style(Style::default().fg(GRAPH_COLOUR))
|
|
||||||
.bounds([0.0, constants::TIME_STARTS_FROM as f64]);
|
|
||||||
|
|
||||||
// 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<&str> = Axis::default()
|
||||||
.style(Style::default().fg(GRAPH_COLOUR))
|
.style(self.colours.text_style)
|
||||||
|
.labels_style(self.colours.text_style)
|
||||||
.bounds([-0.5, 100.5])
|
.bounds([-0.5, 100.5])
|
||||||
.labels(&["0%", "100%"]);
|
.labels(&["0%", "100%"]);
|
||||||
|
|
||||||
|
@ -586,7 +721,7 @@ impl Painter {
|
||||||
} else {
|
} else {
|
||||||
Marker::Braille
|
Marker::Braille
|
||||||
})
|
})
|
||||||
.style(Style::default().fg(COLOUR_LIST[0]))
|
.style(Style::default().fg(self.colours.ram_colour))
|
||||||
.data(&mem_data)];
|
.data(&mem_data)];
|
||||||
|
|
||||||
if !(&swap_data).is_empty() {
|
if !(&swap_data).is_empty() {
|
||||||
|
@ -598,7 +733,7 @@ impl Painter {
|
||||||
} else {
|
} else {
|
||||||
Marker::Braille
|
Marker::Braille
|
||||||
})
|
})
|
||||||
.style(Style::default().fg(COLOUR_LIST[1]))
|
.style(Style::default().fg(self.colours.swap_colour))
|
||||||
.data(&swap_data),
|
.data(&swap_data),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -606,11 +741,12 @@ impl Painter {
|
||||||
Chart::default()
|
Chart::default()
|
||||||
.block(
|
.block(
|
||||||
Block::default()
|
Block::default()
|
||||||
.title("Memory")
|
.title(" Memory ")
|
||||||
|
.title_style(self.colours.text_style)
|
||||||
.borders(Borders::ALL)
|
.borders(Borders::ALL)
|
||||||
.border_style(match app_state.current_widget_selected {
|
.border_style(match app_state.current_widget_selected {
|
||||||
app::WidgetPosition::Mem => *CANVAS_HIGHLIGHTED_BORDER_STYLE,
|
app::WidgetPosition::Mem => self.colours.highlighted_border_style,
|
||||||
_ => *CANVAS_BORDER_STYLE,
|
_ => self.colours.border_style,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.x_axis(x_axis)
|
.x_axis(x_axis)
|
||||||
|
@ -625,21 +761,21 @@ impl 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 x_axis: Axis<String> = Axis::default()
|
let x_axis: Axis<String> = Axis::default().bounds([0.0, 60_000.0]);
|
||||||
.style(Style::default().fg(GRAPH_COLOUR))
|
|
||||||
.bounds([0.0, 60_000.0]);
|
|
||||||
let y_axis = Axis::default()
|
let y_axis = Axis::default()
|
||||||
.style(Style::default().fg(GRAPH_COLOUR))
|
.style(self.colours.text_style)
|
||||||
|
.labels_style(self.colours.text_style)
|
||||||
.bounds([-0.5, 30_f64])
|
.bounds([-0.5, 30_f64])
|
||||||
.labels(&["0B", "1KiB", "1MiB", "1GiB"]);
|
.labels(&["0B", "1KiB", "1MiB", "1GiB"]);
|
||||||
Chart::default()
|
Chart::default()
|
||||||
.block(
|
.block(
|
||||||
Block::default()
|
Block::default()
|
||||||
.title("Network")
|
.title(" Network ")
|
||||||
|
.title_style(self.colours.text_style)
|
||||||
.borders(Borders::ALL)
|
.borders(Borders::ALL)
|
||||||
.border_style(match app_state.current_widget_selected {
|
.border_style(match app_state.current_widget_selected {
|
||||||
app::WidgetPosition::Network => *CANVAS_HIGHLIGHTED_BORDER_STYLE,
|
app::WidgetPosition::Network => self.colours.highlighted_border_style,
|
||||||
_ => *CANVAS_BORDER_STYLE,
|
_ => self.colours.border_style,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.x_axis(x_axis)
|
.x_axis(x_axis)
|
||||||
|
@ -652,7 +788,7 @@ impl Painter {
|
||||||
} else {
|
} else {
|
||||||
Marker::Braille
|
Marker::Braille
|
||||||
})
|
})
|
||||||
.style(Style::default().fg(COLOUR_LIST[0]))
|
.style(Style::default().fg(self.colours.rx_colour))
|
||||||
.data(&network_data_rx),
|
.data(&network_data_rx),
|
||||||
Dataset::default()
|
Dataset::default()
|
||||||
.name("TX")
|
.name("TX")
|
||||||
|
@ -661,7 +797,7 @@ impl Painter {
|
||||||
} else {
|
} else {
|
||||||
Marker::Braille
|
Marker::Braille
|
||||||
})
|
})
|
||||||
.style(Style::default().fg(COLOUR_LIST[1]))
|
.style(Style::default().fg(self.colours.tx_colour))
|
||||||
.data(&network_data_tx),
|
.data(&network_data_tx),
|
||||||
])
|
])
|
||||||
.render(f, draw_loc);
|
.render(f, draw_loc);
|
||||||
|
@ -686,7 +822,9 @@ impl Painter {
|
||||||
} else {
|
} else {
|
||||||
vec![vec![rx_display, tx_display]]
|
vec![vec![rx_display, tx_display]]
|
||||||
};
|
};
|
||||||
let mapped_network = total_network.iter().map(|val| Row::Data(val.iter()));
|
let mapped_network = total_network
|
||||||
|
.iter()
|
||||||
|
.map(|val| Row::StyledData(val.iter(), self.colours.text_style));
|
||||||
|
|
||||||
// Calculate widths
|
// Calculate widths
|
||||||
let width_ratios: Vec<f64>;
|
let width_ratios: Vec<f64>;
|
||||||
|
@ -716,11 +854,12 @@ impl Painter {
|
||||||
)
|
)
|
||||||
.block(Block::default().borders(Borders::ALL).border_style(
|
.block(Block::default().borders(Borders::ALL).border_style(
|
||||||
match app_state.current_widget_selected {
|
match app_state.current_widget_selected {
|
||||||
app::WidgetPosition::Network => *CANVAS_HIGHLIGHTED_BORDER_STYLE,
|
app::WidgetPosition::Network => self.colours.highlighted_border_style,
|
||||||
_ => *CANVAS_BORDER_STYLE,
|
_ => self.colours.border_style,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
.header_style(Style::default().fg(TABLE_HEADER_COLOUR))
|
.header_style(Style::default().fg(self.colours.table_header_colour))
|
||||||
|
.style(Style::default().fg(self.colours.text_colour))
|
||||||
.widths(
|
.widths(
|
||||||
&(intrinsic_widths
|
&(intrinsic_widths
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -755,15 +894,15 @@ impl Painter {
|
||||||
== app_state.currently_selected_temperature_position - start_position
|
== app_state.currently_selected_temperature_position - start_position
|
||||||
{
|
{
|
||||||
temp_row_counter = -1;
|
temp_row_counter = -1;
|
||||||
Style::default().fg(Color::Black).bg(Color::Cyan)
|
self.colours.scroll_entry_style
|
||||||
} else {
|
} else {
|
||||||
if temp_row_counter >= 0 {
|
if temp_row_counter >= 0 {
|
||||||
temp_row_counter += 1;
|
temp_row_counter += 1;
|
||||||
}
|
}
|
||||||
Style::default().fg(TEXT_COLOUR)
|
Style::default().fg(self.colours.text_colour)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => Style::default().fg(TEXT_COLOUR),
|
_ => Style::default().fg(self.colours.text_colour),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
@ -779,14 +918,15 @@ impl Painter {
|
||||||
Table::new(TEMP_HEADERS.iter(), temperature_rows)
|
Table::new(TEMP_HEADERS.iter(), temperature_rows)
|
||||||
.block(
|
.block(
|
||||||
Block::default()
|
Block::default()
|
||||||
.title("Temperatures")
|
.title(" Temperatures ")
|
||||||
|
.title_style(self.colours.text_style)
|
||||||
.borders(Borders::ALL)
|
.borders(Borders::ALL)
|
||||||
.border_style(match app_state.current_widget_selected {
|
.border_style(match app_state.current_widget_selected {
|
||||||
app::WidgetPosition::Temp => *CANVAS_HIGHLIGHTED_BORDER_STYLE,
|
app::WidgetPosition::Temp => self.colours.highlighted_border_style,
|
||||||
_ => *CANVAS_BORDER_STYLE,
|
_ => self.colours.border_style,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.header_style(Style::default().fg(TABLE_HEADER_COLOUR))
|
.header_style(Style::default().fg(self.colours.table_header_colour))
|
||||||
.widths(
|
.widths(
|
||||||
&(intrinsic_widths
|
&(intrinsic_widths
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -820,21 +960,21 @@ impl Painter {
|
||||||
== app_state.currently_selected_disk_position - start_position
|
== app_state.currently_selected_disk_position - start_position
|
||||||
{
|
{
|
||||||
disk_counter = -1;
|
disk_counter = -1;
|
||||||
Style::default().fg(Color::Black).bg(Color::Cyan)
|
self.colours.scroll_entry_style
|
||||||
} else {
|
} else {
|
||||||
if disk_counter >= 0 {
|
if disk_counter >= 0 {
|
||||||
disk_counter += 1;
|
disk_counter += 1;
|
||||||
}
|
}
|
||||||
Style::default().fg(TEXT_COLOUR)
|
Style::default().fg(self.colours.text_colour)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => Style::default().fg(TEXT_COLOUR),
|
_ => Style::default().fg(self.colours.text_colour),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
// Calculate widths
|
// Calculate widths
|
||||||
// TODO: Ellipsis on strings?
|
// TODO: [PRETTY] Ellipsis on strings?
|
||||||
let width = f64::from(draw_loc.width);
|
let width = f64::from(draw_loc.width);
|
||||||
let width_ratios = [0.2, 0.15, 0.13, 0.13, 0.13, 0.13, 0.13];
|
let width_ratios = [0.2, 0.15, 0.13, 0.13, 0.13, 0.13, 0.13];
|
||||||
let variable_intrinsic_results =
|
let variable_intrinsic_results =
|
||||||
|
@ -845,14 +985,15 @@ impl Painter {
|
||||||
Table::new(DISK_HEADERS.iter(), disk_rows)
|
Table::new(DISK_HEADERS.iter(), disk_rows)
|
||||||
.block(
|
.block(
|
||||||
Block::default()
|
Block::default()
|
||||||
.title("Disk")
|
.title(" Disk ")
|
||||||
|
.title_style(self.colours.text_style)
|
||||||
.borders(Borders::ALL)
|
.borders(Borders::ALL)
|
||||||
.border_style(match app_state.current_widget_selected {
|
.border_style(match app_state.current_widget_selected {
|
||||||
app::WidgetPosition::Disk => *CANVAS_HIGHLIGHTED_BORDER_STYLE,
|
app::WidgetPosition::Disk => self.colours.highlighted_border_style,
|
||||||
_ => *CANVAS_BORDER_STYLE,
|
_ => self.colours.border_style,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.header_style(Style::default().fg(TABLE_HEADER_COLOUR))
|
.header_style(Style::default().fg(self.colours.table_header_colour))
|
||||||
.widths(
|
.widths(
|
||||||
&(intrinsic_widths
|
&(intrinsic_widths
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -875,89 +1016,101 @@ impl Painter {
|
||||||
|
|
||||||
let cursor_position = app_state.get_cursor_position();
|
let cursor_position = app_state.get_cursor_position();
|
||||||
|
|
||||||
let query_with_cursor: Vec<Text> =
|
let query_with_cursor: Vec<Text> = if let app::WidgetPosition::ProcessSearch =
|
||||||
if let app::WidgetPosition::ProcessSearch = app_state.current_widget_selected {
|
app_state.current_widget_selected
|
||||||
if cursor_position >= query.len() {
|
{
|
||||||
let mut q = vec![Text::styled(
|
if cursor_position >= query.len() {
|
||||||
shrunk_query.to_string(),
|
let mut q = vec![Text::styled(
|
||||||
Style::default().fg(TEXT_COLOUR),
|
|
||||||
)];
|
|
||||||
|
|
||||||
q.push(Text::styled(
|
|
||||||
" ".to_string(),
|
|
||||||
Style::default().fg(TEXT_COLOUR).bg(TABLE_HEADER_COLOUR),
|
|
||||||
));
|
|
||||||
|
|
||||||
q
|
|
||||||
} else {
|
|
||||||
shrunk_query
|
|
||||||
.chars()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(itx, c)| {
|
|
||||||
if let app::WidgetPosition::ProcessSearch =
|
|
||||||
app_state.current_widget_selected
|
|
||||||
{
|
|
||||||
if itx == cursor_position {
|
|
||||||
return Text::styled(
|
|
||||||
c.to_string(),
|
|
||||||
Style::default().fg(TEXT_COLOUR).bg(TABLE_HEADER_COLOUR),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Text::styled(c.to_string(), Style::default().fg(TEXT_COLOUR))
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
vec![Text::styled(
|
|
||||||
shrunk_query.to_string(),
|
shrunk_query.to_string(),
|
||||||
Style::default().fg(TEXT_COLOUR),
|
Style::default().fg(self.colours.text_colour),
|
||||||
)]
|
)];
|
||||||
};
|
|
||||||
|
q.push(Text::styled(
|
||||||
|
" ".to_string(),
|
||||||
|
Style::default().bg(self.colours.cursor_colour),
|
||||||
|
));
|
||||||
|
|
||||||
|
q
|
||||||
|
} else {
|
||||||
|
shrunk_query
|
||||||
|
.chars()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(itx, c)| {
|
||||||
|
if let app::WidgetPosition::ProcessSearch =
|
||||||
|
app_state.current_widget_selected
|
||||||
|
{
|
||||||
|
if itx == cursor_position {
|
||||||
|
return Text::styled(
|
||||||
|
c.to_string(),
|
||||||
|
Style::default()
|
||||||
|
.fg(self.colours.text_colour)
|
||||||
|
.bg(self.colours.table_header_colour),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Text::styled(c.to_string(), Style::default().fg(self.colours.text_colour))
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
vec![Text::styled(
|
||||||
|
shrunk_query.to_string(),
|
||||||
|
Style::default().fg(self.colours.text_colour),
|
||||||
|
)]
|
||||||
|
};
|
||||||
|
|
||||||
let mut search_text = vec![if app_state.search_state.is_searching_with_pid() {
|
let mut search_text = vec![if app_state.search_state.is_searching_with_pid() {
|
||||||
Text::styled(
|
Text::styled(
|
||||||
"Search by PID (Tab for Name): ",
|
"Search by PID (Tab for Name): ",
|
||||||
Style::default().fg(TABLE_HEADER_COLOUR),
|
Style::default().fg(self.colours.table_header_colour),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Text::styled(
|
Text::styled(
|
||||||
"Search by Name (Tab for PID): ",
|
"Search by Name (Tab for PID): ",
|
||||||
Style::default().fg(TABLE_HEADER_COLOUR),
|
Style::default().fg(self.colours.table_header_colour),
|
||||||
)
|
)
|
||||||
}];
|
}];
|
||||||
|
|
||||||
// Text options shamelessly stolen from VS Code.
|
// Text options shamelessly stolen from VS Code.
|
||||||
let option_text = vec![
|
let option_text = vec![
|
||||||
Text::styled("\n\n", Style::default().fg(TABLE_HEADER_COLOUR)),
|
Text::styled(
|
||||||
|
"\n\n",
|
||||||
|
Style::default().fg(self.colours.table_header_colour),
|
||||||
|
),
|
||||||
Text::styled(
|
Text::styled(
|
||||||
"Match Case (Alt+C)",
|
"Match Case (Alt+C)",
|
||||||
Style::default().fg(TABLE_HEADER_COLOUR),
|
Style::default().fg(self.colours.table_header_colour),
|
||||||
),
|
),
|
||||||
if !app_state.search_state.is_ignoring_case() {
|
if !app_state.search_state.is_ignoring_case() {
|
||||||
Text::styled("[*]", Style::default().fg(TABLE_HEADER_COLOUR))
|
Text::styled("[*]", Style::default().fg(self.colours.table_header_colour))
|
||||||
} else {
|
} else {
|
||||||
Text::styled("[ ]", Style::default().fg(TABLE_HEADER_COLOUR))
|
Text::styled("[ ]", Style::default().fg(self.colours.table_header_colour))
|
||||||
},
|
},
|
||||||
Text::styled(" ", Style::default().fg(TABLE_HEADER_COLOUR)),
|
Text::styled(
|
||||||
|
" ",
|
||||||
|
Style::default().fg(self.colours.table_header_colour),
|
||||||
|
),
|
||||||
Text::styled(
|
Text::styled(
|
||||||
"Match Whole Word (Alt+W)",
|
"Match Whole Word (Alt+W)",
|
||||||
Style::default().fg(TABLE_HEADER_COLOUR),
|
Style::default().fg(self.colours.table_header_colour),
|
||||||
),
|
),
|
||||||
if app_state.search_state.is_searching_whole_word() {
|
if app_state.search_state.is_searching_whole_word() {
|
||||||
Text::styled("[*]", Style::default().fg(TABLE_HEADER_COLOUR))
|
Text::styled("[*]", Style::default().fg(self.colours.table_header_colour))
|
||||||
} else {
|
} else {
|
||||||
Text::styled("[ ]", Style::default().fg(TABLE_HEADER_COLOUR))
|
Text::styled("[ ]", Style::default().fg(self.colours.table_header_colour))
|
||||||
},
|
},
|
||||||
Text::styled(" ", Style::default().fg(TABLE_HEADER_COLOUR)),
|
Text::styled(
|
||||||
|
" ",
|
||||||
|
Style::default().fg(self.colours.table_header_colour),
|
||||||
|
),
|
||||||
Text::styled(
|
Text::styled(
|
||||||
"Use Regex (Alt+R)",
|
"Use Regex (Alt+R)",
|
||||||
Style::default().fg(TABLE_HEADER_COLOUR),
|
Style::default().fg(self.colours.table_header_colour),
|
||||||
),
|
),
|
||||||
if app_state.search_state.is_searching_with_regex() {
|
if app_state.search_state.is_searching_with_regex() {
|
||||||
Text::styled("[*]", Style::default().fg(TABLE_HEADER_COLOUR))
|
Text::styled("[*]", Style::default().fg(self.colours.table_header_colour))
|
||||||
} else {
|
} else {
|
||||||
Text::styled("[ ]", Style::default().fg(TABLE_HEADER_COLOUR))
|
Text::styled("[ ]", Style::default().fg(self.colours.table_header_colour))
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -970,12 +1123,12 @@ impl Painter {
|
||||||
Style::default().fg(Color::Red)
|
Style::default().fg(Color::Red)
|
||||||
} else {
|
} else {
|
||||||
match app_state.current_widget_selected {
|
match app_state.current_widget_selected {
|
||||||
app::WidgetPosition::ProcessSearch => *CANVAS_HIGHLIGHTED_BORDER_STYLE,
|
app::WidgetPosition::ProcessSearch => self.colours.highlighted_border_style,
|
||||||
_ => *CANVAS_BORDER_STYLE,
|
_ => self.colours.border_style,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
.style(Style::default().fg(Color::Gray))
|
.style(Style::default().fg(self.colours.text_colour))
|
||||||
.alignment(Alignment::Left)
|
.alignment(Alignment::Left)
|
||||||
.wrap(false)
|
.wrap(false)
|
||||||
.render(f, draw_loc);
|
.render(f, draw_loc);
|
||||||
|
@ -1033,15 +1186,15 @@ impl Painter {
|
||||||
== app_state.currently_selected_process_position - start_position
|
== app_state.currently_selected_process_position - start_position
|
||||||
{
|
{
|
||||||
process_counter = -1;
|
process_counter = -1;
|
||||||
Style::default().fg(Color::Black).bg(Color::Cyan)
|
self.colours.scroll_entry_style
|
||||||
} else {
|
} else {
|
||||||
if process_counter >= 0 {
|
if process_counter >= 0 {
|
||||||
process_counter += 1;
|
process_counter += 1;
|
||||||
}
|
}
|
||||||
Style::default().fg(TEXT_COLOUR)
|
Style::default().fg(self.colours.text_colour)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => Style::default().fg(TEXT_COLOUR),
|
_ => Style::default().fg(self.colours.text_colour),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
@ -1086,14 +1239,15 @@ impl Painter {
|
||||||
Table::new(process_headers.iter(), process_rows)
|
Table::new(process_headers.iter(), process_rows)
|
||||||
.block(
|
.block(
|
||||||
Block::default()
|
Block::default()
|
||||||
.title("Processes")
|
.title(" Processes ")
|
||||||
|
.title_style(self.colours.text_style)
|
||||||
.borders(Borders::ALL)
|
.borders(Borders::ALL)
|
||||||
.border_style(match app_state.current_widget_selected {
|
.border_style(match app_state.current_widget_selected {
|
||||||
app::WidgetPosition::Process => *CANVAS_HIGHLIGHTED_BORDER_STYLE,
|
app::WidgetPosition::Process => self.colours.highlighted_border_style,
|
||||||
_ => *CANVAS_BORDER_STYLE,
|
_ => self.colours.border_style,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.header_style(Style::default().fg(TABLE_HEADER_COLOUR))
|
.header_style(Style::default().fg(self.colours.table_header_colour))
|
||||||
.widths(
|
.widths(
|
||||||
&(intrinsic_widths
|
&(intrinsic_widths
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
183
src/main.rs
183
src/main.rs
|
@ -57,6 +57,12 @@ enum ResetEvent {
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct Config {
|
struct Config {
|
||||||
|
flags: Option<ConfigFlags>,
|
||||||
|
colors: Option<ConfigColours>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct ConfigFlags {
|
||||||
avg_cpu: Option<bool>,
|
avg_cpu: Option<bool>,
|
||||||
dot_marker: Option<bool>,
|
dot_marker: Option<bool>,
|
||||||
temperature_type: Option<String>,
|
temperature_type: Option<String>,
|
||||||
|
@ -69,6 +75,22 @@ struct Config {
|
||||||
regex: Option<bool>,
|
regex: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct ConfigColours {
|
||||||
|
table_header_color: Option<String>,
|
||||||
|
cpu_core_colors: Option<Vec<String>>,
|
||||||
|
ram_color: Option<String>,
|
||||||
|
swap_color: Option<String>,
|
||||||
|
rx_color: Option<String>,
|
||||||
|
tx_color: Option<String>,
|
||||||
|
border_color: Option<String>,
|
||||||
|
highlighted_border_color: Option<String>,
|
||||||
|
text_color: Option<String>,
|
||||||
|
cursor_color: Option<String>,
|
||||||
|
scroll_entry_text_color: Option<String>,
|
||||||
|
scroll_entry_bg_color: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
fn main() -> error::Result<()> {
|
fn main() -> error::Result<()> {
|
||||||
//Parse command line options
|
//Parse command line options
|
||||||
let matches = clap_app!(app =>
|
let matches = clap_app!(app =>
|
||||||
|
@ -119,8 +141,12 @@ fn main() -> error::Result<()> {
|
||||||
.value_of("RATE_MILLIS")
|
.value_of("RATE_MILLIS")
|
||||||
.unwrap_or(&DEFAULT_REFRESH_RATE_IN_MILLISECONDS.to_string())
|
.unwrap_or(&DEFAULT_REFRESH_RATE_IN_MILLISECONDS.to_string())
|
||||||
.parse::<u128>()?
|
.parse::<u128>()?
|
||||||
} else if let Some(rate) = config_toml.rate {
|
} else if let Some(flags) = &config_toml.flags {
|
||||||
rate as u128
|
if let Some(rate) = flags.rate {
|
||||||
|
rate as u128
|
||||||
|
} else {
|
||||||
|
constants::DEFAULT_REFRESH_RATE_IN_MILLISECONDS
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
constants::DEFAULT_REFRESH_RATE_IN_MILLISECONDS
|
constants::DEFAULT_REFRESH_RATE_IN_MILLISECONDS
|
||||||
};
|
};
|
||||||
|
@ -142,43 +168,63 @@ fn main() -> error::Result<()> {
|
||||||
data_harvester::temperature::TemperatureType::Kelvin
|
data_harvester::temperature::TemperatureType::Kelvin
|
||||||
} else if matches.is_present("CELSIUS") {
|
} else if matches.is_present("CELSIUS") {
|
||||||
data_harvester::temperature::TemperatureType::Celsius
|
data_harvester::temperature::TemperatureType::Celsius
|
||||||
} else if let Some(temp_type) = config_toml.temperature_type {
|
} else if let Some(flags) = &config_toml.flags {
|
||||||
// Give lowest priority to config.
|
if let Some(temp_type) = &flags.temperature_type {
|
||||||
match temp_type.as_str() {
|
// Give lowest priority to config.
|
||||||
"fahrenheit" | "f" => data_harvester::temperature::TemperatureType::Fahrenheit,
|
match temp_type.as_str() {
|
||||||
"kelvin" | "k" => data_harvester::temperature::TemperatureType::Kelvin,
|
"fahrenheit" | "f" => data_harvester::temperature::TemperatureType::Fahrenheit,
|
||||||
"celsius" | "c" => data_harvester::temperature::TemperatureType::Celsius,
|
"kelvin" | "k" => data_harvester::temperature::TemperatureType::Kelvin,
|
||||||
_ => data_harvester::temperature::TemperatureType::Celsius,
|
"celsius" | "c" => data_harvester::temperature::TemperatureType::Celsius,
|
||||||
|
_ => data_harvester::temperature::TemperatureType::Celsius,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data_harvester::temperature::TemperatureType::Celsius
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
data_harvester::temperature::TemperatureType::Celsius
|
data_harvester::temperature::TemperatureType::Celsius
|
||||||
};
|
};
|
||||||
let show_average_cpu = if matches.is_present("AVG_CPU") {
|
let show_average_cpu = if matches.is_present("AVG_CPU") {
|
||||||
true
|
true
|
||||||
} else if let Some(avg_cpu) = config_toml.avg_cpu {
|
} else if let Some(flags) = &config_toml.flags {
|
||||||
avg_cpu
|
if let Some(avg_cpu) = flags.avg_cpu {
|
||||||
|
avg_cpu
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
let use_dot = if matches.is_present("DOT_MARKER") {
|
let use_dot = if matches.is_present("DOT_MARKER") {
|
||||||
true
|
true
|
||||||
} else if let Some(dot_marker) = config_toml.dot_marker {
|
} else if let Some(flags) = &config_toml.flags {
|
||||||
dot_marker
|
if let Some(dot_marker) = flags.dot_marker {
|
||||||
|
dot_marker
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
let left_legend = if matches.is_present("LEFT_LEGEND") {
|
let left_legend = if matches.is_present("LEFT_LEGEND") {
|
||||||
true
|
true
|
||||||
} else if let Some(left_legend) = config_toml.left_legend {
|
} else if let Some(flags) = &config_toml.flags {
|
||||||
left_legend
|
if let Some(left_legend) = flags.left_legend {
|
||||||
|
left_legend
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
let use_current_cpu_total = if matches.is_present("USE_CURR_USAGE") {
|
let use_current_cpu_total = if matches.is_present("USE_CURR_USAGE") {
|
||||||
true
|
true
|
||||||
} else if let Some(current_usage) = config_toml.current_usage {
|
} else if let Some(flags) = &config_toml.flags {
|
||||||
current_usage
|
if let Some(current_usage) = flags.current_usage {
|
||||||
|
current_usage
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
|
@ -196,34 +242,42 @@ fn main() -> error::Result<()> {
|
||||||
// Enable grouping immediately if set.
|
// Enable grouping immediately if set.
|
||||||
if matches.is_present("GROUP_PROCESSES") {
|
if matches.is_present("GROUP_PROCESSES") {
|
||||||
app.toggle_grouping();
|
app.toggle_grouping();
|
||||||
} else if let Some(grouping) = config_toml.group_processes {
|
} else if let Some(flags) = &config_toml.flags {
|
||||||
if grouping {
|
if let Some(grouping) = flags.group_processes {
|
||||||
app.toggle_grouping();
|
if grouping {
|
||||||
|
app.toggle_grouping();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set default search method
|
// Set default search method
|
||||||
if matches.is_present("CASE_SENSITIVE") {
|
if matches.is_present("CASE_SENSITIVE") {
|
||||||
app.search_state.toggle_ignore_case();
|
app.search_state.toggle_ignore_case();
|
||||||
} else if let Some(case_sensitive) = config_toml.case_sensitive {
|
} else if let Some(flags) = &config_toml.flags {
|
||||||
if case_sensitive {
|
if let Some(case_sensitive) = flags.case_sensitive {
|
||||||
app.search_state.toggle_ignore_case();
|
if case_sensitive {
|
||||||
|
app.search_state.toggle_ignore_case();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if matches.is_present("WHOLE_WORD") {
|
if matches.is_present("WHOLE_WORD") {
|
||||||
app.search_state.toggle_search_whole_word();
|
app.search_state.toggle_search_whole_word();
|
||||||
} else if let Some(whole_word) = config_toml.whole_word {
|
} else if let Some(flags) = &config_toml.flags {
|
||||||
if whole_word {
|
if let Some(whole_word) = flags.whole_word {
|
||||||
app.search_state.toggle_search_whole_word();
|
if whole_word {
|
||||||
|
app.search_state.toggle_search_whole_word();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if matches.is_present("REGEX_DEFAULT") {
|
if matches.is_present("REGEX_DEFAULT") {
|
||||||
app.search_state.toggle_search_regex();
|
app.search_state.toggle_search_regex();
|
||||||
} else if let Some(regex) = config_toml.regex {
|
} else if let Some(flags) = &config_toml.flags {
|
||||||
if regex {
|
if let Some(regex) = flags.regex {
|
||||||
app.search_state.toggle_search_regex();
|
if regex {
|
||||||
|
app.search_state.toggle_search_regex();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,6 +366,13 @@ fn main() -> error::Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut painter = canvas::Painter::default();
|
let mut painter = canvas::Painter::default();
|
||||||
|
if let Err(config_check) = generate_config_colours(&config_toml, &mut painter) {
|
||||||
|
cleanup_terminal(&mut terminal)?;
|
||||||
|
return Err(config_check);
|
||||||
|
}
|
||||||
|
|
||||||
|
painter.colours.generate_remaining_cpu_colours();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// TODO: [OPT] this should not block...
|
// TODO: [OPT] this should not block...
|
||||||
if let Ok(recv) = rx.recv_timeout(Duration::from_millis(TICK_RATE_IN_MILLISECONDS)) {
|
if let Ok(recv) = rx.recv_timeout(Duration::from_millis(TICK_RATE_IN_MILLISECONDS)) {
|
||||||
|
@ -485,6 +546,70 @@ fn cleanup_terminal(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn generate_config_colours(
|
||||||
|
config_toml: &Config, painter: &mut canvas::Painter,
|
||||||
|
) -> error::Result<()> {
|
||||||
|
if let Some(colours) = &config_toml.colors {
|
||||||
|
if let Some(border_color) = &colours.border_color {
|
||||||
|
painter.colours.set_border_colour(border_color)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(highlighted_border_color) = &colours.highlighted_border_color {
|
||||||
|
painter
|
||||||
|
.colours
|
||||||
|
.set_highlighted_border_colour(highlighted_border_color)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(text_color) = &colours.text_color {
|
||||||
|
painter.colours.set_text_colour(text_color)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(cpu_core_colors) = &(colours.cpu_core_colors) {
|
||||||
|
painter.colours.set_cpu_colours(cpu_core_colors)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ram_color) = &colours.ram_color {
|
||||||
|
painter.colours.set_ram_colour(ram_color)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(swap_color) = &colours.swap_color {
|
||||||
|
painter.colours.set_swap_colour(swap_color)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(rx_color) = &colours.rx_color {
|
||||||
|
painter.colours.set_rx_colour(rx_color)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(tx_color) = &colours.tx_color {
|
||||||
|
painter.colours.set_tx_colour(tx_color)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(cursor_color) = &colours.cursor_color {
|
||||||
|
painter.colours.set_cursor_colour(cursor_color)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(table_header_color) = &colours.table_header_color {
|
||||||
|
painter
|
||||||
|
.colours
|
||||||
|
.set_table_header_colour(table_header_color)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(scroll_entry_text_color) = &colours.scroll_entry_text_color {
|
||||||
|
painter
|
||||||
|
.colours
|
||||||
|
.set_scroll_entry_text_color(scroll_entry_text_color)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(scroll_entry_bg_color) = &colours.scroll_entry_bg_color {
|
||||||
|
painter
|
||||||
|
.colours
|
||||||
|
.set_scroll_entry_bg_color(scroll_entry_bg_color)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Based on https://github.com/Rigellute/spotify-tui/blob/master/src/main.rs
|
/// Based on https://github.com/Rigellute/spotify-tui/blob/master/src/main.rs
|
||||||
fn panic_hook(panic_info: &PanicInfo<'_>) {
|
fn panic_hook(panic_info: &PanicInfo<'_>) {
|
||||||
let mut stdout = stdout();
|
let mut stdout = stdout();
|
||||||
|
|
Loading…
Reference in a new issue