refactor: Moved markdown code to a separate packge.

This commit is contained in:
Spencer Brower
2026-07-17 14:13:25 -04:00
parent 618fabf0e4
commit 085811b312
10 changed files with 112 additions and 100 deletions
+12 -7
View File
@@ -46,16 +46,21 @@
- [ ] Import/export packages. Hugo, jekyll, WordPress, etc. - [ ] Import/export packages. Hugo, jekyll, WordPress, etc.
- [ ] Review every file in thor - [ ] Review every file in thor
- [ ] Review assets.odin - [ ] Review assets.odin
- [ ] Review alerts.odin
- [ ] Review content.odin - [ ] Review content.odin
- [ ] Review emoji.odin - [ ] Review defaults.odin
- [ ] Review feed.odin - [ ] Review feed.odin
- [ ] Review footnotes.odin
- [ ] Review frontmatter.odin - [ ] Review frontmatter.odin
- [ ] Review highlight.odin
- [ ] Review main.odin - [ ] Review main.odin
- [ ] Review minifiy.odin - [ ] Review minify.odin
- [ ] Review render.odin - [ ] Review `markdown/`
- [ ] Review alerts.odin
- [ ] Review emoji.odin
- [ ] Review footnotes.odin
- [ ] Review footnotes_test.odin
- [ ] Review highlight.odin
- [ ] Review markdown.odin
- [ ] Review sectionate.odin - [ ] Review sectionate.odin
- [ ] Review render.odin
- [x] Review site.odin - [x] Review site.odin
- [ ] Review tree_sitter.odin - [ ] Review treesitter/treesitter.odin
- [ ] Review vfs.odin
+3 -25
View File
@@ -1,6 +1,6 @@
package main package main
import cm "vendor:commonmark" import md "markdown"
import "core:fmt" import "core:fmt"
import "core:log" import "core:log"
@@ -101,7 +101,7 @@ load_page :: proc(
section: string, section: string,
slug: string, slug: string,
is_index: bool, is_index: bool,
ext: bit_set[Markdown_Extension], ext: bit_set[md.Extension],
) -> ( ) -> (
page: Page, page: Page,
ok: bool, ok: bool,
@@ -132,29 +132,7 @@ load_page :: proc(
if strings.has_suffix(file_path, ".html") { if strings.has_suffix(file_path, ".html") {
page.body_html = strings.clone(body) page.body_html = strings.clone(body)
} else { } else {
sn_defs := make(map[string]string) page.body_html = md.process(body, ext, file_path)
mn_defs := make(map[string]string)
clean_body := body
if .Sidenotes in ext {
clean_body, sn_defs, mn_defs = strip_definitions(body)
}
html := cm.markdown_to_html_from_string(clean_body, {.Unsafe})
if .Emoji in ext {
html = expand_emoji(html)
}
if .Sidenotes in ext {
html = inject_notes(html, sn_defs, mn_defs)
}
if .Alerts in ext {
html = inject_alerts(html)
}
if .Highlight in ext {
html = highlight_code(html, file_path)
}
if .Sections in ext {
html = wrap_sections(html)
}
page.body_html = html
} }
if section == "" && is_index { if section == "" && is_index {
+1 -1
View File
@@ -1,5 +1,5 @@
#+feature dynamic-literals #+feature dynamic-literals
package main package markdown
import "core:fmt" import "core:fmt"
import "core:strings" import "core:strings"
+1 -1
View File
@@ -1,5 +1,5 @@
#+feature dynamic-literals #+feature dynamic-literals
package main package markdown
import "core:strings" import "core:strings"
+1 -1
View File
@@ -1,4 +1,4 @@
package main package markdown
import cm "vendor:commonmark" import cm "vendor:commonmark"
@@ -1,6 +1,6 @@
#+feature dynamic-literals #+feature dynamic-literals
#+test #+test
package main package markdown
import "core:strings" import "core:strings"
import "core:testing" import "core:testing"
+2 -2
View File
@@ -1,6 +1,6 @@
package main package markdown
import ts "treesitter" import ts "../treesitter"
import "core:fmt" import "core:fmt"
import "core:log" import "core:log"
+83
View File
@@ -0,0 +1,83 @@
package markdown
import cm "vendor:commonmark"
import "core:encoding/json"
import "core:strings"
Extension :: enum {
Emoji,
Sidenotes,
Alerts,
Highlight,
Sections,
}
DEFAULT_EXTENSIONS :: bit_set[Extension]{.Emoji, .Sidenotes, .Alerts}
process :: proc(body: string, ext: bit_set[Extension], file_path: string) -> string {
side_notes := make(map[string]string)
margin_notes := make(map[string]string)
clean_body := body
if .Sidenotes in ext {
clean_body, side_notes, margin_notes = strip_definitions(body)
}
html := cm.markdown_to_html_from_string(clean_body, {.Unsafe})
if .Emoji in ext {
html = expand_emoji(html)
}
if .Sidenotes in ext {
html = inject_notes(html, side_notes, margin_notes)
}
if .Alerts in ext {
html = inject_alerts(html)
}
if .Highlight in ext {
html = highlight_code(html, file_path)
}
if .Sections in ext {
html = wrap_sections(html)
}
return html
}
// Convert a ',' separated list of case-insensitive extension names to a bit set.
parse_extension_list :: proc(s: string) -> (result: bit_set[Extension]) {
for part in strings.split(s, ",", allocator = context.temp_allocator) {
name := strings.to_lower(strings.trim_space(part), allocator = context.temp_allocator)
switch name {
case "emoji":
result += {.Emoji}
case "sidenotes":
result += {.Sidenotes}
case "alerts":
result += {.Alerts}
case "highlight":
result += {.Highlight}
case "sections":
result += {.Sections}
}
}
return result
}
// Given a map[Extension]bool, apply it to ext.
apply_extension_config :: proc(ext: ^bit_set[Extension], config: json.Object) {
for name, val in config {
// TODO: Silently discards invalid values.
enabled := val.(json.Boolean) or_continue
switch name {
case "emoji":
if enabled {ext^ += {.Emoji}} else {ext^ -= {.Emoji}}
case "sidenotes":
if enabled {ext^ += {.Sidenotes}} else {ext^ -= {.Sidenotes}}
case "alerts":
if enabled {ext^ += {.Alerts}} else {ext^ -= {.Alerts}}
case "highlight":
if enabled {ext^ += {.Highlight}} else {ext^ -= {.Highlight}}
case "sections":
if enabled {ext^ += {.Sections}} else {ext^ -= {.Sections}}
}
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
package main package markdown
import "core:strings" import "core:strings"
+7 -61
View File
@@ -8,6 +8,8 @@ import "core:mem"
import "core:os" import "core:os"
import "core:strings" import "core:strings"
import md "markdown"
// Site is the primary workhorse. // Site is the primary workhorse.
Site :: struct { Site :: struct {
@@ -26,7 +28,7 @@ Site :: struct {
layouts_dir: string, layouts_dir: string,
params: json.Object, params: json.Object,
features: bit_set[Feature], features: bit_set[Feature],
markdown_extensions: bit_set[Markdown_Extension], markdown_extensions: bit_set[md.Extension],
} }
Feature :: enum { Feature :: enum {
@@ -35,22 +37,6 @@ Feature :: enum {
Watch, Watch,
} }
Markdown_Extension :: enum {
Emoji,
Sidenotes,
Alerts,
Highlight,
Sections,
}
DEFAULT_MARKDOWN_EXTENSIONS :: bit_set[Markdown_Extension] {
.Emoji,
.Sidenotes,
.Alerts,
// .Highlight,
// .Sections,
}
// Configuration loaded from `thor.json`. Gets folded in to Site before // Configuration loaded from `thor.json`. Gets folded in to Site before
// Flags // Flags
Config_File :: struct { Config_File :: struct {
@@ -89,7 +75,7 @@ init_site :: proc(site: ^Site, args: []string) {
// Set defaults // Set defaults
site.base_url = "http://localhost:8080" site.base_url = "http://localhost:8080"
site.markdown_extensions = DEFAULT_MARKDOWN_EXTENSIONS site.markdown_extensions = md.DEFAULT_EXTENSIONS
_flags: Flags _flags: Flags
flags.parse_or_exit(&_flags, args, .Odin, alloc) flags.parse_or_exit(&_flags, args, .Odin, alloc)
@@ -163,7 +149,7 @@ site_apply_config :: proc(site: ^Site, config: Config_File, config_dir: string)
// Apply markdown extensions from config // Apply markdown extensions from config
if ext_obj, ok := config.markdown_extensions.(json.Object); ok { if ext_obj, ok := config.markdown_extensions.(json.Object); ok {
apply_extension_config(&site.markdown_extensions, ext_obj) md.apply_extension_config(&site.markdown_extensions, ext_obj)
} }
if modules_arr, ok := config.modules.(json.Array); ok { if modules_arr, ok := config.modules.(json.Array); ok {
@@ -193,48 +179,8 @@ site_apply_cli_flags :: proc(site: ^Site, flags: Flags) {
if flags.watch {site.features += {.Watch}} if flags.watch {site.features += {.Watch}}
if flags.minify {site.features += {.Minify}} if flags.minify {site.features += {.Minify}}
site.markdown_extensions += parse_extension_list(flags.md_enable) site.markdown_extensions += md.parse_extension_list(flags.md_enable)
site.markdown_extensions -= parse_extension_list(flags.md_disable) site.markdown_extensions -= md.parse_extension_list(flags.md_disable)
}
parse_extension_list :: proc(s: string) -> bit_set[Markdown_Extension] {
result: bit_set[Markdown_Extension]
if s == "" do return result
for part in strings.split(s, ",", allocator = context.temp_allocator) {
name := strings.to_lower(strings.trim_space(part), allocator = context.temp_allocator)
switch name {
case "emoji":
result += {.Emoji}
case "sidenotes":
result += {.Sidenotes}
case "alerts":
result += {.Alerts}
case "highlight":
result += {.Highlight}
case "sections":
result += {.Sections}
}
}
return result
}
apply_extension_config :: proc(ext: ^bit_set[Markdown_Extension], config: json.Object) {
for name, val in config {
enabled, is_bool := val.(json.Boolean)
if !is_bool do continue
switch name {
case "emoji":
if enabled {ext^ += {.Emoji}} else {ext^ -= {.Emoji}}
case "sidenotes":
if enabled {ext^ += {.Sidenotes}} else {ext^ -= {.Sidenotes}}
case "alerts":
if enabled {ext^ += {.Alerts}} else {ext^ -= {.Alerts}}
case "highlight":
if enabled {ext^ += {.Highlight}} else {ext^ -= {.Highlight}}
case "sections":
if enabled {ext^ += {.Sections}} else {ext^ -= {.Sections}}
}
}
} }
site_allocator :: proc(site: ^Site) -> mem.Allocator { site_allocator :: proc(site: ^Site) -> mem.Allocator {