use std::fmt::{Display, Formatter};
use std::io::Write;
use std::str::FromStr;
use crate::error;
use crate::model::Document;
#[cfg(feature = "fmt_html")]
use crate::write::html::HtmlWriter;
#[cfg(feature = "fmt_json")]
use crate::write::json::JsonWriter;
#[cfg(feature = "fmt_latex")]
use crate::write::latex::LatexWriter;
#[cfg(feature = "fmt_markdown")]
use crate::write::markdown::{MarkdownFlavor, MarkdownWriter};
#[derive(Clone, Debug, PartialEq)]
pub enum OutputFormat {
#[cfg(feature = "fmt_markdown")]
Markdown(MarkdownFlavor),
#[cfg(feature = "fmt_html")]
Html,
#[cfg(feature = "fmt_json")]
Json,
#[cfg(feature = "fmt_latex")]
Latex,
}
pub trait Writer<'a, W: Write> {
fn new(w: &'a mut W) -> Self
where
Self: Sized;
fn write_document(&self, doc: &Document) -> crate::error::Result<()>;
}
pub trait ConfigurableWriter<'a, W: Write, T: Default>: Writer<'a, W> {
fn new_with(w: &'a mut W, config: T) -> Self;
}
pub fn write_document<W: Write>(
doc: &Document,
format: OutputFormat,
w: &mut W,
) -> crate::error::Result<()> {
match format {
#[cfg(feature = "fmt_markdown")]
OutputFormat::Markdown(flavor) => {
let writer = MarkdownWriter::new_with(w, flavor);
writer.write_document(doc)
}
#[cfg(feature = "fmt_html")]
OutputFormat::Html => {
let writer = HtmlWriter::new(w);
writer.write_document(doc)
}
#[cfg(feature = "fmt_json")]
OutputFormat::Json => {
let writer = JsonWriter::new(w);
writer.write_document(doc)
}
#[cfg(feature = "fmt_latex")]
OutputFormat::Latex => {
let writer = LatexWriter::new(w);
writer.write_document(doc)
}
}
}
pub fn write_document_to_string(
doc: &Document,
format: OutputFormat,
) -> crate::error::Result<String> {
use std::io::Cursor;
let mut buffer = Cursor::new(Vec::new());
write_document(doc, format, &mut buffer)?;
Ok(String::from_utf8(buffer.into_inner()).unwrap())
}
impl Default for OutputFormat {
fn default() -> Self {
Self::Markdown(Default::default())
}
}
impl Display for OutputFormat {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
#[cfg(feature = "fmt_markdown")]
Self::Markdown(f) => format!("markdown+{}", f.to_string()),
#[cfg(feature = "fmt_html")]
Self::Html => "html".to_string(),
#[cfg(feature = "fmt_json")]
Self::Json => "json".to_string(),
#[cfg(feature = "fmt_latex")]
Self::Latex => "latex".to_string(),
}
)
}
}
impl FromStr for OutputFormat {
type Err = error::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let parts: Vec<&str> = s.split('+').collect();
if parts.len() < 1 || parts.len() > 2 {
Err(error::ErrorKind::UnknownFormat.into())
} else {
match *parts.first().unwrap() {
#[cfg(feature = "fmt_markdown")]
"md" | "markdown" => {
if let Some(flavor) = parts.get(1) {
Ok(Self::Markdown(MarkdownFlavor::from_str(flavor)?))
} else {
Ok(Self::Markdown(MarkdownFlavor::default()))
}
}
#[cfg(feature = "fmt_markdown")]
"xwiki" => Ok(Self::Markdown(MarkdownFlavor::XWiki)),
#[cfg(feature = "fmt_html")]
"html" => Ok(Self::Html),
#[cfg(feature = "fmt_json")]
"json" => Ok(Self::Json),
#[cfg(feature = "fmt_latex")]
"latex" | "tex" => Ok(Self::Latex),
_ => Err(error::ErrorKind::UnknownFormat.into()),
}
}
}
}
#[cfg(feature = "fmt_html")]
pub mod html;
#[cfg(feature = "fmt_json")]
pub mod json;
#[cfg(feature = "fmt_latex")]
pub mod latex;
#[cfg(feature = "fmt_markdown")]
pub mod markdown;
pub(crate) mod utils;