start working on a cli app #7

Merged
schrottkatze merged 12 commits from :app into main 2024-01-20 19:09:52 +00:00
5 changed files with 25 additions and 6 deletions
Showing only changes of commit 0615ea653c - Show all commits

View file

@ -14,6 +14,7 @@ pub struct Config {
}
impl Config {
/// Get the configs from all possible places (args, file, env...)
pub fn read() -> Self {
let args = Args::parse();
let config_path = if let Some(config_path) = args.config_path {
@ -22,6 +23,7 @@ impl Config {
find_config_file()
};
// try to read a maybe existing config file
let file_config = if let Ok(config_path) = config_path {
let file_config = Configs::read(config_path);
@ -52,13 +54,22 @@ impl Config {
}
pub mod error {
/// Errors that can occur when reading configs
#[derive(Debug)]
pub enum ConfigError {
/// 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<String>),
/// Wrapper around an `Error` from `serde_json`
SerdeJsonError(serde_json::Error),
/// Wrapper around a `SpannedError` from `ron`
SerdeRonError(ron::error::SpannedError),
}

View file

@ -7,6 +7,9 @@ pub(crate) struct Args {
/// Read this config file.
#[arg(short, long)]
pub config_path: Option<PathBuf>,
/// Turn off the startup message.
schrottkatze marked this conversation as resolved Outdated
Might want a [`clap::builder::BoolishValueParser`](https://docs.rs/clap/latest/clap/builder/struct.BoolishValueParser.html) here.

How do I use that with claps derive api?

How do I use that with claps derive api?

Through

-    #[arg(long, env = "NO_STARTUP_MESSAGE", default_value = "false")] 
+    #[arg(long, env = "NO_STARTUP_MESSAGE", action = ArgAction::SetTrue, value_parser = BoolishValueParser::new())]
Through ```diff - #[arg(long, env = "NO_STARTUP_MESSAGE", default_value = "false")] + #[arg(long, env = "NO_STARTUP_MESSAGE", action = ArgAction::SetTrue, value_parser = BoolishValueParser::new())] ```
///
/// The startup message is not constant and depends on the time.
#[arg(long, env = "NO_STARTUP_MESSAGE", default_value = "false")]
pub no_startup_message: bool,
}

View file

@ -11,7 +11,7 @@ use super::error::ConfigError;
pub struct Configs {
#[serde(default = "default_example_value")]
pub example_value: i32,
#[serde(default = "default_no_startup_msg")]
#[serde(default)]
schrottkatze marked this conversation as resolved Outdated

Since the default is false which is also returned by `bool::default, the extra function is not necessary:

-    #[serde(default = "default_no_startup_msg")]
+    #[serde(default)]

If you do desire to keep the functions to allow more detailed behavior in future, I suggest renaming default_no_startup_msg to to just bool_false and creating a bool_true counterpart once necessary.

Since the default is `false` which is also returned by `bool::default, the extra function is not necessary: ```diff - #[serde(default = "default_no_startup_msg")] + #[serde(default)] ``` If you do desire to keep the functions to allow more detailed behavior in future, I suggest renaming `default_no_startup_msg` to to just `bool_false` and creating a `bool_true` counterpart once necessary.
pub no_startup_message: bool,
}
@ -20,10 +20,7 @@ fn default_example_value() -> i32 {
43
}
fn default_no_startup_msg() -> bool {
false
}
/// Find the location of a config file and check if there is, in fact, a file
pub(super) fn find_config_file() -> Result<PathBuf, ConfigError> {
let Some(config_path) = dirs::config_dir() else {
return Err(ConfigError::NoConfigDir);

View file

@ -2,16 +2,19 @@ use std::process;
use ron::error::Position;
/// Report an `Error` from the `serde_json` crate
pub fn report_serde_json_err(src: &str, err: serde_json::Error) -> ! {
report_serde_err(src, err.line(), err.column(), err.to_string())
}
/// Report a `SpannedError` from the `ron` crate
pub fn report_serde_ron_err(src: &str, err: ron::error::SpannedError) -> ! {
let Position { line, col } = err.position;
report_serde_err(src, line, col, err.to_string())
}
multisamplednight marked this conversation as resolved Outdated

Maybe report_serde_err could take a custom error, which the errors from ron and serde_json are converted into.

Then that streamlined error could report a bit more specific using serde_error::Error::classify and ron::Error.

Maybe `report_serde_err` could take a custom error, which the errors from `ron` and `serde_json` are converted into. Then that streamlined error could report a bit more specific using `serde_error::Error::classify` and `ron::Error`.

ye, that's a hack bc i was too lazy to implement a proper error type ^^'

ye, that's a hack bc i was too lazy to implement a proper error type ^^'
pub fn report_serde_err(src: &str, line: usize, col: usize, msg: String) -> ! {
/// Basic function for reporting serde type of errors
fn report_serde_err(src: &str, line: usize, col: usize, msg: String) -> ! {
use ariadne::{Label, Report, Source};
let offset = try_reconstruct_loc(src, line, col);
@ -24,6 +27,8 @@ pub fn report_serde_err(src: &str, line: usize, col: usize, msg: String) -> ! {
.unwrap();
process::exit(1);
}
/// Reconstruct a byte offset from the line + column numbers typical from serde crates
fn try_reconstruct_loc(src: &str, line_nr: usize, col_nr: usize) -> usize {
let (line_nr, col_nr) = (line_nr - 1, col_nr - 1);

View file

@ -1,11 +1,14 @@
use time::{Month, OffsetDateTime};
/// Print the startup message which changes depending on system time.
pub fn print_startup_msg() {
// now or fallback to utc
multisamplednight marked this conversation as resolved Outdated

Can always use now_utc, since no calculations are performed based on the timezone.

Can always use `now_utc`, since no calculations are performed based on the timezone.

the day might very well be timezone dependent, depending on where you live though?

the day might very well be timezone dependent, depending on where you live though?

Nevermind, I misinterpreted now_utc. I thought it'd return the current system time and assume it to be UTC (like SystemTime::now does), but it doesn't:

>> :dep time = { features = ["local-offset"] }
   Compiling libc v0.2.152
   Compiling powerfmt v0.2.0
   Compiling num_threads v0.1.6
   Compiling deranged v0.3.11
   Compiling time v0.3.31
>> use time::OffsetDateTime;
>> OffsetDateTime::now_utc()
2024-01-12 21:03:54.32211146 +00:00:00
>> OffsetDateTime::now_local()
Ok(2024-01-12 22:03:58.663618677 +01:00:00)
Nevermind, I misinterpreted `now_utc`. I thought it'd return the current system time and assume it to be UTC (like `SystemTime::now` does), but it doesn't: ``` >> :dep time = { features = ["local-offset"] } Compiling libc v0.2.152 Compiling powerfmt v0.2.0 Compiling num_threads v0.1.6 Compiling deranged v0.3.11 Compiling time v0.3.31 >> use time::OffsetDateTime; >> OffsetDateTime::now_utc() 2024-01-12 21:03:54.32211146 +00:00:00 >> OffsetDateTime::now_local() Ok(2024-01-12 22:03:58.663618677 +01:00:00) ```
let now = OffsetDateTime::now_local().unwrap_or_else(|_| OffsetDateTime::now_utc());
if now.month() == Month::June {
// pride startup message
println!("Hello, thanks for using iOwO and happy pride month!");
// TODO: proper link with explaination
println!("Why pride month is important in {}", now.year());
} else {
println!("Hello, thanks for using iOwO! :3");