feat: better error reporting
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
use core::panic;
|
||||
use std::{fs, path::PathBuf};
|
||||
use std::{any::type_name, fs, path::PathBuf};
|
||||
|
||||
use crossterm::style::Color;
|
||||
use ini::configparser::ini::Ini;
|
||||
|
||||
use crate::{
|
||||
eprintln_quit,
|
||||
modes::debug,
|
||||
rendering::color::{generate_gradient, parse_hex_color, ComputableColor},
|
||||
};
|
||||
@@ -21,46 +21,69 @@ const DEFAULT_CONFIG: &str = include_str!("default_config");
|
||||
|
||||
pub fn load_from_file(path: PathBuf, debug_mode: bool) -> Config {
|
||||
let mut ini = Ini::new();
|
||||
ini.load(&path.to_str().unwrap()).unwrap();
|
||||
ini.load(
|
||||
&path
|
||||
.to_str()
|
||||
.unwrap_or_else(|| eprintln_quit!("Invalid configuration path")),
|
||||
)
|
||||
.unwrap_or_else(|_| eprintln_quit!("Unable to parse configuration file"));
|
||||
|
||||
Config {
|
||||
be_polite: ini.getbool("general", "polite").unwrap().unwrap(),
|
||||
fps: ini.getuint("general", "fps").unwrap().unwrap(),
|
||||
be_polite: get_ini_value(&ini, "general", "polite"),
|
||||
fps: get_ini_value(&ini, "general", "fps"),
|
||||
color: load_color(&ini, debug_mode),
|
||||
time_format: ini.get("format", "time").unwrap(),
|
||||
date_format: ini.get("format", "date").unwrap(),
|
||||
time_format: get_ini_value(&ini, "format", "time"),
|
||||
date_format: get_ini_value(&ini, "format", "date"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_default_config(path: PathBuf) -> () {
|
||||
// Write default config file to target path
|
||||
let parent = path.parent().unwrap();
|
||||
let parent = path
|
||||
.parent()
|
||||
.unwrap_or_else(|| eprintln_quit!("Invalid configuration path"));
|
||||
let _ = fs::create_dir_all(parent);
|
||||
let _ = fs::write(path, DEFAULT_CONFIG);
|
||||
}
|
||||
|
||||
fn get_ini_value<T: std::str::FromStr>(ini: &Ini, section: &str, key: &str) -> T {
|
||||
if let Some(value) = ini.get(section, key) {
|
||||
value.parse::<T>().unwrap_or_else(|_| {
|
||||
eprintln_quit!(
|
||||
"Invalid value at {}.{}: Expected {}, got '{}'",
|
||||
section,
|
||||
key,
|
||||
type_name::<T>(),
|
||||
value
|
||||
)
|
||||
})
|
||||
} else {
|
||||
eprintln_quit!("Missing required config key: {}.{}", section, key)
|
||||
}
|
||||
}
|
||||
|
||||
fn load_color(ini: &Ini, debug_mode: bool) -> ComputableColor {
|
||||
let color_mode = ini.get("styling", "color_mode").unwrap();
|
||||
let color_mode: String = get_ini_value(&ini, "styling", "color_mode");
|
||||
|
||||
match color_mode.as_str() {
|
||||
"term" => {
|
||||
let color = ini.getint("styling", "color_term").unwrap().unwrap();
|
||||
let color: u8 = get_ini_value(&ini, "styling", "color_term");
|
||||
ComputableColor::from(load_term_color(color))
|
||||
}
|
||||
"hex" => {
|
||||
let color = ini.get("styling", "color_hex").unwrap();
|
||||
let color: String = get_ini_value(&ini, "styling", "color_hex");
|
||||
ComputableColor::from(load_hex_color(&color))
|
||||
}
|
||||
"ansi" => {
|
||||
let color = ini.getint("styling", "color_ansi").unwrap().unwrap();
|
||||
let color: u8 = get_ini_value(&ini, "styling", "color_ansi");
|
||||
ComputableColor::from(load_ansi_color(color))
|
||||
}
|
||||
"gradient" => load_gradient(ini, debug_mode),
|
||||
_ => panic!("ERROR: Invalid color mode: {}", color_mode),
|
||||
_ => eprintln_quit!("Invalid color mode: {}", color_mode),
|
||||
}
|
||||
}
|
||||
|
||||
fn load_term_color(value: i64) -> Color {
|
||||
fn load_term_color(value: u8) -> Color {
|
||||
match value {
|
||||
0 => Color::Black,
|
||||
1 => Color::DarkRed,
|
||||
@@ -78,7 +101,7 @@ fn load_term_color(value: i64) -> Color {
|
||||
13 => Color::Magenta,
|
||||
14 => Color::Cyan,
|
||||
15 => Color::White,
|
||||
_ => panic!("ERROR: Invalid terminal color: {}", value),
|
||||
_ => eprintln_quit!("Invalid terminal color: {}", value),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,8 +114,8 @@ fn load_hex_color(value: &str) -> Color {
|
||||
}
|
||||
}
|
||||
|
||||
fn load_ansi_color(value: i64) -> Color {
|
||||
Color::AnsiValue(value.try_into().unwrap())
|
||||
fn load_ansi_color(value: u8) -> Color {
|
||||
Color::AnsiValue(value)
|
||||
}
|
||||
|
||||
fn load_gradient(ini: &Ini, debug_mode: bool) -> ComputableColor {
|
||||
@@ -109,11 +132,9 @@ fn load_gradient(ini: &Ini, debug_mode: bool) -> ComputableColor {
|
||||
}
|
||||
|
||||
// Generate gradient loop if needed
|
||||
if !debug_mode && ini.getbool("gradient", "gradient_loop").unwrap().unwrap() {
|
||||
let mut loop_keys = keys.clone();
|
||||
loop_keys.reverse();
|
||||
for i in 1..loop_keys.len() {
|
||||
keys.push(*loop_keys.get(i).unwrap());
|
||||
if !debug_mode && get_ini_value(&ini, "gradient", "gradient_loop") {
|
||||
for &key in keys.clone().iter().rev().skip(1) {
|
||||
keys.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,11 +142,7 @@ fn load_gradient(ini: &Ini, debug_mode: bool) -> ComputableColor {
|
||||
let steps: usize = if debug_mode {
|
||||
debug::DEBUG_COLOR_DISPLAY_SIZE * 2
|
||||
} else {
|
||||
ini.getuint("gradient", "gradient_steps")
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap()
|
||||
get_ini_value(&ini, "gradient", "gradient_steps")
|
||||
};
|
||||
generate_gradient(keys, steps - 1)
|
||||
}
|
||||
|
||||
@@ -57,7 +57,10 @@ fn main() -> io::Result<()> {
|
||||
PathBuf::from(custom_config)
|
||||
} else {
|
||||
// Or default one, located in ~/.config/tlock
|
||||
let config_file = config_dir().unwrap().join("tlock").join("config");
|
||||
let config_file = config_dir()
|
||||
.unwrap_or_else(|| eprintln_quit!("Unble to get configuration directory"))
|
||||
.join("tlock")
|
||||
.join("config");
|
||||
if !config_file.exists() {
|
||||
write_default_config(config_file.clone());
|
||||
default_generated = true;
|
||||
@@ -128,7 +131,7 @@ fn main() -> io::Result<()> {
|
||||
}
|
||||
|
||||
// Disale raw mode, leave the alternate screen and show the cursor back
|
||||
let _ = terminal::disable_raw_mode().unwrap();
|
||||
let _ = terminal::disable_raw_mode()?;
|
||||
execute!(stdout, terminal::LeaveAlternateScreen, cursor::Show)?;
|
||||
|
||||
// Be polite
|
||||
|
||||
@@ -10,11 +10,11 @@ use crossterm::{
|
||||
terminal::{self, ClearType},
|
||||
};
|
||||
|
||||
use crate::utils;
|
||||
use crate::{
|
||||
config::Config,
|
||||
rendering::{self, symbols},
|
||||
};
|
||||
use crate::{eprintln_quit, utils};
|
||||
|
||||
struct Timer {
|
||||
duration: Duration,
|
||||
@@ -74,7 +74,8 @@ impl Timer {
|
||||
pub fn main_loop(config: &mut Config, duration: &str) -> io::Result<()> {
|
||||
let mut stdout = io::stdout();
|
||||
|
||||
let duration = parse_duration::parse(duration).unwrap();
|
||||
let duration = parse_duration::parse(duration)
|
||||
.unwrap_or_else(|_| eprintln_quit!("Invalid duration provided"));
|
||||
let mut timer = Timer::new(duration);
|
||||
|
||||
let mut quit = false;
|
||||
|
||||
@@ -86,9 +86,14 @@ pub fn parse_hex_color(value: &str) -> (u8, u8, u8) {
|
||||
panic!("ERROR: Invalid hex color: {}", value);
|
||||
}
|
||||
|
||||
let r = u8::from_str_radix(&value[0..2], 16).unwrap();
|
||||
let g = u8::from_str_radix(&value[2..4], 16).unwrap();
|
||||
let b = u8::from_str_radix(&value[4..6], 16).unwrap();
|
||||
let extract_component = |index: usize| {
|
||||
u8::from_str_radix(&value[index * 2..(index + 1) * 2], 16)
|
||||
.unwrap_or_else(|_| panic!("error: invalid hex color: {}", value))
|
||||
};
|
||||
|
||||
(r, g, b)
|
||||
(
|
||||
extract_component(0),
|
||||
extract_component(1),
|
||||
extract_component(2),
|
||||
)
|
||||
}
|
||||
|
||||
10
src/utils.rs
10
src/utils.rs
@@ -8,3 +8,13 @@ pub fn format_duration(duration: time::Duration) -> String {
|
||||
|
||||
format!("{:02}:{:02}:{:02}", hours, minutes, seconds)
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! eprintln_quit {
|
||||
($($arg:tt)*) => ({
|
||||
use std::io::Write;
|
||||
write!(&mut std::io::stderr(), "ERROR: ").unwrap();
|
||||
writeln!(&mut std::io::stderr(), $($arg)*).unwrap();
|
||||
std::process::exit(1)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user