From a7026cde72198160a53df39022b7b4cdaf3b8db0 Mon Sep 17 00:00:00 2001 From: Ryan Brue Date: Fri, 13 Dec 2024 00:40:52 -0600 Subject: [PATCH] Default to a simpler static site generation Signed-off-by: Ryan Brue --- .gitignore | 3 +- ...mand_reference.dj => command_reference.md} | 2 +- docs/{index.dj => index.md} | 0 ...{contact-ryanabx.dj => contact-ryanabx.md} | 2 +- .../{djot-example.dj => djot-example.md} | 2 +- docs/notes/markdown-example.md | 4 +- src/main.rs | 108 +++++++++++++++++- src/markdown.rs | 71 ++++++++++++ src/tests.rs | 2 + 9 files changed, 187 insertions(+), 7 deletions(-) rename docs/{command_reference.dj => command_reference.md} (97%) rename docs/{index.dj => index.md} (100%) rename docs/notes/{contact-ryanabx.dj => contact-ryanabx.md} (76%) rename docs/notes/{djot-example.dj => djot-example.md} (82%) create mode 100644 src/markdown.rs diff --git a/.gitignore b/.gitignore index d7a1baa..0e30c6e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target /test -/docs-out \ No newline at end of file +/docs-out +/out \ No newline at end of file diff --git a/docs/command_reference.dj b/docs/command_reference.md similarity index 97% rename from docs/command_reference.dj rename to docs/command_reference.md index 5d0bacc..cb5b8d2 100644 --- a/docs/command_reference.dj +++ b/docs/command_reference.md @@ -1,6 +1,6 @@ # Djot command reference -[Back to main page](./index.dj) +[Back to main page](./index.md) ## Installation diff --git a/docs/index.dj b/docs/index.md similarity index 100% rename from docs/index.dj rename to docs/index.md diff --git a/docs/notes/contact-ryanabx.dj b/docs/notes/contact-ryanabx.md similarity index 76% rename from docs/notes/contact-ryanabx.dj rename to docs/notes/contact-ryanabx.md index 4088d70..d2ac74a 100644 --- a/docs/notes/contact-ryanabx.dj +++ b/docs/notes/contact-ryanabx.md @@ -1,4 +1,4 @@ -[Back to home page](../index.dj) +[Back to home page](../index.md) # Contact Ryanabx diff --git a/docs/notes/djot-example.dj b/docs/notes/djot-example.md similarity index 82% rename from docs/notes/djot-example.dj rename to docs/notes/djot-example.md index 80f3d82..e1a2d68 100644 --- a/docs/notes/djot-example.dj +++ b/docs/notes/djot-example.md @@ -6,4 +6,4 @@ This is a simple djot example to showcase this static site generator! It gets pu --- -For more, see the [Markdown example](./markdown-example.md) and go to the command reference at [../command_reference.dj](../command_reference.dj) \ No newline at end of file +For more, see the [Markdown example](./markdown-example.md) and go to the command reference at [../command_reference.md](../command_reference.md) \ No newline at end of file diff --git a/docs/notes/markdown-example.md b/docs/notes/markdown-example.md index 95a01ef..0bb31ae 100644 --- a/docs/notes/markdown-example.md +++ b/docs/notes/markdown-example.md @@ -2,7 +2,7 @@ This static site generator also supports Markdown, using [pulldown-cmark](https://github.com/pulldown-cmark/pulldown-cmark)! -This provides an example of using markdown alongside djot documents in the same static site! See: [../index.dj](../index.dj) for the home page, and [../command_reference](../command_reference.dj) for the command reference! +This provides an example of using markdown alongside djot documents in the same static site! See: [../index.md](../index.md) for the home page, and [../command_reference](../command_reference.md) for the command reference! -Contact me [here](contact-ryanabx.dj) \ No newline at end of file +Contact me [here](contact-ryanabx.md) \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 00cd7d4..0e20229 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ use jotdown::{Container, Event}; use pulldown_cmark::{CowStr, Options}; use std::{ env, + fs::{self, read_dir}, path::{Path, PathBuf}, }; use templates::BuiltInTemplate; @@ -17,6 +18,8 @@ mod templates; mod tests; mod utils; +mod markdown; + /// Djot static site generator #[derive(Parser, Debug)] #[command(version, about, long_about = None)] @@ -40,13 +43,37 @@ struct ConsoleArgs { /// directories. #[arg(short, long)] template: Option, + /// Try the legacy method of generating a static site + #[arg(long)] + legacy: bool, } fn main() -> anyhow::Result<()> { env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("warn")).init(); log::trace!("Begin simple-ssg::main()"); let args = ConsoleArgs::parse(); - run_program(args) + if args.legacy { + run_program(args) + } else { + run_program_2(args) + } +} + +fn run_program_2(args: ConsoleArgs) -> anyhow::Result<()> { + if args.directory.is_none() + || args.file.is_some() + || args.template.is_some() + || args.output_path.is_none() + { + log::error!("Args incorrect"); + anyhow::bail!("Args incorrect"); + } + generate_site_2( + &args.directory.unwrap(), + &args.output_path.unwrap(), + args.web_prefix.as_deref(), + )?; + Ok(()) } fn run_program(args: ConsoleArgs) -> anyhow::Result<()> { @@ -112,6 +139,85 @@ pub enum FirstPassResult { }, } +fn generate_site_2( + root_dir: &Path, + output_dir: &Path, + web_prefix: Option<&str>, +) -> anyhow::Result<()> { + let root_dir = root_dir.canonicalize()?; + let _ = fs::create_dir_all(&output_dir); + let output_dir = output_dir.canonicalize()?; + + for x in WalkDir::new(&root_dir) { + let x = x?; + let x_path = x.path(); + log::info!("{:?}", x_path); + if x_path.is_dir() { + if !x_path.join("index.md").exists() { + let mut directory_index = String::new(); + if x.depth() > 0 { + // let parent_dir = x_path.parent().unwrap(); + + directory_index.push_str("[../](..)\n"); + } + directory_index.push_str(&create_directory_index(x_path)?); + log::info!("{}", &directory_index); + let html = markdown::md_to_html(&directory_index, x_path, web_prefix)?; + let result_path = + output_dir.join(x_path.join("index.html").strip_prefix(&root_dir)?); + log::info!("Result path: {:?}", &result_path); + let _ = std::fs::create_dir_all(result_path.parent().unwrap()); + std::fs::write(&result_path, html.as_bytes())?; + } + } else if x_path.is_file() { + let result_path = + output_dir.join(x_path.with_extension("html").strip_prefix(&root_dir)?); + if x_path.extension().is_some_and(|ext| ext == "md") { + let md = fs::read_to_string(x_path)?; + let html = markdown::md_to_html(&md, x_path.parent().unwrap(), web_prefix)?; + std::fs::write(&result_path, html.as_bytes())?; + } else { + std::fs::copy(x_path, &result_path)?; + } + } + } + + Ok(()) +} + +fn get_relative_url(root_path: &Path, target_path: &Path) -> String { + log::info!("{:?}.strip({:?})", target_path, root_path); + target_path + .strip_prefix(root_path) + .unwrap() + .to_string_lossy() + .to_string() +} + +fn create_directory_index(folder: &Path) -> anyhow::Result { + let mut result = String::new(); + + for x in read_dir(folder)? { + let x_path = &x?.path(); + result.push_str(&directory_string( + folder, + &x_path, + &x_path.file_name().unwrap().to_string_lossy(), + )); + result.push_str("\n"); + } + + Ok(result) +} + +fn directory_string(root_path: &Path, target_path: &Path, name: &str) -> String { + format!( + "[{}](./{})\n", + name, + get_relative_url(root_path, target_path) + ) +} + fn generate_site( target_path: &Path, output_path: &Path, diff --git a/src/markdown.rs b/src/markdown.rs new file mode 100644 index 0000000..ebc4f01 --- /dev/null +++ b/src/markdown.rs @@ -0,0 +1,71 @@ +use std::path::Path; + +use pulldown_cmark::{CowStr, Options}; + + +/// Take markdown input, and change links if necessary +pub fn md_to_html( + markdown: &str, + file_parent_dir: &Path, + web_prefix: Option<&str>, +) -> anyhow::Result { + log::info!("Markdown to html: {:?}", file_parent_dir); + let mut options = Options::empty(); + options.insert(Options::ENABLE_GFM); + let events = pulldown_cmark::Parser::new_ext(markdown, options) + .map(|event| -> anyhow::Result { + match event { + pulldown_cmark::Event::Start(pulldown_cmark::Tag::Link { + link_type, + dest_url, + title, + id, + }) => { + let inner = dest_url.to_string(); + let referenced_path = file_parent_dir.join(&inner); + if referenced_path + .extension() + .is_some_and(|ext| ext == "md") + { + let new_path = Path::new(&inner).with_extension("html"); + log::info!("Path: {:?} -> {:?}", &inner, &new_path); + if !referenced_path.exists() { + log::warn!("Path {:?} doesn't exist!", referenced_path); + Ok(pulldown_cmark::Event::Start(pulldown_cmark::Tag::Link { + link_type, + dest_url, + title, + id, + })) + } + else { + // Create destination url + let dest_url = CowStr::Boxed( + format!("{}{}", web_prefix.unwrap_or(""), new_path.to_string_lossy()) + .into_boxed_str(), + ); + Ok(pulldown_cmark::Event::Start(pulldown_cmark::Tag::Link { + link_type, + dest_url, + title, + id, + })) + } + } else { + Ok(pulldown_cmark::Event::Start(pulldown_cmark::Tag::Link { + link_type, + dest_url, + title, + id, + })) + } + } + _ => Ok(event), + } + }) + .collect::, _>>()?; + log::info!("Done"); + let mut html = String::new(); + pulldown_cmark::html::push_html(&mut html, events.iter().cloned()); + Ok(html) +} \ No newline at end of file diff --git a/src/tests.rs b/src/tests.rs index 5ba41a6..cd2d681 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -49,6 +49,7 @@ fn site_with_links() -> anyhow::Result<()> { clean: false, web_prefix: None, template: Some(crate::templates::BuiltInTemplate::ForceNone), + legacy: true }; log::trace!("Running program"); crate::run_program(args)?; @@ -103,6 +104,7 @@ fn site_warn_without_index() -> anyhow::Result<()> { web_prefix: None, template: Some(crate::templates::BuiltInTemplate::ForceNone), file: None, + legacy: true, }; crate::run_program(args)?; Ok(())