etch 0.4.2

Not just a text formatter, don't mark it down, etch it.
Documentation
use crate::nodes::Node;
use crate::plugins::Plugin;
use crate::state::*;
use glue::prelude::*;
use std::collections::HashMap;

#[derive(Debug, PartialEq)]
pub struct MetadataPlugin {
    pub data: HashMap<String, String>,
}

impl MetadataPlugin {
    pub fn new() -> Shared<Self> {
        Shared::share(MetadataPlugin {
            data: HashMap::new(),
        })
    }

    pub fn get_metadata<'a>(&'a self) -> &'a HashMap<String, String> {
        &self.data
    }
}

impl Plugin for MetadataPlugin {
    fn on_parse_processing_instruction<'a>(
        &mut self,
        _state: SharedState,
        ctx: ParserContext<'a>,
    ) -> ParserResult<'a, Node> {
        use crate::parsers::common::*;
        use crate::parsers::tags::*;
        use glue::combinators::structures::*;
        use glue::combinators::whitespace::*;

        match delimited(
            take_all((indent(0..), is("#meta["))),
            separated(
                tag_name(),
                take_all((is(':'), space(0..))),
                take_until(take_all((space(0..), is(']'))), is(any)),
            ),
            take_all((space(0..), is(']'))),
        ).parse(ctx)
            .map_error(|error| error.tag("metadata declaration #meta[key: value]"))?
        {
            (ctx, (name, value)) => {
                self.data.entry(name.into()).or_insert(value.into());

                Ok((ctx, Node::Removed))
            }
        }
    }
}