use std::{env, fs};
use std::path::PathBuf;
use clap::{Parser, Subcommand};
use clap::builder::Styles;
use clap_verbosity_flag::Verbosity;
use directories::ProjectDirs;
use lazy_static::lazy_static;
use regex::Regex;
use crate::cli::commands::collection_commands::collection_commands::CollectionCommand;
use crate::cli::commands::completions::CompletionsCommand;
use crate::cli::commands::import::ImportCommand;
use crate::cli::commands::request_commands::request_commands::RequestCommand;
use crate::app::files::utils::expand_tilde;
use crate::cli::commands::env::EnvCommand;
use crate::cli::commands::man::ManCommand;
use crate::cli::commands::try_command::TryCommand;
use crate::panic_error;
#[derive(Parser, Debug)]
#[command(
version,
about,
long_about = r#"ATAC is Arguably a Terminal API Client.
It is based on well-known clients such as Postman, Insomnia, or even Bruno, but inside your terminal without any specific graphical environment needed.
The philosophy of ATAC is to be free, account-less, and offline for now and forever."#,
styles = Styles::styled()
)]
pub struct Args {
#[arg(short, long, value_hint = clap::ValueHint::DirPath)]
pub directory: Option<PathBuf>,
#[command(subcommand)]
pub command: Option<Command>,
#[arg(long, global = true)]
pub filter: Option<Regex>,
#[arg(long, global = true, default_value_t = false)]
pub tui: bool,
#[arg(long, global = true, default_value_t = false, display_order = 99)]
pub dry_run: bool,
#[arg(long, global = true, default_value_t = false)]
pub no_ansi_log: bool,
#[command(flatten)]
pub verbose: Verbosity
}
#[derive(Subcommand, Debug, Clone)]
pub enum Command {
Collection(CollectionCommand),
Request(RequestCommand),
Try(TryCommand),
Env(EnvCommand),
Import(ImportCommand),
Completions(CompletionsCommand),
Man(ManCommand),
}
lazy_static! {
pub static ref ARGS: GlobalArgs = {
let args = Args::parse();
let config_directory = get_app_config_dir();
let (directory, should_parse_directory) = match &args.command {
Some(command) => match command.clone() {
Command::Completions(CompletionsCommand { output_directory, .. }) | Command::Man(ManCommand { output_directory, .. }) => (output_directory, false),
Command::Try(_) => (None, false),
_ => (Some(choose_app_directory(args.directory, &config_directory)), true)
},
None => (Some(choose_app_directory(args.directory, &config_directory)), true)
};
GlobalArgs {
directory,
config_directory,
command: args.command,
collection_filter: args.filter,
should_run_tui: args.tui,
should_save: !args.dry_run,
should_parse_directory,
verbosity: args.verbose,
ansi_log: !args.no_ansi_log
}
};
}
fn get_app_config_dir() -> Option<PathBuf> {
let project_directory = ProjectDirs::from("com", "Julien-cpsn", "ATAC");
let config_directory = match project_directory {
Some(project_directory) => {
let config_directory = project_directory.config_dir().to_path_buf();
if !config_directory.exists() {
fs::create_dir_all(&config_directory).expect(&format!("Could not recursively create folder \"{}\"", config_directory.display()));
}
Some(config_directory)
},
None => None
};
return config_directory;
}
fn choose_app_directory(path_buf: Option<PathBuf>, config_directory: &Option<PathBuf>) -> PathBuf {
match path_buf {
Some(directory) => expand_tilde(directory),
None => match env::var("ATAC_MAIN_DIR") {
Ok(env_directory) => expand_tilde(PathBuf::from(env_directory)),
Err(_) => match config_directory {
Some(config_directory) => config_directory.clone(),
None => panic_error("No directory provided, provide one either with `--directory <dir>` or via the environment variable `ATAC_MAIN_DIR`")
}
}
}
}
#[derive(Debug)]
pub struct GlobalArgs {
pub directory: Option<PathBuf>,
pub config_directory: Option<PathBuf>,
pub command: Option<Command>,
pub collection_filter: Option<Regex>,
pub should_run_tui: bool,
pub should_save: bool,
pub should_parse_directory: bool,
pub verbosity: Verbosity,
pub ansi_log: bool
}