use std::path::PathBuf;
use chrono::FixedOffset;
use clap::{builder::TypedValueParser, Parser, ValueEnum, error::ErrorKind};
use grep::{
matcher::{Captures, Matcher},
regex::RegexMatcher,
};
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
pub struct Args {
#[arg(short = 'n', long = "no-ignore")]
pub no_ignore: bool,
#[arg(short = 'e', long = "no-error")]
pub no_error: bool,
#[arg(
value_enum,
rename_all = "kebab_case",
short = 'd',
long = "display-mode",
default_value = "default"
)]
pub display_mode: DisplayMode,
#[arg(value_parser, default_value = "./")]
pub root_directory: PathBuf,
#[arg(short = 'p', long = "pattern", value_parser, default_value = "*")]
pub ignore_pattern: String,
#[arg(short = 't', long = "timezone-offset", value_parser = FixedOffsetParser, default_value = "+00:00", allow_hyphen_values = true)]
pub timezone_offset: FixedOffset,
}
#[derive(ValueEnum, Debug, Clone)]
pub enum DisplayMode {
Concise,
OverdueOnly,
Default,
}
#[derive(Clone)]
struct FixedOffsetParser;
impl TypedValueParser for FixedOffsetParser {
type Value = FixedOffset;
fn parse_ref(
&self,
_cmd: &clap::Command,
_arg: Option<&clap::Arg>,
value: &std::ffi::OsStr,
) -> Result<FixedOffset, clap::Error> {
let offset_string = value.to_str().expect("Should be string!");
const OFFSET_PATTERN: &str = r"(-|\+)(0[0-9]|1[0-9]|2[0-3]):([0-5][0-9])";
let matcher = RegexMatcher::new(OFFSET_PATTERN).expect("Regex should be valid");
let mut captures = matcher.new_captures().expect("Regex should be valid");
matcher
.captures(offset_string.as_bytes(), &mut captures)
.expect("Regex should be valid");
if matcher.capture_count() != 4 {
Err(clap::Error::raw(
ErrorKind::ValueValidation,
"UTC offset does not follow the format [+|-][HH]:[SS]",
))
} else {
let offset_seconds: i32 = (3600
* offset_string[captures.get(2).unwrap()]
.parse::<i32>()
.unwrap())
+ (60
* offset_string[captures.get(3).unwrap()]
.parse::<i32>()
.unwrap());
if &offset_string[captures.get(1).unwrap()] == "+" {
Ok(FixedOffset::east(offset_seconds))
} else {
Ok(FixedOffset::west(offset_seconds))
}
}
}
}