diff --git a/src/markdown.rs b/src/markdown.rs index 575064b..d4f6351 100644 --- a/src/markdown.rs +++ b/src/markdown.rs @@ -1,6 +1,9 @@ -use std::{io::BufWriter, path::Path}; +use std::{ + io::{BufWriter, Write}, + path::Path, +}; -use pulldown_cmark::{Options, Parser}; +use pulldown_cmark::{CowStr, Options, Parser}; pub fn compile_markdown( src: impl AsRef, @@ -9,53 +12,260 @@ pub fn compile_markdown( ) -> std::io::Result<()> { let src_text = std::fs::read_to_string(src)?; - let html = create_file(html)?; - let gmi = create_file(gmi)?; + let mut html = create_file(html)?; + let mut gmi = create_file(gmi)?; + + let mut state = State::Start; + let mut counter: u64 = 0; + let mut links: Vec> = vec![]; for event in Parser::new_ext(&src_text, Options::all()) { use pulldown_cmark::Event::*; match event { Start(tag) => { - use pulldown_cmark::Tag::*; + use pulldown_cmark::{CodeBlockKind, HeadingLevel, Tag::*}; - println!("{tag:?}"); + match tag { + Paragraph => { + html.write_all(b"

")?; + if state != State::Start { + gmi.write_all(b"\r\n\r\n")?; + } + } + + Heading { level, id, .. } => { + if let Some(id) = id { + html.write_fmt(format_args!("<{} id=\"{}\">", level, id))?; + } else { + html.write_fmt(format_args!("<{}>", level))?; + } + + let hashes = match level { + HeadingLevel::H1 => "# ", + HeadingLevel::H2 => "## ", + _ => "### ", + }; + gmi.write_all(hashes.as_bytes())?; + state = State::GmiPrefix(hashes); + } + + BlockQuote(_kind) => { + html.write_all(b"

")?; + gmi.write_all(b"> ")?; + state = State::GmiPrefix("> "); + } + + CodeBlock(CodeBlockKind::Fenced(lang)) => { + html.write_all(b"
")?;
+                        // TODO: highlighting with syntect
+                        gmi.write_fmt(format_args!("```{}\r\n", lang))?;
+                    }
+
+                    CodeBlock(CodeBlockKind::Indented) => {
+                        html.write_all(b"
")?;
+                        gmi.write_all(b"```")?;
+                    }
+
+                    List(None) => {
+                        html.write_all(b"
    ")?; + } + + List(Some(counter_start)) => { + counter = counter_start; + if counter_start == 1 { + html.write_all(b"
      ")?; + } else { + html.write_fmt(format_args!("
        ", counter_start))?; + } + } + + Item => { + html.write_all(b"
      1. ")?; + gmi.write_fmt(format_args!("{}. ", counter))?; + counter += 1; + } + + Strong => { + html.write_all(b"")?; + gmi.write_all(b"**")?; + } + + Emphasis => { + html.write_all(b"")?; + gmi.write_all(b"*")?; + } + + Strikethrough => { + html.write_all(b"")?; + gmi.write_all(b"~")?; + } + + Link { + dest_url, title, .. + } => { + html.write_fmt(format_args!("{}", dest_url, title))?; + + gmi.write_fmt(format_args!("{}[{}]", &title, links.len() + 1))?; + links.push(GmiLink { + title, + url: dest_url, + }); + } + + Image { + dest_url, title, .. + } => { + html.write_fmt(format_args!( + "\"{}\"", + dest_url, title + ))?; + + gmi.write_fmt(format_args!("{}[{}]", &title, links.len() + 1))?; + links.push(GmiLink { + title, + url: dest_url, + }); + } + + Table(_align) => { + html.write_all(b"")?; + // gmi ?? + } + + TableHead => { + html.write_all(b"")?; + state = State::TableHead; + } + + TableRow => { + html.write_all(b"")?; + } + + TableCell => { + if state == State::TableHead { + html.write_all(b"")?, + TableRow => html.write_all(b"")?, + TableCell => { + if state == State::TableHead { + html.write_all(b"")? + } else { + html.write_all(b"")? + } + } + Table => html.write_all(b"
        ")?; + } else { + html.write_all(b"")?; + } + } + + other => { + eprintln!("Unsupported tag: {:?}", other); + } + } } End(tag) => { - use pulldown_cmark::Tag::*; + use pulldown_cmark::TagEnd::*; - println!("{tag:?}"); + match tag { + Paragraph => { + html.write_all(b"

        ")?; + + if !links.is_empty() { + gmi.write_all(b"\r\n\r\n")?; + for (i, link) in links.iter().enumerate() { + gmi.write_fmt(format_args!( + "=> {} [{}]: {}", + link.url, i, link.title, + ))?; + } + links.clear(); + } + } + Heading(level) => html.write_fmt(format_args!("<{}>", level))?, + BlockQuote(_) => html.write_all(b"")?, + CodeBlock => { + html.write_all(b"")?; + gmi.write_all(b"```")?; + } + List(ordered) => { + if ordered { + html.write_all(b"")?; + } else { + html.write_all(b"")?; + } + } + Item => html.write_all(b"")?, + Strong => { + html.write_all(b"")?; + gmi.write_all(b"**")?; + } + Emphasis => { + html.write_all(b"")?; + gmi.write_all(b"*")?; + } + Strikethrough => { + html.write_all(b"")?; + gmi.write_all(b"~")?; + } + Link => {} + TableHead => html.write_all(b"
        ")?, + _ => {} + } + + state = State::Paragraph; } Text(text) => { - println!("!{text}!"); + html.write_all(text.as_bytes())?; + gmi.write_all(text.as_bytes())?; } Code(code) => { - println!("`{code}`"); + html.write_all(b"")?; + html.write_all(code.as_bytes())?; + html.write_all(b"")?; + + gmi.write_all(b"`")?; + gmi.write_all(code.as_bytes())?; + gmi.write_all(b"`")?; } SoftBreak => {} HardBreak => { - println!("
        "); + html.write_all(b"
        ")?; + gmi.write_all(b"\r\n")?; + if let State::GmiPrefix(prefix) = state { + gmi.write_all(prefix.as_bytes())?; + } } Rule => { - println!("------"); + html.write_all(b"
        ")?; + gmi.write_all(b"---")?; } TaskListMarker(state) => { - println!("[{state}] task"); + if state { + html.write_all(b"")?; + gmi.write_all(b"[x]")?; + } else { + html.write_all(b"")?; + gmi.write_all(b"[ ]")?; + } } other => { - eprintln!("Unsupported markdown event: {:?}", other); + eprintln!("Unsupported event: {:?}", other); } } } + html.flush()?; + gmi.flush()?; + Ok(()) } @@ -67,3 +277,16 @@ fn create_file(path: impl AsRef) -> std::io::Result { + title: CowStr<'link>, + url: CowStr<'link>, +}