From 91606a22231b044071ec43ba57a93fe7803fb817 Mon Sep 17 00:00:00 2001 From: Spencer Brower <6729162+sbrow@users.noreply.github.com> Date: Tue, 14 Jul 2026 12:48:38 -0400 Subject: [PATCH] feat: Added `-watch` flag. --- TODOS.md | 4 ++++ content.odin | 12 +++++++++--- main.odin | 20 +++++++++++++++----- site.odin | 4 ++++ 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/TODOS.md b/TODOS.md index 4683713..465843f 100644 --- a/TODOS.md +++ b/TODOS.md @@ -27,6 +27,10 @@ - [ ] `
` blocks need to set background to theme background,
   regardless of prefers-dark. (or use a different theme)
 - [ ] `-watch` flag
+  - [x] basic poll loop
+  - [ ] filesystem poll loop
+  - [ ] event based
+- [ ] Free cmark HTML output (`body_html`) — cmark allocates via C malloc, not the arena, so it leaks per iteration in watch mode
 - [ ] commands
 - [ ] Review every file in thor
   - [ ] Review alerts.odin
diff --git a/content.odin b/content.odin
index 32b5b3a..d9479d3 100644
--- a/content.odin
+++ b/content.odin
@@ -32,8 +32,14 @@ Page :: struct {
 // (or all pages if include_drafts is true).
 //
 // TODO: What is the lifetime of pages?
-walk_content :: proc(content_path: string, include_drafts: bool, sectionate: bool) -> []Page {
-	pages: [dynamic]Page
+walk_content :: proc(site: ^Site) -> []Page {
+	content_path := site.content_dir
+	include_drafts := site.drafts
+	sectionate := site.sectionate
+
+	allocator := site_allocator(site)
+
+	pages := make([dynamic]Page, allocator)
 
 	collect_home(&pages, content_path, sectionate)
 	collect_standalone(&pages, content_path, sectionate)
@@ -46,7 +52,7 @@ walk_content :: proc(content_path: string, include_drafts: bool, sectionate: boo
 	if include_drafts {
 		return pages[:]
 	} else {
-		filtered: [dynamic]Page
+		filtered := make([dynamic]Page, allocator)
 		for &page in pages {
 			if !page.draft {
 				append(&filtered, page)
diff --git a/main.odin b/main.odin
index 21193ee..f18f080 100644
--- a/main.odin
+++ b/main.odin
@@ -2,18 +2,28 @@ package main
 
 import "core:log"
 import "core:os"
+import "core:time"
 
 main :: proc() {
 	console_logger := log.create_console_logger()
 	context.logger = console_logger
 	defer log.destroy_console_logger(console_logger)
 
-	site: Site
-	init_site(&site, os.args)
-	defer destroy_site(&site)
+	for {
+		defer free_all(context.temp_allocator)
+		site: Site
+		init_site(&site, os.args)
+		defer destroy_site(&site)
+		// TODO: Make it so this isn't necessary
+		context.allocator = site_allocator(&site)
 
-	pages := walk_content(site.content_dir, site.drafts, site.sectionate)
+		pages := walk_content(&site)
+		render_site(pages, site)
 
-	render_site(pages, site)
+		if !site.watch {
+			break
+		}
+		time.sleep(5 * time.Second)
+	}
 }
 
diff --git a/site.odin b/site.odin
index 9f11ce9..0aedefc 100644
--- a/site.odin
+++ b/site.odin
@@ -21,6 +21,7 @@ Site :: struct {
 	params:      json.Value,
 	sectionate:  bool,
 	drafts:      bool `args:"name=drafts"`,
+	watch:       bool
 }
 
 init_site :: proc(site: ^Site, args: []string) {
@@ -98,6 +99,9 @@ site_merge :: proc(config: ^Site, flags: Site) {
 	if flags.drafts {
 		config.drafts = true
 	}
+	if flags.watch {
+		config.watch = true
+	}
 	config.config_path = flags.config_path
 }