feat: better error reporting

This commit is contained in:
Pihkaal
2024-03-25 23:50:20 +01:00
parent ac66044508
commit 1e6cf30fea
5 changed files with 84 additions and 48 deletions

View File

@@ -1,10 +1,10 @@
use core::panic; use std::{any::type_name, fs, path::PathBuf};
use std::{fs, path::PathBuf};
use crossterm::style::Color; use crossterm::style::Color;
use ini::configparser::ini::Ini; use ini::configparser::ini::Ini;
use crate::{ use crate::{
eprintln_quit,
modes::debug, modes::debug,
rendering::color::{generate_gradient, parse_hex_color, ComputableColor}, 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 { pub fn load_from_file(path: PathBuf, debug_mode: bool) -> Config {
let mut ini = Ini::new(); 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 { Config {
be_polite: ini.getbool("general", "polite").unwrap().unwrap(), be_polite: get_ini_value(&ini, "general", "polite"),
fps: ini.getuint("general", "fps").unwrap().unwrap(), fps: get_ini_value(&ini, "general", "fps"),
color: load_color(&ini, debug_mode), color: load_color(&ini, debug_mode),
time_format: ini.get("format", "time").unwrap(), time_format: get_ini_value(&ini, "format", "time"),
date_format: ini.get("format", "date").unwrap(), date_format: get_ini_value(&ini, "format", "date"),
} }
} }
pub fn write_default_config(path: PathBuf) -> () { pub fn write_default_config(path: PathBuf) -> () {
// Write default config file to target path // 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::create_dir_all(parent);
let _ = fs::write(path, DEFAULT_CONFIG); let _ = fs::write(path, DEFAULT_CONFIG);
} }
fn load_color(ini: &Ini, debug_mode: bool) -> ComputableColor { fn get_ini_value<T: std::str::FromStr>(ini: &Ini, section: &str, key: &str) -> T {
let color_mode = ini.get("styling", "color_mode").unwrap(); if let Some(value) = ini.get(section, key) {
value.parse::<T>().unwrap_or_else(|_| {
match color_mode.as_str() { eprintln_quit!(
"term" => { "Invalid value at {}.{}: Expected {}, got '{}'",
let color = ini.getint("styling", "color_term").unwrap().unwrap(); section,
ComputableColor::from(load_term_color(color)) key,
} type_name::<T>(),
"hex" => { value
let color = ini.get("styling", "color_hex").unwrap(); )
ComputableColor::from(load_hex_color(&color)) })
} } else {
"ansi" => { eprintln_quit!("Missing required config key: {}.{}", section, key)
let color = ini.getint("styling", "color_ansi").unwrap().unwrap();
ComputableColor::from(load_ansi_color(color))
}
"gradient" => load_gradient(ini, debug_mode),
_ => panic!("ERROR: Invalid color mode: {}", color_mode),
} }
} }
fn load_term_color(value: i64) -> Color { fn load_color(ini: &Ini, debug_mode: bool) -> ComputableColor {
let color_mode: String = get_ini_value(&ini, "styling", "color_mode");
match color_mode.as_str() {
"term" => {
let color: u8 = get_ini_value(&ini, "styling", "color_term");
ComputableColor::from(load_term_color(color))
}
"hex" => {
let color: String = get_ini_value(&ini, "styling", "color_hex");
ComputableColor::from(load_hex_color(&color))
}
"ansi" => {
let color: u8 = get_ini_value(&ini, "styling", "color_ansi");
ComputableColor::from(load_ansi_color(color))
}
"gradient" => load_gradient(ini, debug_mode),
_ => eprintln_quit!("Invalid color mode: {}", color_mode),
}
}
fn load_term_color(value: u8) -> Color {
match value { match value {
0 => Color::Black, 0 => Color::Black,
1 => Color::DarkRed, 1 => Color::DarkRed,
@@ -78,7 +101,7 @@ fn load_term_color(value: i64) -> Color {
13 => Color::Magenta, 13 => Color::Magenta,
14 => Color::Cyan, 14 => Color::Cyan,
15 => Color::White, 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 { fn load_ansi_color(value: u8) -> Color {
Color::AnsiValue(value.try_into().unwrap()) Color::AnsiValue(value)
} }
fn load_gradient(ini: &Ini, debug_mode: bool) -> ComputableColor { 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 // Generate gradient loop if needed
if !debug_mode && ini.getbool("gradient", "gradient_loop").unwrap().unwrap() { if !debug_mode && get_ini_value(&ini, "gradient", "gradient_loop") {
let mut loop_keys = keys.clone(); for &key in keys.clone().iter().rev().skip(1) {
loop_keys.reverse(); keys.push(key);
for i in 1..loop_keys.len() {
keys.push(*loop_keys.get(i).unwrap());
} }
} }
@@ -121,11 +142,7 @@ fn load_gradient(ini: &Ini, debug_mode: bool) -> ComputableColor {
let steps: usize = if debug_mode { let steps: usize = if debug_mode {
debug::DEBUG_COLOR_DISPLAY_SIZE * 2 debug::DEBUG_COLOR_DISPLAY_SIZE * 2
} else { } else {
ini.getuint("gradient", "gradient_steps") get_ini_value(&ini, "gradient", "gradient_steps")
.unwrap()
.unwrap()
.try_into()
.unwrap()
}; };
generate_gradient(keys, steps - 1) generate_gradient(keys, steps - 1)
} }

View File

@@ -57,7 +57,10 @@ fn main() -> io::Result<()> {
PathBuf::from(custom_config) PathBuf::from(custom_config)
} else { } else {
// Or default one, located in ~/.config/tlock // 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() { if !config_file.exists() {
write_default_config(config_file.clone()); write_default_config(config_file.clone());
default_generated = true; default_generated = true;
@@ -128,7 +131,7 @@ fn main() -> io::Result<()> {
} }
// Disale raw mode, leave the alternate screen and show the cursor back // 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)?; execute!(stdout, terminal::LeaveAlternateScreen, cursor::Show)?;
// Be polite // Be polite

View File

@@ -10,11 +10,11 @@ use crossterm::{
terminal::{self, ClearType}, terminal::{self, ClearType},
}; };
use crate::utils;
use crate::{ use crate::{
config::Config, config::Config,
rendering::{self, symbols}, rendering::{self, symbols},
}; };
use crate::{eprintln_quit, utils};
struct Timer { struct Timer {
duration: Duration, duration: Duration,
@@ -74,7 +74,8 @@ impl Timer {
pub fn main_loop(config: &mut Config, duration: &str) -> io::Result<()> { pub fn main_loop(config: &mut Config, duration: &str) -> io::Result<()> {
let mut stdout = io::stdout(); 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 timer = Timer::new(duration);
let mut quit = false; let mut quit = false;

View File

@@ -86,9 +86,14 @@ pub fn parse_hex_color(value: &str) -> (u8, u8, u8) {
panic!("ERROR: Invalid hex color: {}", value); panic!("ERROR: Invalid hex color: {}", value);
} }
let r = u8::from_str_radix(&value[0..2], 16).unwrap(); let extract_component = |index: usize| {
let g = u8::from_str_radix(&value[2..4], 16).unwrap(); u8::from_str_radix(&value[index * 2..(index + 1) * 2], 16)
let b = u8::from_str_radix(&value[4..6], 16).unwrap(); .unwrap_or_else(|_| panic!("error: invalid hex color: {}", value))
};
(r, g, b) (
extract_component(0),
extract_component(1),
extract_component(2),
)
} }

View File

@@ -8,3 +8,13 @@ pub fn format_duration(duration: time::Duration) -> String {
format!("{:02}:{:02}:{:02}", hours, minutes, seconds) 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)
})
}