diff --git a/src/elements.rs b/src/elements.rs index ad77089..aa83865 100644 --- a/src/elements.rs +++ b/src/elements.rs @@ -18,48 +18,43 @@ pub enum Inline { #[derive(Clone, Debug)] pub struct Document { - elements: Vec, + pub(crate) elements: Vec, } #[derive(Clone, Debug)] pub struct Section { - header: Header, - elements: Vec, + pub(crate) header: Header, + pub(crate) elements: Vec, } #[derive(Clone, Debug)] pub struct Header { - pub size: u8, - pub line: Inline, -} - -#[derive(Clone, Debug)] -pub struct BlockQuote { - paragraph: Paragraph, + pub(crate) size: u8, + pub(crate) line: Inline, } #[derive(Clone, Debug)] pub struct Paragraph { - pub elements: Vec, + pub(crate) elements: Vec, } #[derive(Clone, Debug)] pub struct List { - pub ordered: bool, - pub items: Vec, + pub(crate) ordered: bool, + pub(crate) items: Vec, } #[derive(Clone, Debug)] pub struct ListItem { - text: Inline, + pub(crate) text: Inline, pub(crate) level: u16, pub(crate) children: Vec, } #[derive(Clone, Debug)] pub struct Table { - header: Row, - pub rows: Vec, + pub(crate) header: Row, + pub(crate) rows: Vec, } #[derive(Clone, Debug)] @@ -155,8 +150,8 @@ pub struct MonospaceText { #[derive(Clone, Debug)] pub struct Url { - description: Option, - url: String, + pub description: Option, + pub url: String, } #[derive(Clone, Debug)] diff --git a/src/format/html.rs b/src/format/html.rs new file mode 100644 index 0000000..06ce14d --- /dev/null +++ b/src/format/html.rs @@ -0,0 +1,243 @@ +use crate::elements::*; + +pub trait ToHtml { + fn to_html(&self) -> String; +} + +impl ToHtml for Inline { + fn to_html(&self) -> String { + match self { + Inline::Text(text) => text.to_html(), + } + } +} + +impl ToHtml for SubText { + fn to_html(&self) -> String { + match self { + SubText::Url(url) => url.to_html(), + SubText::Monospace(mono) => mono.to_html(), + SubText::Striked(striked) => striked.to_html(), + SubText::Plain(plain) => plain.to_html(), + SubText::Italic(italic) => italic.to_html(), + SubText::Underlined(under) => under.to_html(), + SubText::Bold(bold) => bold.to_html(), + SubText::Image(img) => img.to_html(), + _ => "".to_string(), + } + } +} + +impl ToHtml for Block { + fn to_html(&self) -> String { + match self { + Block::Paragraph(para) => para.to_html(), + Block::List(list) => list.to_html(), + Block::Table(table) => table.to_html(), + Block::CodeBlock(code) => code.to_html(), + Block::Quote(quote) => quote.to_html(), + Block::Section(section) => section.to_html(), + Block::Import(import) => import.to_html(), + } + } +} + +impl ToHtml for Document { + fn to_html(&self) -> String { + let inner = self + .elements + .iter() + .fold("".to_string(), |a, b| format!("{}{}", a, b.to_html())); + format!("{}", inner) + } +} + +impl ToHtml for Import { + fn to_html(&self) -> String { + let anchor = self.anchor.lock().unwrap(); + if let Some(document) = &anchor.document { + document.to_html() + } else { + "".to_string() + } + } +} + +impl ToHtml for Section { + fn to_html(&self) -> String { + let inner = self + .elements + .iter() + .fold("".to_string(), |a, b| format!("{}{}", a, b.to_html())); + format!("
{}{}
", self.header.to_html(), inner) + } +} + +impl ToHtml for Header { + fn to_html(&self) -> String { + format!("{1}", self.size, self.line.to_html()) + } +} + +impl ToHtml for Paragraph { + fn to_html(&self) -> String { + let inner = self + .elements + .iter() + .fold("".to_string(), |a, b| format!("{}{}", a, b.to_html())); + format!("

{}

", inner) + } +} + +impl ToHtml for List { + fn to_html(&self) -> String { + let inner = self + .items + .iter() + .fold("".to_string(), |a, b| format!("{}{}", a, b.to_html())); + if self.ordered { + format!("
    {}
", inner) + } else { + format!("
    {}
", inner) + } + } +} + +impl ToHtml for ListItem { + fn to_html(&self) -> String { + let inner = self + .children + .iter() + .fold("".to_string(), |a, b| format!("{}{}", a, b.to_html())); + format!("
  • {}
      {}
  • ", self.text.to_html(), inner) + } +} + +impl ToHtml for Table { + fn to_html(&self) -> String { + let head = self.header.cells.iter().fold("".to_string(), |a, b| { + format!("{}{}", a, b.text.to_html()) + }); + let body = self + .rows + .iter() + .fold("".to_string(), |a, b| format!("{}{}", a, b.to_html())); + format!("{}{}
    ", head, body) + } +} + +impl ToHtml for Row { + fn to_html(&self) -> String { + let inner = self + .cells + .iter() + .fold("".to_string(), |a, b| format!("{}{}", a, b.to_html())); + format!("{}", inner) + } +} + +impl ToHtml for Cell { + fn to_html(&self) -> String { + format!("{}", self.text.to_html()) + } +} + +impl ToHtml for CodeBlock { + fn to_html(&self) -> String { + format!( + "
    {}
    ", + self.language.clone(), + self.code.clone() + ) + } +} + +impl ToHtml for Quote { + fn to_html(&self) -> String { + let text = self + .text + .iter() + .fold("".to_string(), |a, b| format!("{}
    {}", a, b.to_html())); + if let Some(meta) = self.metadata.clone() { + format!( + "
    {}
    - {}
    ", + text, meta.data + ) + } else { + format!("
    {}
    ", text) + } + } +} + +impl ToHtml for Text { + fn to_html(&self) -> String { + self.subtext + .iter() + .fold("".to_string(), |a, b| format!("{}{}", a, b.to_html())) + } +} + +impl ToHtml for Image { + fn to_html(&self) -> String { + if let Some(description) = self.url.description.clone() { + format!( + "
    \ + \ + {1}\ + \ + +
    ", + self.url.url.clone(), + description + ) + } else { + format!("", self.url.url.clone(),) + } + } +} + +impl ToHtml for BoldText { + fn to_html(&self) -> String { + format!("{}", self.value.to_html()) + } +} + +impl ToHtml for UnderlinedText { + fn to_html(&self) -> String { + format!("{}", self.value.to_html()) + } +} + +impl ToHtml for ItalicText { + fn to_html(&self) -> String { + format!("{}", self.value.to_html()) + } +} + +impl ToHtml for StrikedText { + fn to_html(&self) -> String { + format!("{}", self.value.to_html()) + } +} + +impl ToHtml for MonospaceText { + fn to_html(&self) -> String { + format!("{}", self.value.to_html()) + } +} + +impl ToHtml for Url { + fn to_html(&self) -> String { + if let Some(description) = self.description.clone() { + format!("{}", self.url.clone(), description) + } else { + format!("{}", self.url.clone(), self.url.clone()) + } + } +} + +impl ToHtml for PlainText { + fn to_html(&self) -> String { + self.value.clone() + } +} diff --git a/src/format/mod.rs b/src/format/mod.rs new file mode 100644 index 0000000..3d4613d --- /dev/null +++ b/src/format/mod.rs @@ -0,0 +1 @@ +pub mod html; diff --git a/src/lib.rs b/src/lib.rs index 30340b7..b74ec28 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ pub mod elements; +pub mod format; pub mod parser; pub mod tokens; diff --git a/src/main.rs b/src/main.rs index 4ffb031..6e8bcf8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +use markdown_rs::format::html::ToHtml; use markdown_rs::parser::Parser; use std::fs::{read_to_string, write}; use std::time::Instant; @@ -12,4 +13,5 @@ fn main() { let document = parser.parse(); println!("Total duration: {:?}", start.elapsed()); write("test/document.ast", format!("{:#?}", document)).unwrap(); + write("test/document.html", document.to_html()).unwrap() }