quicklatex 0.1.0

A program to help me write LaTeX quickly
Documentation
use colored::Colorize;

use crate::replacements::Replacement;

macro_rules! make_noisy_print {
    ($func_name: ident,
     $element_name: ident,
     $warn_string_singular: expr,
     $warn_string_plural: expr,
     $for_pattern: pat,
     $for_body: block) => {
        fn $func_name(&self)
        {
            if self.$element_name.is_empty()
            {
                return;
            }

            let warn_string = if self.$element_name.len() == 1
            {
                $warn_string_singular
            }
            else
            {
                $warn_string_plural
            };
            println!("{}\n", warn_string.bold().red().underline().on_green());

            for $for_pattern in &self.$element_name
            {
                $for_body
            }
            println!();
        }
    };
}

/// All warnings to be printed noisily
///
/// This struct holds all warnings that `quicklatex` has generated for
/// one file.  Use [`Noisy::print`](Self::print) to print them out in
/// a very *noisy* manner.
///
/// Each warning is of exactly one of (so far) six categories, each
/// stored in one of the fields of this struct.
#[derive(Debug, Default, PartialEq, Eq)]
pub struct Noisy
{
    /// All noisy replacement rules triggered in the document.  A
    /// given rule is always at most once listed here, even if a
    /// replacement is done multiple times.
    pub(crate) repls: Vec<Replacement>,
    /// All labels that were `ref`erenced, but never declared
    /// anywhere.  LaTeX itself also warns against that, but not in
    /// such an flashy way as this program does.
    pub(crate) missing_labels: Vec<String>,
    /// All multiply defined labels.  If a label is defined trice, it
    /// will be listed twice and analogous for more then trice.
    pub(crate) duplicated_labels: Vec<String>,
    /// All instances of labels being not in numerically increasing
    /// order.  The first string in this pair is the label that comes
    /// first in the text (i.e. is wrongly bigger) and the second
    /// string is the one that comes later.
    pub(crate) disordered_labels: Vec<(String, String)>,
    /// All pieces of a label that are not a number (or more
    /// precisely: not an `i128`).  The first string in the pair is
    /// the full label that has an error in it and the second string
    /// is the piece that is not a number.
    pub(crate) malformatted_number_in_label: Vec<(String, String)>,
    /// All pairs of consecutive labels that consist out of a
    /// different number of pieces.  The first string is the earlier
    /// label and the second string is the latter label.
    pub(crate) inconsistent_length_of_labels: Vec<(String, String)>,
}

impl Noisy
{
    #[must_use]
    pub(crate) const fn from_replacements(repls: Vec<Replacement>) -> Self
    {
        Self {
            repls,
            missing_labels: vec![],
            duplicated_labels: vec![],
            disordered_labels: vec![],
            malformatted_number_in_label: vec![],
            inconsistent_length_of_labels: vec![],
        }
    }

    pub(crate) fn append_labels(
        &mut self,
        missing_labels: &mut Vec<String>,
        duplicated_labels: &mut Vec<String>,
        disordered_labels: &mut Vec<(String, String)>,
        malformatted_number_in_label: &mut Vec<(String, String)>,
        inconsistent_length_of_labels: &mut Vec<(String, String)>,
    )
    {
        self.missing_labels.append(missing_labels);
        self.duplicated_labels.append(duplicated_labels);
        self.disordered_labels.append(disordered_labels);
        self.malformatted_number_in_label.append(malformatted_number_in_label);
        self.inconsistent_length_of_labels.append(inconsistent_length_of_labels);
    }

    const fn is_empty(&self) -> bool
    {
        self.repls.is_empty()
            && self.missing_labels.is_empty()
            && self.duplicated_labels.is_empty()
            && self.disordered_labels.is_empty()
            && self.malformatted_number_in_label.is_empty()
            && self.inconsistent_length_of_labels.is_empty()
    }

    make_noisy_print!(
        print_repls,
        repls,
        "The following noisy replacement rule was triggered:",
        "The following noisy replacement rules were triggered:",
        rule,
        {
            println!("* Replacement of {:?} to {:?}", rule.from, rule.to);
        }
    );

    make_noisy_print!(
        print_missing_labels,
        missing_labels,
        "The following label is missing:",
        "The following labels are missing:",
        label,
        {
            println!("* {label:?}");
        }
    );

    make_noisy_print!(
        print_duplicated_labels,
        duplicated_labels,
        "The following label is duplicated:",
        "The following labels are duplicated:",
        label,
        {
            println!("* {label:?}");
        }
    );

    make_noisy_print!(
        print_disordered_labels,
        disordered_labels,
        "The following labels are out of order:",
        "The following labels are out of order:",
        (label_a, label_b),
        {
            println!("* Label {label_a:?} is before label {label_b:?}");
        }
    );

    make_noisy_print!(
        print_malformatted_number_in_labels,
        malformatted_number_in_label,
        "The following label has the following bad number in it:",
        "The following labels have the following bad numbers in them:",
        (label, num),
        {
            println!("* Label {label:?} wrongly contains {num:?}");
        }
    );

    make_noisy_print!(
        print_inconsistent_lengths_of_labels,
        inconsistent_length_of_labels,
        "The following label pair consists out of different number of pieces:",
        "The following label pairs consist out of different number of pieces:",
        (label_a, label_b),
        {
            println!("* {label_a:?} and {label_b:?}");
        }
    );

    pub fn print(&self)
    {
        if self.is_empty()
        {
            return;
        }

        println!("{}\n\n", "\n\n\n\n\n\n\n\n".blink().bold().cyan().on_bright_red());

        self.print_repls();
        self.print_missing_labels();
        self.print_duplicated_labels();
        self.print_disordered_labels();
        self.print_malformatted_number_in_labels();
        self.print_inconsistent_lengths_of_labels();

        println!("{}", "\n\n\n\n\n\n\n\n".blink().bold().cyan().on_bright_red());
    }
}