1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
use std::fmt::Display;
use crate::prelude::*;

/// Currently, only these few types are supported.
/// There is also nothing preventing you from putting a \part{} in a document of class "part",
/// but latex will show an error. If you want those restrictions to be implemented, please put
/// up an issue
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DocumentClassType {
    Article,
    Amsart,
    Part,
    Report,
    Book,
    Beamer,
}
impl Display for DocumentClassType {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{}",
            match &self {
                Self::Article => "article",
                Self::Part => "part",
                Self::Report => "report",
                Self::Book => "book",
                Self::Amsart => "amsart",
                Self::Beamer => "beamer",
            }
        )?;

        Ok(())
    }
}
impl From<&str> for DocumentClassType {
    fn from(value: &str) -> Self {
        match value {
            "article" => Self::Article,
            "part" => Self::Part,
            "book" => Self::Book,
            "report" => Self::Report,
            "amsart" => Self::Amsart,
            "beamer" => Self::Beamer,
            _ => Self::Article,
        }
    }
}

/// Wrapper around `DocumentClassType`, contains whatever options you want to add.
/// Nothing prevents you from adding absolute gibberish as an option. If you want those
/// restrictions implemented, please put up an issue.
#[derive(Debug, Clone)]
pub struct DocumentClass {
    pub(crate) typ: DocumentClassType,
    pub(crate) opt: Vec<String>,
}
impl DocumentClass {
    pub fn new(typ: &str) -> Self {
        Self {
            typ: typ.into(),
            opt: vec![],
        }
    }
}
impl AsLatex for DocumentClass {
    fn to_string(&self) -> String {
        let options = self
            .opt
            .iter()
            .map(|s| format!("{}, ", s))
            .collect::<String>();
        format!("\\documentclass[{}]{{{}}}", options, self.typ.to_string())
    }
}
impl Opt for DocumentClass {
    fn add_option(&mut self, opt: &str) {
        self.opt.push(opt.to_string())
    }
}