use std::fmt::Debug;
pub use attatch::*;
pub use error::*;
use std::io::Write;
use std::path::{Path, PathBuf};
pub mod attatch;
pub mod error;
#[derive(Debug, Clone)]
pub struct Latex {
pub document_class: Class,
pub metadata: Metadata,
pub packages: Vec<Package>,
pub document_elements: Vec<Element>,
}
#[derive(Debug, Clone)]
pub enum Class {
Article,
Book,
Report,
Beamer,
}
#[derive(Debug, Clone)]
pub struct Metadata {
pub author: String,
pub title: String,
pub date: String,
}
#[derive(Debug, Clone)]
pub struct Package(pub String);
#[derive(Debug, Clone)]
pub struct Part(pub String, pub Vec<Element>);
#[derive(Debug, Clone)]
pub struct Chapter(pub String, pub Vec<Element>);
#[derive(Debug, Clone)]
pub struct Section(pub String, pub Vec<Element>);
#[derive(Debug, Clone)]
pub struct Paragraph(pub String, pub Option<Vec<Element>>);
#[derive(Debug, Clone)]
pub struct Text(pub String, pub TextType);
#[derive(Debug, Clone)]
pub struct Input(pub String);
#[derive(Debug, Clone)]
pub enum Element {
Part(Part),
Chapter(Chapter),
Section(Section),
Paragraph(Paragraph),
Text(Text),
Input(Input),
}
#[derive(Debug, Clone)]
pub enum TextType {
Normal,
Bold,
Italic,
Underline,
Verbatim,
Roman,
}
pub trait Convert {
fn to_latex_string(&self) -> String;
}
impl Element {
pub fn rank(&self) -> u8 {
match self {
Element::Part(_) => 0,
Element::Chapter(_) => 1,
Element::Section(_) => 2,
Element::Paragraph(_) => 3,
Element::Text(_) => 4,
Element::Input(_) => 5,
}
}
pub fn return_value<K>(&self) -> K
where K: Convert + Clone + From<Part> + From<Chapter> + From<Section> + From<Paragraph> + From<Text> + From<Input>{
match &self {
Element::Part(p) => {p.to_owned().into()}
Element::Chapter(c) => {c.to_owned().into()}
Element::Section(s) => {s.to_owned().into()}
Element::Paragraph(p) => {p.to_owned().into()}
Element::Text(t) => {t.to_owned().into()}
Element::Input(i) => {i.to_owned().into()}
}
}
pub fn get_vec(&self) -> Option<Vec<Element>>{
match &self{
Element::Part(p) => {Some(p.to_owned().1)}
Element::Chapter(c) => {Some(c.to_owned().1)}
Element::Section(s) => {Some(s.to_owned().1)}
Element::Paragraph(p) => {Some(p.to_owned().1.unwrap())}
Element::Text(t) => {None}
Element::Input(i) => {None}
}
}
pub fn loop_through(&self) -> String{
let vec = match self.get_vec(){
Some(a) => a,
None => return "".to_string()
};
let mut s = Vec::new();
if vec.is_empty(){
return "".to_string()
} else {
for i in &vec{
s.push(i.to_latex_string());
s.push(i.loop_through())
}
}
s.join("\n")
}
}
impl Class {
pub fn as_class_str(&self) -> String {
match self {
Class::Article => "article".to_string(),
Class::Book => "book".to_string(),
Class::Report => "report".to_string(),
Class::Beamer => "beamer".to_string(),
}
}
}
impl Metadata {
pub fn new(title: &str, author: &str, date: &str) -> Self {
Self {
title: title.to_string(),
author: author.to_string(),
date: date.to_string(),
}
}
}
impl Default for Metadata {
fn default() -> Self {
Self {
author: "default author".to_string(),
title: "default title".to_string(),
date: "what day is it?".to_string(),
}
}
}
impl Latex {
pub fn new() -> Self {
Self {
document_class: Class::Article,
metadata: Metadata::default(),
packages: Vec::new(),
document_elements: Vec::new(),
}
}
pub fn set_class(&mut self, class: Class) {
self.document_class = class;
}
pub fn set_metadata(&mut self, meta: Metadata) {
self.metadata = meta;
}
pub fn set_packages(&mut self, packages: &Vec<Package>) {
self.packages = packages.to_owned();
}
pub fn add_package(&mut self, package: String) {
self.packages.push(Package(package));
}
pub fn set_elements(&mut self, elements: &Vec<Element>) {
self.document_elements = elements.to_owned();
}
pub fn write(&self, path: PathBuf) -> Result<(), std::io::Error> {
let path = path.as_path();
let mut file = std::fs::File::create(path)?;
let mut s: Vec<String> = Vec::new();
s.push(self.document_class.to_latex_string());
s.push(self.metadata.to_latex_string());
for i in &self.packages {
s.push(i.to_latex_string())
}
s.push(String::from("\\begin{document}"));
s.push(String::from("\\maketitle\n\\newpage"));
for i in &self.document_elements {
match i {
Element::Part(e) => {
s.push(e.to_latex_string());
for j in &e.1 {
s.push(j.to_latex_string());
s.push(j.loop_through())
}
}
Element::Chapter(e) => {
s.push(e.to_latex_string());
for j in &e.1 {
s.push(j.to_latex_string());
s.push(j.loop_through())
}
}
Element::Section(e) => {
s.push(e.to_latex_string());
for j in &e.1 {
s.push(j.to_latex_string());
s.push(j.loop_through())
}
}
Element::Paragraph(e) => {
s.push(e.to_latex_string());
for j in e.1.as_ref().unwrap() {
s.push(j.to_latex_string());
s.push(j.loop_through())
}
}
Element::Text(e) => s.push(e.to_latex_string()),
Element::Input(e) => s.push(e.to_latex_string()),
}
}
s.push(String::from("\\end{document}"));
let content = s.join("\n");
file.write_all(&content.as_bytes())?;
Ok(())
}
}
impl Part {
pub fn new(text: &str) -> Self {
Self(text.to_string(), Vec::new())
}
}
impl Chapter {
pub fn new(text: &str) -> Self {
Self(text.to_string(), Vec::new())
}
}
impl Section {
pub fn new(text: &str) -> Self {
Self(text.to_string(), Vec::new())
}
}
impl Paragraph {
pub fn new(text: &str) -> Self {
Self(text.to_string(), Some(Vec::new()))
}
}
impl Text {
pub fn new(text: &str, textType: TextType) -> Self {
Self(text.to_string(), textType)
}
}
impl Input {
pub fn new(text: &str) -> Self {
Self(text.to_string())
}
}
impl Package{
pub fn new(pkg: &str) -> Self{
Package(pkg.to_string())
}
}
impl Convert for Class {
fn to_latex_string(&self) -> String {
let s = r#"\documentclass[11pt, letterpaper]{_class}"#;
s.replace("_class", &self.as_class_str())
}
}
impl Convert for Metadata {
fn to_latex_string(&self) -> String {
let v = vec![
format!("\\author{{{}}}", &self.author),
format!("\\title{{{}}}", &self.title),
format!("\\date{{{}}}", &self.date),
];
v.join("\n")
}
}
impl Convert for Package {
fn to_latex_string(&self) -> String {
format!("\\usepackage{{{}}}", &self.0)
}
}
impl Convert for Part {
fn to_latex_string(&self) -> String {
format!("\\part{{{}}}", &self.0)
}
}
impl Convert for Chapter {
fn to_latex_string(&self) -> String {
format!("\\chapter{{{}}}", &self.0)
}
}
impl Convert for Section {
fn to_latex_string(&self) -> String {
format!("\\section{{{}}}", &self.0)
}
}
impl Convert for Paragraph {
fn to_latex_string(&self) -> String {
format!("\\paragraph{{{}}}", &self.0)
}
}
impl Convert for Text {
fn to_latex_string(&self) -> String {
let par = "\\par";
let mut text = String::new();
match &self.1 {
TextType::Normal => text = self.0.clone(),
TextType::Bold => {
text = format!("\\textbf{{{}}}", &self.0);
}
TextType::Italic => {
text = format!("\\textit{{{}}}", &self.0);
}
TextType::Roman => {
text = format!("\\textrm{{{}}}", &self.0);
}
TextType::Underline => {
text = format!("\\underline{{{}}}", &self.0);
}
TextType::Verbatim => {
text = format!("\\verb!{}!", &self.0);
}
}
format!("{} {}", par, &text)
}
}
impl Convert for Input {
fn to_latex_string(&self) -> String {
format!("\\input{{{}}}", &self.0)
}
}
impl Convert for Element {
fn to_latex_string(&self) -> String {
match self {
Element::Part(e) => e.to_latex_string(),
Element::Chapter(e) => e.to_latex_string(),
Element::Section(e) => e.to_latex_string(),
Element::Paragraph(e) => e.to_latex_string(),
Element::Text(e) => e.to_latex_string(),
Element::Input(e) => e.to_latex_string(),
}
}
}
impl From<Part> for Element {
fn from(p: Part) -> Self {
Element::Part(p)
}
}
impl From<Chapter> for Element{
fn from(c: Chapter) -> Self {
Element::Chapter(c)
}
}
impl From<Section> for Element{
fn from(s: Section) -> Self {
Element::Section(s)
}
}
impl From<Paragraph> for Element{
fn from(p: Paragraph) -> Self {
Element::Paragraph(p)
}
}
impl From<Text> for Element{
fn from(t: Text) -> Self {
Element::Text(t)
}
}
impl From<Input> for Element{
fn from(i: Input) -> Self {
Element::Input(i)
}
}