aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSoispha <soispha@vhack.eu>2023-06-18 16:32:47 +0200
committerSoispha <soispha@vhack.eu>2023-06-18 16:32:47 +0200
commit369bf07cbb36d8e72025014bfd4ddc52d9049fde (patch)
tree545b32762ec8af521484f6c520dc568edaf8a2f7 /src
downloadlpm-369bf07cbb36d8e72025014bfd4ddc52d9049fde.zip
Chore: Initial commit
Diffstat (limited to '')
-rw-r--r--src/command_line_interface.rs42
-rw-r--r--src/data.rs28
-rw-r--r--src/main.rs40
-rw-r--r--src/new/chapter.rs63
-rw-r--r--src/new/mod.rs99
-rw-r--r--src/new/project.rs110
-rw-r--r--src/new/section.rs63
7 files changed, 445 insertions, 0 deletions
diff --git a/src/command_line_interface.rs b/src/command_line_interface.rs
new file mode 100644
index 0000000..66d8122
--- /dev/null
+++ b/src/command_line_interface.rs
@@ -0,0 +1,42 @@
+use clap::{Subcommand, Parser};
+
+/// A project manager for LaTeX
+#[derive(Parser, Debug)]
+#[clap(author, version, about, long_about = None)]
+pub struct Args {
+ #[command(subcommand)]
+ pub cli: Command,
+}
+
+#[derive(Subcommand, Debug)]
+pub enum Command {
+ /// Generates a new part
+ #[command(subcommand)]
+ New (SubCommand),
+}
+
+
+#[derive(Subcommand, Debug)]
+pub enum SubCommand {
+ /// Adds a section
+ Section {
+ /// Name of the new Section
+ name: String,
+ },
+
+ /// Adds a chapter
+ Chapter {
+ /// Name of the new Chapter
+ name: String,
+ },
+
+ /// generates a new project
+ Project {
+ /// Name of the new Project
+ name: String,
+ /// Name of the first chapter
+ first_chapter: String,
+ // /// Name of the first section
+ // first_section: String,
+ },
+}
diff --git a/src/data.rs b/src/data.rs
new file mode 100644
index 0000000..4966e88
--- /dev/null
+++ b/src/data.rs
@@ -0,0 +1,28 @@
+use serde_derive::{Deserialize, Serialize};
+
+#[derive(Deserialize, Serialize)]
+pub struct Data {
+ pub last_chapter: LastChapter,
+}
+
+#[derive(Deserialize, Serialize)]
+pub struct LastChapter {
+ pub user_name: String,
+ pub number: u32,
+}
+
+
+//fn main() {
+// let config: Config = toml::from_str(r#"
+// ip = '127.0.0.1'
+//
+// [keys]
+// github = 'xxxxxxxxxxxxxxxxx'
+// travis = 'yyyyyyyyyyyyyyyyy'
+// "#).unwrap();
+//
+// assert_eq!(config.ip, "127.0.0.1");
+// assert_eq!(config.port, None);
+// assert_eq!(config.keys.github, "xxxxxxxxxxxxxxxxx");
+// assert_eq!(config.keys.travis.as_ref().unwrap(), "yyyyyyyyyyyyyyyyy");
+//}
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..b056c88
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,40 @@
+use std::path::PathBuf;
+
+use clap::Parser;
+use command_line_interface::{
+ Args,
+ Command::New,
+ SubCommand::{Chapter, Project, Section},
+};
+use new::{chapter::generate_new_chapter, project::generate_new_project, section::generate_new_section};
+
+pub mod command_line_interface;
+pub mod data;
+pub mod new;
+
+fn main() {
+ let args = Args::parse();
+
+ match args.cli {
+ New(new_command) => match new_command {
+ Section { name } => generate_new_section(name).unwrap(),
+ Chapter { name } => generate_new_chapter(name).unwrap(),
+ Project {
+ name,
+ first_chapter,
+ //first_section,
+ } => {
+ let preamble_path = PathBuf::from("/home/dt/repos/tex/preset/headers/preamble.tex");
+ let resource_path = PathBuf::from("/home/dt/repos/tex/preset/resources");
+ generate_new_project(
+ name,
+ first_chapter,
+ //first_section,
+ preamble_path,
+ resource_path,
+ )
+ .unwrap()
+ }
+ },
+ }
+}
diff --git a/src/new/chapter.rs b/src/new/chapter.rs
new file mode 100644
index 0000000..9cc12d0
--- /dev/null
+++ b/src/new/chapter.rs
@@ -0,0 +1,63 @@
+use std::{
+ fs::{self, File},
+ io::{self, Write},
+};
+
+use convert_case::{Case, Casing};
+
+use crate::data::Data;
+
+use super::{get_project_root, CHAPTER};
+
+
+pub fn generate_new_chapter(name: String) -> io::Result<()> {
+ let project_root = get_project_root().unwrap();
+
+ let raw_data_file = fs::read_to_string(project_root.join("lpm.toml")).unwrap();
+ let mut data_file: Data = toml::from_str(&raw_data_file).unwrap();
+ let mut main_file = fs::read_to_string(project_root.join("main.tex")).unwrap();
+
+ fs::create_dir(project_root.join(format!("content/{}", name.to_case(Case::Snake),))).unwrap();
+ let mut new_chapter = File::create(project_root.join(format!(
+ "content/{}/chapter_{:02}.tex",
+ name.to_case(Case::Snake),
+ data_file.last_chapter.number + 1
+ ))).unwrap();
+ new_chapter.write_all(CHAPTER.replace("REPLACEMENT_CHAPTER", &name).as_bytes()).unwrap();
+
+ fs::create_dir(project_root.join(format!("content/{}/sections", name.to_case(Case::Snake),))).unwrap();
+
+ main_file = main_file.replace(
+ &format!(
+ "\\includeonly{{content/{}/{}}}",
+ &data_file.last_chapter.user_name,
+ &format!("chapter_{:02}", data_file.last_chapter.number)
+ ),
+ &format!(
+ "\\includeonly{{content/{}/{}}}",
+ name.to_case(Case::Snake),
+ &format!("chapter_{:02}", data_file.last_chapter.number + 1)
+ ),
+ );
+ let find_index = main_file.find("% NEXT_CHAPTER").unwrap();
+ main_file.insert_str(
+ find_index,
+ &format!(
+ "\\include{{content/{}/{}}}\n ",
+ name.to_case(Case::Snake),
+ &format!("chapter_{:02}", data_file.last_chapter.number + 1)
+ ),
+ );
+
+ data_file.last_chapter.user_name = name.to_case(Case::Snake);
+ data_file.last_chapter.number += 1;
+
+ fs::write(
+ project_root.join("lpm.toml"),
+ toml::to_string(&data_file).expect("We changed it ourselfes, the conversion should work"),
+ ).unwrap();
+
+ fs::write(project_root.join("main.tex"), main_file).unwrap();
+
+ Ok(())
+}
diff --git a/src/new/mod.rs b/src/new/mod.rs
new file mode 100644
index 0000000..efc55cd
--- /dev/null
+++ b/src/new/mod.rs
@@ -0,0 +1,99 @@
+pub mod chapter;
+pub mod project;
+pub mod section;
+
+use std::{
+ env,
+ ffi::OsString,
+ fs::read_dir,
+ io::{self, ErrorKind},
+ path::PathBuf,
+};
+
+const SECTION: &'static str = r#"%! TEX root = ../../../main.tex
+% LTeX: language=de-DE
+
+\lesson{REPLACMENT_SECTION_TITLE}{DATE}{}
+Dies ist etwas Text
+"#;
+
+const CHAPTER: &'static str = r#"%! TEX root = ../main.tex
+% LTeX: language=de-DE
+
+\chapter{REPLACEMENT_CHAPTER}
+"#;
+
+const TITLE_FILE: &'static str = r#"% LTeX: language=de-DE
+
+\maketitle
+\tableofcontents
+\vspace*{\fill}
+\makeatletter
+Copyright \textcopyright{} \@authors{} \@years{}\\
+\ \\
+Dieses Werk ist lizenziert unter den Bedingungen der CC BY-SA 4.0.
+Der Lizenztext ist online unter \url{http://creativecommons.org/licenses/by-sa/4.0/legalcode} abrufbar.
+\makeatother
+\clearpage
+"#;
+
+const MAIN_FILE: &'static str = r#"%\documentclass[a4paper, 12pt, nosolutions]{report}
+\documentclass[a4paper, 12pt]{report}
+% LTeX: language=de-DE
+\input{headers/preamble.tex}
+\input{headers/preamble_local.tex}
+
+
+\title{\textbf{Titel}}
+\author{Name\thanks{Beispiel}}
+\authors{Name}
+\years{2022 - 2023}
+\date{\DTMDate{2002-12-4}}
+
+\includeonly{content/REPLACEMENT_CHAPTER/chapter_01}
+
+\begin{document}
+ \input{content/static/title}
+
+ \include{content/REPLACEMENT_CHAPTER/chapter_01}
+ % NEXT_CHAPTER
+
+ \printbibliography\relax
+\end{document}
+"#;
+
+
+
+pub fn get_project_root() -> io::Result<PathBuf> {
+ let path = env::current_dir()?;
+ let mut path_ancestors = path.as_path().ancestors();
+
+ while let Some(path_segment) = path_ancestors.next() {
+ if read_dir(path_segment)?.into_iter().any(|path_segment| {
+ path_segment
+ .expect("The read_dir shouldn't error out here")
+ .file_name()
+ == OsString::from("lpm.toml")
+ }) {
+ return Ok(PathBuf::from(path_segment));
+ }
+ }
+ Err(io::Error::new(
+ ErrorKind::NotFound,
+ "Ran out of places to find lpm.toml",
+ ))
+}
+
+pub fn get_all_chapters() -> io::Result<Vec<String>> {
+ let path = get_project_root()?;
+ let output = read_dir(path.join("content"))?
+ .map(|path| {
+ path.expect("The values sholud be fine")
+ .file_name()
+ .to_str()
+ .expect("all names should be valid utf-8")
+ .to_owned()
+ })
+ .collect();
+ Ok(output)
+}
diff --git a/src/new/project.rs b/src/new/project.rs
new file mode 100644
index 0000000..e04d138
--- /dev/null
+++ b/src/new/project.rs
@@ -0,0 +1,110 @@
+use std::{
+ env,
+ fs::{self, File},
+ io::{self, Write},
+ path::PathBuf,
+ process::Command,
+};
+
+
+use convert_case::{Case, Casing};
+
+use crate::data::Data;
+
+use super::{TITLE_FILE, CHAPTER, MAIN_FILE};
+
+const NEEDED_DIRECTORYS: &'static [&'static str] =
+ &["build", "content", "headers", "references", "resources"];
+
+
+pub fn generate_new_project(
+ name: String,
+ first_chapter: String,
+ //first_section: String,
+ preamble_path: PathBuf,
+ resource_path: PathBuf,
+) -> io::Result<()> {
+ fs::create_dir(&name).unwrap();
+ env::set_current_dir(&name).unwrap();
+ let project_root = env::current_dir().unwrap();
+
+ for directory in NEEDED_DIRECTORYS {
+ fs::create_dir(directory).unwrap();
+ }
+
+ // content
+ env::set_current_dir(project_root.join("content")).unwrap();
+ fs::create_dir(&first_chapter.to_case(Case::Snake)).unwrap();
+ fs::create_dir("static").unwrap();
+
+ env::set_current_dir("static").unwrap();
+ let mut title_file = File::create("title.tex").unwrap();
+ title_file.write_all(TITLE_FILE.as_bytes()).unwrap();
+
+ env::set_current_dir(project_root.join("content").join(&first_chapter.to_case(Case::Snake))).unwrap();
+ fs::create_dir("sections").unwrap();
+ let mut chapter_file = File::create("chapter_01.tex").unwrap();
+ chapter_file
+ .write_all(
+ CHAPTER
+ .replace("REPLACEMENT_CHAPTER", &first_chapter)
+ .as_bytes(),
+ )
+ .unwrap();
+
+ //env::set_current_dir("sections").unwrap();
+ //let mut section_file = File::create(format!("{}.tex", &first_section)).unwrap();
+ //section_file
+ // .write_all(SECTION.as_bytes())
+ // .unwrap();
+
+ // headers
+ env::set_current_dir(project_root.join("headers")).unwrap();
+ File::create("preamble_local.tex").unwrap();
+ fs::copy(fs::canonicalize(preamble_path).unwrap(), "preamble.tex").unwrap();
+
+ // resources
+ env::set_current_dir(project_root.join("resources")).unwrap();
+ fs::canonicalize(resource_path)
+ .unwrap()
+ .read_dir()
+ .unwrap()
+ .map(|path| path.expect("The provided path should work"))
+ .for_each(|path| {
+ fs::copy(path.path(), path.file_name()).unwrap();
+ });
+
+ // root files
+ env::set_current_dir(project_root).unwrap();
+ let mut main_file = File::create("main.tex").unwrap();
+ main_file
+ .write_all(
+ MAIN_FILE
+ .replace("REPLACEMENT_CHAPTER", &first_chapter.to_case(Case::Snake))
+ .as_bytes(),
+ )
+ .unwrap();
+
+ let data_file = Data {
+ last_chapter: crate::data::LastChapter {
+ user_name: first_chapter.to_case(Case::Snake),
+ number: 1,
+ },
+ };
+ let mut lpm_file = File::create("lpm.toml").unwrap();
+ lpm_file
+ .write_all(toml::to_string(&data_file).unwrap().as_bytes())
+ .unwrap();
+
+ Command::new("git")
+ .arg("init")
+ .output()
+ .expect("failed to execute process");
+
+ let mut lpm_file = File::create(".gitignore").unwrap();
+ lpm_file
+ .write_all(b"/build")
+ .unwrap();
+
+ Ok(())
+}
diff --git a/src/new/section.rs b/src/new/section.rs
new file mode 100644
index 0000000..31742c2
--- /dev/null
+++ b/src/new/section.rs
@@ -0,0 +1,63 @@
+use std::{
+ env,
+ fs::{self, read_dir},
+ io::{self, ErrorKind},
+ path::PathBuf,
+ time::SystemTime,
+};
+
+use chrono::{DateTime, Local};
+use convert_case::{Case, Casing};
+
+use super::SECTION;
+
+pub fn generate_new_section(name: String) -> io::Result<()> {
+ let chapter_root = get_section_root()?;
+ let chapter_main_file_path = read_dir(&chapter_root)?
+ .into_iter()
+ .map(|path| path.unwrap())
+ .filter(|path| path.file_name().to_str().unwrap().contains("chapter_"))
+ .last()
+ .unwrap()
+ .path();
+ let mut main_file = fs::read_to_string(&chapter_main_file_path).unwrap();
+
+ main_file.push_str(&format!(
+ "\\input{{content/{}/sections/{}}}\n",
+ chapter_root.file_name().unwrap().to_str().unwrap(),
+ &name.to_case(Case::Snake)
+ ));
+ fs::write(chapter_main_file_path, main_file)?;
+ fs::write(
+ chapter_root.join(format!("sections/{}.tex", name.to_case(Case::Snake))),
+ SECTION.replace("REPLACMENT_SECTION_TITLE", &name).replace(
+ "DATE",
+ &format!(
+ "{}",
+ DateTime::<Local>::from(SystemTime::now()).format("%Y-%m-%d")
+ ),
+ ),
+ )?;
+ Ok(())
+}
+
+pub fn get_section_root() -> io::Result<PathBuf> {
+ let path = env::current_dir()?;
+ let mut path_ancestors = path.as_path().ancestors();
+
+ while let Some(path_segment) = path_ancestors.next() {
+ if read_dir(path_segment)?.into_iter().any(|path| {
+ path.expect("The read_dir shouldn't error out here")
+ .file_name()
+ .to_str()
+ .unwrap()
+ .contains("chapter_")
+ }) {
+ return Ok(PathBuf::from(path_segment));
+ }
+ }
+ Err(io::Error::new(
+ ErrorKind::NotFound,
+ "Ran out of places to find chapter_root",
+ ))
+}