summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClement Tsang <34804052+ClementTsang@users.noreply.github.com>2020-08-31 23:59:33 -0400
committerGitHub <noreply@github.com>2020-08-31 23:59:33 -0400
commita4ddd649e140e1bc7cab29a53662d4f345f4f1ff (patch)
tree931e2614a77a7351eb7dc2fe6e9c1c734898dff0
parent5ed573157c00a0617c786edde0a241bd75e81666 (diff)
refactor: Update error messages w/ anyhow and thiserror (#216)
Refactoring and updating of error messages + tests to be more useful.
-rwxr-xr-x.cargo-husky/hooks/pre-push2
-rw-r--r--.vscode/settings.json1
-rw-r--r--Cargo.lock28
-rw-r--r--Cargo.toml12
-rw-r--r--README.md2
-rw-r--r--src/app/data_harvester/processes.rs6
-rw-r--r--src/app/layout_manager.rs20
-rw-r--r--src/bin/main.rs13
-rw-r--r--src/canvas/canvas_colours.rs6
-rw-r--r--src/canvas/canvas_colours/colour_utils.rs32
-rw-r--r--src/clap.rs2
-rw-r--r--src/lib.rs95
-rw-r--r--src/options.rs55
-rw-r--r--src/utils/error.rs47
-rw-r--r--tests/arg_tests.rs16
-rw-r--r--tests/invalid_config_tests.rs31
-rw-r--r--tests/invalid_configs/empty_battery.toml2
17 files changed, 240 insertions, 130 deletions
diff --git a/.cargo-husky/hooks/pre-push b/.cargo-husky/hooks/pre-push
new file mode 100755
index 00000000..46fb32d2
--- /dev/null
+++ b/.cargo-husky/hooks/pre-push
@@ -0,0 +1,2 @@
+echo "Running pre-push hook: cargo +nightly clippy -- -D clippy::all"
+cargo +nightly clippy -- -D clippy::all \ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
index d3f49cfa..b5030dc0 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -38,6 +38,7 @@
"curr",
"czvf",
"fpath",
+ "fract",
"gotop",
"gtop",
"haase",
diff --git a/Cargo.lock b/Cargo.lock
index 9c458943..20f2221f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -28,6 +28,12 @@ dependencies = [
]
[[package]]
+name = "anyhow"
+version = "1.0.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b"
+
+[[package]]
name = "arc-swap"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -131,6 +137,7 @@ dependencies = [
name = "bottom"
version = "0.4.7"
dependencies = [
+ "anyhow",
"assert_cmd",
"backtrace",
"battery",
@@ -151,6 +158,7 @@ dependencies = [
"regex",
"serde",
"sysinfo",
+ "thiserror",
"toml",
"tui",
"typed-builder",
@@ -1274,6 +1282,26 @@ dependencies = [
]
[[package]]
+name = "thiserror"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7dfdd070ccd8ccb78f4ad66bf1982dc37f620ef696c6b5028fe2ed83dd3d0d08"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "thread_local"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index ce60333a..cdac5df4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -24,14 +24,17 @@ lto = "fat"
codegen-units = 1
[dependencies]
+anyhow = "1.0.32"
battery = "0.7.6"
-crossterm = "0.17"
chrono = "0.4.15"
+crossterm = "0.17"
+ctrlc = {version = "3.1", features = ["termination"]}
clap = "2.33"
dirs = "3.0.1"
futures = "0.3.5"
heim = "0.0.10"
itertools = "0.9.0"
+libc = "0.2"
regex = "1.3"
sysinfo = "0.15.1"
toml = "0.5.6"
@@ -41,8 +44,7 @@ backtrace = "0.3"
serde = {version = "1.0", features = ["derive"] }
unicode-segmentation = "1.6.0"
unicode-width = "0.1"
-libc = "0.2"
-ctrlc = {version = "3.1", features = ["termination"]}
+thiserror = "1.0.20"
tui = {version = "0.9.5", features = ["crossterm"], default-features = false }
# For debugging only...
@@ -82,5 +84,5 @@ output = "bottom_x86_64_installer.msi"
[dev-dependencies.cargo-husky]
version = "1"
-default-features = false
-features = ["prepush-hook", "run-cargo-clippy"] \ No newline at end of file
+default-features = false
+features = ["user-hooks"] \ No newline at end of file
diff --git a/README.md b/README.md
index 0083f3f7..cbf5b55e 100644
--- a/README.md
+++ b/README.md
@@ -509,7 +509,7 @@ Supported named colours are one of the following strings: `Reset, Black, Red, Gr
| Cursor colour | The cursor's colour | `cursor_color="#ffffff"` |
| Selected text colour | The colour of text that is selected | `scroll_entry_text_color="#ffffff"` |
| Selected text background colour | The background colour of text that is selected | `scroll_entry_bg_color="#ffffff"` |
-| Battery bar colours | Colour used is based on percentage and no. of colours | `battery_colours=["green", "yellow", "red"]` |
+| Battery bar colours | Colour used is based on percentage and no. of colours | `battery_colors=["green", "yellow", "red"]` |
#### Layout
diff --git a/src/app/data_harvester/processes.rs b/src/app/data_harvester/processes.rs
index bdd6a609..dcd6d647 100644
--- a/src/app/data_harvester/processes.rs
+++ b/src/app/data_harvester/processes.rs
@@ -253,11 +253,11 @@ fn read_proc<S: core::hash::BuildHasher>(
.splitn(2, '(')
.collect::<Vec<_>>()
.last()
- .ok_or(BottomError::MinorError())?
+ .ok_or(BottomError::MinorError)?
.rsplitn(2, ')')
.collect::<Vec<_>>()
.last()
- .ok_or(BottomError::MinorError())?
+ .ok_or(BottomError::MinorError)?
.to_string();
let command = {
let cmd = read_path_contents(&pid_stat.proc_cmdline_path)?;
@@ -271,7 +271,7 @@ fn read_proc<S: core::hash::BuildHasher>(
.split(')')
.collect::<Vec<_>>()
.last()
- .ok_or(BottomError::MinorError())?
+ .ok_or(BottomError::MinorError)?
.split_whitespace()
.collect::<Vec<&str>>();
let (process_state_char, process_state) = get_linux_process_state(&stat);
diff --git a/src/app/layout_manager.rs b/src/app/layout_manager.rs
index 35c6e02f..6036c2a5 100644
--- a/src/app/layout_manager.rs
+++ b/src/app/layout_manager.rs
@@ -943,7 +943,25 @@ impl std::str::FromStr for BottomWidgetType {
"empty" => Ok(BottomWidgetType::Empty),
"battery" | "batt" => Ok(BottomWidgetType::Battery),
_ => Err(BottomError::ConfigError(format!(
- "invalid widget type: {}", // FIXME: Make this more helpful, specify valid widget types (just go through the list)
+ "\"{}\" is an invalid widget name.
+
+Supported widget names:
++--------------------------+
+| cpu |
++--------------------------+
+| mem, memory |
++--------------------------+
+| net, network |
++--------------------------+
+| proc, process, processes |
++--------------------------+
+| temp, temperature |
++--------------------------+
+| disk |
++--------------------------+
+| batt, battery |
++--------------------------+
+ ",
s
))),
}
diff --git a/src/bin/main.rs b/src/bin/main.rs
index 95444491..7f8b9900 100644
--- a/src/bin/main.rs
+++ b/src/bin/main.rs
@@ -3,7 +3,7 @@
#[macro_use]
extern crate log;
-use bottom::{canvas, constants::*, data_conversion::*, options::*, utils::error, *};
+use bottom::{canvas, constants::*, data_conversion::*, options::*, *};
use std::{
boxed::Box,
@@ -17,6 +17,7 @@ use std::{
time::Duration,
};
+use anyhow::{Context, Result};
use crossterm::{
event::EnableMouseCapture,
execute,
@@ -24,18 +25,22 @@ use crossterm::{
};
use tui::{backend::CrosstermBackend, Terminal};
-fn main() -> error::Result<()> {
+fn main() -> Result<()> {
#[cfg(debug_assertions)]
{
utils::logging::init_logger()?;
}
let matches = clap::get_matches();
- let config: Config = create_config(matches.value_of("CONFIG_LOCATION"))?;
+ let config_path = read_config(matches.value_of("CONFIG_LOCATION"))
+ .context("Unable to access the given config file location.")?;
+ let config: Config = create_or_get_config(&config_path)
+ .context("Unable to properly parse or create the config file.")?;
// Get widget layout separately
let (widget_layout, default_widget_id, default_widget_type_option) =
- get_widget_layout(&matches, &config)?;
+ get_widget_layout(&matches, &config)
+ .context("Found an issue while trying to build the widget layout.")?;
// Create "app" struct, which will control most of the program and store settings/state
let mut app = build_app(
diff --git a/src/canvas/canvas_colours.rs b/src/canvas/canvas_colours.rs
index 86c96f4b..98932d5d 100644
--- a/src/canvas/canvas_colours.rs
+++ b/src/canvas/canvas_colours.rs
@@ -1,5 +1,4 @@
use tui::style::{Color, Style};
-// use tui::style::Modifier;
use colour_utils::*;
@@ -175,11 +174,10 @@ impl CanvasColours {
Ok(())
}
- pub fn set_battery_colours(&mut self, colours: &[String]) -> error::Result<()> {
+ pub fn set_battery_colors(&mut self, colours: &[String]) -> error::Result<()> {
if colours.is_empty() {
Err(error::BottomError::ConfigError(
- "invalid colour config: battery colour list must have at least one colour!"
- .to_string(),
+ "battery colour list must have at least one colour.".to_string(),
))
} else {
let generated_colours: Result<Vec<_>, _> = colours
diff --git a/src/canvas/canvas_colours/colour_utils.rs b/src/canvas/canvas_colours/colour_utils.rs
index 8b2f0594..f94b9bd9 100644
--- a/src/canvas/canvas_colours/colour_utils.rs
+++ b/src/canvas/canvas_colours/colour_utils.rs
@@ -100,7 +100,7 @@ pub fn convert_hex_to_color(hex: &str) -> error::Result<Color> {
fn hex_err(hex: &str) -> error::Result<u8> {
Err(
error::BottomError::ConfigError(format!(
- "invalid color hex: error when parsing hex value {}. It must be a valid 7 character hex string of the (ie: \"#112233\")."
+ "\"{}\" is an invalid hex colour. It must be a valid 7 character hex string of the (ie: \"#112233\")."
, hex))
)
}
@@ -124,7 +124,7 @@ pub fn convert_hex_to_color(hex: &str) -> error::Result<Color> {
}
Err(error::BottomError::ConfigError(format!(
- "invalid color hex: value {} is not of valid length. It must be a 7 character string of the form \"#112233\".",
+ "\"{}\" is an invalid hex colour. It must be a 7 character string of the form \"#112233\".",
hex
)))
}
@@ -144,7 +144,7 @@ pub fn get_style_from_config(input_val: &str) -> error::Result<Style> {
}
} else {
Err(error::BottomError::ConfigError(format!(
- "invalid color: value {} is not valid.",
+ "value \"{}\" is not valid.",
input_val
)))
}
@@ -161,7 +161,7 @@ pub fn get_colour_from_config(input_val: &str) -> error::Result<Color> {
}
} else {
Err(error::BottomError::ConfigError(format!(
- "invalid color: value {} is not valid.",
+ "value \"{}\" is not valid.",
input_val
)))
}
@@ -175,7 +175,7 @@ fn convert_rgb_to_color(rgb_str: &str) -> error::Result<Color> {
let rgb_list = rgb_str.split(',').collect::<Vec<&str>>();
if rgb_list.len() != 3 {
return Err(error::BottomError::ConfigError(format!(
- "invalid RGB color: value {} is not of valid length. It must be a comma separated value with 3 integers from 0 to 255 (ie: \"255, 0, 155\").",
+ "value \"{}\" is an invalid RGB colour. It must be a comma separated value with 3 integers from 0 to 255 (ie: \"255, 0, 155\").",
rgb_str
)));
}
@@ -194,7 +194,7 @@ fn convert_rgb_to_color(rgb_str: &str) -> error::Result<Color> {
Ok(Color::Rgb(rgb[0], rgb[1], rgb[2]))
} else {
Err(error::BottomError::ConfigError(format!(
- "invalid RGB color: value {} contained invalid RGB values. It must be a comma separated value with 3 integers from 0 to 255 (ie: \"255, 0, 155\").",
+ "value \"{}\" contained invalid RGB values. It must be a comma separated value with 3 integers from 0 to 255 (ie: \"255, 0, 155\").",
rgb_str
)))
}
@@ -211,9 +211,23 @@ fn convert_name_to_color(color_name: &str) -> error::Result<Color> {
}
Err(error::BottomError::ConfigError(format!(
- "invalid named color: value {} is not a supported named colour. The following are supported strings: \
- Reset, Black, Red, Green, Yellow, Blue, Magenta, Cyan, Gray, DarkGray, LightRed, LightGreen, \
- LightYellow, LightBlue, LightMagenta, LightCyan, White",
+ "\"{}\" is an invalid named colour.
+
+The following are supported strings:
++--------+------------+--------------+
+| Reset | Magenta | LightYellow |
++--------+------------+--------------+
+| Black | Cyan | LightBlue |
++--------+------------+--------------+
+| Red | Gray | LightMagenta |
++--------+------------+--------------+
+| Green | DarkGray | LightCyan |
++--------+------------+--------------+
+| Yellow | LightRed | White |
++--------+------------+--------------+
+| Blue | LightGreen | |
++--------+------------+--------------+
+ ",
color_name
)))
}
diff --git a/src/clap.rs b/src/clap.rs
index e4bed377..6b63ba42 100644
--- a/src/clap.rs
+++ b/src/clap.rs
@@ -239,7 +239,7 @@ For example, suppose we have a layout that looks like:
Setting '--default_widget_type Temp' will make the Temperature
widget selected by default.
-Supported widget types:
+Supported widget names:
+--------------------------+
| cpu |
+--------------------------+
diff --git a/src/lib.rs b/src/lib.rs
index 4850d48c..207c2963 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -5,8 +5,10 @@ extern crate log;
use std::{
boxed::Box,
+ fs,
io::{stdout, Write},
panic::PanicInfo,
+ path::PathBuf,
thread,
time::{Duration, Instant},
};
@@ -18,6 +20,8 @@ use crossterm::{
terminal::{disable_raw_mode, LeaveAlternateScreen},
};
+use anyhow::Context;
+
use app::{
data_harvester::{self, processes::ProcessSorting},
layout_manager::{UsedWidgets, WidgetDirection},
@@ -164,15 +168,14 @@ pub fn handle_key_event_or_break(
false
}
-pub fn create_config(flag_config_location: Option<&str>) -> error::Result<Config> {
- use std::{ffi::OsString, fs};
- let config_path = if let Some(conf_loc) = flag_config_location {
- Some(OsString::from(conf_loc))
+pub fn read_config(config_location: Option<&str>) -> error::Result<Option<PathBuf>> {
+ let config_path = if let Some(conf_loc) = config_location {
+ Some(PathBuf::from(conf_loc))
} else if cfg!(target_os = "windows") {
if let Some(home_path) = dirs::config_dir() {
let mut path = home_path;
path.push(DEFAULT_CONFIG_FILE_PATH);
- Some(path.into_os_string())
+ Some(path)
} else {
None
}
@@ -182,13 +185,13 @@ pub fn create_config(flag_config_location: Option<&str>) -> error::Result<Config
path.push(DEFAULT_CONFIG_FILE_PATH);
if path.exists() {
// If it already exists, use the old one.
- Some(path.into_os_string())
+ Some(path)
} else {
// If it does not, use the new one!
if let Some(config_path) = dirs::config_dir() {
let mut path = config_path;
path.push(DEFAULT_CONFIG_FILE_PATH);
- Some(path.into_os_string())
+ Some(path)
} else {
None
}
@@ -197,9 +200,11 @@ pub fn create_config(flag_config_location: Option<&str>) -> error::Result<Config
None
};
- if let Some(config_path) = config_path {
- let path = std::path::Path::new(&config_path);
+ Ok(config_path)
+}
+pub fn create_or_get_config(config_path: &Option<PathBuf>) -> error::Result<Config> {
+ if let Some(path) = config_path {
if let Ok(config_string) = fs::read_to_string(path) {
Ok(toml::from_str(config_string.as_str())?)
} else {
@@ -229,48 +234,76 @@ pub fn try_drawing(
pub fn generate_config_colours(
config: &Config, painter: &mut canvas::Painter,
-) -> error::Result<()> {
+) -> anyhow::Result<()> {
if let Some(colours) = &config.colors {
if let Some(border_color) = &colours.border_color {
- painter.colours.set_border_colour(border_color)?;
+ painter
+ .colours
+ .set_border_colour(border_color)
+ .context("Update 'border_color' in your config file..")?;
}
if let Some(highlighted_border_color) = &colours.highlighted_border_color {
painter
.colours
- .set_highlighted_border_colour(highlighted_border_color)?;
+ .set_highlighted_border_colour(highlighted_border_color)
+ .context("Update 'highlighted_border_color' in your config file..")?;
}
if let Some(text_color) = &colours.text_color {
- painter.colours.set_text_colour(text_color)?;
+ painter
+ .colours
+ .set_text_colour(text_color)
+ .context("Update 'text_color' in your config file..")?;
}
if let Some(avg_cpu_color) = &colours.avg_cpu_color {
- painter.colours.set_avg_cpu_colour(avg_cpu_color)?;
+ painter
+ .colours
+ .set_avg_cpu_colour(avg_cpu_color)
+ .context("Update 'avg_cpu_color' in your config file..")?;
}
if let Some(all_cpu_color) = &colours.all_cpu_color {
- painter.colours.set_all_cpu_colour(all_cpu_color)?;
+ painter
+ .colours
+ .set_all_cpu_colour(all_cpu_color)
+ .context("Update 'all_cpu_color' in your config file..")?;
}
if let Some(cpu_core_colors) = &colours.cpu_core_colors {
- painter.colours.set_cpu_colours(cpu_core_colors)?;
+ painter
+ .colours
+ .set_cpu_colours(cpu_core_colors)
+ .context("Update 'cpu_core_colors' in your config file..")?;
}
if let Some(ram_color) = &colours.ram_color {
- painter.colours.set_ram_colour(ram_color)?;
+ painter
+ .colours
+ .set_ram_colour(ram_color)
+ .context("Update 'ram_color' in your config file..")?;
}
if let Some(swap_color) = &colours.swap_color {
- painter.colours.set_swap_colour(swap_color)?;
+ painter
+ .colours
+ .set_swap_colour(swap_color)
+ .context("Update 'swap_color' in your config file..")?;
}
if let Some(rx_color) = &colours.rx_color {
- painter.colours.set_rx_colour(rx_color)?;
+ painter
+ .colours
+ .set_rx_colour(rx_color)
+ .context("Update 'rx_color' in your config file..")?;
}
if let Some(tx_color) = &colours.tx_color {
- painter.colours.set_tx_colour(tx_color)?;
+ painter
+ .colours
+ .set_tx_colour(tx_color)
+ .context("Update 'tx_color' in your config file..")?;
}
// if let Some(rx_total_color) = &colours.rx_total_color {
@@ -284,33 +317,43 @@ pub fn generate_config_colours(
if let Some(table_header_color) = &colours.table_header_color {
painter
.colours
- .set_table_header_colour(table_header_color)?;
+ .set_table_header_colour(table_header_color)
+ .context("Update 'table_header_color' in your config file..")?;
}
if let Some(scroll_entry_text_color) = &colours.selected_text_color {
painter
.colours
- .set_scroll_entry_text_color(scroll_entry_text_color)?;
+ .set_scroll_entry_text_color(scroll_entry_text_color)
+ .context("Update 'selected_text_color' in your config file..")?;
}
if let Some(scroll_entry_bg_color) = &colours.selected_bg_color {
painter
.colours
- .set_scroll_entry_bg_color(scroll_entry_bg_color)?;
+ .set_scroll_entry_bg_color(scroll_entry_bg_color)
+ .context("Update 'selected_bg_color' in your config file..")?;
}
if let Some(widget_title_color) = &colours.widget_title_color {
painter
.colours
- .set_widget_title_colour(widget_title_color)?;
+ .set_widget_title_colour(widget_title_color)
+ .context("Update 'widget_title_color' in your config file..")?;
}
if let Some(graph_color) = &colours.graph_color {
- painter.colours.set_graph_colour(graph_color)?;
+ painter
+ .colours
+ .set_graph_colour(graph_color)
+ .context("Update 'graph_color' in your config file..")?;
}
if let Some(battery_colors) = &colours.battery_colors {
- painter.colours.set_battery_colours(battery_colors)?;
+ painter
+ .colours
+ .set_battery_colors(battery_colors)
+ .context("Update 'battery_colors' in your config file.")?;
}
}
diff --git a/src/options.rs b/src/options.rs
index 41059f9c..c2e33993 100644
--- a/src/options.rs
+++ b/src/options.rs
@@ -12,6 +12,8 @@ use layout_options::*;
pub mod layout_options;
+use anyhow::{Context, Result};
+
#[derive(Default, Deserialize)]
pub struct Config {
pub flags: Option<ConfigFlags>,
@@ -70,10 +72,11 @@ pub struct ConfigColours {
pub fn build_app(
matches: &clap::ArgMatches<'static>, config: &Config, widget_layout: &BottomLayout,
default_widget_id: u64, default_widget_type_option: &Option<BottomWidgetType>,
-) -> error::Result<App> {
+) -> Result<App> {
use BottomWidgetType::*;
let autohide_time = get_autohide_time(&matches, &config);
- let default_time_value = get_default_time_value(&matches, &config)?;
+ let default_time_value = get_default_time_value(&matches, &config)
+ .context("Update 'default_time_value' in your config file.")?;
let use_basic_mode = get_use_basic_mode(&matches, &config);
// For processes
@@ -213,15 +216,18 @@ pub fn build_app(
};
let app_config_fields = AppConfigFields {
- update_rate_in_milliseconds: get_update_rate_in_milliseconds(matches, config)?,
- temperature_type: get_temperature(matches, config)?,
+ update_rate_in_milliseconds: get_update_rate_in_milliseconds(matches, config)
+ .context("Update 'rate' in your config file.")?,
+ temperature_type: get_temperature(matches, config)
+ .context("Update 'temperature_type' in your config file.")?,
show_average_cpu: get_show_average_cpu(matches, config),
use_dot: get_use_dot(matches, config),
left_legend: get_use_left_legend(matches, config),
use_current_cpu_total: get_use_current_cpu_total(matches, config),
use_basic_mode,
default_time_value,
- time_interval: get_time_interval(matches, config)?,
+ time_interval: get_time_interval(matches, config)
+ .context("Update 'time_delta' in your config file.")?,
hide_time: get_hide_time(matches, config),
autohide_time,
use_old_network_legend: get_use_old_network_legend(matches, config),
@@ -316,7 +322,7 @@ pub fn get_widget_layout(
ret_bottom_layout
} else {
return Err(error::BottomError::ConfigError(
- "invalid layout config: please have at least one widget.".to_string(),
+ "please have at least one widget under the '[[row]]' section.".to_string(),
));
}
};
@@ -340,12 +346,12 @@ fn get_update_rate_in_milliseconds(
};
if update_rate_in_milliseconds < 250 {
- return Err(BottomError::InvalidArg(
- "Please set your update rate to be at least 250 milliseconds.".to_string(),
+ return Err(BottomError::ConfigError(
+ "set your update rate to be at least 250 milliseconds.".to_string(),
));
} else if update_rate_in_milliseconds as u128 > std::u64::MAX as u128 {
- return Err(BottomError::InvalidArg(
- "Please set your update rate to be at most unsigned INT_MAX.".to_string(),
+ return Err(BottomError::ConfigError(
+ "set your update rate to be at most unsigned INT_MAX.".to_string(),
));
}
@@ -368,11 +374,10 @@ fn get_temperature(
"fahrenheit" | "f" => Ok(data_harvester::temperature::TemperatureType::Fahrenheit),
"kelvin" | "k" => Ok(data_harvester::temperature::TemperatureType::Kelvin),
"celsius" | "c" => Ok(data_harvester::temperature::TemperatureType::Celsius),
- _ => Err(BottomError::ConfigError(
- "invalid temperature type: please have the value be of the form \
- <kelvin|k|celsius|c|fahrenheit|f>"
- .to_string(),
- )),
+ _ => Err(BottomError::ConfigError(format!(
+ "\"{}\" is an invalid temperature type, use \"<kelvin|k|celsius|c|fahrenheit|f>\".",
+ temp_type
+ ))),
};
}
}
@@ -455,12 +460,12 @@ fn get_default_time_value(
};
if default_time < 30000 {
- return Err(BottomError::InvalidArg(
- "Please set your default value to be at least 30000 milliseconds.".to_string(),
+ return Err(BottomError::ConfigError(
+ "set your default value to be at least 30000 milliseconds.".to_string(),
));
} else if default_time as u128 > STALE_MAX_MILLISECONDS as u128 {
- return Err(BottomError::InvalidArg(format!(
- "Please set your default value to be at most {} milliseconds.",
+ return Err(BottomError::ConfigError(format!(
+ "set your default value to be at most {} milliseconds.",
STALE_MAX_MILLISECONDS
)));
}
@@ -482,12 +487,12 @@ fn get_time_interval(matches: &clap::ArgMatches<'static>, config: &Config) -> er
};
if time_interval < 1000 {
- return Err(BottomError::InvalidArg(
- "Please set your time delta to be at least 1000 milliseconds.".to_string(),
+ return Err(BottomError::ConfigError(
+ "set your time delta to be at least 1000 milliseconds.".to_string(),
));
} else if time_interval > STALE_MAX_MILLISECONDS as u128 {
- return Err(BottomError::InvalidArg(format!(
- "Please set your time delta to be at most {} milliseconds.",
+ return Err(BottomError::ConfigError(format!(
+ "set your time delta to be at most {} milliseconds.",
STALE_MAX_MILLISECONDS
)));
}
@@ -601,8 +606,8 @@ fn get_default_widget_and_count(
};
if widget_count > std::u64::MAX as u128 {
- Err(BottomError::InvalidArg(
- "Please set your widget count to be at most unsigned INT_MAX.".to_string(),
+ Err(BottomError::ConfigError(
+ "set your widget count to be at most unsigned INT_MAX.".to_string(),
))
} else {
Ok((widget_type, widget_count as u64))
diff --git a/src/utils/error.rs b/src/utils/error.rs
index 4c607ebe..1cb17595 100644
--- a/src/utils/error.rs
+++ b/src/utils/error.rs
@@ -1,60 +1,39 @@
use std::{borrow::Cow, result};
+use thiserror::Error;
/// 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)]
+#[derive(Debug, Error)]
pub enum BottomError {
/// An error when there is an IO exception.
+ #[error("IO exception, {0}")]
InvalidIO(String),
- /// An error when there is an invalid argument passed in.
- InvalidArg(String),
/// An error when the heim library encounters a problem.
+ #[error("Error caused by Heim, {0}")]
InvalidHeim(String),
/// An error when the Crossterm library encounters a problem.
+ #[error("Error caused by Crossterm, {0}")]
CrosstermError(String),
/// An error to represent generic errors.
+ #[error("Generic error, {0}")]
GenericError(String),
/// An error to represent errors with fern.
+ #[error("Fern error, {0}")]
FernError(String),
/// An error to represent errors with the config.
+ #[error("Configuration file error, {0}")]
ConfigError(String),
/// An error to represent errors with converting between data types.
+ #[error("Conversion error, {0}")]
ConversionError(String),
/// An error to represent errors with querying.
+ #[error("Query error, {0}")]
QueryError(Cow<'static, str>),
/// An error that just signifies something minor went wrong; no message.
- MinorError(),
-}
-
-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)
- }
- BottomError::ConversionError(ref message) => {
- write!(f, "unable to convert: {}", message)
- }
- BottomError::QueryError(ref message) => write!(f, "{}", message),
- BottomError::MinorError() => write!(f, "Minor error."),
- }
- }
+ #[error("Minor error.")]
+ MinorError,
}
impl From<std::io::Error> for BottomError {
@@ -77,7 +56,7 @@ impl From<crossterm::ErrorKind> for BottomError {
impl From<std::num::ParseIntError> for BottomError {
fn from(err: std::num::ParseIntError) -> Self {
- BottomError::InvalidArg(err.to_string())
+ BottomError::ConfigError(err.to_string())
}
}
diff --git a/tests/arg_tests.rs b/tests/arg_tests.rs
index 134d9615..f6dac340 100644
--- a/tests/arg_tests.rs
+++ b/tests/arg_tests.rs
@@ -18,7 +18,7 @@ fn test_small_rate() -> Result<(), Box<dyn std::error::Error>> {
.assert()
.failure()
.stderr(predicate::str::contains(
- "Please set your update rate to be at least 250 milliseconds.",
+ "set you