etch 0.4.2

Not just a text formatter, don't mark it down, etch it.
Documentation
mod metadata;
#[cfg(feature = "syntect-plugin")]
mod syntect;
mod widowed_words;
mod word_count;

pub use self::metadata::*;
#[cfg(feature = "syntect-plugin")]
pub use self::syntect::*;
pub use self::widowed_words::*;
pub use self::word_count::*;

use crate::nodes::Node;
use crate::state::{Shared, SharedState};
use std::fmt::Debug;
use glue::prelude::*;

pub trait PluginDispatch {
    fn on_node_parsed(&mut self, token: Node) -> Node;
    fn on_node_tagged(&mut self, token: Node) -> Node;
    fn on_node_finished(&mut self, token: Node) -> Node;
    fn on_parse_processing_instruction<'a>(
        &self,
        state: SharedState,
        ctx: ParserContext<'a>,
    ) -> ParserResult<'a, Node>;
}

pub type Plugins = Vec<SharedPlugin>;

impl PluginDispatch for Plugins {
    fn on_node_parsed(&mut self, mut token: Node) -> Node {
        for plugin in self {
            token = plugin.borrow_mut().on_node_parsed(token);
        }

        token
    }

    fn on_node_tagged(&mut self, mut token: Node) -> Node {
        for plugin in self {
            token = plugin.borrow_mut().on_node_tagged(token);
        }

        token
    }

    fn on_node_finished(&mut self, mut token: Node) -> Node {
        for plugin in self {
            token = plugin.borrow_mut().on_node_finished(token);
        }

        token
    }

    fn on_parse_processing_instruction<'a>(
        &self,
        state: SharedState,
        ctx: ParserContext<'a>,
    ) -> ParserResult<'a, Node> {
        let mut errors = Vec::new();

        for plugin in self {
            match plugin
                .borrow_mut()
                .on_parse_processing_instruction(state.clone(), ctx.clone())
            {
                Ok(result) => return Ok(result),
                Err((_, error)) => errors.push(error),
            };
        }

        Err((ctx, SourceError::Ranges(errors)))
    }
}

pub type SharedPlugin = Shared<dyn Plugin>;

pub trait Plugin: Debug + 'static {
    fn on_node_parsed(&mut self, token: Node) -> Node {
        token
    }

    fn on_node_tagged(&mut self, token: Node) -> Node {
        token
    }

    fn on_node_finished(&mut self, token: Node) -> Node {
        token
    }

    fn on_parse_processing_instruction<'a>(
        &mut self,
        _state: SharedState,
        ctx: ParserContext<'a>,
    ) -> ParserResult<'a, Node> {
        Err((ctx.clone(), SourceError::Range(ctx.bounds)))
    }
}