use crate::{db::Database, error::WHResult, path::FilePath};
use clap::Parser;
use std::str::FromStr;
#[derive(Parser, Debug)]
pub struct Init {
shell: Shell,
#[clap(long, default_value = "wh")]
worm_hole: String,
#[clap(long, default_value = "whcd")]
cd: String,
#[clap(long)]
add: Option<String>,
#[clap(long)]
remove: Option<String>,
#[clap(long)]
list: Option<String>,
#[clap(long)]
search: Option<String>,
#[clap(long)]
query: Option<String>,
#[clap(long)]
edit: Option<String>,
#[clap(long)]
rename: Option<String>,
}
impl Init {
pub fn run(&self, database: &Database, db_path: &str) -> WHResult<()> {
database.init();
println!("{}", self.shell.get_init_code(self, db_path));
Ok(())
}
}
#[derive(clap::ValueEnum, Debug, Clone)]
enum Shell {
Bash,
Fish,
Zsh,
Nu,
}
impl Shell {
fn new_alias(&self, alias: &str, command: &str) -> String {
match self {
Shell::Bash | Shell::Zsh | Shell::Fish => format!("alias {}='{}'", alias, command),
Shell::Nu => format!("alias {} = {}", alias, command),
}
}
pub fn get_init_code(&self, aliases: &Init, db_path: &str) -> String {
let mut builder = Vec::new();
let wh = &aliases.worm_hole;
builder.push(self.new_alias(
&aliases.worm_hole,
&format!("worm_hole --db-path {}", FilePath::from_str(db_path).unwrap().str()),
));
builder.push(self.get_cd_function(aliases));
if let Some(add) = &aliases.add {
builder.push(self.new_alias(add, &format!("{wh} add")));
}
if let Some(remove) = &aliases.remove {
builder.push(self.new_alias(remove, &format!("{wh} rm")));
}
if let Some(list) = &aliases.list {
builder.push(match self {
Shell::Nu => format!("#List all aliases and the corresponding path\ndef --wrapped {list} [ ...args --help(-h) ]: nothing -> table<alias: string, path: string> {{ {wh} ls ...$args | parse --regex '(?P<alias>.+?)\\s+-> (?P<path>.+)' }}"),
_ => self.new_alias(list, &format!("{wh} ls"))
});
}
if let Some(search) = &aliases.search {
builder.push(match self {
Shell::Nu => format!("#Search for aliases with path matching a pattern\ndef --wrapped {search} [ pattern: string ...args --help(-h) ]: nothing -> table<alias: string, path: string> {{ {wh} search $pattern | parse --regex '(?P<alias>.+?)\\s+-> (?P<path>.+)' }}"),
_ => self.new_alias(search, &format!("{wh} search"))
});
}
if let Some(query) = &aliases.query {
builder.push(self.new_alias(query, &format!("{wh} query")));
}
if let Some(edit) = &aliases.edit {
builder.push(self.new_alias(edit, &format!("{wh} edit")));
}
if let Some(rename) = &aliases.rename {
builder.push(self.new_alias(rename, &format!("{wh} rename")));
}
builder.push(match self {
Shell::Bash | Shell::Zsh => format!("export WH_ALIAS=\"{wh}\""),
Shell::Fish => format!("set -gx WH_ALIAS \"{wh}\""),
Shell::Nu => format!("$env.WH_ALIAS = '{wh}'"),
});
builder.join("\n")
}
#[rustfmt::skip]
fn get_cd_function(&self, aliases: &Init) -> String {
let cd = &aliases.cd;
let wh = &aliases.worm_hole;
match self {
Shell::Bash | Shell::Zsh => vec![
format!("{cd}() {{"),
String::from(" if [ -z \"$1\" ]"),
String::from(" then"),
String::from(" cd $HOME"),
String::from(" else"),
format!(" CD=$({wh} query \"$1\") && \\builtin cd \"$CD\""),
String::from(" fi"),
String::from("}"),
],
Shell::Fish => vec![
format!("function {cd}"),
String::from(" if test -z $argv"),
String::from(" cd $HOME"),
String::from(" else"),
format!(" set -l CD ({wh} query \"$argv\")"),
String::from(" if test -n $CD"),
String::from(" builtin cd \"$CD\""),
String::from(" end"),
String::from(" end"),
String::from("end"),
],
Shell::Nu => vec![
format!("def __worm_hole_list [] {{ ({wh} ls | parse --regex '(?P<value>.+?)\\s+-> (?P<description>.+)') }}"),
format!("def --env {cd} [alias?: string@__worm_hole_list] {{"),
String::from(" if $alias == null {"),
String::from(" cd $env.HOME"),
String::from(" } else {"),
format!(" let CD = {wh} query $alias"),
String::from(" if $CD != null {"),
String::from(" cd $CD"),
String::from(" }"),
String::from(" }"),
String::from("}"),
],
}.join("\n")
}
}