use std::fs;
use std::io;
use std::path::{PathBuf, Path};
use std::collections::HashSet;
use pulldown_cmark::{Parser, Options, Event, html};
pub struct Renderer {
pub md_path: PathBuf,
pub canonical_md_path: PathBuf,
}
impl Renderer {
pub fn new(md_path: PathBuf) -> Self {
let canonical_md_path = md_path.canonicalize().
unwrap_or_else(|_| md_path.clone());
Renderer { md_path, canonical_md_path }
}
pub fn run(&self) -> Result<RenderedContent, io::Error> {
let markdown = fs::read_to_string(&self.canonical_md_path)?;
let root_dir = self.canonical_md_path.parent().unwrap_or_else(|| Path::new(""));
let mut options = Options::empty();
options.insert(Options::ENABLE_TABLES);
options.insert(Options::ENABLE_FOOTNOTES);
options.insert(Options::ENABLE_TASKLISTS);
options.insert(Options::ENABLE_STRIKETHROUGH);
let parser = Parser::new_ext(&markdown, options);
let mut languages = HashSet::new();
let parser = parser.map(|mut event| {
use pulldown_cmark::{Tag, CodeBlockKind};
match &mut event {
Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(content))) => {
if content.len() > 0 {
languages.insert(content.to_string());
}
},
Event::Start(Tag::Image(_, url, _)) if url.starts_with("./") => {
*url = format!("file://{}/{}", root_dir.display(), &url[2..]).into();
},
_ => (),
}
event
});
let mut output = String::new();
html::push_html(&mut output, parser);
Ok(RenderedContent {
html: output,
code_languages: languages,
})
}
}
#[derive(Debug, Default)]
pub struct RenderedContent {
pub html: String,
pub code_languages: HashSet<String>,
}