use std::{collections::HashMap, fs, path::PathBuf, process::Command};
use serde::{Serialize, Deserialize};
use toml;
#[derive(Debug, Default, Clone, Deserialize, Serialize)]
struct MapFormula{
p_map_formula: HashMap<String, String>,
}
fn load_map_formula(filename: &PathBuf) -> MapFormula {
let config: MapFormula = match fs::read_to_string(filename) {
Ok(str) => match toml::from_str(&str){
Ok(value) => value,
Err(error) => panic!("load_map_formula : cannot parse file contaning formulae {:?}, parsing error {}", filename, error)
},
Err(_) => Default::default()
};
return config;
}
fn save_map_formula(filename: &PathBuf, map_formula: &MapFormula){
let body: String = match toml::to_string(map_formula) {
Ok(value) => value,
Err(err) => panic!("save_map_formula : cannot serialise MapFormula in toml\n\tError {}", err)
};
match fs::write(filename, body) {
Ok(_) => {},
Err(err) => panic!("save_map_formula : cannot save the map of formula in the file {:?}\n\tError {}", filename, err)
}
}
pub struct PFormulaManager{
p_output_directory: PathBuf,
p_formula_config_file: PathBuf,
p_map_formula: MapFormula,
p_script_create_formula: PathBuf,
}
impl Drop for PFormulaManager{
fn drop(&mut self) {
fs::remove_file(&self.p_script_create_formula).unwrap();
save_map_formula(&self.p_formula_config_file, &self.p_map_formula);
}
}
impl PFormulaManager {
pub fn new(output_directory: &PathBuf) -> Self{
let config_formula: PathBuf = output_directory.join(PathBuf::from("formulae.toml"));
let script_create_formula: PathBuf = output_directory.join(PathBuf::from("script_create_formula.sh"));
let output_formula_dir: PathBuf = output_directory.join(PathBuf::from("formulae"));
match fs::create_dir_all(&output_formula_dir){
Ok(_) => {},
Err(err) => panic!("PFormulaManager::new : cannot create output formula directory {:?}\n\tError {}", output_formula_dir, err)
}
create_script_formula(&script_create_formula);
PFormulaManager{
p_output_directory: output_directory.clone(),
p_formula_config_file: config_formula.clone(),
p_map_formula: load_map_formula(&config_formula),
p_script_create_formula: script_create_formula.clone(),
}
}
pub fn formula_to_html(&mut self, formula: &String) -> String{
let trim_formula = String::from(formula.trim());
let matched_formula: String = match self.p_map_formula.p_map_formula.get(&trim_formula) {
Some(html) => html.clone(),
None => String::from("")
};
if !matched_formula.is_empty() {
return matched_formula;
}
return self.create_formula(&trim_formula);
}
fn create_formula(&mut self, trim_formula: &String) -> String{
let image_index: usize = self.p_map_formula.p_map_formula.len() + 1;
let image = String::from(&format!("formulae/{}.png", image_index));
let absolute_image_path: PathBuf = self.p_output_directory.join(PathBuf::from(&image));
create_latex_formula_file(&self.p_output_directory, image_index, &trim_formula);
match Command::new(&self.p_script_create_formula)
.arg(image_index.to_string())
.arg(&absolute_image_path)
.current_dir(&self.p_output_directory)
.output()
{
Ok(_) => {},
Err(err) => panic!("PFormulaManager::create_formula : cannot create file {:?}\n\tWith formula '{}'\n\tError {}", absolute_image_path, trim_formula, err)
}
let html = String::from(&format!("<img src=\"{}\" alt=\"formula\" />", image));
self.p_map_formula.p_map_formula.insert(trim_formula.clone(), html.clone());
return html;
}
}
fn create_latex_formula_file(output_directory: &PathBuf, image_index: usize, trim_formula: &String){
let mut body = String::from("");
if trim_formula.starts_with('$') {
body += &String::from("\\documentclass[8pt]{article}\n");
}else{
body += &String::from("\\documentclass[20pt]{article}\n");
}
body += &String::from("\\usepackage[T1]{fontenc}\n\\usepackage[utf8]{inputenc}\n\\usepackage{lmodern}\n");
body += &String::from("\\usepackage{calc}\n\\usepackage{amssymb}\n\\usepackage{color}\n\\usepackage{amsfonts}\n\\usepackage{bbm}\n\\pagestyle{empty}\n");
body += &String::from("\\usepackage{amsmath}\n\\usepackage{esint}\n");
body += &String::from("\\begin{document}\n");
body += &String::from("\\def\\sgn{\\mathop{\\mathgroup\\symoperators sgn}\\nolimits}\n");
body += &String::from("\\pagecolor{black}\\color{white}");
body += &String::from(trim_formula);
body += &String::from("\n");
body += &String::from("\\end{document}\n");
let output_file = output_directory.join(format!("{}_tmp_file.tex", image_index));
match fs::write(&output_file, &body) {
Ok(_) => {},
Err(err) => panic!("Cannot create latex file {:?}\n\tError {}", output_file, err)
}
}
fn create_script_formula(filename: &PathBuf){
let body = String::from(r#"#!/bin/bash
#fichier png que l'on veut générer avec le fichier tex
IMAGE_INDEX="$1"
FILE_OUTPUT_PNG="$2"
#fichier tex que l'on veut générer en dvi
FILE_TEX="${IMAGE_INDEX}_tmp_file.tex"
FILE_DVI="${IMAGE_INDEX}_tmp_file.dvi"
# FILE_TMP_LOG="/tmp/fileTmpLogTex.txt"
# cd /tmp/
# latex -halt-on-error ${FILE_TEX} > FILE_TMP_LOG && dvipng -D 200 ${FILE_DVI} -T tight -bg transparent -o ${FILE_OUTPUT_PNG} > FILE_TMP_LOG && rm file.tex file.aux file.log file.dvi
#le fichier de sortie console de latex
LOG_FILE="logOfLatex.log"
#Je commence à en avoir marre que bash se foute de moi
function quitOnError {
echo "====== Fail to create image formula :"
cat ${FILE_TEX}
echo "====== Error :"
cat $LOG_FILE | tail -n 100
exit 1
}
latex -halt-on-error ${FILE_TEX} ${FILE_DVI} > $LOG_FILE || quitOnError
# echo "Latex Success"
dvipng -D 180 ${FILE_DVI} -T tight -bg transparent -o ${FILE_OUTPUT_PNG} > /dev/null
# dvipng -D 130 ${FILE_DVI} -T tight -o ${FILE_OUTPUT_PNG} > /dev/null
# echo "Génération de l'image OK"
# rm ${FILE_DVI} *.aux *.log
rm ${FILE_DVI} *.aux *.log ${FILE_TEX}
exit 0
"#);
match fs::write(&filename, &body){
Ok(_) => println!("PFormulaManager::create_script_formula : Create formula script {:?}", filename),
Err(err) => panic!("create_script_formula : Cannot save the script {:?}\n\tError {}", filename, err)
}
Command::new("chmod").arg("a+x").arg(&filename).output().expect(&format!("create_script_formula : Cannot change permission of the script {:?}", filename));
}