use std::path::PathBuf;
use rust_i18n::t;
#[derive(Clone, Debug)]
pub enum Error {
NoneSpecified { subject: Subject },
Invalid {
subject: Subject,
examples: Option<Vec<String>>,
},
AmbiguousShortRecipe {
query: String,
possibilities: Vec<String>,
},
DestructionWarning { name: String },
Exclude { cause: String },
FsDenied { which: PathBuf, context: Context },
NotUTF8 { which: PathBuf },
NotTTY,
InteractiveCancelled,
#[allow(unused)]
Serialisation {
which: PathBuf,
cause: String,
context: Context,
},
Deserialisation {
which: PathBuf,
cause: String,
context: Context,
},
}
impl std::error::Error for Error {}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::NoneSpecified { subject } => {
write!(f, "{}", t!("errors.none_specified", subject => subject))
}
Error::Invalid { subject, examples } => {
let base = t!("errors.invalid", subject => subject);
match examples.as_deref() {
Some(eg) => {
write!(
f,
"{base}:{}{}",
if eg.len() > 1 { "\n" } else { " " },
eg.join("\n")
)
}
None => {
write!(f, "{base}")
}
}
}
Error::AmbiguousShortRecipe {
query,
possibilities,
} => {
let ps = possibilities.join(", ");
write!(f, "{} '{query}' ({ps})", t!("errors.ambiguous"))
}
Error::Exclude { cause } => {
write!(f, "{}: {cause}", t!("errors.exclude"))
}
Error::FsDenied { which, context } => write!(
f,
"{}",
t!("errors.fs_denied", which => which.to_string_lossy(), context => context),
),
Error::NotUTF8 { which } => write!(
f,
"{}",
t!("errors.not_utf8", file => which.to_string_lossy())
),
Error::NotTTY => write!(f, "{}", t!("errors.not_tty")),
Error::InteractiveCancelled => write!(f, "{}", t!("errors.interrupted")),
Error::DestructionWarning { name } => {
write!(f, "{}", t!("errors.destruction", name => name))
}
Error::Serialisation {
which,
cause,
context,
} => {
write!(
f,
"{}\n{cause}",
t!("errors.serialise", which => which.to_string_lossy(), context => context)
)
}
Error::Deserialisation {
which,
cause,
context,
} => {
write!(
f,
"{}\n{cause}",
t!("errors.deserialise", which => which.to_string_lossy(), context => context)
)
}
}
}
}
#[derive(Clone, Copy, Debug)]
pub enum Context {
Config,
Delete,
Evoke,
Gather,
Imprint,
Man,
Tempfile,
}
impl std::fmt::Display for Context {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Context::Config => t!("contexts.config"),
Context::Delete => t!("contexts.delete"),
Context::Evoke => t!("contexts.evocation"),
Context::Gather => t!("context.gather"),
Context::Imprint => t!("contexts.imprint"),
Context::Man => t!("contexts.man"),
Context::Tempfile => t!("contexts.tempfile"),
}
)
}
}
#[derive(Clone, Copy, Debug)]
pub enum Subject {
Recipe,
Recipes,
}
impl Subject {
pub fn from_count(count: usize) -> Self {
match count {
1 => Self::Recipe,
2.. => Self::Recipes,
0 => crate::borked!(count),
}
}
}
impl std::fmt::Display for Subject {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Self::Recipe => t!("subject.recipe"),
Self::Recipes => t!("subject.recipes"),
}
)
}
}
#[macro_export]
macro_rules! warning {
($($arg:tt)*) => {{
use colored::Colorize;
eprintln!("{} {}", "[ warning ]".yellow(), format_args!($($arg)*));
}};
}
#[macro_export]
macro_rules! die {
($($arg:tt)*) => {{
use colored::Colorize;
eprintln!("{} {}", "[ error ]".red(), format_args!($($arg)*));
std::process::exit(1);
}};
}
#[macro_export]
macro_rules! borked {
($err:expr) => {{
$crate::die!("{} unexpected error: please make an issue at https://github.com/4jamesccraven/mkdev !!\n{}", $crate::ctx!(""), $err);
}};
}
#[macro_export]
macro_rules! ctx {
($msg:literal) => {
concat!("[", file!(), ":", line!(), "] ", $msg)
};
}
impl From<ignore::Error> for Error {
fn from(e: ignore::Error) -> Self {
Error::Exclude {
cause: e.to_string(),
}
}
}
impl From<inquire::error::InquireError> for Error {
fn from(value: inquire::error::InquireError) -> Self {
match value {
inquire::InquireError::NotTTY => Error::NotTTY,
inquire::InquireError::OperationCanceled => Error::InteractiveCancelled,
inquire::InquireError::OperationInterrupted => Error::InteractiveCancelled,
_ => borked!(value),
}
}
}