Compare commits

..
21 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
7 changed files with 407 additions and 83 deletions
+2
View File
@@ -3,3 +3,5 @@ cm
test/ test/
website_update.sh website_update.sh
site.png site.png
*.sublime-project
*.sublime-workspace
+11 -6
View File
@@ -7,9 +7,6 @@ Note: This is incredibly specific! If you want to use this for your own sites, I
your own! 😅 your own! 😅
## Usage ## Usage
### Requirements
* Odin
* A site, I guess?
### Build ### Build
```bash ```bash
@@ -18,10 +15,18 @@ odin build .
### Usage ### Usage
```bash ```bash
./cm > ./cm -h
Usage: Usage:
cm [working dir] [output dir]
Note:USE FULL PATH! Flag format for this program:
-<flag>=<value>
-dir:
input directory of .MD files (default: ) (required)
-out:
output directory (html files) (default: ) (required)
``` ```
### Todo ### Todo
+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)
}
}
}
+34 -18
View File
@@ -1,10 +1,17 @@
#+vet explicit-allocators
package main package main
import "core:fmt" import "core:fmt"
import "core:os" import "core:os"
import "core:strings" 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_START_MD := `
(\ (\
\'\ \'\
@@ -24,8 +31,7 @@ BLOG_BACK_MD := `
[<= Back](./..) [<= Back](./..)
` `
generate_blog_md_file :: proc(path: string, allocator := context.allocator) { generate_blog_md_file :: proc(path: string, allocator := context.allocator) {
blog_list := make([dynamic]string, allocator)
blog_list := make([dynamic]string)
sb := strings.builder_make(allocator) sb := strings.builder_make(allocator)
blog_md_file := strings.builder_make(allocator) blog_md_file := strings.builder_make(allocator)
@@ -34,35 +40,45 @@ generate_blog_md_file :: proc(path: string, allocator := context.allocator) {
blog_dir := strings.to_string(sb) blog_dir := strings.to_string(sb)
//os.write_string(file, BLOG_START) //os.write_string(file, BLOG_START)
blogs := walk_tree_and_get_md_names(blog_dir) blogs := walk_tree_and_get_md_names(blog_dir, allocator)
// *********** BLOG PARSING **************
for blog in blogs { for blog in blogs {
b := strings.split(blog, blog_dir) b := strings.split(blog, blog_dir, allocator = context.temp_allocator)
trim_b := strings.trim_right(b[1], ".md") trim_b := strings.trim_right(b[1], ".md")
if trim_b == "index" {continue}
if trim_b == "index_non_blank" {continue} if trim_b == "index" {continue} //Ignore Index
if trim_b == "test" {continue} if strings.starts_with(trim_b, "!") {continue} //Ignore WIP files!
if trim_b == "test_blog" {continue}
// now add to blog list
append(&blog_list, blog) append(&blog_list, blog)
free_all(context.temp_allocator)
} }
for blog_entry in blog_list { // sck: note we are doing this in reverse - means the blogs are ordered
b := strings.split(blog_entry, blog_dir) // 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") trim_b := strings.trim_right(b[1], ".md")
strings.write_string(&blog_md_file, fmt.aprintf("* [%s](./%s.html)", trim_b, trim_b))
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") strings.write_string(&blog_md_file, "\n")
free_all(context.temp_allocator)
} }
os.change_directory(blog_dir) os.change_directory(blog_dir)
index_file, err := os.create("index.md") index_file, err := os.create("index.md")
if err != nil { if err != nil {
fmt.eprintfln( fmt.eprintfln("ERROR in generate_blog_md_file: Could not open file %s: %s", index_file, os.error_string(err))
"ERROR in generate_blog_md_file: Could not open file %s: %s",
index_file,
os.error_string(err),
)
} }
os.write_string(index_file, "```")
// 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, BLOG_START_MD)
os.write_string(index_file, "```\n") os.write_string(index_file, "```\n")
os.write_string(index_file, BLOG_TITLE_MD) os.write_string(index_file, BLOG_TITLE_MD)
+30 -28
View File
@@ -1,56 +1,55 @@
#+vet explicit-allocators
package main package main
import "core:fmt" import "core:fmt"
import vmem "core:mem/virtual" import vmem "core:mem/virtual"
import "core:os" import "core:os"
import "core:sort"
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!
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 start := time.tick_now() //start timer for footer
generate_blog_md_file(directory) 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)
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... //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)
//print html file name //print html file name
sb := strings.builder_make(arena_alloc) //sb for writing to files, resets ever iteration 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")
@@ -60,9 +59,12 @@ main :: proc() {
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))
} }
write_prefixs_to_html_file(file)
os.write_string(file, html)
write_prefixs_to_html_file(file)
os.write_string(file, html) //WRITE PAGE
//Defer this as we want the last page written to have
//accurate timings
defer {
switch trimmed_filename { switch trimmed_filename {
case "index": case "index":
buf: [1024]u8 buf: [1024]u8
@@ -70,12 +72,12 @@ main :: proc() {
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)
} }
+25 -23
View File
@@ -1,3 +1,4 @@
#+vet explicit-allocators
package main package main
import "core:fmt" import "core:fmt"
@@ -8,46 +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>"
write_prefixs_to_html_file :: proc(file: ^os.File) { write_prefixs_to_html_file :: proc(file: ^os.File) {
file_info, err := os.fstat(file, context.temp_allocator)
if err != nil {
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, UTF8_PREFIX)
os.write_string(file, CSS_PREFIX) os.write_string(file, CSS_PREFIX)
os.write_string(file, FAVICON_PREFIX)
os.write_string(file, MASTODON_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( walk_tree_and_get_md_names :: proc(path: string, allocator := context.allocator) -> [dynamic]string {
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)
@@ -68,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
@@ -79,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.

Before

Width:  |  Height:  |  Size: 245 KiB

After

Width:  |  Height:  |  Size: 255 KiB