use clap::{crate_authors, Parser};
use std::collections::HashSet;
use std::io;
use std::path::{Path, PathBuf};
use super::clean::clean_dirs_names;
use super::read::{combine_path_like, read_path};
use super::write::replace_path;
#[derive(Debug, Parser)]
#[clap(
about = "Add a directory",
author = crate_authors!(),
)]
pub struct AddOpt {
#[clap(default_value = ".", name = "dir")]
dirs: Vec<PathBuf>,
#[clap(short, long)]
force: bool,
#[clap(short, long)]
prepend: bool,
#[clap(short, long)]
quiet: bool,
#[clap(short = 'H', long)]
history: bool,
#[clap(short = 'n', long = "dry-run")]
dry_run: bool,
}
impl AddOpt {
pub fn validate(&self) -> io::Result<()> {
if self.force {
return Ok(());
}
for d in &self.dirs {
if !d.exists() {
let err_nonexistent = io::Error::new(
io::ErrorKind::InvalidData,
format!(
"Directory `{}` does not exist. Please double check the directories you intend to add.",
d.display()
)
);
if !self.quiet {
eprintln!("{}", err_nonexistent);
}
return Err(err_nonexistent);
}
}
let cleaned_dirs: Vec<PathBuf> = clean_dirs_names(&self.dirs);
let _current_dirs: HashSet<PathBuf> = read_path().iter().cloned().collect();
let _new_dirs: HashSet<PathBuf> = cleaned_dirs.iter().cloned().collect();
let _intersecting_dirs: Vec<&Path> = _current_dirs
.intersection(&_new_dirs)
.into_iter()
.map(|d| d.as_path())
.collect();
if !_intersecting_dirs.is_empty() {
let err_duplicated = io::Error::new(
io::ErrorKind::AlreadyExists,
format!(
"Directory `{}` already exists in `$PATH`. Use `pad up/dn` to change priority of this directory, or `pad add -f` to force it. No changes made.",
_intersecting_dirs[0].display()
)
);
if !self.quiet {
eprintln!("{}", err_duplicated);
}
return Err(err_duplicated);
}
Ok(())
}
}
pub fn add_to_path(opts: &AddOpt) -> io::Result<()> {
let mut current_path: Vec<PathBuf> = read_path();
let mut cleaned_dirs: Vec<PathBuf> = clean_dirs_names(&opts.dirs);
let newpath = match opts.prepend {
true => {
cleaned_dirs.append(&mut current_path);
combine_path_like(cleaned_dirs)
}
false => {
current_path.append(&mut cleaned_dirs);
combine_path_like(current_path)
}
}?;
match replace_path(newpath, opts.dry_run, opts.history, opts.quiet) {
Ok(()) => Ok(()),
Err(e) => {
if !opts.quiet {
eprintln!("{}", e);
}
Err(e)
}
}
}