add: support a template.html file

This commit is contained in:
2025-12-17 22:53:23 -08:00
parent b2fab32d37
commit a01cda4566
4 changed files with 90 additions and 9 deletions

25
Cargo.lock generated
View File

@@ -631,6 +631,12 @@ version = "2.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
[[package]]
name = "memo-map"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38d1115007560874e373613744c6fba374c17688327a71c1476d1a5954cc857b"
[[package]] [[package]]
name = "mime" name = "mime"
version = "0.3.17" version = "0.3.17"
@@ -647,6 +653,17 @@ dependencies = [
"unicase", "unicase",
] ]
[[package]]
name = "minijinja"
version = "2.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12ea9ac0a51fb5112607099560fdf0f90366ab088a2a9e6e8ae176794e9806aa"
dependencies = [
"memo-map",
"self_cell",
"serde",
]
[[package]] [[package]]
name = "multipart" name = "multipart"
version = "0.18.0" version = "0.18.0"
@@ -841,7 +858,9 @@ dependencies = [
"clap", "clap",
"git2", "git2",
"markdown", "markdown",
"minijinja",
"rouille", "rouille",
"serde",
] ]
[[package]] [[package]]
@@ -899,6 +918,12 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"
[[package]]
name = "self_cell"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16c2f82143577edb4921b71ede051dac62ca3c16084e918bf7b40c96ae10eb33"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.228" version = "1.0.228"

View File

@@ -8,3 +8,5 @@ clap = { version = "4.5.4", features = ["derive"] }
git2 = "0.20.3" git2 = "0.20.3"
markdown = "1.0.0" markdown = "1.0.0"
rouille = "3.6.2" rouille = "3.6.2"
minijinja = { version = "2.1.0", features = ["loader"] }
serde = { version = "1.0.203", features = ["derive"] }

View File

@@ -16,3 +16,6 @@ The arguments supported include:
- --git-repo the URL of the git repo to load - --git-repo the URL of the git repo to load
- --listen address to listen on, in the form of 0.0.0.0:8080 - --listen address to listen on, in the form of 0.0.0.0:8080
Additionally, if there is a './template.html' file in the repo, is will be used to wrap
the generated HTML. Specifically, the 'body' block will be replaced by the markdown content.

View File

@@ -1,9 +1,12 @@
use clap::Parser; use clap::Parser;
use git2::Repository; use git2::Repository;
use minijinja::Environment;
use rouille::Response; use rouille::Response;
use serde::Serialize;
use std::env; use std::env;
use std::fs; use std::fs;
use std::path::Path; use std::path::{Path, PathBuf};
/// A Rust-based wiki with markdown. /// A Rust-based wiki with markdown.
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
@@ -18,12 +21,60 @@ struct Args {
listen: String, listen: String,
} }
fn render_markdown(path: &Path) -> Response { #[derive(Serialize)]
match fs::read_to_string(path) { struct Context {}
Ok(md) => Response::html(markdown::to_html(&md)),
fn render_page(repo_path: &PathBuf, path: &Path) -> Response {
let md = match fs::read_to_string(path) {
Ok(md) => md,
Err(e) => { Err(e) => {
eprintln!("Error reading file {:?}: {}", path, e); eprintln!("Error reading file {:?}: {}", path, e);
Response::text("Error reading file").with_status_code(500) return Response::text("Error reading file").with_status_code(500);
}
};
let body_html = markdown::to_html(&md);
let template_path = repo_path.join("template.html");
if !template_path.is_file() {
return Response::html(body_html);
}
let template_str = match fs::read_to_string(&template_path) {
Ok(s) => s,
Err(e) => {
eprintln!("Error reading template file {:?}: {}", &template_path, e);
// Fallback to no template
return Response::html(body_html);
}
};
let context = Context {};
let mut env = Environment::new();
if let Err(e) = env.add_template("template", &template_str) {
eprintln!("Error adding template: {}", e);
return Response::text("Error rendering template").with_status_code(500);
};
let content = format!(
r#"
{{% extends 'template' %}}
{{% block body %}}
{}
{{% endblock %}}
"#,
body_html
);
if let Err(e) = env.add_template("content", &content) {
eprintln!("Error adding template: {}", e);
return Response::text("Error rendering populated template").with_status_code(500);
}
let tmpl = env.get_template("content").unwrap();
match tmpl.render(context) {
Ok(rendered) => Response::html(rendered),
Err(e) => {
eprintln!("Error rendering template: {}", e);
Response::text("Error rendering template").with_status_code(500)
} }
} }
} }
@@ -52,18 +103,18 @@ fn main() {
if requested_path.is_dir() { if requested_path.is_dir() {
let index_path = requested_path.join("index.md"); let index_path = requested_path.join("index.md");
if index_path.is_file() { if index_path.is_file() {
return render_markdown(&index_path); return render_page(&repo_path, &index_path);
} }
let readme_path = requested_path.join("README.md"); let readme_path = requested_path.join("README.md");
if readme_path.is_file() { if readme_path.is_file() {
return render_markdown(&readme_path); return render_page(&repo_path, &readme_path);
} }
} }
// Check if the path as-is is a file. e.g. /README.md // Check if the path as-is is a file. e.g. /README.md
if requested_path.is_file() { if requested_path.is_file() {
if requested_path.extension().and_then(std::ffi::OsStr::to_str) == Some("md") { if requested_path.extension().and_then(std::ffi::OsStr::to_str) == Some("md") {
return render_markdown(&requested_path); return render_page(&repo_path, &requested_path);
} }
// For now, 404 on other file types. A real implementation might serve static files. // For now, 404 on other file types. A real implementation might serve static files.
return Response::empty_404(); return Response::empty_404();
@@ -73,7 +124,7 @@ fn main() {
let mut md_path = requested_path; let mut md_path = requested_path;
md_path.set_extension("md"); md_path.set_extension("md");
if md_path.is_file() { if md_path.is_file() {
return render_markdown(&md_path); return render_page(&repo_path, &md_path);
} }
Response::empty_404() Response::empty_404()