mirror of
https://github.com/sbrow/thor.git
synced 2026-08-26 11:23:32 -04:00
176 lines
4.2 KiB
Odin
176 lines
4.2 KiB
Odin
package main
|
|
|
|
import md "markdown"
|
|
|
|
import "core:fmt"
|
|
import "core:log"
|
|
import "core:os"
|
|
import "core:strings"
|
|
|
|
// Fields with underscores should never be set by the user.
|
|
Page :: struct {
|
|
section: string,
|
|
slug: string,
|
|
layout: string,
|
|
permalink: string,
|
|
url: string,
|
|
title: string,
|
|
description: string,
|
|
date: string,
|
|
lastmod: string,
|
|
menu: string,
|
|
body_html: string,
|
|
og: Open_Graph,
|
|
draft: bool,
|
|
is_starred: bool,
|
|
_is_index: bool `private`,
|
|
}
|
|
|
|
// site_load_content reads the content directory and populates site.pages.
|
|
// Drafts are excluded unless .Drafts is enabled.
|
|
site_load_content :: proc(site: ^Site) {
|
|
site.pages = make([dynamic]Page, 0, 8, site_allocator(site))
|
|
scan_content(site, site.content_dir, "")
|
|
|
|
for &page in site.pages {
|
|
page.url = fmt.tprintf("%s%s", site.base_url, page.permalink)
|
|
}
|
|
}
|
|
|
|
// scan_content walks the content directory. At the root level (section=""),
|
|
// directories are treated as sections. Within a section, directories are
|
|
// treated as leaf bundles (directory with an index file).
|
|
scan_content :: proc(site: ^Site, dir: string, section: string) {
|
|
entries, err := os.read_all_directory_by_path(dir, context.allocator)
|
|
if err != nil {
|
|
log.warnf("cannot read %s: %v", dir, err)
|
|
return
|
|
}
|
|
defer os.file_info_slice_delete(entries, context.allocator)
|
|
|
|
for entry in entries {
|
|
switch entry.type {
|
|
case .Regular:
|
|
if !is_content_file(entry.name) {
|
|
continue
|
|
}
|
|
|
|
filename := strip_extension(entry.name)
|
|
is_idx := filename == "index"
|
|
slug := is_idx ? "" : filename
|
|
|
|
page, ok := load_page(entry.fullpath, section, slug, is_idx, site.markdown_extensions)
|
|
if ok && (!page.draft || .Drafts in site.features) {
|
|
append(&site.pages, page)
|
|
}
|
|
|
|
case .Directory:
|
|
if section == "" {
|
|
scan_content(site, entry.fullpath, entry.name)
|
|
} else {
|
|
index_path := fmt.tprintf("%s/index.html", entry.fullpath)
|
|
if !os.exists(index_path) {
|
|
index_path = fmt.tprintf("%s/index.md", entry.fullpath)
|
|
}
|
|
if os.exists(index_path) {
|
|
page, ok := load_page(
|
|
index_path,
|
|
section,
|
|
entry.name,
|
|
false,
|
|
site.markdown_extensions,
|
|
)
|
|
if ok && (!page.draft || .Drafts in site.features) {
|
|
append(&site.pages, page)
|
|
}
|
|
}
|
|
}
|
|
case .Undetermined, .Symlink, .Named_Pipe, .Socket, .Block_Device, .Character_Device:
|
|
}
|
|
}
|
|
}
|
|
|
|
infer_layout :: proc(section: string, is_index: bool) -> string {
|
|
if section == "" && is_index {
|
|
return "home"
|
|
}
|
|
if is_index {
|
|
return fmt.tprintf("%s_index", section)
|
|
}
|
|
if section != "" {
|
|
if len(section) > 1 && section[len(section) - 1] == 's' {
|
|
return section[:len(section) - 1]
|
|
}
|
|
return section
|
|
}
|
|
return "page"
|
|
}
|
|
|
|
load_page :: proc(
|
|
file_path: string,
|
|
section: string,
|
|
slug: string,
|
|
is_index: bool,
|
|
ext: bit_set[md.Extension],
|
|
) -> (
|
|
page: Page,
|
|
ok: bool,
|
|
) {
|
|
data, err := os.read_entire_file_from_path(file_path, context.allocator)
|
|
if err != nil {
|
|
log.warnf("cannot read %s: %v", file_path, err)
|
|
return
|
|
}
|
|
|
|
content := string(data)
|
|
fm, body, parsed := parse_frontmatter(content)
|
|
if !parsed {
|
|
body = strings.trim_left(content, " \t\r\n")
|
|
}
|
|
|
|
page.section = section
|
|
page.slug = slug
|
|
page._is_index = is_index
|
|
page.title = fm.title
|
|
page.description = fm.description
|
|
page.date = fm.date
|
|
page.lastmod = fm.lastmod
|
|
page.draft = fm.draft
|
|
page.is_starred = fm.isStarred
|
|
page.menu = fm.menu
|
|
page.layout = fm.layout if fm.layout != "" else infer_layout(section, is_index)
|
|
page.og = fm.og
|
|
|
|
if strings.has_suffix(file_path, ".html") {
|
|
page.body_html = strings.clone(body)
|
|
} else {
|
|
page.body_html = md.process(body, ext, file_path)
|
|
}
|
|
|
|
if section == "" && is_index {
|
|
page.permalink = "/"
|
|
} else if is_index {
|
|
page.permalink = fmt.aprintf("/%s/", section)
|
|
} else if section == "" {
|
|
page.permalink = fmt.aprintf("/%s/", slug)
|
|
} else {
|
|
page.permalink = fmt.aprintf("/%s/%s/", section, slug)
|
|
}
|
|
|
|
ok = true
|
|
return
|
|
}
|
|
|
|
is_content_file :: proc(name: string) -> bool {
|
|
return strings.has_suffix(name, ".md") || strings.has_suffix(name, ".html")
|
|
}
|
|
|
|
strip_extension :: proc(name: string) -> string {
|
|
dot := strings.last_index(name, ".")
|
|
if dot < 0 {
|
|
return name
|
|
}
|
|
return name[:dot]
|
|
}
|
|
|