mod agent_commands;
mod analysis_commands;
mod analyze;
mod args;
mod basic;
mod build;
mod build_structures;
mod commands_extra;
mod convert;
mod dispatch;
mod docs_commands;
mod engine_commands;
mod ff_commands;
mod format;
mod input;
mod limits;
mod measure;
mod mesh;
mod model_commands;
mod mof_commands;
mod output;
mod powder_commands;
mod pxrd;
mod spacegroup;
mod symmetry;
mod symmetry_analysis;
use clap::Parser;
use std::process::ExitCode;
use args::Command;
use limits::Limits;
const ERROR_EXIT_CODE: u8 = 3;
#[derive(Debug, Parser)]
#[command(
name = "xtalforge",
version,
about = "Build, manipulate, analyse and export crystal structures",
disable_help_subcommand = true
)]
struct Cli {
#[arg(long, global = true)]
json: bool,
#[arg(long, global = true)]
quiet: bool,
#[arg(long, global = true)]
strict: bool,
#[arg(long, global = true, value_name = "N")]
threads: Option<usize>,
#[arg(long, global = true, value_enum, default_value_t = Limits::Standard)]
limits: Limits,
#[command(subcommand)]
command: Command,
}
#[derive(Debug)]
pub(crate) struct CliError {
pub(crate) code: &'static str,
pub(crate) message: String,
}
impl CliError {
pub(crate) fn new(code: &'static str, message: impl Into<String>) -> Self {
Self {
code,
message: message.into(),
}
}
pub(crate) fn input(message: impl Into<String>) -> Self {
Self::new("invalid_input", message)
}
pub(crate) fn core(error: xtalforge::core::Error) -> Self {
Self::new(error.code(), error.message())
}
pub(crate) fn ff(error: xtalforge::ff::Error) -> Self {
Self::new(error.code(), error.message())
}
pub(crate) fn analysis(error: xtalforge::analysis::Error) -> Self {
Self::new(error.code(), error.message())
}
pub(crate) fn mof(error: xtalforge::mof::Error) -> Self {
Self::new(error.code(), error.message())
}
}
fn main() -> ExitCode {
let cli = Cli::parse();
match dispatch::run(&cli) {
Ok(()) => ExitCode::SUCCESS,
Err(error) => {
dispatch::report_error(&cli, &error);
ExitCode::from(ERROR_EXIT_CODE)
}
}
}