use std::path::PathBuf; use clap::Parser; use self::{ cli::Args, config_file::{find_config_file, Configs}, }; mod cli; mod config_file; /// this struct may hold all configuration pub struct Config { pub source: PathBuf, pub evaluator: eval::Available, pub startup_msg: bool, } impl Config { /// Get the configs from all possible places (args, file, env...) pub fn read() -> Self { let args = Args::parse(); let config = if let Some(config) = args.config_path { Ok(config) } else { find_config_file() }; // try to read a maybe existing config file let config = config.ok().and_then(|path| { Configs::read(path).map_or_else( |e| { eprintln!("Config error: {e:?}"); eprintln!("Proceeding with defaults or cli args..."); None }, Some, ) }); if let Some(file) = config { Self { source: args.source, evaluator: args.evaluator.and(file.evaluator).unwrap_or_default(), // this is negated because to an outward api, the negative is more intuitive, // while in the source the other way around is more intuitive startup_msg: !(args.no_startup_message || file.no_startup_message), } } else { Self { source: args.source, startup_msg: !args.no_startup_message, evaluator: args.evaluator.unwrap_or_default(), } } } } pub mod error { /// Errors that can occur when reading configs #[derive(Debug)] pub enum Config { /// The config dir doesn't exist NoConfigDir, /// We didn't find a config file in the config dir NoConfigFileFound, /// An io error happened while reading/opening it! IoError(std::io::Error), /// The given extension (via an argument) isn't known. /// /// Occurs if the extension is neither `.json` nor `.ron` (including if there is no extension, in which case this will be `None`). UnknownExtension(Option), /// Wrapper around an `Error` from `serde_json` SerdeJsonError(serde_json::Error), /// Wrapper around a `SpannedError` from `ron` SerdeRonError(ron::error::SpannedError), } impl From for Config { fn from(value: std::io::Error) -> Self { Self::IoError(value) } } impl From for Config { fn from(value: serde_json::Error) -> Self { Self::SerdeJsonError(value) } } impl From for Config { fn from(value: ron::error::SpannedError) -> Self { Self::SerdeRonError(value) } } }