use crate::nodes::{Node, NodeTags};
use crate::plugins::Plugin;
use crate::state::*;
use syntect::html::ClassedHTMLGenerator;
use syntect::parsing::{SyntaxReference, SyntaxSet};
#[derive(Debug)]
pub struct SyntectPlugin {
syntax_set: SyntaxSet,
}
impl SyntectPlugin {
pub fn new() -> Shared<Self> {
Shared::share(SyntectPlugin {
syntax_set: SyntaxSet::load_defaults_newlines(),
})
}
fn get_syntax<'a>(&self, tags: &'a NodeTags) -> Option<SyntaxReference> {
if let Some(tags) = tags {
for tag in tags {
if let Some(syntax) = self.syntax_set.find_syntax_by_extension(tag) {
return Some(syntax.clone());
}
if let Some(syntax) = self.syntax_set.find_syntax_by_name(tag) {
return Some(syntax.clone());
}
}
}
None
}
fn highlight(&self, syntax: SyntaxReference, source: String) -> String {
let mut html_generator = ClassedHTMLGenerator::new(&syntax, &self.syntax_set);
for line in source.lines() {
html_generator.parse_html_for_line(&format!("{}\n", line));
}
html_generator.finalize()
}
}
impl Plugin for SyntectPlugin {
fn on_node_tagged(&mut self, token: Node) -> Node {
match token.clone() {
Node::Element {
name,
tags,
attributes,
children,
} => {
if name == "pre" || name == "code" {
if let Some(syntax) = self.get_syntax(&tags) {
if let Some(children) = &children.clone() {
if let [Node::Text { text }] = children.as_slice() {
Node::Element {
name,
tags,
attributes,
children: Some(vec![
Node::Html {
html: self.highlight(syntax, text.to_string()),
},
]),
}
} else {
token
}
} else {
token
}
} else {
token
}
} else {
token
}
}
_ => token,
}
}
}