{
+ let ps = SyntaxSet::load_defaults_newlines();
+ let ts = ThemeSet::load_defaults();
+ let syntax_elements: Vec<_> = match document.select("syntaxhighlight") {
+ Ok(e) => e.collect(),
+ Err(()) => return Err(anyhow!("Unable to find syntaxhighlight elements")),
+ };
+ for node in syntax_elements {
+ let attrs = match node.as_node().as_element() {
+ Some(e) => e.attributes.borrow(),
+ None => continue,
+ };
+ let language = attrs.get("lang").unwrap_or("text");
+ let theme_name = attrs.get("theme").unwrap_or("base16-ocean.dark");
+ if let Some(text_node) = node.as_node().first_child() {
+ if let Some(code_text) = text_node.as_text() {
+ let syntax = ps
+ .find_syntax_by_extension(language)
+ .or_else(|| ps.find_syntax_by_name(language))
+ .unwrap_or_else(|| ps.find_syntax_plain_text());
+ let theme = &ts.themes[theme_name];
+ let mut h = HighlightLines::new(syntax, theme);
+ let mut html_output = String::new();
+ write!(html_output, r#""#)?;
+ html_output.push_str("");
+ for line in LinesWithEndings::from(&code_text.borrow()) {
+ let ranges: Vec<(Style, &str)> = h.highlight_line(line, &ps).unwrap();
+ let escaped = styled_line_to_highlighted_html(&ranges[..], IncludeBackground::No).unwrap();
+ html_output.push_str(&escaped);
+ }
+ html_output.push_str("");
+ let html_fragment = kuchikiki::parse_html().one(html_output);
+ for child in html_fragment.children() {
+ node.as_node().insert_before(child);
+ }
+ // Remove the original syntaxhighlight node.
+ node.as_node().detach();
+ }
+ }
+ }
+ Ok(document)
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -237,7 +289,6 @@ mod tests {
let text = d.select_first("#inc1").unwrap().as_node().text_contents();
assert_eq!(text, "included1");
assert!(d.select_first("include").is_err());
-
}
#[test]
@@ -292,7 +343,7 @@ mod tests {
#[test]
fn basic_markdown() {
- let page = r#"
+ let page = r"
@@ -311,11 +362,41 @@ This is a paragraph with **bold text** and *italic text*.
- "#;
+