Newer
Older
use orgize::elements::Keyword;
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
use orgize::elements::Timestamp;
use orgize::{
export::{DefaultHtmlHandler, HtmlHandler},
Element, Org,
};
use std::io::Write;
use syntect::{
highlighting::{Theme, ThemeSet},
html::highlighted_html_for_string,
parsing::SyntaxSet,
};
use time::macros::format_description;
use time::Date;
pub trait Parser<T> {
fn start(&mut self, _: &Element) -> anyhow::Result<()>;
fn end(&mut self, _: &Element) -> anyhow::Result<()>;
fn render(self) -> anyhow::Result<T>;
}
pub fn parse<T, P: Parser<T>>(mut p: P, org: &str) -> anyhow::Result<T> {
for e in Org::parse(org).iter() {
match e {
orgize::Event::Start(ele) => p.start(ele)?,
orgize::Event::End(ele) => p.end(ele)?,
}
}
p.render()
}
pub struct CustomHtmlHandler {
fallback: DefaultHtmlHandler,
ps: SyntaxSet,
theme: Theme,
}
impl Default for CustomHtmlHandler {
fn default() -> Self {
let mut ts = ThemeSet::load_defaults();
Self {
fallback: Default::default(),
ps: SyntaxSet::load_defaults_newlines(),
theme: ts
.themes
.remove("base16-eighties.dark")
.expect("Could not load theme"),
}
}
}
impl HtmlHandler<Error> for CustomHtmlHandler {
fn start<W: Write>(&mut self, mut w: W, element: &Element) -> Result<(), Error> {
match element {
Element::SourceBlock(block) => {
let syntax = self
.ps
.find_syntax_by_token(&block.language)
.with_context(|| format!("Unknown language {}", block.language))?;
let html =
highlighted_html_for_string(&block.contents, &self.ps, syntax, &self.theme)?;
write!(w, "{html}")?;
}
Element::SpecialBlock(block) => match block.name.as_ref() {
"JUSTIFYRIGHT" => {
write!(w, r#"<div class="justify-right">"#)?;
}
_ => bail!("Unrecognized special block name {}", block.name),
},
Element::Timestamp(Timestamp::Active { start, .. }) => {
let date = Date::from_calendar_date(
start.year.into(),
start.month.try_into()?,
start.day,
)?;
date.format_into(
&mut w,
format_description!("[day] [month repr:short] [year]"),
)?;
}
Element::Link(Link { path, desc }) if desc.is_none() => {
write!(w, r#"<a href="/img/{path}"><img src="/thumb/{path}">"#)?;
}
Element::Keyword(Keyword { key, value, .. }) if key == "VIDEO" => {
write!(
w,
r#"<video controls="controls"><source src="{value}"></video>"#
)?;
}
// fallback to default handler
_ => self.fallback.start(w, element)?,
}
Ok(())
}
fn end<W: Write>(&mut self, mut w: W, element: &Element) -> Result<(), Error> {
match element {
Element::SpecialBlock(block) => match block.name.as_ref() {
"JUSTIFYRIGHT" => {
write!(w, "</div>")?;
}
_ => bail!("Unrecognized special block name {}", block.name),
},
Element::Link(Link { desc, .. }) if desc.is_none() => {
write!(w, r#"</img></a>"#)?;
}