From ed9cd8edcc3a2a9243a1066c27d68a55b8d131d1 Mon Sep 17 00:00:00 2001 From: emma Date: Mon, 13 Mar 2023 18:41:22 -0400 Subject: [PATCH] added supporting parser functions --- Cargo.toml | 2 + src/config.rs | 2 + src/main.rs | 162 +++++++++++++------------------------------------- src/parse.rs | 135 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 179 insertions(+), 122 deletions(-) create mode 100644 src/parse.rs diff --git a/Cargo.toml b/Cargo.toml index 2c64f21..0de032f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,8 @@ name = "plaque" version = "0.0.1" edition = "2021" +license = "AGPL-3.0-or-later" +authors = [ "Emma Tebibyte " ] [dependencies] charsets = { git = "https://git.tebibyte.media/emma/rust-charsets.git", version = "0.3.0" } diff --git a/src/config.rs b/src/config.rs index 2e0d727..22fa8ff 100644 --- a/src/config.rs +++ b/src/config.rs @@ -51,6 +51,8 @@ pub struct PageMeta { pub lang: Language, pub template: String, + + pub kind: String, } pub fn get_path(xdg: &str) -> Result { diff --git a/src/main.rs b/src/main.rs index f49e28b..d76fa98 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,83 +19,21 @@ */ mod config; +mod parse; use std::{ env::args, - io::{ Read, Write }, - fs::{ File, ReadDir, read_dir }, + io::Write, + fs::{ File, read_dir }, }; use config::*; +use parse::*; use pulldown_cmark::{ Parser, Options, html }; -use toml::Value; -use tl::ParserOptions; +use tl::Node; use yacexits::*; -fn get_contents(dir: ReadDir) -> Result, (String, u32)> { - let mut out: Vec<(String, Value)> = Vec::new(); - let mut md: String; - let mut toml = String::new(); - - for entry in dir { - let mut buf = Vec::new(); - - let file = match entry { - Ok(file) => file, - Err(_) => break, - }; - - let file_name = match file.file_name().into_string() { - Ok(name) => name, - Err(_) => { - return Err((format!("Invalid file name."), EX_DATAERR)); - }, - }; - - let contents = match File::open(&file_name) { - Ok(mut md_file) => { - md_file.read_to_end(&mut buf).unwrap(); - String::from_utf8(buf).unwrap() - }, - Err(_) => { - return Err(( - format!("{}: No such file or directory.", file_name), - EX_UNAVAILABLE - )); - }, - }; - - let mut lines = contents.lines(); - - if lines.next() == Some("+++\n") { - let mut line = lines.next(); - - while line.unwrap() != "+++\n" { - toml.push_str(&mut line.unwrap()); - line = lines.next(); - } - md = lines.collect::>().as_mut_slice().join(""); - - let parsed_toml = match toml.parse::() { - Ok(val) => val, - Err(_) => { - return Err(( - format!( - "{}: Could not parse TOML.", - file_name, - ), - EX_DATAERR, - )); - }, - }; - - out.push((md, parsed_toml)); - } - } - Ok(out) -} - fn main() { let argv = args().collect::>(); let mut options = Options::empty(); @@ -117,6 +55,14 @@ fn main() { } }; + let template_files = match read_dir(&config.template_dir) { + Ok(files) => files, + Err(_) => { + eprintln!("{}: {}: Directory not found.", argv[0], &config.template_dir); + exit(EX_UNAVAILABLE); + }, + }; + let content_files = match read_dir(&config.content_dir) { Ok(files) => files, Err(_) => { @@ -125,16 +71,26 @@ fn main() { }, }; - let files = match get_contents(content_files) { + let mut files = match get_contents(content_files) { Ok(files) => files, Err((err, code)) => { eprintln!("{}: {}", argv[0], err); exit(code); }, }; - - for element in files.iter() { - let (md, toml) = element; + + let mut templates = match get_templates(template_files) { + Ok(templates) => templates, + Err((err, code)) => { + eprintln!("{}: {}", argv[0], err); + exit(code); + }, + }; + + for content_file in files.drain() { + let (content_name, (md, toml)) = content_file; + let mut output = String::new(); + html::push_html(&mut output, Parser::new_ext(&md, options)); let meta_info = match PageMeta::read_meta(toml.to_owned()) { Ok(info) => info, @@ -144,57 +100,23 @@ fn main() { }, }; - let mut template = match File::open(format!( - "{}/{}.html", - config.template_dir, - meta_info.template, - )) { - Ok(file) => file, - /* - * TODO: better matching: - * Err(err) => { - * match err { - * whatever_message => File does not exist - * whichever_message => whatever else - */ - Err(_) => { - eprintln!("{}: {}: File does not exist.", argv[0], meta_info.template); - exit(EX_OSERR); + let template = match templates.get_mut(&meta_info.template) { + Some(template) => template, + None => { + eprintln!( + "{}: {}: No such template “{}”.", + argv[0], + content_name, + meta_info.template, + ); + exit(EX_UNAVAILABLE); }, }; - let mut html: Vec = Vec::new(); - - match template.read_to_end(&mut html) { - Ok(_) => {}, - Err(err) => { - eprintln!("{}: {}", argv[0], err); - exit(1); - }, - }; - - let parsed_html = match String::from_utf8(html) { - Ok(html) => html, - Err(err) => { - eprintln!("{}: {}", argv[0], err); - exit(1); - }, - }; - - let dom = match tl::parse(&parsed_html, ParserOptions::default()) { - Ok(dom) => dom, - Err(err) => { - eprintln!("{}: {}", argv[0], err); - exit(1); - }, - }; - - let parser = dom.parser(); - let mut html_file = match File::create(format!( - "{}/{}.html", - config.output_dir, - meta_info.template, + "{}/{}.html", + config.output_dir, + meta_info.template, )) { Ok(file) => file, Err(_) => { @@ -207,10 +129,6 @@ fn main() { }, }; - let mut output = String::new(); - - html::push_html(&mut output, Parser::new_ext(&md, options)); - match html_file.write(output.as_bytes()) { Ok(_) => {}, Err(err) => { diff --git a/src/parse.rs b/src/parse.rs new file mode 100644 index 0000000..a4a38d4 --- /dev/null +++ b/src/parse.rs @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2023 Emma Tebibyte + * SPDX-License-Identifier: AGPL-3.0-or-later + * + * This file is part of Plaque. + * + * Plaque is free software: you can redistribute it and/or modify it under the + * terms of the GNU Affero General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Plaque is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ + +use std::{ + collections::HashMap, + io::{ Read }, + fs::{ File, ReadDir }, +}; + +use tl::{ ParserOptions, VDomGuard }; +use toml::Value; +use yacexits::*; + +pub fn get_contents( + dir: ReadDir, +) -> Result, (String, u32)> { + let mut out: HashMap = HashMap::new(); + let mut md: String; + let mut toml = String::new(); + + let mut files = match read_files(dir) { + Ok(files) => files, + Err(err) => return Err(err), + }; + + for entry in files.drain() { + let (file_name, contents) = entry; + let mut lines = contents.lines(); + + if lines.next() == Some("+++\n") { + let mut line = lines.next(); + + while line.unwrap() != "+++\n" { + toml.push_str(&mut line.unwrap()); + line = lines.next(); + } + md = lines.collect::>().as_mut_slice().join(""); + + let parsed_toml = match toml.parse::() { + Ok(val) => val, + Err(_) => { + return Err(( + format!( + "{}: Could not parse TOML.", + file_name, + ), + EX_DATAERR, + )); + }, + }; + + out.insert(file_name, (md, parsed_toml)); + } + } + Ok(out) +} + +pub fn get_templates( + dir: ReadDir, +) -> Result, (String, u32)> { + let mut out = HashMap::new(); + + let mut files = match read_files(dir) { + Ok(files) => files, + Err(err) => return Err(err), + }; + + for entry in files.drain() { + let (file_name, contents) = entry; + + let dom = match unsafe { + tl::parse_owned(contents, ParserOptions::default()) } + { + Ok(dom) => dom, + Err(err) => return Err((format!("{:?}", err), EX_DATAERR)), + }; + + out.insert(file_name, dom); + } + Ok(out) +} + +pub fn read_files( + dir: ReadDir, +) -> Result, (String, u32)> { + let mut out = HashMap::new(); + + for entry in dir { + let mut buf = Vec::new(); + let file = match entry { + Ok(file) => file, + Err(_) => break, + }; + + let file_name = match file.file_name().into_string() { + Ok(name) => name, + Err(_) => { + return Err((format!("Invalid file name."), EX_DATAERR)); + }, + }; + + let contents = match File::open(&file_name) { + Ok(mut md_file) => { + md_file.read_to_end(&mut buf).unwrap(); + String::from_utf8(buf).unwrap() + }, + Err(_) => { + return Err(( + format!("{}: No such file or directory.", file_name), + EX_UNAVAILABLE + )); + }, + }; + + out.insert(file_name, contents); + } + Ok(out) +}