add: vibe-coded basic structure

This commit is contained in:
2025-12-17 20:01:04 -08:00
commit b2fab32d37
5 changed files with 1538 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/target

1428
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

10
Cargo.toml Normal file
View File

@@ -0,0 +1,10 @@
[package]
name = "rikidown"
version = "0.1.0"
edition = "2021"
[dependencies]
clap = { version = "4.5.4", features = ["derive"] }
git2 = "0.20.3"
markdown = "1.0.0"
rouille = "3.6.2"

18
README.md Normal file
View File

@@ -0,0 +1,18 @@
# rikidown
A Rust-based wiki with markdown.
Simply write your wiki pages in Markdown, commit to a git repo and push.
rikidown will refresh its git repo, then render your markdown pages inside of a template.
## How does it work
GET /README.md HTTP/1.1
When rikidown recieves a GET request for a markdown page, it renders it using markdown-rs.
rikidown uses rouille to start the http server, and clap to configure arguments.
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

81
src/main.rs Normal file
View File

@@ -0,0 +1,81 @@
use clap::Parser;
use git2::Repository;
use rouille::Response;
use std::env;
use std::fs;
use std::path::Path;
/// A Rust-based wiki with markdown.
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
/// The URL of the git repo to load
#[arg(long)]
git_repo: String,
/// Address to listen on, in the form of 0.0.0.0:8080
#[arg(long, default_value = "0.0.0.0:8080")]
listen: String,
}
fn render_markdown(path: &Path) -> Response {
match fs::read_to_string(path) {
Ok(md) => Response::html(markdown::to_html(&md)),
Err(e) => {
eprintln!("Error reading file {:?}: {}", path, e);
Response::text("Error reading file").with_status_code(500)
}
}
}
fn main() {
let args = Args::parse();
println!("Cloning git repo: {}", args.git_repo);
let repo_path = env::temp_dir().join("rikidown_repo");
if repo_path.exists() {
std::fs::remove_dir_all(&repo_path).expect("Failed to clear old repo");
}
match Repository::clone(&args.git_repo, &repo_path) {
Ok(_) => println!("Cloned repo into {:?}", &repo_path),
Err(e) => panic!("failed to clone: {}", e),
};
println!("Listening on: {}", args.listen);
rouille::start_server(args.listen, move |request| {
let url = request.url();
let requested_path = repo_path.join(url.trim_start_matches('/'));
// Check if it's a directory, then look for index/README.
if requested_path.is_dir() {
let index_path = requested_path.join("index.md");
if index_path.is_file() {
return render_markdown(&index_path);
}
let readme_path = requested_path.join("README.md");
if readme_path.is_file() {
return render_markdown(&readme_path);
}
}
// 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_markdown(&requested_path);
}
// For now, 404 on other file types. A real implementation might serve static files.
return Response::empty_404();
}
// Check if adding a `.md` extension makes it a file. e.g. /README -> /README.md
let mut md_path = requested_path;
md_path.set_extension("md");
if md_path.is_file() {
return render_markdown(&md_path);
}
Response::empty_404()
});
}