chore: Updated AGENTS.md

This commit is contained in:
Spencer Brower
2026-07-16 17:25:19 -04:00
parent f70205876f
commit a4b16e1b0a
2 changed files with 38 additions and 19 deletions
+37 -18
View File
@@ -17,7 +17,7 @@ public/ ← build output (generated)
| File | Responsibility |
|---|---|
| `main.odin` | Entry point. Sets `context.logger`, calls `init_site`, `walk_content`, `render_site`. Optional Spall profiling via `SPALL` config flag. |
| `site.odin` | `Flags` (parsed config), `Site` (runtime state + arena), `Feature` bit_set enum, `init_site`, `load_site_config`, `merge_flags`, `site_apply_flags`, `find_config` (walks up dir tree for `thor.json`) |
| `site.odin` | `Flags` (CLI args), `Config_File` (from `thor.json`), `Site` (runtime state + arena), `Feature` + `Markdown_Extension` bit_set enums, `DEFAULT_MARKDOWN_EXTENSIONS`, 5-step `init_site` (defaults → flags → config → apply config → apply flags), `load_config_file`, `apply_config`, `apply_cli_flags`, `parse_extension_list`, `find_config` |
| `frontmatter.odin` | JSON frontmatter parser (`{ }` delimited) |
| `content.odin` | `Page` struct, content walker, page loader, cmark integration, full markdown pipeline, `copy_assets_dir` (recursive copy with CSS minification) |
| `footnotes.odin` | Note definition stripping (pre-cmark) + sidenote/marginnote injection (post-cmark) |
@@ -36,10 +36,16 @@ Icon SVGs live as HTML partials in `layouts/partials/icons/` (home, github, rss,
### Data flow
```
thor.json → find_config → init_site → Flags → merge_flags → site_apply_flags → Site (config + Dynamic_Arena + features: bit_set)
thor.json → find_config → init_site:
1. set defaults (base_url, DEFAULT_MARKDOWN_EXTENSIONS)
2. parse CLI flags (Flags struct)
3. load config file (Config_File from thor.json)
4. apply_config — non-empty config fields override defaults
5. apply_cli_flags — flags override config, -ext/-no-ext adjust extensions
→ Site (config + Dynamic_Arena + features: bit_set + markdown_extensions: bit_set)
content/ → walk_content → []Page (with body_html from pipeline)
layouts/*.html → parse() → mustache.Template (parsed once)
render_site → mustache.render(Page_Data, partials) → optional minify_html → public/
@@ -47,12 +53,19 @@ render_site → mustache.render(Page_Data, partials) → optional minify_html
### Config system
Config is split into `Flags` (parsed from CLI args + JSON) and `Site` (runtime state):
Config is split into three structs with a clear 5-step initialization flow:
- **`Flags`** — pure parsed config struct. CLI args via `core:flags`, JSON via `json.unmarshal_string`.
- **`Site`** — runtime state: arena, resolved config values, `features: bit_set[Feature]`.
- **`Feature` enum** — `Sections`, `Drafts`, `Minify`, `Watch`. Checked with `.Minify in site.features`.
- **`find_config`** — walks up from CWD looking for `thor.json`. Falls back to `./thor.json`.
- **`Flags`** — CLI args only. Parsed by `core:flags`. Includes path overrides, build-mode toggles, and `-ext`/`-no-ext` for markdown extension overrides.
- **`Config_File`** — parsed from `thor.json` via `json.unmarshal_string`. Holds title, paths, `markdown_extensions` (JSON), `params` (JSON).
- **`Site`** — runtime state: arena, resolved config values, `features: bit_set[Feature]`, `markdown_extensions: bit_set[Markdown_Extension]`.
**`Feature` enum** — build-mode toggles: `Drafts`, `Minify`, `Watch`. Checked with `.Minify in site.features`.
**`Markdown_Extension` enum** — content pipeline toggles: `Emoji`, `Sidenotes`, `Alerts`, `Highlight`, `Sections`. Default is `DEFAULT_MARKDOWN_EXTENSIONS` (currently `.Emoji, .Sidenotes, .Alerts`). Configurable via:
- `thor.json`: `"markdown_extensions": { "emoji": true, "highlight": false, ... }`
- CLI: `-ext:highlight,sections` (enable) / `-no-ext:emoji` (disable). Comma-separated, case-insensitive.
**`find_config`** — walks up from CWD looking for `thor.json`. Falls back to `./thor.json`.
Config precedence: `CLI flags > thor.json values > hardcoded defaults`.
@@ -61,7 +74,13 @@ Config precedence: `CLI flags > thor.json values > hardcoded defaults`.
"title": "...",
"base_url": "...",
"author": "...",
"sectionate": true,
"markdown_extensions": {
"emoji": true,
"sidenotes": true,
"alerts": true,
"highlight": true,
"sections": true
},
"params": {
"social": [
{ "name": "github", "url": "...", "icon": "icons/github" }
@@ -86,7 +105,7 @@ Templates use Mustache with template inheritance (`{{<base}}` / `{{$block}}`):
{{/base}}
```
Data is passed as **typed structs** (not `map[string]any`). Mustache resolves struct fields via Odin reflection, including `using`-embedded fields:
Data is passed as **typed structs** (not `map[string]any`). Mustache resolves struct fields via Odin reflection, including `using`-embedded fields. Date presence is checked via string truthiness (`{{#date_iso}}`) — no separate `has_date` bool needed.
```odin
Base_Data :: struct {
@@ -108,16 +127,16 @@ Page_Data :: struct {
```
raw markdown
→ strip_definitions (pre-cmark: extract [^id]: definitions)
→ strip_definitions (pre-cmark: extract [^id]: definitions — only if .Sidenotes enabled)
→ cmark markdown_to_html (Unsafe mode for HTML passthrough)
→ expand_emoji (post-cmark: :shortcode: → unicode, avoids cmark escape issues)
→ inject_notes (post-cmark: [^id] → <label><input><span> markup)
→ inject_alerts (post-cmark: [!TYPE] blockquotes → styled alerts)
→ highlight_code (post-cmark: tree-sitter per code block, with error reporting)
→ wrap_sections (post-cmark: if .Sections in features, wraps content in <section> at <h2>)
→ expand_emoji (post-cmark: :shortcode: → unicode — only if .Emoji enabled)
→ inject_notes (post-cmark: [^id] → <label><input><span> markup — only if .Sidenotes enabled)
→ inject_alerts (post-cmark: [!TYPE] blockquotes → styled alerts — only if .Alerts enabled)
→ highlight_code (post-cmark: tree-sitter per code block — only if .Highlight enabled)
→ wrap_sections (post-cmark: wraps content in <section> at <h2> — only if .Sections enabled)
```
`.html` content files skip cmark entirely — body is used as-is.
Each step is gated by `bit_set[Markdown_Extension]`. All `.html` content files skip the pipeline entirely — body is used as-is.
### Syntax highlighting
+1 -1
View File
@@ -152,7 +152,7 @@ site_apply_config :: proc(site: ^Site, config: Config_File, config_dir: string)
site.layouts_dir =
config.layouts_dir if config.layouts_dir != "" else fmt.tprintf("%s/layouts", config_dir)
if params, ok := config.markdown_extensions.(json.Object); ok {
if params, ok := config.params.(json.Object); ok {
site.params = params
}