v6/src/generator/markdown/highlight.rs

71 lines
2.1 KiB
Rust

use crate::generator::highlight::highlight;
use pulldown_cmark::{CodeBlockKind, Event, Tag};
pub fn new<'a, I: Iterator<Item = Event<'a>>>(iter: I) -> Highlight<'a, I> {
Highlight { iter }
}
pub struct Highlight<'a, I: Iterator<Item = Event<'a>>> {
iter: I,
}
impl<'a, I: Iterator<Item = Event<'a>>> Iterator for Highlight<'a, I> {
type Item = Event<'a>;
fn next(&mut self) -> Option<Event<'a>> {
match self.iter.next() {
Some(Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(label)))) => {
let code = self.consume_code_block();
let mut highlighted = highlight(&code, &label);
highlighted.insert_str(
0,
&format!("<pre class=\"highlight\" data-lang=\"{}\"><code>", label),
);
highlighted.push_str("</code></pre>");
Some(Event::Html(highlighted.into()))
}
e => e,
}
}
}
impl<'a, I: Iterator<Item = Event<'a>>> Highlight<'a, I> {
fn consume_code_block(&mut self) -> String {
let mut buf = String::new();
loop {
match self.iter.next() {
Some(Event::End(Tag::CodeBlock(CodeBlockKind::Fenced(_)))) => {
break;
}
Some(Event::Text(s)) => {
buf.push_str(&s);
}
e => panic!("unexpected event in fenced code block: {:?}", e),
}
}
buf
}
}
#[cfg(test)]
mod tests {
use pulldown_cmark::{html, Parser};
fn render(s: &str) -> String {
let mut out = String::new();
let parser = Parser::new(s);
let heading_anchors = super::new(parser);
html::push_html(&mut out, heading_anchors);
out
}
#[test]
fn test_higlight_markdown() {
assert_eq!(
render("```js\nfoo(bar, 123)\n```".into()),
r#"<pre class="highlight" data-lang="js"><code><span class="hl-fn">foo</span>(<span class="hl-var">bar</span>, <span class="hl-num">123</span>)
</code></pre>"#
);
}
}