add: basic obsidian mode

This commit is contained in:
2025-12-17 23:36:41 -08:00
parent a01cda4566
commit 379ac5869d
4 changed files with 73 additions and 5 deletions

39
Cargo.lock generated
View File

@@ -8,6 +8,15 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
[[package]]
name = "aho-corasick"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
dependencies = [
"memchr",
]
[[package]]
name = "alloc-no-stdlib"
version = "2.0.4"
@@ -851,6 +860,35 @@ dependencies = [
"bitflags",
]
[[package]]
name = "regex"
version = "1.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
[[package]]
name = "rikidown"
version = "0.1.0"
@@ -859,6 +897,7 @@ dependencies = [
"git2",
"markdown",
"minijinja",
"regex",
"rouille",
"serde",
]

View File

@@ -10,3 +10,4 @@ markdown = "1.0.0"
rouille = "3.6.2"
minijinja = { version = "2.1.0", features = ["loader"] }
serde = { version = "1.0.203", features = ["derive"] }
regex = "1"

View File

@@ -16,6 +16,17 @@ The arguments supported include:
- --git-repo the URL of the git repo to load
- --listen address to listen on, in the form of 0.0.0.0:8080
- --obsidian-mode pre-processes markdown files to make them more standard compliant
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.
## Obsidian mode
Intended to create compatibility with Obsidian, because it has a fancy UI.
Specifically, this replaces `[[thing]]` with `[thing](thing.md)`
None of the other options in https://help.obsidian.md/obsidian-flavored-markdown are included.
## Future work
Replace the Obisdian markdown with https://crates.io/crates/obsidian-export.

View File

@@ -1,6 +1,7 @@
use clap::Parser;
use git2::Repository;
use minijinja::Environment;
use regex::Regex;
use rouille::Response;
use serde::Serialize;
@@ -19,12 +20,21 @@ struct Args {
/// Address to listen on, in the form of 0.0.0.0:8080
#[arg(long, default_value = "0.0.0.0:8080")]
listen: String,
/// pre-processes markdown files to make them more standard compliant
#[arg(long)]
obsidian_mode: bool,
}
#[derive(Serialize)]
struct Context {}
fn render_page(repo_path: &PathBuf, path: &Path) -> Response {
fn preprocess_obsidian(md: &str) -> String {
let re = Regex::new(r"\[\[(.*?)\]\]").unwrap();
re.replace_all(md, "[$1]($1.md)").to_string()
}
fn render_page(repo_path: &PathBuf, path: &Path, obsidian_mode: bool) -> Response {
let md = match fs::read_to_string(path) {
Ok(md) => md,
Err(e) => {
@@ -33,6 +43,12 @@ fn render_page(repo_path: &PathBuf, path: &Path) -> Response {
}
};
let md = if obsidian_mode {
preprocess_obsidian(&md)
} else {
md
};
let body_html = markdown::to_html(&md);
let template_path = repo_path.join("template.html");
@@ -95,6 +111,7 @@ fn main() {
println!("Listening on: {}", args.listen);
let obsidian_mode = args.obsidian_mode;
rouille::start_server(args.listen, move |request| {
let url = request.url();
let requested_path = repo_path.join(url.trim_start_matches('/'));
@@ -103,18 +120,18 @@ fn main() {
if requested_path.is_dir() {
let index_path = requested_path.join("index.md");
if index_path.is_file() {
return render_page(&repo_path, &index_path);
return render_page(&repo_path, &index_path, obsidian_mode);
}
let readme_path = requested_path.join("README.md");
if readme_path.is_file() {
return render_page(&repo_path, &readme_path);
return render_page(&repo_path, &readme_path, obsidian_mode);
}
}
// Check if the path as-is is a file. e.g. /README.md
if requested_path.is_file() {
if requested_path.extension().and_then(std::ffi::OsStr::to_str) == Some("md") {
return render_page(&repo_path, &requested_path);
return render_page(&repo_path, &requested_path, obsidian_mode);
}
// For now, 404 on other file types. A real implementation might serve static files.
return Response::empty_404();
@@ -124,7 +141,7 @@ fn main() {
let mut md_path = requested_path;
md_path.set_extension("md");
if md_path.is_file() {
return render_page(&repo_path, &md_path);
return render_page(&repo_path, &md_path, obsidian_mode);
}
Response::empty_404()