use crate::build_command::parse_build_args;
use crate::run::usage;
use voltaic_driver::CheckOutcome;
use voltaic_driver::diagnose;
use std::path::PathBuf;
pub(crate) fn check_command(args: &[String]) -> Result<(), String> {
let parsed = parse_build_args(args)?;
let shown = parsed.input.display().to_string();
let source = std::fs::read_to_string(&parsed.input)
.map_err(|e| format!("error: cannot read {}: {}", shown, e))?;
let outcome = voltaic_driver::check(&parsed.input, &source)?;
report(&outcome, parsed.plain)
}
pub(crate) fn report(outcome: &CheckOutcome, plain: bool) -> Result<(), String> {
if outcome.diagnostics.is_empty() {
return Ok(());
}
let rendered = voltaic_diag::render(&outcome.diagnostics, plain);
if outcome.failed {
return Err(rendered);
}
eprintln!("{}", rendered);
Ok(())
}
pub(crate) fn fmt_command(args: &[String]) -> Result<(), String> {
let parsed = parse_fmt_args(args)?;
let mut unformatted: Vec<String> = Vec::new();
for path in &parsed.inputs {
let shown = path.display().to_string();
let source =
std::fs::read_to_string(path).map_err(|e| format!("error: cannot read {}: {}", shown, e))?;
let program = voltaic_parser::parse_source(&source)
.map_err(|failure| voltaic_diag::render(&diagnose(path, &source, &failure), parsed.plain))?;
let formatted = voltaic_fmt::format(&program, &source);
if formatted == source {
continue;
}
if parsed.check {
unformatted.push(shown);
} else {
std::fs::write(path, &formatted)
.map_err(|e| format!("error: cannot write {}: {}", shown, e))?;
}
}
if unformatted.is_empty() {
return Ok(());
}
let indented: Vec<String> = unformatted.iter().map(|p| format!(" {}", p)).collect();
let listed = indented.join("\n");
Err(format!(
"error: not formatted:\n{}\nrun `voltaic fmt` on them\n",
listed
))
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct FmtArgs {
pub(crate) inputs: Vec<PathBuf>,
pub(crate) check: bool,
pub(crate) plain: bool,
}
pub(crate) fn parse_fmt_args(args: &[String]) -> Result<FmtArgs, String> {
let mut inputs = Vec::new();
let mut check = false;
let mut plain = false;
for arg in args {
match arg.as_str() {
"--check" => check = true,
"--plain" => plain = true,
flag if flag.starts_with('-') => {
let help = usage();
return Err(format!("error: unknown flag `{}`\n\n{}", flag, help));
}
path => inputs.push(PathBuf::from(path)),
};
}
if inputs.is_empty() {
let help = usage();
return Err(format!("error: fmt needs at least one .sdx\n\n{}", help));
}
Ok(FmtArgs {
inputs,
check,
plain,
})
}