commit 364059abef99c04e5210fb1ee437a3ec5bb67bcb
Author: CrispyPin
Date: Fri Apr 26 14:40:44 2024 +0200
init
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9624d02
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+/target
+/write
+/site
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..5ea6197
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "htmd"
+version = "0.1.0"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..77b1bed
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "htmd"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..53f4661
--- /dev/null
+++ b/README.md
@@ -0,0 +1,12 @@
+# static site generator
+
+all files get copied from the `write` dir to the `site` dir
+md files get converted to html in the process
+using `template.html`, which should include `TITLE` and `CONTENT`
+utf-8 is required
+
+/blog/post_1.md -> /blog/post_1/index.html
+/blog/ferret.mp4 -> /blog/post_1/ferret.mp4
+
+/blog/post_2/post_2.md -> /blog/post_2/index.html
+/blog/post_2/cat.png -> /blog/post_2/cat.png
diff --git a/rustfmt.toml b/rustfmt.toml
new file mode 100644
index 0000000..218e203
--- /dev/null
+++ b/rustfmt.toml
@@ -0,0 +1 @@
+hard_tabs = true
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..174c815
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,166 @@
+use std::{
+ error::Error,
+ ffi::OsStr,
+ fs::{read_dir, read_to_string, File},
+ io::Write,
+ path::{Path, PathBuf},
+};
+
+const SRC_DIR: &str = "write";
+const OUT_DIR: &str = "site";
+type Result = core::result::Result<(), Box>;
+
+fn main() -> Result {
+ let src_dir = PathBuf::from(SRC_DIR);
+ build_dir(&src_dir)
+}
+
+fn build_dir(dir: &Path) -> Result {
+ for entry in read_dir(dir).unwrap().flatten() {
+ let ftype = entry.file_type()?;
+ if ftype.is_dir() {
+ build_dir(&entry.path())?;
+ } else if ftype.is_file() {
+ build_file(&entry.path())?;
+ }
+ }
+ Ok(())
+}
+
+fn build_file(path: &Path) -> Result {
+ if path.extension().and_then(OsStr::to_str) == Some("md") {
+ convert_file(path)
+ } else {
+ todo!("move file")
+ }
+}
+
+#[derive(Debug, Clone, PartialEq)]
+enum S {
+ None,
+ P,
+ Code,
+ UList,
+ OList,
+}
+
+fn convert_file(path: &Path) -> Result {
+ let markdown = read_to_string(path)?;
+ let out_path = PathBuf::from(OUT_DIR).join(path.strip_prefix(SRC_DIR)?);
+ let out_path = out_path.with_extension("html");
+
+ let mut html = String::new();
+ let mut state = S::None;
+
+ for line in markdown.lines() {
+ if line.starts_with("```") {
+ if state == S::Code {
+ html += "\n";
+ state = S::None;
+ continue;
+ } else {
+ if state == S::P {
+ html += "
\n";
+ }
+ state = S::Code;
+ html += "\n";
+ continue;
+ }
+ }
+
+ if state == S::Code {
+ html += line;
+ html += "\n";
+ continue;
+ }
+
+ if let Some((start, header)) = line.split_once(' ') {
+ let level = start.len();
+ if (1..=6).contains(&level) && start.chars().all(|c| c == '#') {
+ if state == S::P {
+ state = S::None;
+ html += "\n";
+ }
+ let header = &convert_line(header);
+ html += &format!("{header}\n");
+ continue;
+ }
+ }
+
+ if state == S::P && line.is_empty() {
+ state = S::None;
+ html += "\n";
+ } else if !line.is_empty() {
+ if state == S::None {
+ state = S::P;
+ html += "\n";
+ }
+ html += &convert_line(line);
+ html += "
\n";
+ }
+ }
+
+ let template = read_to_string("template.html")?;
+ let html = template.replace("CONTENT HERE", &html);
+
+ let mut file = File::create(out_path)?;
+ file.write_all(html.as_bytes())?;
+
+ Ok(())
+}
+
+fn convert_line(source: &str) -> String {
+ let mut out = String::new();
+ let mut is_em = false;
+ let mut is_b = false;
+ let mut is_code = false;
+ let mut is_ul = false;
+ let toggle = |state: bool, tag: &str| {
+ if state {
+ format!("<{tag}>")
+ } else {
+ format!("{tag}>")
+ }
+ };
+
+ let mut chars = source.chars().peekable();
+ while let Some(c) = chars.next() {
+ if c == '*' {
+ if chars.peek() == Some(&'*') {
+ _ = chars.next();
+ is_b = !is_b;
+ // out += b_tag();
+ out += &toggle(is_b, "strong");
+ } else {
+ is_em = !is_em;
+ out += &toggle(is_em, "em");
+ // out += if is_em { "" } else { "" };
+ }
+ } else if c == '`' {
+ is_code = !is_code;
+ out += &toggle(is_code, "code");
+
+ // out += if is_code { "" } else { "
" };
+ } else if c == '_' {
+ is_ul = !is_ul;
+ out += &toggle(is_ul, "u");
+
+ // out += if is_ul { "" } else { "" };
+ } else {
+ out.push(c);
+ }
+ }
+ if is_em {
+ out += &toggle(false, "em");
+ }
+ if is_b {
+ out += &toggle(false, "b");
+ }
+ if is_code {
+ out += &toggle(false, "code");
+ }
+ if is_ul {
+ out += &toggle(false, "u");
+ }
+ out
+}