#[macro_export]
macro_rules! create_recursive {
($path:expr) => {
let create_recursive_dir = |p: &std::path::Path| {
if !p.exists() || !p.is_dir() {
let mut builder = std::fs::DirBuilder::new();
builder.recursive(true);
builder.create(p).expect("Recursive mode won't panic");
}
};
create_recursive_dir($path)
};
}
#[macro_export]
macro_rules! map_miette {
($expr:expr, $wrap_msg:expr, $usage:expr, help = $add_help:expr) => {
$expr.map_err(|e| {
use crossterm::style::Stylize;
miette::miette!(
help = format!("{}\nFor more information, try `sericom --help`.", $add_help),
"{e}"
)
.wrap_err(format!("{}\n\n{}\n", $wrap_msg, $usage).red())
})
};
($expr:expr, $wrap_msg:expr, $usage:expr) => {
$expr.map_err(|e| {
use crossterm::style::Stylize;
miette::miette!(help = "For more information, try `sericom --help`.", "{e}")
.wrap_err(format!("{}\n\n{}\n", $wrap_msg, $usage).red())
})
};
($expr:expr, $wrap_msg:expr, help = $add_help:expr) => {
$expr.map_err(|e| {
use crossterm::style::Stylize;
miette::miette!(
help = format!("{}\nFor more information, try `sericom --help`.", $add_help),
"{e}"
)
.wrap_err(format!("{}", $wrap_msg).red())
})
};
($expr:expr, $wrap_msg:expr) => {
$expr.map_err(|e| {
use crossterm::style::Stylize;
miette::miette!(help = "For more information, try `sericom --help`.", "{e}")
.wrap_err(format!("{}", $wrap_msg).red())
})
};
}
#[macro_export]
macro_rules! compat_port_path {
($port:expr, prefix = $prefix:literal) => {{
use chrono;
use std::path::PathBuf;
let path_port = $crate::path_utils::get_compat_port_path($port)?;
PathBuf::from(format!(
"./{}-{}-{}.txt",
$prefix,
path_port.display(),
chrono::Utc::now().format("%m%d%H%M"),
))
}};
($out_dir:expr, $port:expr, prefix = $prefix:expr) => {{
use chrono;
let path_port = $crate::path_utils::get_compat_port_path($port)?;
$out_dir.join(format!(
"./{}-{}-{}.txt",
$prefix,
path_port.display(),
chrono::Utc::now().format("%m%d%H%M"),
))
}};
($out_dir:expr, $port:expr) => {{
use chrono;
let path_port = $crate::path_utils::get_compat_port_path($port)?;
$out_dir.join(format!(
"./{}-{}.txt",
path_port.display(),
chrono::Utc::now().format("%m%d%H%M"),
))
}};
($port:expr) => {{
use chrono;
let path_port = $crate::path_utils::get_compat_port_path($port)?;
PathBuf::from(format!(
"./{}-{}.txt",
path_port.display(),
chrono::Utc::now().format("%m%d%H%M"),
))
}};
}
#[doc(hidden)]
pub fn get_compat_port_path<S>(port: S) -> miette::Result<std::path::PathBuf>
where
S: Into<std::path::PathBuf>,
{
#[cfg(windows)]
{
Ok(port.into())
}
#[cfg(unix)]
{
use miette::{self, WrapErr};
use std::path::PathBuf;
let p: PathBuf = port.into();
Ok(PathBuf::from(p.file_name().ok_or(std::io::ErrorKind::InvalidFilename)
.map_err(|e| miette::miette!(
help = format!("The name of the tracing file is tied to the port being opened, make sure you are using a valid port."),
"{e}: '{}'\n",
p.display()
)).wrap_err_with(|| format!("Could not create file: '{}' for tracing output.\n", p.display()))?))
}
}
macro_rules! push_n_check {
($home:expr, $push:literal) => {
$home.push($push);
if !$home.exists() {
return None;
}
};
}
macro_rules! expand_path {
($self:ident, $expand:literal, to = $expand_to:literal) => {{
use std::{env, path::PathBuf};
if $self.starts_with($expand) {
let mut home = env::home_dir()?;
let expanded: PathBuf = $self.components().skip(1).collect();
push_n_check!(home, $expand_to);
$self = home.join(expanded);
}
}};
($self:ident, $expand:literal) => {{
use std::{env, path::PathBuf};
if $self.starts_with($expand) {
let home = env::home_dir()?;
let expanded: PathBuf = $self.components().skip(1).collect();
$self = home.join(expanded);
}
}};
}
#[cfg(windows)]
macro_rules! expand_env_path {
($self:ident, $expand:literal, env_var = $env_var:literal) => {{
use std::{env, path::PathBuf};
if $self.starts_with($expand) {
if let Ok(base_path) = env::var($env_var) {
let expanded: PathBuf = $self.components().skip(1).collect();
$self = PathBuf::from(base_path).join(expanded)
}
}
}};
}
pub trait ExpandPaths {
fn get_expanded_path(self) -> Option<std::path::PathBuf>;
}
impl ExpandPaths for std::path::PathBuf {
#[cfg(unix)]
fn get_expanded_path(mut self) -> Option<Self> {
expand_path!(self, "~");
expand_path!(self, "$HOME");
expand_path!(self, "$XDG_CACHE_HOME", to = ".cache");
expand_path!(self, "$XDG_CONFIG_HOME", to = ".config");
expand_path!(self, "$XDG_DATA_HOME", to = ".local/share");
expand_path!(self, "$XDG_DESKTOP_DIR", to = "Desktop");
expand_path!(self, "$XDG_DOCUMENTS_DIR", to = "Documents");
expand_path!(self, "$XDG_DOWNLOAD_DIR", to = "Downloads");
expand_path!(self, "$XDG_MUSIC_DIR", to = "Music");
expand_path!(self, "$XDG_PICTURES_DIR", to = "Pictures");
expand_path!(self, "$XDG_PUBLICSHARE_DIR", to = "Public");
expand_path!(self, "$XDG_STATE_HOME", to = ".local/state");
expand_path!(self, "$XDG_TEMPLATES_DIR", to = "Templates");
Some(self)
}
#[cfg(windows)]
fn get_expanded_path(mut self) -> Option<Self> {
expand_path!(self, "~");
expand_env_path!(self, "%USERPROFILE%", env_var = "USERPROFILE");
expand_env_path!(self, "%APPDATA%", env_var = "APPDATA");
expand_env_path!(self, "%LOCALAPPDATA%", env_var = "LOCALAPPDATA");
expand_env_path!(self, "%TEMP%", env_var = "TEMP");
expand_env_path!(self, "%TMP%", env_var = "TMP");
expand_path!(self, "%DESKTOP%", to = "Desktop");
expand_path!(self, "%DOCUMENTS%", to = "Documents");
expand_path!(self, "%DOWNLOADS%", to = "Downloads");
expand_path!(self, "%MUSIC%", to = "Music");
expand_path!(self, "%PICTURES%", to = "Pictures");
expand_path!(self, "%VIDEOS%", to = "Videos");
expand_path!(self, "%PUBLIC%", to = "Public");
Some(self)
}
}