snekdown 0.33.4

A parser for the custom snekdown markdown syntax
Documentation
/*
 * Snekdown - Custom Markdown flavour and parser
 * Copyright (C) 2021  Trivernis
 * See LICENSE for more information.
 */

use crate::elements::*;
use crate::references::bibliography::create_bib_list;
use chrono::prelude::*;
use regex::Regex;

macro_rules! block {
    ($inner:expr) => {
        Element::Block(Box::new($inner))
    };
}

#[allow(unused)]
macro_rules! line {
    ($inner:expr) => {
        Element::Line(Box::new($inner))
    };
}

macro_rules! inline {
    ($inner:expr) => {
        Element::Inline(Box::new($inner))
    };
}

pub(crate) trait ProcessPlaceholders {
    fn process_placeholders(&mut self);
    fn process_definitions(&mut self);
}

const S_VALUE: &str = "value";

const P_TOC: &str = "toc";
const P_BIB: &str = "bib";
const P_GLS: &str = "gls";
const P_DATE: &str = "date";
const P_TIME: &str = "time";
const P_DATETIME: &str = "datetime";
const P_AUTHOR: &str = "author";
const P_TITLE: &str = "title";

impl ProcessPlaceholders for Document {
    /// parses all placeholders and assigns values to them
    fn process_placeholders(&mut self) {
        self.placeholders.iter().for_each(|p| {
            let mut pholder = p.write().unwrap();
            match pholder.name.to_lowercase().as_str() {
                P_TOC => {
                    let ordered = if let Some(meta) = &pholder.metadata {
                        meta.get_bool("ordered")
                    } else {
                        false
                    };
                    pholder.set_value(block!(Block::List(self.create_toc(ordered))))
                }
                P_BIB => pholder.set_value(block!(Block::List(create_bib_list(
                    self.bibliography.get_entry_list_by_occurrence()
                )))),
                P_GLS => pholder.set_value(block!(Block::List(
                    self.glossary.lock().create_glossary_list()
                ))),
                P_DATE => pholder.set_value(inline!(Inline::Plain(PlainText {
                    value: get_date_string()
                }))),
                P_TIME => pholder.set_value(inline!(Inline::Plain(PlainText {
                    value: get_time_string()
                }))),
                P_DATETIME => pholder.set_value(inline!(Inline::Plain(PlainText {
                    value: format!("{} {}", get_date_string(), get_time_string())
                }))),
                P_AUTHOR => {
                    if let Some(value) = self.config.lock().metadata.author.clone() {
                        pholder.set_value(inline!(Inline::Plain(PlainText { value })))
                    }
                }
                P_TITLE => {
                    if let Some(value) = self.config.lock().metadata.title.clone() {
                        pholder.set_value(inline!(Inline::Plain(PlainText { value })))
                    }
                }
                _ => {
                    if let Some(value) = self
                        .config
                        .lock()
                        .custom_attributes
                        .get(pholder.name.to_lowercase().as_str())
                        .cloned()
                    {
                        pholder.set_value(inline!(Inline::Plain(PlainText { value })))
                    }
                }
            }
        })
    }

    fn process_definitions(&mut self) {
        lazy_static::lazy_static! {
            static ref RE_SET: Regex = Regex::new(r"^set:(.*)$").unwrap();
        }

        let placeholders = self.placeholders.clone();
        placeholders.iter().for_each(|p| {
            let mut pholder = p.write().unwrap();
            let name = pholder.name.clone();

            if let Some(cap) = RE_SET.captures(&name) {
                if let Some(key) = cap.get(1) {
                    let key: &str = key.as_str();
                    pholder.value = Some(inline!(Inline::Plain(PlainText {
                        value: "".to_string()
                    })));
                    if let Some(meta) = &pholder.metadata {
                        if let Some(value) = meta.data.get(S_VALUE) {
                            self.config.lock().set_from_meta(key, value.clone())
                        }
                    }
                }
                return;
            }
        });
    }
}

fn get_time_string() -> String {
    let now = Local::now();
    format!("{:02}:{:02}:{:02}", now.hour(), now.minute(), now.second())
}

fn get_date_string() -> String {
    let now = Local::now();
    format!("{:02}.{:02}.{:04}", now.day(), now.month(), now.year())
}