added supporting parser functions

This commit is contained in:
Emma Tebibyte 2023-03-13 18:41:22 -04:00
parent 017c77366e
commit ed9cd8edcc
Signed by: emma
GPG Key ID: 6D661C738815E7DD
4 changed files with 179 additions and 122 deletions

View File

@ -2,6 +2,8 @@
name = "plaque"
version = "0.0.1"
edition = "2021"
license = "AGPL-3.0-or-later"
authors = [ "Emma Tebibyte <emma@tebibyte.media>" ]
[dependencies]
charsets = { git = "https://git.tebibyte.media/emma/rust-charsets.git", version = "0.3.0" }

View File

@ -51,6 +51,8 @@ pub struct PageMeta {
pub lang: Language,
pub template: String,
pub kind: String,
}
pub fn get_path(xdg: &str) -> Result<String, (String, u32)> {

View File

@ -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<Vec<(String, Value)>, (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::<Vec<&str>>().as_mut_slice().join("");
let parsed_toml = match toml.parse::<Value>() {
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::<Vec<String>>();
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<u8> = 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) => {

135
src/parse.rs Normal file
View File

@ -0,0 +1,135 @@
/*
* Copyright (c) 2023 Emma Tebibyte <emma@tebibyte.media>
* 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<HashMap<String, (String, Value)>, (String, u32)> {
let mut out: HashMap<String, (String, Value)> = 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::<Vec<&str>>().as_mut_slice().join("");
let parsed_toml = match toml.parse::<Value>() {
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<HashMap<String, VDomGuard>, (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<HashMap<String, String>, (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)
}