etch 0.4.2

Not just a text formatter, don't mark it down, etch it.
Documentation
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,
        }
    }
}