mod commands;
mod completions;
mod util;
pub use util::print_error;
#[cfg(feature = "import")]
use crate::commands::import::ImportCommand;
use crate::{
commands::{
collection::CollectionCommand, config::ConfigCommand, db::DbCommand,
generate::GenerateCommand, new::NewCommand, request::RequestCommand,
},
completions::{complete_collection_path, complete_log_level},
};
use clap::{CommandFactory, Parser};
use clap_complete::CompleteEnv;
use slumber_core::collection::{CollectionError, CollectionFile};
use slumber_util::paths;
use std::{path::PathBuf, process::ExitCode};
use tracing::level_filters::LevelFilter;
const COMMAND_NAME: &str = "slumber";
#[derive(Debug, Parser)]
#[clap(author, version, about, name = COMMAND_NAME)]
#[expect(rustdoc::bare_urls)]
pub struct Args {
#[command(flatten)]
pub global: GlobalArgs,
#[command(subcommand)]
pub subcommand: Option<CliCommand>,
}
impl Args {
pub fn complete() {
CompleteEnv::with_factory(Args::command).complete();
}
pub fn parse() -> Self {
<Self as Parser>::parse()
}
}
#[derive(Debug, Parser)]
pub struct GlobalArgs {
#[clap(long, short, add = complete_collection_path())]
pub file: Option<PathBuf>,
#[clap(long, default_value_t = LevelFilter::OFF, add = complete_log_level())]
pub log_level: LevelFilter,
#[clap(long)]
pub print_log_path: bool,
}
impl GlobalArgs {
fn collection_file(&self) -> Result<CollectionFile, CollectionError> {
CollectionFile::new(self.file.clone())
}
}
impl Default for GlobalArgs {
fn default() -> Self {
Self {
file: None,
log_level: LevelFilter::OFF,
print_log_path: false,
}
}
}
#[derive(Clone, Debug, clap::Subcommand)]
pub enum CliCommand {
Collection(CollectionCommand),
Config(ConfigCommand),
Db(DbCommand),
Generate(GenerateCommand),
#[cfg(feature = "import")]
Import(ImportCommand),
New(NewCommand),
Request(RequestCommand),
}
impl CliCommand {
pub async fn execute(self, global: GlobalArgs) -> anyhow::Result<ExitCode> {
if global.print_log_path {
let path = paths::log_file();
println!("Logging to {}", path.display());
}
match self {
Self::Collection(command) => command.execute(global).await,
Self::Config(command) => command.execute(global).await,
Self::Db(command) => command.execute(global).await,
Self::Generate(command) => command.execute(global).await,
#[cfg(feature = "import")]
Self::Import(command) => command.execute(global).await,
Self::New(command) => command.execute(global).await,
Self::Request(command) => command.execute(global).await,
}
}
}
trait Subcommand {
async fn execute(self, global: GlobalArgs) -> anyhow::Result<ExitCode>;
}