use std::fs;
use std::path::{Path, PathBuf};
use std::process::ExitCode;
use base64ct::{Base64Url, Encoding};
use md5::{Digest, Md5};
use crate::codegen::make_latex_format;
use crate::commands::LatexEngineType;
use crate::compile::VestiFile;
use crate::constants;
use crate::error::{self, VestiErr};
use crate::lexer::Lexer;
use crate::parser::Parser;
pub fn compile_vesti(
ves_file: &mut VestiFile,
engine_type: LatexEngineType,
has_sub_vesti: bool,
emit_tex_only: bool,
no_color: bool,
) -> ExitCode {
let pretty_print = if no_color {
crate::error::pretty_print::plain_print
} else {
crate::error::pretty_print::pretty_print
};
let source = match fs::read_to_string(ves_file.filename) {
Ok(content) => content,
Err(err) => {
pretty_print(
None,
VestiErr::from_io_err(
err,
format!("cannot read from {}", ves_file.filename.display()),
),
Some(ves_file.filename),
)
.unwrap();
return ExitCode::FAILURE;
}
};
let mut parser = Parser::new(Lexer::new(&source), !has_sub_vesti);
let contents = match make_latex_format::<false>(&mut parser, engine_type) {
Ok(inner) => inner,
Err(err) => {
pretty_print(Some(source.as_ref()), err, Some(ves_file.filename)).unwrap();
return ExitCode::FAILURE;
}
};
let is_main_vesti = parser.is_main_vesti();
drop(parser);
let output_filename =
match compile_vesti_write_file(ves_file.filename, contents, is_main_vesti, emit_tex_only) {
Ok(name) => name,
Err(err) => {
pretty_print(None, err, None).unwrap();
return ExitCode::FAILURE;
}
};
ves_file.is_main = is_main_vesti;
ves_file.latex_filename = Some(output_filename);
ExitCode::SUCCESS
}
fn vesti_name_mangle(filename: &Path) -> error::Result<String> {
let file_path = match fs::canonicalize(filename) {
Ok(path) => path,
Err(err) => {
return Err(VestiErr::from_io_err(
err,
format!(
"cannot get the canonicalized name for {}",
filename.display()
),
))
}
};
let mut hasher = Md5::new();
hasher.update(file_path.into_os_string().into_encoded_bytes());
let hash = hasher.finalize();
let base64_hash = Base64Url::encode_string(&hash);
Ok(format!("@vesti__{}.tex", base64_hash))
}
fn compile_vesti_write_file(
filename: &Path,
contents: String,
is_main_vesti: bool,
_emit_tex_only: bool,
) -> error::Result<PathBuf> {
let output_filename = if !is_main_vesti {
vesti_name_mangle(filename)?
} else {
let tmp = filename.with_extension("tex");
let Some(raw_filename) = tmp.iter().next_back() else {
return Err(VestiErr::make_util_err(
error::VestiUtilErrKind::NoFilenameInputErr,
));
};
let Some(raw_filename) = raw_filename.to_str() else {
return Err(VestiErr::make_util_err(
error::VestiUtilErrKind::NoFilenameInputErr,
));
};
raw_filename.to_string()
};
let output_filename1 = format!("{}/{}", constants::VESTI_LOCAL_DUMMY_DIR, output_filename);
match fs::write(&output_filename1, contents) {
Ok(()) => {}
Err(err) => {
return Err(VestiErr::from_io_err(
err,
format!("cannot write into {output_filename1}"),
))
}
}
Ok(PathBuf::from(output_filename))
}