blog: refactor: apply highlight via idomatic Iterator operations

This commit is contained in:
Peter Cai 2020-04-18 16:05:34 +08:00
parent 8fcb7fef17
commit 994da996bc
No known key found for this signature in database
GPG Key ID: 71F5FB4E4F3FD54F
1 changed files with 44 additions and 26 deletions

View File

@ -231,6 +231,43 @@ impl PostContentCache {
}
}
fn transform_code_block_highlight<'iter, 'ev>(
parser: impl Iterator<Item = Event<'ev>>
) -> impl Iterator<Item = Event<'ev>> {
let mut in_code_block = false;
let mut code_block_lang = None;
parser.map(move |ev| {
match &ev {
Event::Start(Tag::CodeBlock(block)) => {
in_code_block = true;
match block {
CodeBlockKind::Fenced(lang) => code_block_lang = Some(lang.to_string()),
CodeBlockKind::Indented => code_block_lang = None
}
},
Event::End(Tag::CodeBlock(_)) => {
in_code_block = false;
code_block_lang = None;
},
Event::Text(text) => {
if in_code_block {
let highlighted = if let Some(ref code_block_lang) = code_block_lang {
crate::hljs::highlight(&code_block_lang, text)
} else {
crate::hljs::highlight_auto(text)
};
return Event::Html(
highlighted.into());
}
}
_ => ()
}
ev
})
}
// Do some HTML-level transformations to the compiled result
// Because the Markdown parser doesn't always allow us to do
// everything, like adding `id` attributes to tags
@ -276,41 +313,22 @@ impl PostContentCache {
// because we need to asynchronously transform the events
// which could not be done through mapping on iterators
let mut parser: Vec<Event> = Parser::new_ext(&post.content, Options::all()).collect();
let mut in_code_block = false;
let mut code_block_lang = "";
for ev in parser.iter_mut() {
match ev {
Event::Start(Tag::CodeBlock(block)) => {
in_code_block = true;
match block {
CodeBlockKind::Fenced(lang) => code_block_lang = lang,
CodeBlockKind::Indented => code_block_lang = ""
}
},
Event::End(Tag::CodeBlock(_)) => {
in_code_block = false;
code_block_lang = "";
},
Event::Start(tag) | Event::End(tag) => {
Self::transform_tag(tag).await;
},
Event::Text(text) => {
if in_code_block {
let highlighted = if code_block_lang != "" {
crate::hljs::highlight(code_block_lang, text)
} else {
crate::hljs::highlight_auto(text)
};
*ev = Event::Html(
highlighted.into());
}
}
_ => ()
};
}
// Now some pure iterator operations
let parser = parser.into_iter();
// Apply code highlighting via Highlight.js
let parser = Self::transform_code_block_highlight(parser);
let mut html_output = String::new();
html::push_html(&mut html_output, parser.into_iter());
html::push_html(&mut html_output, parser);
html_output = Self::transform_html(html_output);
PostContentCache {
uuid: post.uuid.clone(),