use std::path::PathBuf;
use crate::document::{
BuildTargetType, InputFile, OutputProfile, DEFAULT_INDEX_FILE, DEFAULT_POSTAMBLE_FILE,
DEFAULT_PREAMBLE_FILE,
};
use serde::{Deserialize, Serialize, Serializer};
#[derive(Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct TomlDocument {
pub doc: TomlDocSection,
#[serde(rename = "output")]
pub outputs: Vec<TomlOutputProfile>,
}
#[derive(Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct TomlDocSection {
pub name: String,
pub bundle: String,
pub metadata: Option<toml::Value>,
pub extra_paths: Option<Vec<PathBuf>>,
}
#[derive(Debug, Deserialize)]
#[serde(untagged)]
pub enum StringOrInputVec {
String(TomlInputFile),
Vec(Vec<TomlInputFile>),
}
impl Serialize for StringOrInputVec {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
Self::String(s) => s.serialize(serializer),
Self::Vec(v) => {
if v.len() == 1 {
v[0].serialize(serializer)
} else {
v.serialize(serializer)
}
}
}
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(untagged)]
pub enum TomlInputFile {
Inline { inline: String },
Path(String),
}
impl From<&InputFile> for TomlInputFile {
fn from(val: &InputFile) -> TomlInputFile {
match val {
InputFile::Inline(inline) => TomlInputFile::Inline {
inline: inline.clone(),
},
InputFile::File(f) => TomlInputFile::Path(f.clone()),
}
}
}
impl From<TomlInputFile> for InputFile {
fn from(val: TomlInputFile) -> InputFile {
match val {
TomlInputFile::Inline { inline } => InputFile::Inline(inline),
TomlInputFile::Path(f) => InputFile::File(f),
}
}
}
#[derive(Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct TomlOutputProfile {
pub name: String,
#[serde(rename = "type")]
pub target_type: TomlBuildTargetType,
pub tex_format: Option<String>,
pub shell_escape: Option<bool>,
pub shell_escape_cwd: Option<String>,
pub synctex: Option<bool>,
pub inputs: Option<StringOrInputVec>,
#[serde(rename = "preamble")]
pub preamble_file: Option<String>,
#[serde(rename = "index")]
pub index_file: Option<String>,
#[serde(rename = "postamble")]
pub postamble_file: Option<String>,
}
impl From<&TomlOutputProfile> for OutputProfile {
fn from(val: &TomlOutputProfile) -> OutputProfile {
let shell_escape_default = val.shell_escape_cwd.is_some();
let synctex_default = false;
let inputs = {
if let Some(inputs) = &val.inputs {
match inputs {
StringOrInputVec::String(s) => vec![s.clone().into()],
StringOrInputVec::Vec(v) => v.iter().map(|x| x.clone().into()).collect(),
}
} else {
vec![
TomlInputFile::Path(
val.preamble_file
.clone()
.unwrap_or(DEFAULT_PREAMBLE_FILE.to_string()),
)
.into(),
TomlInputFile::Path(
val.index_file
.clone()
.unwrap_or(DEFAULT_INDEX_FILE.to_string()),
)
.into(),
TomlInputFile::Path(
val.postamble_file
.clone()
.unwrap_or(DEFAULT_POSTAMBLE_FILE.to_string()),
)
.into(),
]
}
};
OutputProfile {
name: val.name.clone(),
target_type: val.target_type.into(),
tex_format: val
.tex_format
.as_ref()
.map(|s| s.as_ref())
.unwrap_or("latex")
.to_owned(),
inputs,
shell_escape: val.shell_escape.unwrap_or(shell_escape_default),
shell_escape_cwd: val.shell_escape_cwd.clone(),
synctex: val.synctex.unwrap_or(synctex_default),
}
}
}
impl From<&OutputProfile> for TomlOutputProfile {
fn from(rt: &OutputProfile) -> Self {
let tex_format = if rt.tex_format == "latex" {
None
} else {
Some(rt.tex_format.clone())
};
let inputs: StringOrInputVec =
StringOrInputVec::Vec(rt.inputs.clone().iter().map(TomlInputFile::from).collect());
let shell_escape = if !rt.shell_escape { None } else { Some(true) };
let shell_escape_cwd = rt.shell_escape_cwd.clone();
let synctex = if !rt.synctex { None } else { Some(true) };
TomlOutputProfile {
name: rt.name.clone(),
target_type: TomlBuildTargetType::from(&rt.target_type),
tex_format,
inputs: Some(inputs),
shell_escape,
shell_escape_cwd,
synctex,
preamble_file: None,
index_file: None,
postamble_file: None,
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum TomlBuildTargetType {
#[serde(rename = "html")]
Html,
#[serde(rename = "pdf")]
Pdf,
}
impl From<TomlBuildTargetType> for BuildTargetType {
fn from(val: TomlBuildTargetType) -> BuildTargetType {
match val {
TomlBuildTargetType::Html => BuildTargetType::Html,
TomlBuildTargetType::Pdf => BuildTargetType::Pdf,
}
}
}
impl From<&BuildTargetType> for TomlBuildTargetType {
fn from(s: &BuildTargetType) -> Self {
match s {
BuildTargetType::Html => TomlBuildTargetType::Html,
BuildTargetType::Pdf => TomlBuildTargetType::Pdf,
}
}
}