#![forbid(unsafe_code)]
mod check;
mod compile;
mod diagnostics;
mod eval;
mod explain;
mod fingerprint;
mod fmt;
mod from_ron;
mod init;
mod layers;
mod ron;
mod value;
use std::process::ExitCode;
use clap::error::ErrorKind;
use clap::{CommandFactory, Parser, Subcommand, ValueEnum};
#[derive(Debug, Parser)]
#[command(name = "crol", version, arg_required_else_help = true)]
struct Cli {
#[arg(long, value_enum, default_value_t = ColorWhen::Auto, global = true)]
color: ColorWhen,
#[arg(long, value_enum, default_value_t = MessageFormat::Human, global = true)]
message_format: MessageFormat,
#[arg(long)]
init: bool,
#[command(subcommand)]
command: Option<Command>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
enum ColorWhen {
Auto,
Always,
Never,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
enum MessageFormat {
Human,
Json,
}
#[derive(Debug, Subcommand)]
enum Command {
Check(check::Args),
Eval(eval::Args),
Explain(explain::Args),
Fingerprint(fingerprint::Args),
Compile(compile::Args),
Fmt(fmt::Args),
FromRon(from_ron::Args),
Init,
Lsp,
}
fn main() -> ExitCode {
let cli = Cli::parse();
let mut reporter = diagnostics::Reporter::new(cli.color, cli.message_format);
let command = match (cli.init, cli.command) {
(false, Some(command)) => command,
(true, None) => Command::Init,
(true, Some(_)) => Cli::command()
.error(ErrorKind::ArgumentConflict, "`--init` takes no command")
.exit(),
(false, None) => Cli::command()
.error(ErrorKind::MissingSubcommand, "a command is required")
.exit(),
};
let ok = match command {
Command::Check(args) => check::run(&args, &mut reporter),
Command::Eval(args) => eval::run(&args, &mut reporter),
Command::Explain(args) => explain::run(&args, &mut reporter),
Command::Fingerprint(args) => fingerprint::run(&args, &mut reporter),
Command::Compile(args) => compile::run(&args, &mut reporter),
Command::Fmt(args) => fmt::run(&args, &mut reporter),
Command::FromRon(args) => from_ron::run(&args, &mut reporter),
Command::Init => init::run(&mut reporter),
Command::Lsp => match crol_lsp::serve_stdio() {
Ok(()) => true,
Err(error) => {
reporter.error(&format!("language server: {error}"));
false
}
},
};
if ok {
ExitCode::SUCCESS
} else {
ExitCode::FAILURE
}
}