use crate::structs::*;
use std::fmt;
fn html_escape(s: &String) -> String {
s.replace("&", "&")
.replace("<", "<")
.replace(">", ">")
}
impl fmt::Display for Textile {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for block in self.0.iter() {
write!(f, "{}\n", block)?
}
Ok(())
}
}
impl fmt::Display for BlockTag {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BlockTag::Basic {
kind,
header,
content,
} => match kind {
BlockKind::Footnote(n) => {
let mut attributes =
header.attributes.clone().unwrap_or(Attributes {
class: None,
id: None,
style: None,
language: None,
});
attributes.class = match attributes.class {
Some(s) => Some(format!("footnote {}", s)),
None => Some(String::from("footnote")),
};
attributes.id = match attributes.id {
Some(s) => Some(format!("fn{} {}", n, s)),
None => Some(format!("fn{}", n)),
};
let new_header = BlockHeader {
attributes: Some(attributes),
indent: header.indent.clone(),
align: header.align,
};
write!(
f,
"<p{}><sup>{}</sup>{}<a href=\"#fnr{}\">&21A9;</a></p>",
new_header, n, content, n
)
}
BlockKind::Paragraph
| BlockKind::BlockQuote
| BlockKind::Header(_) => {
write!(f, "<{}{}>{}</{}>", kind, header, content, kind)
}
_ => Err(fmt::Error),
},
BlockTag::Preformatted {
kind,
header,
content,
} => match kind {
BlockKind::Preformatted => {
write!(f, "<pre{}>{}</pre>", header, html_escape(content))
}
BlockKind::BlockCode => {
let mut attributes =
header.attributes.clone().unwrap_or(Attributes {
class: None,
id: None,
style: None,
language: None,
});
attributes.class = match attributes.class {
Some(s) => Some(format!("blockcode {}", s)),
None => Some(String::from("blockcode")),
};
let new_header = BlockHeader {
attributes: Some(attributes),
indent: header.indent.clone(),
align: header.align,
};
write!(
f,
"<pre{}><code>{}</code></pre>",
new_header,
html_escape(content)
)
}
_ => Err(fmt::Error), },
BlockTag::List { header, content } => {
let tag_name = match content.kind {
ListKind::Numeric => "ol",
ListKind::Bulleted => "ul",
};
write!(f, "<{}{}>\n", tag_name, header)?;
for item in content.items.iter() {
write!(f, "{}\n", item)?;
}
write!(f, "</{}>", tag_name)?;
Ok(())
}
BlockTag::Table { header, rows } => {
write!(f, "<table {}>\n", header)?;
for row in rows {
write!(f, "{}\n", row)?;
}
write!(f, "</table>")?;
Ok(())
}
BlockTag::NoTextile(s) => {
write!(f, "{}", s)
}
}
}
}
impl fmt::Display for BlockKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BlockKind::Paragraph => write!(f, "p"),
BlockKind::Header(n) => write!(f, "h{}", n),
BlockKind::BlockQuote => write!(f, "blockquote"),
_ => Err(fmt::Error), }
}
}
impl fmt::Display for BlockHeader {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.indent.is_none() && self.align.is_none() {
match &self.attributes {
Some(attributes) => write!(f, "{}", attributes),
None => Ok(()),
}
} else {
let indent_style = match &self.indent {
Some(indent) => format!("{}", indent),
None => String::new(),
};
let align_style = match &self.align {
Some(align) => format!("{}", align),
None => String::new(),
};
match &self.attributes {
Some(attributes) => {
if let Some(s) = &attributes.class {
write!(f, " class=\"{}\"", s)?;
}
if let Some(s) = &attributes.id {
write!(f, " id=\"{}\"", s)?;
}
if let Some(s) = &attributes.style {
write!(
f,
" style=\"{}{} {}\"",
indent_style, align_style, s
)?;
}
if let Some(s) = &attributes.language {
write!(f, " lang=\"{}\"", s)?;
}
}
None => {
write!(f, " style=\"{}{}\"", indent_style, align_style)?;
}
}
Ok(())
}
}
}
impl fmt::Display for Indent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.left > 0 {
write!(f, "padding-left: {}em; ", self.left)?;
}
if self.right > 0 {
write!(f, "padding-left: {}em; ", self.right)?;
}
Ok(())
}
}
impl fmt::Display for Align {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Align::Left => write!(f, "text-align: left;"),
Align::Right => write!(f, "text-align: right;"),
Align::Center => write!(f, "text-align: center;"),
Align::Justify => write!(f, "text-align: justify;"),
}
}
}
impl fmt::Display for InlineTag {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
InlineTag::Plaintext(s) => write!(f, "{}", s),
InlineTag::Code(s) => write!(f, "<code>{}</code>", html_escape(s)),
InlineTag::NoTextile(s) => write!(f, "{}", s),
InlineTag::Acronym { title, content } => match title {
Some(title) => {
write!(f, "<abbr title=\"{}\">{}</abbr>", title, content)
}
None => write!(f, "<span class=\"caps\">{}</span>", content),
},
InlineTag::FootnoteRef(n) => write!(
f,
"<sup id=\"fnr{}\"><a href=\"#fn{}\">{}</a></sup>",
n, n, n
),
InlineTag::Link {
attributes,
title,
url,
content,
} => {
let attrs = match attributes {
Some(attributes) => format!("{}", attributes),
None => format!(""),
};
match title {
Some(title) => write!(
f,
"<a{} href=\"{}\" title=\"{}\">{}</a>",
attrs, url, title, content
),
None => write!(
f,
"<a{} href=\"{}\">{}</a>",
attrs, url, content
),
}
}
InlineTag::Image { header, url, alt } => match alt {
Some(alt) => {
write!(
f,
"<img{} src=\"{}\" alt=\"{}\" />",
header, url, alt
)
}
None => write!(f, "<img {} src=\"{}\" />", header, url),
},
InlineTag::Phrase {
kind,
attributes,
content,
} => match kind {
Some(k) => {
match attributes {
Some(attributes) => write!(f, "<{}{}>", k, attributes)?,
None => write!(f, "<{}>", k)?,
};
for phrase in content {
write!(f, "{}", phrase)?;
}
write!(f, "</{}>", k)?;
Ok(())
}
None => {
for phrase in content {
write!(f, "{}", phrase)?;
}
Ok(())
}
},
InlineTag::LineBreak => write!(f, "<br />\n"),
}
}
}
impl fmt::Display for PhraseKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
PhraseKind::Italic => write!(f, "i"),
PhraseKind::Bold => write!(f, "b"),
PhraseKind::Emphasis => write!(f, "em"),
PhraseKind::Strong => write!(f, "strong"),
PhraseKind::Citation => write!(f, "cite"),
PhraseKind::Deleted => write!(f, "del"),
PhraseKind::Inserted => write!(f, "ins"),
PhraseKind::Superscript => write!(f, "sup"),
PhraseKind::Subscript => write!(f, "sub"),
PhraseKind::Span => write!(f, "span"),
}
}
}
impl fmt::Display for Attributes {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(s) = &self.class {
write!(f, " class=\"{}\"", s)?;
}
if let Some(s) = &self.id {
write!(f, " id=\"{}\"", s)?;
}
if let Some(s) = &self.style {
write!(f, " style=\"{}\"", s)?;
}
if let Some(s) = &self.language {
write!(f, " lang=\"{}\"", s)?;
}
Ok(())
}
}
impl fmt::Display for ImageHeader {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.align {
Some(align) => match &self.attributes {
Some(attributes) => {
if let Some(s) = &attributes.class {
write!(f, " class=\"{}\"", s)?;
}
if let Some(s) = &attributes.id {
write!(f, " id=\"{}\"", s)?;
}
if let Some(s) = &attributes.style {
write!(f, " style=\"{} {}\"", align, s)?;
}
if let Some(s) = &attributes.language {
write!(f, " lang=\"{}\"", s)?;
}
Ok(())
}
None => write!(f, " style=\"{}\"", align),
},
None => match &self.attributes {
Some(attributes) => write!(f, "{}", attributes),
None => Ok(()),
},
}
}
}
impl fmt::Display for ImageAlign {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ImageAlign::Left => write!(f, "float: left;"),
ImageAlign::Right => write!(f, "float: right;"),
ImageAlign::Center => write!(f, "display: block; margin: auto;"),
}
}
}
impl fmt::Display for List {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let tag_name = match self.kind {
ListKind::Numeric => "ol",
ListKind::Bulleted => "ul",
};
write!(f, "<{}>\n", tag_name)?;
for item in self.items.iter() {
write!(f, "{}\n", item)?;
}
write!(f, "</{}>", tag_name)?;
Ok(())
}
}
impl fmt::Display for ListItem {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.sublist {
Some(sublist) => {
write!(f, "<li>{}\n{}\n</li>", self.content, sublist)
}
None => write!(f, "<li>{}</li>", self.content),
}
}
}
impl fmt::Display for TableRow {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "<tr{}>\n", self.header)?;
for cell in &self.cells {
write!(f, "{}\n", cell)?;
}
write!(f, "</tr>")?;
Ok(())
}
}
impl fmt::Display for TableCell {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let tag_name = match self.kind {
CellKind::Header => "th",
CellKind::Data => "td",
};
let colspan = match self.col_span {
Some(n) => format!(" colspan={}", n),
None => String::new(),
};
let rowspan = match self.row_span {
Some(n) => format!(" rowspan={}", n),
None => String::new(),
};
write!(
f,
"<{}{}{}{}>{}</{}>",
tag_name, colspan, rowspan, self.header, self.content, tag_name
)?;
Ok(())
}
}
impl fmt::Display for TableHeader {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.h_align.is_none() && self.v_align.is_none() {
match &self.attributes {
Some(attributes) => write!(f, "{}", attributes),
None => Ok(()),
}
} else {
let h_align = match &self.h_align {
Some(align) => format!("{}", align),
None => String::new(),
};
let v_align = match &self.v_align {
Some(align) => format!("{}", align),
None => String::new(),
};
match &self.attributes {
Some(attributes) => {
if let Some(s) = &attributes.class {
write!(f, " class=\"{}\"", s)?;
}
if let Some(s) = &attributes.id {
write!(f, " id=\"{}\"", s)?;
}
if let Some(s) = &attributes.style {
write!(f, " style=\"{}{} {}\"", h_align, v_align, s)?;
}
if let Some(s) = &attributes.language {
write!(f, " lang=\"{}\"", s)?;
}
}
None => {
write!(f, " style=\"{}{}\"", h_align, v_align)?;
}
}
Ok(())
}
}
}
impl fmt::Display for VerticalAlign {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
VerticalAlign::Top => write!(f, "vertical-align: top;"),
VerticalAlign::Middle => write!(f, "vertical-align: middle;"),
VerticalAlign::Bottom => write!(f, "vertical-align: bottom;"),
}
}
}