Compare commits

..
27 Commits
Author SHA1 Message Date
simonkellet df14c0ddcf just use the file instead of symlink, better for distribution of code 2026-08-23 14:07:55 +01:00
simonkellet 21b6dd0b63 now using temp_allocator for string stuff in gen. blog index for mem safety 2026-08-23 14:01:16 +01:00
Simon Kellet 200d3d376a added cond. to add hljs to blogs only 2026-08-23 13:41:01 +01:00
Simon Kellet c0b195ffd0 update png 2026-08-23 13:36:34 +01:00
Simon Kellet 18a1d2ae0b forgor builder_destroy, whoops 2026-08-21 16:59:56 +01:00
Simon Kellet 28bb1838f5 reverse order for index 2026-08-21 16:34:40 +01:00
Simon Kellet 81871b7d89 symlink fleg 2026-08-21 16:34:19 +01:00
Simon Kellet 13ba56785f update readme 2026-07-24 09:46:10 +01:00
Simon Kellet 28c9422dd3 added homemade flag parser yupie 2026-07-24 09:43:52 +01:00
Simon Kellet 1f44124319 added hljs to pages for code highlights. pending solution 2026-07-24 09:43:28 +01:00
Simon Kellet 10d383e4c2 fixed formatting 2026-07-06 20:47:45 +01:00
simonkellet 178815cefe Delete cm.sublime-workspace 2026-06-30 12:51:53 +00:00
Simon Kellet aecd7ae3a0 remove workspace too 2026-06-30 13:50:18 +01:00
Simon Kellet edf62a466f changes 2026-06-30 13:48:43 +01:00
Simon Kellet f96b506abf added fmt and defer 2026-06-22 23:46:06 +01:00
Simon Kellet 437fe17db0 defer on the last page to get accurate timings 2026-06-17 21:06:58 +01:00
Simon Kellet 4d0f58e5b0 formatting 2026-06-17 21:06:47 +01:00
Simon Kellet b49cb5ad27 added fmt file 2026-06-17 21:06:41 +01:00
Simon Kellet 44cecf02e8 added +vet explicit-allocators to all files 2026-03-25 13:54:37 +00:00
Simon Kellet 0fc4e6180b pass arena to generate_blog_md_file proc 2026-03-16 16:41:46 +00:00
Simon Kellet ff7c60bded ignore WIP articles 2026-03-16 16:41:10 +00:00
Simon Kellet d83fc3f75a added blog index generator 2026-03-16 13:11:56 +00:00
Simon Kellet 5c05bedb71 added func to write prefix 2026-03-16 13:11:35 +00:00
Simon Kellet 440562df8b newline 2026-03-12 13:23:37 +00:00
Simon Kellet 02ff07c528 site 2026-03-12 13:23:05 +00:00
Simon Kellet 72f7fbf25c readmeeeeeeee 2026-03-12 13:22:13 +00:00
Simon Kellet 71ff727ee2 readme done (finally lol) 2026-03-12 13:18:56 +00:00
7 changed files with 501 additions and 60 deletions
+3
View File
@@ -2,3 +2,6 @@ cm
.DS_Store .DS_Store
test/ test/
website_update.sh website_update.sh
site.png
*.sublime-project
*.sublime-workspace
+39
View File
@@ -0,0 +1,39 @@
# Site Generator written in Odin
![Site](./site.png)
A simple Odin program that is used to generate my site!
Note: This is incredibly specific! If you want to use this for your own sites, I think it would be easier to write
your own! 😅
## Usage
### Build
```bash
odin build .
```
### Usage
```bash
> ./cm -h
Usage:
Flag format for this program:
-<flag>=<value>
-dir:
input directory of .MD files (default: ) (required)
-out:
output directory (html files) (default: ) (required)
```
### Todo
* Indexing Articles and Blogs
* Page tagging
* Animated ASCII (Can this be done with minimal JS?)
### Credits
* Odin
* cmark
+297
View File
@@ -0,0 +1,297 @@
/*
zlib License
(C) 2026 Simon Kellet
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#+vet explicit-allocators
package fleg
import "base:runtime"
import "core:fmt"
import "core:os"
import "core:strconv"
import "core:strings"
FORCE_HELP_ON_EMPTY_ARGS := false
FLAG_START_CHAR := "-"
FLAG_SEP_CHAR := "="
@(private)
Flag_Value_Ptr :: union {
^bool,
^int,
^i32,
^i64,
^string,
^f32,
^f64,
}
@(private)
Flag :: struct {
name: string,
value: Flag_Value_Ptr,
usage: string,
parsed: bool, // sck: flag to check if it has been parsed
required: bool, // sck: required flag
}
// Global dynamic array of Flags
@(private)
all_flags: [dynamic]Flag
// runtime allocator for the flags
@(private)
flag_allocator: runtime.Allocator
// sck: Used to create a customer allocator
init_custom_allocator :: proc(allocator: runtime.Allocator) {
destroy() // sck: make sure to destory the old allocations
flag_allocator = allocator
all_flags = make([dynamic]Flag, flag_allocator)
}
destroy :: proc() {
delete(all_flags)
all_flags = {}
}
@(private)
print_flags :: proc() {
for f in all_flags {
fmt.printfln("%s: %s (required=%v)", f.name, f.usage, f.required)
}
}
@(private)
print_flag_format :: proc(){
fmt.printfln("Want %s<flag>%s<value>\n", FLAG_START_CHAR, FLAG_SEP_CHAR)
}
@(private)
print_usage :: proc() {
fmt.println("\tUsage: ")
fmt.println("\n\tFlag format for this program:")
fmt.printfln("\t%s<flag>%s<value>\n", FLAG_START_CHAR, FLAG_SEP_CHAR)
for f in all_flags {
req_msg: string
if f.required { req_msg = " (required)"}
switch v in f.value {
case ^bool:
fmt.printfln("\t%s%s:\n\t\t%s (default: %v)%s\n", FLAG_START_CHAR, f.name, f.usage, v^, req_msg)
case ^int:
fmt.printfln("\t%s%s:\n\t\t%s (default: %d)%s\n", FLAG_START_CHAR, f.name, f.usage, v^, req_msg)
case ^i32:
fmt.printfln("\t%s%s:\n\t\t%s (default: %d)%s\n", FLAG_START_CHAR, f.name, f.usage, v^, req_msg)
case ^i64:
fmt.printfln("\t%s%s:\n\t\t%s (default: %d)%s\n", FLAG_START_CHAR, f.name, f.usage, v^, req_msg)
case ^string:
fmt.printfln("\t%s%s:\n\t\t%s (default: %s)%s\n", FLAG_START_CHAR, f.name, f.usage, v^, req_msg)
case ^f32:
fmt.printfln("\t%s%s:\n\t\t%s (default: %f)%s\n", FLAG_START_CHAR, f.name, f.usage, v^, req_msg)
case ^f64:
fmt.printfln("\t%s%s:\n\t\t%s (default: %f)%s\n", FLAG_START_CHAR, f.name, f.usage, v^, req_msg)
}
}
}
BoolVar :: proc(ptr: ^bool, name: string, default: bool, usage: string, required := false) {
if ptr == nil {
fmt.fprintfln(os.stderr, "[ERROR]: Invalid usage of BoolVar: got nil for 'ptr' value!")
os.exit(1)
}
ptr^ = default
append(&all_flags, Flag{name = name, value = ptr, usage = usage, required = required})
}
IntVar :: proc(ptr: ^int, name: string, default: int, usage: string, required := false) {
if ptr == nil {
fmt.fprintfln(os.stderr, "[ERROR]: Invalid usage of IntVar: got nil for 'ptr' value!")
os.exit(1)
}
ptr^ = default
append(&all_flags, Flag{name = name, value = ptr, usage = usage, required = required})
}
Int32Var :: proc(ptr: ^i32, name: string, default: i32, usage: string, required := false) {
if ptr == nil {
fmt.fprintfln(os.stderr, "[ERROR]: Invalid usage of Int32Var: got nil for 'ptr' value!")
os.exit(1)
}
ptr^ = default
append(&all_flags, Flag{name = name, value = ptr, usage = usage, required = required})
}
Int64Var :: proc(ptr: ^i64, name: string, default: i64, usage: string, required := false) {
if ptr == nil {
fmt.fprintfln(os.stderr, "[ERROR]: Invalid usage of Int64Var: got nil for 'ptr' value!")
os.exit(1)
}
ptr^ = default
append(&all_flags, Flag{name = name, value = ptr, usage = usage, required = required})
}
StringVar :: proc(ptr: ^string, name: string, default: string, usage: string, required := false) {
if ptr == nil {
fmt.fprintfln(os.stderr, "[ERROR]: Invalid usage of StringVar: got nil for 'ptr' value!")
os.exit(1)
}
ptr^ = default
append(&all_flags, Flag{name = name, value = ptr, usage = usage, required = required})
}
Float32Var :: proc(ptr: ^f32, name: string, default: f32, usage: string, required := false) {
if ptr == nil {
fmt.fprintfln(os.stderr, "[ERROR]: Invalid usage of Float32Var: got nil for 'ptr' value!")
os.exit(1)
}
ptr^ = default
append(&all_flags, Flag{name = name, value = ptr, usage = usage, required = required})
}
Float64Var :: proc(ptr: ^f64, name: string, default: f64, usage: string, required := false) {
if ptr == nil {
fmt.fprintfln(os.stderr, "[ERROR]: Invalid usage of Float64Var: got nil for 'ptr' value!")
os.exit(1)
}
ptr^ = default
append(&all_flags, Flag{name = name, value = ptr, usage = usage, required = required})
}
parse_flags :: proc() {
// sck: We cannot have the start and seperator formats being the same
if FLAG_START_CHAR == FLAG_SEP_CHAR {
fmt.fprintfln(os.stderr, "[ERROR]: FLAG_START_CHAR and FLAG_SEP_CHAR cannot be the same!")
fmt.printfln("\t FLAG_START_CHAR= \"%s\"\t FLAG_SEP_CHAR= \"%s\"", FLAG_START_CHAR, FLAG_SEP_CHAR)
os.exit(1)
}
if len(os.args) < 2 && FORCE_HELP_ON_EMPTY_ARGS {print_usage()}
// skip the first arg (1:)
for &a in os.args[1:] {
if a == "-h" || a == "-help" || a == "--help" {print_usage(); os.exit(0)}
// sck: if the user has a custom flag format, copy that to the help flag too.
if a == fmt.aprintf("%s%s", FLAG_START_CHAR, "help", allocator = context.temp_allocator) {print_usage(); os.exit(0)}
if a == fmt.aprintf("%s%s", FLAG_START_CHAR, "h", allocator = context.temp_allocator) {print_usage(); os.exit(0)}
defer free_all(context.temp_allocator) //clean up!
// Begin parsing flags...
for &f in all_flags {
if f.parsed {continue}
a = strings.trim_prefix(a, FLAG_START_CHAR)
name := a
value: string
split := strings.index_any(a, FLAG_SEP_CHAR)
if split >= 0 {
name = a[:split]
value = a[split + 1:]
} else {
name = a
fmt.printf("[INFO]: Could not read flag: %s. ", name)
print_flag_format()
break
}
// sck: We are going to parse all the flags
if name == f.name && !f.parsed {
f.parsed = true
switch &v in f.value {
case ^bool:
if value == "" {break}
parsed, ok := strconv.parse_bool(value)
if !ok {
fmt.fprintfln(os.stderr, "[ERROR] Failed to parse flag %s: got %T, wanted bool",
f.name, value)
os.exit(1)
}
v^ = parsed
case ^int:
if value == "" {break}
parsed, ok := strconv.parse_int(value)
if !ok {
fmt.fprintfln(os.stderr, "[ERROR] Failed to parse flag %s: got %T, wanted int",
f.name, value)
os.exit(1)
}
v^ = parsed
case ^i32:
if value == "" {break}
parsed, ok := strconv.parse_int(value)
if !ok {
fmt.fprintfln(os.stderr, "[ERROR] Failed to parse flag %s: got %T, wanted int",
f.name, value)
os.exit(1)
}
v^ = cast(i32)parsed
case ^i64:
if value == "" {break}
parsed, ok := strconv.parse_i64(value)
if !ok {
fmt.fprintfln(os.stderr, "[ERROR] Failed to parse flag %s: got %T, wanted int",
f.name, value)
os.exit(1)
}
v^ = parsed
case ^string:
if value == "" {break}
// TODO: validate string?
v^ = value
case ^f32:
if value == "" {break}
parsed, ok := strconv.parse_f32(value)
if !ok {
fmt.fprintfln(os.stderr, "[ERROR] Failed to parse flag %s: got %T, wanted f32",
f.name, value)
os.exit(1)
}
v^ = parsed
case ^f64:
if value == "" {break}
parsed, ok := strconv.parse_f64(value)
if !ok {
fmt.fprintfln(os.stderr, "[ERROR] Failed to parse flag %s: got %T, wanted f64",
f.name, value)
os.exit(1)
}
v^ = parsed
}
}
}
}
for f in all_flags {
if f.required && !f.parsed {
// sck: INFO or ERROR?
fmt.fprintfln(os.stderr, "[INFO] Missing required flag: %s%s", FLAG_START_CHAR, f.name)
if !FORCE_HELP_ON_EMPTY_ARGS {fmt.fprintfln(os.stderr, "use -help or -h to view all flags")}
os.exit(1)
}
}
}
+89
View File
@@ -0,0 +1,89 @@
#+vet explicit-allocators
package main
import "core:fmt"
import "core:os"
import "core:strings"
/*
* WIP files are denoted with an '!' at the start of the file.
* This stops the files being processed and uploaded to the site
* before you finish writing!
*/
BLOG_START_MD := `
(\
\'\
\'\ __________
/ '| ()_________)
\ '/ \ ~~~~~~~~ \
\ \ ~~~~~~ \
==). \__________\
(__) ()__________)
`
BLOG_TITLE_MD := `
# Articles and Blogs
`
BLOG_BACK_MD := `
[<= Back](./..)
`
generate_blog_md_file :: proc(path: string, allocator := context.allocator) {
blog_list := make([dynamic]string, allocator)
sb := strings.builder_make(allocator)
blog_md_file := strings.builder_make(allocator)
strings.write_string(&sb, path)
strings.write_string(&sb, "blog/")
blog_dir := strings.to_string(sb)
//os.write_string(file, BLOG_START)
blogs := walk_tree_and_get_md_names(blog_dir, allocator)
// *********** BLOG PARSING **************
for blog in blogs {
b := strings.split(blog, blog_dir, allocator = context.temp_allocator)
trim_b := strings.trim_right(b[1], ".md")
if trim_b == "index" {continue} //Ignore Index
if strings.starts_with(trim_b, "!") {continue} //Ignore WIP files!
// now add to blog list
append(&blog_list, blog)
free_all(context.temp_allocator)
}
// sck: note we are doing this in reverse - means the blogs are ordered
// from oldest at the bottom and newest at the top
#reverse for blog_entry in blog_list {
b := strings.split(blog_entry, blog_dir, allocator = context.temp_allocator)
trim_b := strings.trim_right(b[1], ".md")
strings.write_string(&blog_md_file, fmt.aprintf("* [%s](./%s.html)", trim_b, trim_b, allocator = context.temp_allocator))
strings.write_string(&blog_md_file, "\n")
free_all(context.temp_allocator)
}
os.change_directory(blog_dir)
index_file, err := os.create("index.md")
if err != nil {
fmt.eprintfln("ERROR in generate_blog_md_file: Could not open file %s: %s", index_file, os.error_string(err))
}
// sck: final step, write everything in the correct order for the index.html page
// note: we generate the MD file for the blog/index.md
// this saves me time from ordering the blog and allows for automagic
// indexing of blogs/articles
os.write_string(index_file, "```text")
os.write_string(index_file, BLOG_START_MD)
os.write_string(index_file, "```\n")
os.write_string(index_file, BLOG_TITLE_MD)
os.write_string(index_file, "\n")
os.write_string(index_file, strings.to_string(blog_md_file))
os.write_string(index_file, "\n")
os.write_string(index_file, BLOG_BACK_MD)
}
+38 -33
View File
@@ -1,3 +1,4 @@
#+vet explicit-allocators
package main package main
import "core:fmt" import "core:fmt"
@@ -5,74 +6,78 @@ import vmem "core:mem/virtual"
import "core:os" import "core:os"
import "core:strings" import "core:strings"
import "core:time" import "core:time"
import fleg "flag"
print_usage :: proc() {
fmt.println("Usage:\n\tcm [working dir] [output dir]\nNote:USE FULL PATH!")
os.exit(0)
}
main :: proc() { main :: proc() {
if len(os.args) <= 2 || len(os.args) > 3 {
print_usage()
return
}
directory := os.args[1]
output_dir := os.args[2]
arena: vmem.Arena arena: vmem.Arena
arena_err := vmem.arena_init_growing(&arena) arena_err := vmem.arena_init_growing(&arena)
ensure(arena_err == nil) ensure(arena_err == nil)
arena_alloc := vmem.arena_allocator(&arena) arena_alloc := vmem.arena_allocator(&arena)
defer vmem.arena_destroy(&arena) //clean defer vmem.arena_destroy(&arena) //clean up everything!
start := time.tick_now() fleg.init_custom_allocator(arena_alloc)
defer fleg.destroy()
directory: string
output_dir: string
fleg.StringVar(&directory, "dir", "", "input directory of .MD files", required = true)
fleg.StringVar(&output_dir, "out", "", "output directory (html files)", required = true)
fleg.parse_flags()
start := time.tick_now() //start timer for footer
generate_blog_md_file(directory, arena_alloc)
md_files := walk_tree_and_get_md_names(directory, arena_alloc) md_files := walk_tree_and_get_md_names(directory, arena_alloc)
end := time.tick_since(start)
for file, i in md_files { for file, i in md_files {
os.change_directory(directory) os.change_directory(directory)
fmt.printfln("INFO: Parsing %s from .MD to HTML...", file)
html, parse_err := parse_file_md_to_html(file, arena_alloc) html, parse_err := parse_file_md_to_html(file, arena_alloc)
if parse_err != nil { if parse_err != nil {
fmt.eprintfln("ERROR: Could not open file %s: %s", file, os.error_string(parse_err)) fmt.eprintfln("ERROR: Could not open file %s: %s", file, os.error_string(parse_err))
} }
filename := strings.split(file, directory) filename := strings.split(file, directory, arena_alloc)
//fmt.printfln("INFO: filename: %s", filename)
trimmed_filename := strings.trim_right(filename[1], ".md") trimmed_filename := strings.trim_right(filename[1], ".md")
//fmt.printfln("INFO: trimmed_filename: %s", trimmed_filename)
//Change to output directory. Not sure if this is needed
//But messing around with it means I create a lot of
//files to clean up. Works for now!
os.change_directory(output_dir) os.change_directory(output_dir)
sb := strings.builder_make(arena_alloc) //print html file name
sb := strings.builder_make(arena_alloc) //sb for writing to files, resets ever iteration
defer strings.builder_destroy(&sb)
strings.write_string(&sb, fmt.aprintf("%v", trimmed_filename, allocator = arena_alloc)) strings.write_string(&sb, fmt.aprintf("%v", trimmed_filename, allocator = arena_alloc))
strings.write_string(&sb, ".html") strings.write_string(&sb, ".html")
full_filename := strings.to_string(sb)
//get "full" name for creation + writing to html file
full_filename := strings.to_string(sb)
file, file_err := os.create(full_filename) file, file_err := os.create(full_filename)
if file_err != nil { if file_err != nil {
fmt.eprintfln("ERROR: Could not open file %s: %s", file, os.error_string(file_err)) fmt.eprintfln("ERROR: Could not open file %s: %s", file, os.error_string(file_err))
} }
os.write_string(file, UTF8_PREFIX) write_prefixs_to_html_file(file)
os.write_string(file, CSS_PREFIX) os.write_string(file, html) //WRITE PAGE
os.write_string(file, MASTODON_PREFIX) //Defer this as we want the last page written to have
os.write_string(file, html) //accurate timings
defer {
if trimmed_filename == "index" { switch trimmed_filename {
case "index":
buf: [1024]u8 buf: [1024]u8
date := time.now() date := time.now()
end := time.tick_since(start) end := time.tick_since(start)
os.write_string(file, "<br><footer><hr />This site was generated με αγάπη on ") os.write_string(file, "<br><footer><hr />This site was generated με αγάπη on ")
os.write_string(file, fmt.aprintf("%s ", time.to_string_dd_mm_yy(date, buf[:]))) os.write_string(file, fmt.aprintf("%s ", time.to_string_dd_mm_yy(date, buf[:]), allocator = arena_alloc))
os.write_string(file, fmt.aprintf("in %v ", time.duration_round(end, time.Nanosecond))) os.write_string(file, fmt.aprintf("in %v ", time.duration_round(end, time.Nanosecond), allocator = arena_alloc))
os.write_string(file, "<font color=#ea76cb><3</font> </footer><br>") os.write_string(file, "<font color=#ea76cb><3</font> </footer><br>")
} }
fmt.printfln("INFO: Wrote %s into HTML!", md_files[i])
} }
}
//TODO: Do timings now?
free_all(arena_alloc)
} }
+30 -22
View File
@@ -1,3 +1,4 @@
#+vet explicit-allocators
package main package main
import "core:fmt" import "core:fmt"
@@ -8,40 +9,55 @@ import cm "vendor:commonmark"
MD_SUFFIX :: ".md" MD_SUFFIX :: ".md"
UTF8_PREFIX :: "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />\n" UTF8_PREFIX :: "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />\n"
CSS_PREFIX :: "<head><link rel=\"stylesheet\" href=\"./css/style.css\">\n" CSS_PREFIX :: "<head><link rel=\"stylesheet\" href=\"./css/style.css\">\n<title>Simon Kellet</title>"
FAVICON_PREFIX :: "<link rel=\"icon\" type=\"image\\x-icon\" href=\"/imgs/favicon.ico\">\n"
MASTODON_PREFIX :: "<a rel=me href=https://linuxrocks.online/@simonkellet></a>\n" MASTODON_PREFIX :: "<a rel=me href=https://linuxrocks.online/@simonkellet></a>\n"
HIGHLIGHT_JS_PREFIX :: "<script type=\"text/javascript\" src=\"https://unpkg.com/@highlightjs/cdn-assets@11.11.1/highlight.min.js\"></script>\n<script type=\"text/javascript\" src=\"https://unpkg.com/highlightjs-odinlang@1.4.0/dist/odin.min.js\"></script>\n\n<script type=\"text/javascript\">\n hljs.highlightAll();\n</script>"
walk_tree_and_get_md_names :: proc( write_prefixs_to_html_file :: proc(file: ^os.File) {
path: string, file_info, err := os.fstat(file, context.temp_allocator)
allocator := context.allocator, if err != nil {
) -> [dynamic]string { fmt.eprintfln("ERROR in write_prefixs_to_html_file: Could not open file %s: %s", file, os.error_string(err))
}
defer free_all(context.temp_allocator) //clean up file_info
os.write_string(file, UTF8_PREFIX)
os.write_string(file, CSS_PREFIX)
os.write_string(file, FAVICON_PREFIX)
os.write_string(file, MASTODON_PREFIX)
// sck: ONLY apply hljs to blogs/articles. These files will always
// start with a "2" (2026-xx-xx...)
if strings.starts_with(file_info.name, "2") {
os.write_string(file, HIGHLIGHT_JS_PREFIX)
}
}
walk_tree_and_get_md_names :: proc(path: string, allocator := context.allocator) -> [dynamic]string {
files := make([dynamic]string, allocator) files := make([dynamic]string, allocator)
w := os.walker_create(path) w := os.walker_create(path)
defer os.walker_destroy(&w) defer os.walker_destroy(&w)
for info in os.walker_walk(&w) { for info in os.walker_walk(&w) {
//handle errors
if path, err := os.walker_error(&w); err != nil { if path, err := os.walker_error(&w); err != nil {
fmt.eprintfln("failed walking %s: %s", path, err) fmt.eprintfln("failed walking %s: %s", path, err)
continue continue
} }
//Skip a dir // Skip the Git dir
if strings.has_suffix(info.fullpath, ".git") { if strings.has_suffix(info.fullpath, ".git") {
os.walker_skip_dir(&w) os.walker_skip_dir(&w)
continue continue
} }
if !strings.has_suffix(info.name, MD_SUFFIX) { // Skip files that are NOT .md files
continue //skip if !strings.has_suffix(info.name, MD_SUFFIX) {continue}
}
append(&files, strings.clone(info.fullpath, allocator)) append(&files, strings.clone(info.fullpath, allocator))
} }
// Handle error if one happened during iteration at the end: // Handle error if one happened during iteration at the end:
if path, err := os.walker_error(&w); err != nil { if path, err := os.walker_error(&w); err != nil {
fmt.eprintfln("failed walking %s: %v", path, err) fmt.eprintfln("failed walking %s: %v", path, err)
@@ -62,7 +78,6 @@ walk_tree :: proc(path: string) -> []u8 {
fmt.eprintfln("failed walking %s: %s", path, err) fmt.eprintfln("failed walking %s: %s", path, err)
continue continue
} }
//lets play around
filename = info.name filename = info.name
if !strings.has_suffix(info.name, MD_SUFFIX) { if !strings.has_suffix(info.name, MD_SUFFIX) {
continue continue
@@ -73,22 +88,15 @@ walk_tree :: proc(path: string) -> []u8 {
return nil return nil
} }
parse_file_md_to_html :: proc( parse_file_md_to_html :: proc(filename: string, allocator := context.allocator, ) -> (parsed: string, err: os.Error) {
filename: string,
allocator := context.allocator,
) -> (
parsed: string,
err: os.Error,
) {
str := os.read_entire_file_from_path(filename, allocator) or_return str := os.read_entire_file_from_path(filename, allocator) or_return
root := cm.parse_document_from_string(string(str), cm.DEFAULT_OPTIONS)
root := cm.parse_document(raw_data(str), len(str), cm.DEFAULT_OPTIONS) //root := cm.parse_document(raw_data(str), len(str), cm.DEFAULT_OPTIONS)
defer cm.node_free(root) defer cm.node_free(root)
html := cm.render_html(root, cm.DEFAULT_OPTIONS) html := cm.render_html(root, cm.DEFAULT_OPTIONS)
defer cm.free(html) defer cm.free(html)
parsed = strings.clone_from_cstring(html, allocator) parsed = strings.clone_from_cstring(html, allocator)
return parsed, nil return parsed, nil
} }
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 255 KiB