mirror of
https://github.com/ClementTsang/bottom
synced 2024-11-10 14:44:18 +00:00
Update and clean up ? menu... some more work to be done though
This commit is contained in:
parent
b593a29e9c
commit
4ac3a10fbf
9 changed files with 142 additions and 115 deletions
|
@ -23,7 +23,6 @@ lto = true
|
|||
[dependencies]
|
||||
chrono = "0.4.10"
|
||||
clap = "2.33.0"
|
||||
failure = "0.1.6"
|
||||
fern = "0.5.9"
|
||||
futures-timer = "3.0.1"
|
||||
futures = "0.3.3"
|
||||
|
|
|
@ -195,7 +195,6 @@ Note that `q` is disabled while in the search widget.
|
|||
- [chrono](https://github.com/chronotope/chrono)
|
||||
- [clap](https://github.com/clap-rs/clap)
|
||||
- [crossterm](https://github.com/TimonPost/crossterm)
|
||||
- [failure](https://github.com/rust-lang-nursery/failure)
|
||||
- [fern](https://github.com/daboross/fern)
|
||||
- [futures-rs](https://github.com/rust-lang-nursery/futures-rs)
|
||||
- [futures-timer](https://github.com/rustasync/futures-timer)
|
||||
|
@ -204,6 +203,6 @@ Note that `q` is disabled while in the search widget.
|
|||
- [log](https://github.com/rust-lang-nursery/log)
|
||||
- [sysinfo](https://github.com/GuillaumeGomez/sysinfo)
|
||||
- [tokio](https://github.com/tokio-rs/tokio)
|
||||
- [toml-ru](https://github.com/alexcrichton/toml-rs)
|
||||
- [toml-rs](https://github.com/alexcrichton/toml-rs)
|
||||
- [tui-rs](https://github.com/fdehau/tui-rs)
|
||||
- [winapi](https://github.com/retep998/winapi-rs)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[flags]
|
||||
avg_cpu = true
|
||||
dot_marker = true
|
||||
temperature_type = "k"
|
||||
temperature_type = "ke"
|
||||
rate = 1000
|
||||
left_legend = true
|
||||
current_usage = false
|
||||
|
|
|
@ -37,12 +37,10 @@ fn cpu_usage_calculation(
|
|||
|
||||
let split_results = stat_results.split('\n').collect::<Vec<&str>>();
|
||||
if split_results.is_empty() {
|
||||
return Err(error::BottomError::InvalidIO {
|
||||
message: format!(
|
||||
"Unable to properly split the stat results; saw {} values, expected at least 1 value.",
|
||||
split_results.len()
|
||||
),
|
||||
});
|
||||
return Err(error::BottomError::InvalidIO(format!(
|
||||
"Unable to properly split the stat results; saw {} values, expected at least 1 value.",
|
||||
split_results.len()
|
||||
)));
|
||||
} else {
|
||||
first_line = split_results[0];
|
||||
}
|
||||
|
@ -51,12 +49,10 @@ fn cpu_usage_calculation(
|
|||
|
||||
// SC in case that the parsing will fail due to length:
|
||||
if val.len() <= 10 {
|
||||
return Err(error::BottomError::InvalidIO {
|
||||
message: format!(
|
||||
return Err(error::BottomError::InvalidIO(format!(
|
||||
"CPU parsing will fail due to too short of a return value; saw {} values, expected 10 values.",
|
||||
val.len()
|
||||
),
|
||||
});
|
||||
)));
|
||||
}
|
||||
|
||||
let user: f64 = val[1].parse::<_>().unwrap_or(0_f64);
|
||||
|
|
|
@ -42,11 +42,10 @@ pub fn kill_process_given_pid(pid: u32) -> crate::utils::error::Result<()> {
|
|||
process.kill()?;
|
||||
}
|
||||
} else {
|
||||
return Err(BottomError::GenericError {
|
||||
message:
|
||||
"Sorry, support operating systems outside the main three are not implemented yet!"
|
||||
.to_string(),
|
||||
});
|
||||
return Err(BottomError::GenericError(
|
||||
"Sorry, support operating systems outside the main three are not implemented yet!"
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
103
src/canvas.rs
103
src/canvas.rs
|
@ -27,31 +27,78 @@ const WINDOWS_NETWORK_HEADERS: [&str; 4] = ["RX", "TX", "", ""];
|
|||
const FORCE_MIN_THRESHOLD: usize = 5;
|
||||
|
||||
lazy_static! {
|
||||
static ref HELP_TEXT: [Text<'static>; 22] = [
|
||||
Text::raw("\nGeneral Keybindings\n"),
|
||||
Text::raw("q, Ctrl-c to quit. Note if you are currently in the search widget, `q` will not work.\n"),
|
||||
Text::raw("Ctrl-r to reset all data.\n"),
|
||||
Text::raw("f to toggle freezing and unfreezing the display.\n"),
|
||||
Text::raw(
|
||||
"Ctrl/Shift-Up, Ctrl/Shift-Down, Ctrl/Shift-Left, and Ctrl/Shift-Right to navigate between widgets.\n"
|
||||
static ref DEFAULT_TEXT_STYLE: Style = Style::default().fg(Color::Gray);
|
||||
static ref DEFAULT_HEADER_STYLE: Style = Style::default().fg(Color::LightBlue);
|
||||
static ref HELP_TEXT: [Text<'static>; 30] = [
|
||||
Text::styled("\n General Keybindings\n", *DEFAULT_HEADER_STYLE),
|
||||
Text::styled("q, Ctrl-c Quit\n", *DEFAULT_TEXT_STYLE),
|
||||
Text::styled("Ctrl-r Reset all data\n", *DEFAULT_TEXT_STYLE),
|
||||
Text::styled("f Freeze display\n", *DEFAULT_TEXT_STYLE),
|
||||
Text::styled("Ctrl-Arrow Move selected widget\n", *DEFAULT_TEXT_STYLE),
|
||||
Text::styled("Shift-Arrow Move selected widget\n", *DEFAULT_TEXT_STYLE),
|
||||
Text::styled("Up, k Move cursor up\n", *DEFAULT_TEXT_STYLE),
|
||||
Text::styled("Down, j Move cursor down\n", *DEFAULT_TEXT_STYLE),
|
||||
Text::styled("Left, h Move cursor left\n", *DEFAULT_TEXT_STYLE),
|
||||
Text::styled("Right, l Move cursor right\n", *DEFAULT_TEXT_STYLE),
|
||||
Text::styled("Esc Close dialog box\n", *DEFAULT_TEXT_STYLE),
|
||||
Text::styled("? Open the help screen\n", *DEFAULT_TEXT_STYLE),
|
||||
Text::styled(
|
||||
"gg Skip to the first entry of a list\n",
|
||||
*DEFAULT_TEXT_STYLE
|
||||
),
|
||||
Text::raw("Up or k and Down or j scrolls through a list.\n"),
|
||||
Text::raw("Esc to close a dialog window (help or dd confirmation).\n"),
|
||||
Text::raw("? to get this help screen.\n"),
|
||||
Text::raw("\n Process Widget Keybindings\n"),
|
||||
Text::raw("dd to kill the selected process.\n"),
|
||||
Text::raw("c to sort by CPU usage.\n"),
|
||||
Text::raw("m to sort by memory usage.\n"),
|
||||
Text::raw("p to sort by PID.\n"),
|
||||
Text::raw("n to sort by process name.\n"),
|
||||
Text::raw("Tab to group together processes with the same name.\n"),
|
||||
Text::raw("Ctrl-f to toggle searching for a process. / to just open it.\n"),
|
||||
Text::raw("Use Ctrl-p and Ctrl-n to toggle between searching for PID and name.\n"),
|
||||
Text::raw("Use Tab to set the cursor to the start and end of the bar respectively.\n"),
|
||||
Text::raw("Use Alt-c to toggle whether to ignore case.\n"),
|
||||
Text::raw("Use Alt-m to toggle matching the entire word.\n"),
|
||||
Text::raw("Use Alt-r to toggle regex.\n"),
|
||||
Text::raw("\nFor startup flags, type in \"btm -h\".")
|
||||
Text::styled(
|
||||
"G Skip to the last entry of a list\n",
|
||||
*DEFAULT_TEXT_STYLE
|
||||
),
|
||||
Text::styled(
|
||||
"\n Process Keybindings\n",
|
||||
*DEFAULT_HEADER_STYLE
|
||||
),
|
||||
Text::styled(
|
||||
"dd Kill the highlighted process\n",
|
||||
*DEFAULT_TEXT_STYLE
|
||||
),
|
||||
Text::styled("c Sort by CPU usage\n", *DEFAULT_TEXT_STYLE),
|
||||
Text::styled("m Sort by memory usage\n", *DEFAULT_TEXT_STYLE),
|
||||
Text::styled("p Sort by PID\n", *DEFAULT_TEXT_STYLE),
|
||||
Text::styled("n Sort by process name\n", *DEFAULT_TEXT_STYLE),
|
||||
Text::styled(
|
||||
"Tab Group together processes with the same name\n",
|
||||
*DEFAULT_TEXT_STYLE
|
||||
),
|
||||
Text::styled(
|
||||
"Ctrl-f, / Open up the search widget\n",
|
||||
*DEFAULT_TEXT_STYLE
|
||||
),
|
||||
Text::styled("\n Search Keybindings\n", *DEFAULT_HEADER_STYLE),
|
||||
Text::styled(
|
||||
"Tab Toggle between searching for PID and name.\n",
|
||||
*DEFAULT_TEXT_STYLE
|
||||
),
|
||||
Text::styled(
|
||||
"Ctrl-a Skip to the start of search widget\n",
|
||||
*DEFAULT_TEXT_STYLE
|
||||
),
|
||||
Text::styled(
|
||||
"Ctrl-e Skip to the end of search widget\n",
|
||||
*DEFAULT_TEXT_STYLE
|
||||
),
|
||||
Text::styled(
|
||||
"Alt-c Toggle whether to ignore case\n",
|
||||
*DEFAULT_TEXT_STYLE
|
||||
),
|
||||
Text::styled(
|
||||
"Alt-m Toggle whether to match the whole word\n",
|
||||
*DEFAULT_TEXT_STYLE
|
||||
),
|
||||
Text::styled(
|
||||
"Alt-r Toggle whether to use regex\n",
|
||||
*DEFAULT_TEXT_STYLE
|
||||
),
|
||||
Text::styled(
|
||||
"\n For startup flags, type in \"btm -h\".",
|
||||
*DEFAULT_TEXT_STYLE
|
||||
)
|
||||
];
|
||||
static ref DISK_HEADERS_LENS: Vec<usize> = DISK_HEADERS
|
||||
.iter()
|
||||
|
@ -129,9 +176,9 @@ impl Painter {
|
|||
.margin(1)
|
||||
.constraints(
|
||||
[
|
||||
Constraint::Percentage(22),
|
||||
Constraint::Percentage(60),
|
||||
Constraint::Percentage(18),
|
||||
Constraint::Percentage(17),
|
||||
Constraint::Percentage(70),
|
||||
Constraint::Percentage(13),
|
||||
]
|
||||
.as_ref(),
|
||||
)
|
||||
|
@ -153,7 +200,7 @@ impl Painter {
|
|||
Paragraph::new(HELP_TEXT.iter())
|
||||
.block(
|
||||
Block::default()
|
||||
.title(" Help (Press Esc to close) ")
|
||||
.title(" Help ")
|
||||
.title_style(self.colours.widget_title_style)
|
||||
.style(self.colours.border_style)
|
||||
.borders(Borders::ALL),
|
||||
|
|
|
@ -60,12 +60,10 @@ pub fn convert_hex_to_color(hex: &str) -> error::Result<Color> {
|
|||
return Ok((r, g, b));
|
||||
}
|
||||
|
||||
Err(error::BottomError::GenericError {
|
||||
message: format!(
|
||||
Err(error::BottomError::GenericError(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)?;
|
||||
|
|
20
src/main.rs
20
src/main.rs
|
@ -3,8 +3,6 @@ extern crate log;
|
|||
#[macro_use]
|
||||
extern crate clap;
|
||||
#[macro_use]
|
||||
extern crate failure;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
use serde::Deserialize;
|
||||
|
@ -153,13 +151,13 @@ fn main() -> error::Result<()> {
|
|||
};
|
||||
|
||||
if update_rate_in_milliseconds < 250 {
|
||||
return Err(BottomError::InvalidArg {
|
||||
message: "Please set your update rate to be greater than 250 milliseconds.".to_string(),
|
||||
});
|
||||
return Err(BottomError::InvalidArg(
|
||||
"Please set your update rate to be greater than 250 milliseconds.".to_string(),
|
||||
));
|
||||
} else if update_rate_in_milliseconds > u128::from(std::u64::MAX) {
|
||||
return Err(BottomError::InvalidArg {
|
||||
message: "Please set your update rate to be less than unsigned INT_MAX.".to_string(),
|
||||
});
|
||||
return Err(BottomError::InvalidArg(
|
||||
"Please set your update rate to be less than unsigned INT_MAX.".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
// Set other settings
|
||||
|
@ -176,7 +174,11 @@ fn main() -> error::Result<()> {
|
|||
"fahrenheit" | "f" => data_harvester::temperature::TemperatureType::Fahrenheit,
|
||||
"kelvin" | "k" => data_harvester::temperature::TemperatureType::Kelvin,
|
||||
"celsius" | "c" => data_harvester::temperature::TemperatureType::Celsius,
|
||||
_ => data_harvester::temperature::TemperatureType::Celsius,
|
||||
_ => {
|
||||
return Err(BottomError::ConfigError(
|
||||
"Invalid temperature type. Please have the value be of the form <kelvin|k|celsius|c|fahrenheit|f>".to_string()
|
||||
));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
data_harvester::temperature::TemperatureType::Celsius
|
||||
|
|
|
@ -1,102 +1,89 @@
|
|||
use failure::Fail;
|
||||
use std::result;
|
||||
|
||||
/// A type alias for handling errors related to Bottom.
|
||||
pub type Result<T> = result::Result<T, BottomError>;
|
||||
|
||||
/// An error that can occur while Bottom runs.
|
||||
#[derive(Debug, Fail)]
|
||||
#[derive(Debug)]
|
||||
pub enum BottomError {
|
||||
/// An error when there is an IO exception.
|
||||
///
|
||||
/// The data provided is the error found.
|
||||
#[fail(display = "ERROR: Encountered an IO exception: {}", message)]
|
||||
InvalidIO { message: String },
|
||||
InvalidIO(String),
|
||||
/// An error when there is an invalid argument passed in.
|
||||
///
|
||||
/// The data provided is the error found.
|
||||
#[fail(display = "ERROR: Invalid argument: {}", message)]
|
||||
InvalidArg { message: String },
|
||||
InvalidArg(String),
|
||||
/// An error when the heim library encounters a problem.
|
||||
///
|
||||
/// The data provided is the error found.
|
||||
#[fail(
|
||||
display = "ERROR: Invalid error during data collection due to Heim: {}",
|
||||
message
|
||||
)]
|
||||
InvalidHeim { message: String },
|
||||
InvalidHeim(String),
|
||||
/// An error when the Crossterm library encounters a problem.
|
||||
///
|
||||
/// The data provided is the error found.
|
||||
#[fail(display = "ERROR: Invalid error due to Crossterm: {}", message)]
|
||||
CrosstermError { message: String },
|
||||
/// An error to represent generic errors
|
||||
///
|
||||
/// The data provided is the error found.
|
||||
#[fail(display = "ERROR: Invalid generic error: {}", message)]
|
||||
GenericError { message: String },
|
||||
/// An error to represent errors with fern
|
||||
///
|
||||
/// The data provided is the error found.
|
||||
#[fail(display = "ERROR: Invalid fern error: {}", message)]
|
||||
FernError { message: String },
|
||||
/// An error to represent errors with fern
|
||||
///
|
||||
/// The data provided is the error found.
|
||||
#[fail(display = "ERROR: Invalid config file error: {}", message)]
|
||||
ConfigError { message: String },
|
||||
CrosstermError(String),
|
||||
/// An error to represent generic errors.
|
||||
GenericError(String),
|
||||
/// An error to represent errors with fern.
|
||||
FernError(String),
|
||||
/// An error to represent errors with the config.
|
||||
ConfigError(String),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for BottomError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match *self {
|
||||
BottomError::InvalidIO(ref message) => {
|
||||
write!(f, "Encountered an IO exception: {}", message)
|
||||
}
|
||||
BottomError::InvalidArg(ref message) => write!(f, "Invalid argument: {}", message),
|
||||
BottomError::InvalidHeim(ref message) => write!(
|
||||
f,
|
||||
"Invalid error during data collection due to Heim: {}",
|
||||
message
|
||||
),
|
||||
BottomError::CrosstermError(ref message) => {
|
||||
write!(f, "Invalid error due to Crossterm: {}", message)
|
||||
}
|
||||
BottomError::GenericError(ref message) => write!(f, "{}", message),
|
||||
BottomError::FernError(ref message) => write!(f, "Invalid fern error: {}", message),
|
||||
BottomError::ConfigError(ref message) => {
|
||||
write!(f, "Invalid config file error: {}", message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for BottomError {
|
||||
fn from(err: std::io::Error) -> Self {
|
||||
BottomError::InvalidIO {
|
||||
message: err.to_string(),
|
||||
}
|
||||
BottomError::InvalidIO(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<heim::Error> for BottomError {
|
||||
fn from(err: heim::Error) -> Self {
|
||||
BottomError::InvalidHeim {
|
||||
message: err.to_string(),
|
||||
}
|
||||
BottomError::InvalidHeim(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crossterm::ErrorKind> for BottomError {
|
||||
fn from(err: crossterm::ErrorKind) -> Self {
|
||||
BottomError::CrosstermError {
|
||||
message: err.to_string(),
|
||||
}
|
||||
BottomError::CrosstermError(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::num::ParseIntError> for BottomError {
|
||||
fn from(err: std::num::ParseIntError) -> Self {
|
||||
BottomError::InvalidArg {
|
||||
message: err.to_string(),
|
||||
}
|
||||
BottomError::InvalidArg(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::string::String> for BottomError {
|
||||
fn from(err: std::string::String) -> Self {
|
||||
BottomError::GenericError { message: err }
|
||||
BottomError::GenericError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<toml::de::Error> for BottomError {
|
||||
fn from(err: toml::de::Error) -> Self {
|
||||
BottomError::ConfigError {
|
||||
message: err.to_string(),
|
||||
}
|
||||
BottomError::ConfigError(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<fern::InitError> for BottomError {
|
||||
fn from(err: fern::InitError) -> Self {
|
||||
BottomError::FernError {
|
||||
message: err.to_string(),
|
||||
}
|
||||
BottomError::FernError(err.to_string())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue