changeset 64:a30944e5719e

Added vibe coded markdown to html script since it is useful for me. Updated Dowa so that it can be compiled without dirnet for windows.
author June Park <parkjune1995@gmail.com>
date Tue, 23 Dec 2025 15:18:46 -0800
parents fff1b048dda6
children ecb6ee6a22c3
files dowa/BUILD dowa/d_memory.c dowa/dowa.h dowa/dowa_test.c gui_ze/gui_ze.bzl markdown_converter/BUILD markdown_converter/main.js markdown_converter/markdown_to_html.js mrjunejune/BUILD mrjunejune/pages/markdown_to_html/index.html seobeo/seobeo.h seobeo/seobeo_internal.h
diffstat 12 files changed, 577 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- a/dowa/BUILD	Tue Dec 23 14:00:37 2025 -0800
+++ b/dowa/BUILD	Tue Dec 23 15:18:46 2025 -0800
@@ -1,6 +1,19 @@
 load("@rules_cc//cc:cc_library.bzl", "cc_library")
 load("@rules_cc//cc:cc_test.bzl", "cc_test")
 
+# TODO: Fix so that we can just define in the header instead of defining in the cc_library because this is ass.
+cc_library(
+  name = "dowa_generic",
+  srcs = [
+    "d_string.c",
+    "d_memory.c",
+  ],
+  hdrs = [
+    "dowa.h",
+    "dowa_internal.h"
+  ],
+  visibility = ["//visibility:public"],
+)
 
 cc_library(
   name = "dowa",
@@ -12,6 +25,7 @@
     "dowa.h",
     "dowa_internal.h"
   ],
+  copts = ["-DDIRECTORY"],
   visibility = ["//visibility:public"],
 )
 
--- a/dowa/d_memory.c	Tue Dec 23 14:00:37 2025 -0800
+++ b/dowa/d_memory.c	Tue Dec 23 15:18:46 2025 -0800
@@ -474,6 +474,7 @@
   printf("-----------\n");
 }
 
+#ifdef DIRECTORY
 int Dowa_HashMap_Cache_Folder(Dowa_PHashMap p_hash_map, const char *folder_path)
 {
   if (!p_hash_map || !folder_path)
@@ -503,12 +504,12 @@
       FILE *f = fopen(fullpath, "rb");
       if (!f) { perror("fopen"); continue; }
 
+      // Allocate exact file size (no extra byte for null terminator)
       void *buf = p_hash_map->p_arena ?
-        Dowa_Arena_Allocate(p_hash_map->p_arena, size + 1) :
-        malloc(size + 1);
+        Dowa_Arena_Allocate(p_hash_map->p_arena, size) :
+        malloc(size);
       if (!buf) { perror("malloc"); fclose(f); closedir(dir); return -1; }
 
-
       if (fread(buf, 1, size, f) != size)
       {
         perror("fread");
@@ -518,8 +519,8 @@
       }
       fclose(f);
 
-      ((char *)buf)[size] = '\0';
-      Dowa_HashMap_Push_Value_With_Type(p_hash_map, entry->d_name, buf, size + 1, DOWA_HASH_MAP_TYPE_STRING);
+      // Store file data as-is without null terminator (for binary files like images)
+      Dowa_HashMap_Push_Value_With_Type(p_hash_map, entry->d_name, buf, size, DOWA_HASH_MAP_TYPE_STRING);
       if (!p_hash_map->p_arena)
         Dowa_Free(buf);  // Dowa_HashMap_PushValue made its own copy
     }
@@ -550,3 +551,4 @@
   closedir(dir);
   return 0;
 }
+#endif
--- a/dowa/dowa.h	Tue Dec 23 14:00:37 2025 -0800
+++ b/dowa/dowa.h	Tue Dec 23 15:18:46 2025 -0800
@@ -11,6 +11,7 @@
 // Maybe move this into seobeo file directly?
 #include <dirent.h> // some functions loop through files
 #endif
+
 #include <math.h> // I am not re-writing stuff I guess...
 
 #include <sys/stat.h>
@@ -119,8 +120,10 @@
 // --- Utility Functions --- //
 /* Prints all entries in the hashmap to stdout for debugging purposes. */
 extern void          Dowa_HashMap_Print(Dowa_PHashMap map);
+#ifdef DIRECTORY
 /* Loads all files from the specified folder into the hashmap. Uses file names as keys and file contents as values. Returns 0 on success, or -1 on failure. */
 extern int           Dowa_HashMap_Cache_Folder(Dowa_PHashMap map, const char *folder_path);
+#endif
 
 
 #endif
--- a/dowa/dowa_test.c	Tue Dec 23 14:00:37 2025 -0800
+++ b/dowa/dowa_test.c	Tue Dec 23 15:18:46 2025 -0800
@@ -2,6 +2,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
+#define DIRECTORY
 #include "dowa.h"
 
 int main(void)
--- a/gui_ze/gui_ze.bzl	Tue Dec 23 14:00:37 2025 -0800
+++ b/gui_ze/gui_ze.bzl	Tue Dec 23 15:18:46 2025 -0800
@@ -143,13 +143,17 @@
 
 def _move_files_into_dir_impl(ctx):
   srcs = ctx.files.srcs
+  outs = []
   for src in srcs:
     out = ctx.actions.declare_file(ctx.attr.dest + "/" + src.basename)
-    ctx.actions.symlink(
-      output = out,
-      target_file = src,
+    ctx.actions.run_shell(
+      inputs = [src],
+      outputs = [out],
+      command = "cp \"$1\" \"$2\"",
+      arguments = [src.path, out.path],
     )
-  return [DefaultInfo(files = depset([out]))]
+    outs.append(out)
+  return [DefaultInfo(files = depset(outs))]
 
 move_files_into_dir = rule(
   implementation = _move_files_into_dir_impl,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/markdown_converter/BUILD	Tue Dec 23 15:18:46 2025 -0800
@@ -0,0 +1,9 @@
+filegroup(
+  name = "markdown_to_html",
+  srcs = glob([
+      "**/*.js",
+  ], allow_empty=True),
+  visibility = ["//visibility:public"],
+)
+
+
--- a/markdown_converter/main.js	Tue Dec 23 14:00:37 2025 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-// #
-// ##
-// []()
-// _ _
-// * *
-// 1.
-// -
-// \s\s
-//
-
-function Lexer(character) {
-}
-
-/**
- * @params
- *   value: string
- */
-function mardownConverter(value) {
-  let i = 0;
-  let character;
-  const domElements = [];
-  while (i < value.length) {
-    character = value[i]
-    switch(character) {
-      case "#": {
-        if 
-        const dom = document.createElement("h1");
-        domElements.append(dom)
-      }
-      case "_": {
-      }
-      case "_" {
-      }
-      case "*" {
-      }
-      default {
-        return character;
-      }
-    }
-  }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/markdown_converter/markdown_to_html.js	Tue Dec 23 15:18:46 2025 -0800
@@ -0,0 +1,269 @@
+/**
+ * Simple Markdown to HTML Converter
+ * Supports: headers, bold, italic, links, lists, code blocks, line breaks
+ */
+
+/**
+ * Create heading element (H1-H6)
+ * @param {string} text - The heading text
+ * @param {number} level - Heading level (1-6)
+ * @returns {HTMLElement}
+ */
+function createHeadingElement(text, level) {
+  const h = document.createElement(`H${level}`);
+  const t = document.createTextNode(text.trim());
+  h.appendChild(t);
+  return h;
+}
+
+/**
+ * Create paragraph element
+ * @param {string} text - The paragraph text
+ * @returns {HTMLElement}
+ */
+function createParagraphElement(text) {
+  const p = document.createElement("P");
+  p.innerHTML = processInlineMarkdown(text.trim());
+  return p;
+}
+
+/**
+ * Create link element
+ * @param {string} text - Link text
+ * @param {string} url - Link URL
+ * @returns {HTMLElement}
+ */
+function createLinkElement(text, url) {
+  const a = document.createElement("A");
+  a.href = url;
+  a.textContent = text;
+  return a;
+}
+
+/**
+ * Create unordered list element
+ * @param {Array<string>} items - List items
+ * @returns {HTMLElement}
+ */
+function createUnorderedList(items) {
+  const ul = document.createElement("UL");
+  items.forEach(item => {
+    const li = document.createElement("LI");
+    li.innerHTML = processInlineMarkdown(item.trim());
+    ul.appendChild(li);
+  });
+  return ul;
+}
+
+/**
+ * Create ordered list element
+ * @param {Array<string>} items - List items
+ * @returns {HTMLElement}
+ */
+function createOrderedList(items) {
+  const ol = document.createElement("OL");
+  items.forEach(item => {
+    const li = document.createElement("LI");
+    li.innerHTML = processInlineMarkdown(item.trim());
+    ol.appendChild(li);
+  });
+  return ol;
+}
+
+/**
+ * Create code block element
+ * @param {string} code - Code content
+ * @returns {HTMLElement}
+ */
+function createCodeBlock(code) {
+  const pre = document.createElement("PRE");
+  const codeEl = document.createElement("CODE");
+  codeEl.textContent = code;
+  pre.appendChild(codeEl);
+  return pre;
+}
+
+/**
+ * Create blockquote element
+ * @param {string} text - Quote text
+ * @returns {HTMLElement}
+ */
+function createBlockquote(text) {
+  const blockquote = document.createElement("BLOCKQUOTE");
+  blockquote.innerHTML = processInlineMarkdown(text.trim());
+  return blockquote;
+}
+
+/**
+ * Create horizontal rule
+ * @returns {HTMLElement}
+ */
+function createHorizontalRule() {
+  return document.createElement("HR");
+}
+
+/**
+ * Process inline markdown (bold, italic, code, links)
+ * @param {string} text - Text with inline markdown
+ * @returns {string} HTML string
+ */
+function processInlineMarkdown(text) {
+  // Links: [text](url)
+  text = text.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2">$1</a>');
+  
+  // Images: ![alt](url)
+  text = text.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '<img src="$2" alt="$1">');
+  
+  // Bold: **text** or __text__
+  text = text.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
+  text = text.replace(/__([^_]+)__/g, '<strong>$1</strong>');
+  
+  // Italic: *text* or _text_
+  text = text.replace(/\*([^*]+)\*/g, '<em>$1</em>');
+  text = text.replace(/_([^_]+)_/g, '<em>$1</em>');
+  
+  // Inline code: `code`
+  const x = /`([^`]+)`/g;
+  text = text.replace(x, '<code>$1</code>');
+  
+  // Strikethrough: ~~text~~
+  text = text.replace(/~~([^~]+)~~/g, '<del>$1</del>');
+  
+  // Line breaks: two spaces at end of line
+  text = text.replace(/  \n/g, '<br>\n');
+  
+  return text;
+}
+
+/**
+ * Main markdown converter function
+ * @param {string} value - Markdown string
+ * @returns {Array<HTMLElement>} Array of DOM elements
+ */
+function markdownConverter(value) {
+  const lines = value.split('\n');
+  const domElements = [];
+  let i = 0;
+  
+  while (i < lines.length) {
+    const line = lines[i];
+    const trimmedLine = line.trim();
+    
+    // Skip empty lines
+    if (trimmedLine === '') {
+      i++;
+      continue;
+    }
+    
+    if (trimmedLine.startsWith('#'))
+    {
+      const match = trimmedLine.match(/^(#{1,6})\s+(.+)$/);
+      if (match) {
+        const level = match[1].length;
+        const text = match[2];
+        domElements.push(createHeadingElement(text, level));
+        i++;
+        continue;
+      }
+    }
+    
+    if (trimmedLine.startsWith('```')) {
+      let codeContent = '';
+      i++; // Skip opening ```
+      while (i < lines.length && !lines[i].trim().startsWith('```')) {
+        codeContent += lines[i] + '\n';
+        i++;
+      }
+      domElements.push(createCodeBlock(codeContent));
+      i++; // Skip closing ```
+      continue;
+    }
+    
+    // Blockquote: >
+    if (trimmedLine.startsWith('>')) {
+      let quoteContent = '';
+      while (i < lines.length && lines[i].trim().startsWith('>')) {
+        quoteContent += lines[i].trim().substring(1).trim() + ' ';
+        i++;
+      }
+      domElements.push(createBlockquote(quoteContent));
+      continue;
+    }
+    
+    // Horizontal rule: ---, ***, ___
+    if (trimmedLine.match(/^(-{3,}|\*{3,}|_{3,})$/)) {
+      domElements.push(createHorizontalRule());
+      i++;
+      continue;
+    }
+    
+    // Unordered list: -, *, +
+    if (trimmedLine.match(/^[-*+]\s+/)) {
+      const listItems = [];
+      while (i < lines.length && lines[i].trim().match(/^[-*+]\s+/)) {
+        listItems.push(lines[i].trim().substring(2));
+        i++;
+      }
+      domElements.push(createUnorderedList(listItems));
+      continue;
+    }
+    
+    // Ordered list: 1., 2., etc.
+    if (trimmedLine.match(/^\d+\.\s+/)) {
+      const listItems = [];
+      while (i < lines.length && lines[i].trim().match(/^\d+\.\s+/)) {
+        listItems.push(lines[i].trim().replace(/^\d+\.\s+/, ''));
+        i++;
+      }
+      domElements.push(createOrderedList(listItems));
+      continue;
+    }
+    
+    // Regular paragraph
+    let paragraphContent = '';
+    while (i < lines.length && lines[i].trim() !== '' && 
+           !lines[i].trim().match(/^(#{1,6}\s|[-*+]\s|\d+\.\s|>|```|---|\*\*\*|___)/)) {
+      paragraphContent += lines[i] + ' ';
+      i++;
+    }
+    if (paragraphContent.trim()) {
+      domElements.push(createParagraphElement(paragraphContent));
+    }
+  }
+  
+  return domElements;
+}
+
+/**
+ * Helper function to append all elements to a container
+ * @param {HTMLElement} container - Container element
+ * @param {string} markdown - Markdown string
+ */
+function renderMarkdown(container, markdown) {
+  const elements = markdownConverter(markdown);
+  elements.forEach(el => container.appendChild(el));
+}
+
+// Example usage:
+// const markdown = `
+// # Heading 1
+// ## Heading 2
+// 
+// This is a paragraph with **bold** and *italic* text.
+// 
+// - List item 1
+// - List item 2
+// 
+// 1. Ordered item 1
+// 2. Ordered item 2
+// 
+// [Link text](https://example.com)
+// `;
+// 
+// const container = document.getElementById('content');
+// renderMarkdown(container, markdown);
+
+// Export for use in other files
+if (typeof module !== 'undefined' && module.exports) {
+  module.exports = { markdownConverter, renderMarkdown };
+}
--- a/mrjunejune/BUILD	Tue Dec 23 14:00:37 2025 -0800
+++ b/mrjunejune/BUILD	Tue Dec 23 15:18:46 2025 -0800
@@ -7,6 +7,7 @@
   name = "compiled_ts",
   srcs = [
     "//playground:hello",
+    "//markdown_converter:markdown_to_html"
   ],
   dest = "pages",
 )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mrjunejune/pages/markdown_to_html/index.html	Tue Dec 23 15:18:46 2025 -0800
@@ -0,0 +1,257 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Markdown to HTML Converter</title>
+    <style>
+        * {
+            margin: 0;
+            padding: 0;
+            box-sizing: border-box;
+        }
+        
+        body {
+            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
+            line-height: 1.6;
+            padding: 20px;
+            max-width: 1200px;
+            margin: 0 auto;
+            background: #f5f5f5;
+        }
+        
+        .container {
+            display: grid;
+            grid-template-columns: 1fr 1fr;
+            gap: 20px;
+            margin-top: 20px;
+        }
+        
+        .panel {
+            background: white;
+            border-radius: 8px;
+            padding: 20px;
+            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
+        }
+        
+        h1 {
+            color: #333;
+            margin-bottom: 20px;
+        }
+        
+        textarea {
+            width: 100%;
+            height: 500px;
+            padding: 15px;
+            border: 1px solid #ddd;
+            border-radius: 4px;
+            font-family: 'Courier New', monospace;
+            font-size: 14px;
+            resize: vertical;
+        }
+        
+        #output {
+            min-height: 500px;
+            padding: 15px;
+            border: 1px solid #ddd;
+            border-radius: 4px;
+            background: #fafafa;
+        }
+        
+        #output h1, #output h2, #output h3, #output h4, #output h5, #output h6 {
+            margin: 20px 0 10px 0;
+            color: #333;
+        }
+        
+        #output h1 { font-size: 2em; }
+        #output h2 { font-size: 1.5em; }
+        #output h3 { font-size: 1.3em; }
+        
+        #output p {
+            margin: 10px 0;
+        }
+        
+        #output ul, #output ol {
+            margin: 10px 0;
+            padding-left: 30px;
+        }
+        
+        #output li {
+            margin: 5px 0;
+        }
+        
+        #output code {
+            background: #f4f4f4;
+            padding: 2px 6px;
+            border-radius: 3px;
+            font-family: 'Courier New', monospace;
+            font-size: 0.9em;
+        }
+        
+        #output pre {
+            background: #282c34;
+            color: #abb2bf;
+            padding: 15px;
+            border-radius: 4px;
+            overflow-x: auto;
+            margin: 10px 0;
+        }
+        
+        #output pre code {
+            background: none;
+            color: inherit;
+            padding: 0;
+        }
+        
+        #output blockquote {
+            border-left: 4px solid #ddd;
+            padding-left: 15px;
+            margin: 10px 0;
+            color: #666;
+            font-style: italic;
+        }
+        
+        #output a {
+            color: #0066cc;
+            text-decoration: none;
+        }
+        
+        #output a:hover {
+            text-decoration: underline;
+        }
+        
+        #output hr {
+            border: none;
+            border-top: 2px solid #ddd;
+            margin: 20px 0;
+        }
+        
+        #output img {
+            max-width: 100%;
+            height: auto;
+        }
+        
+        #output strong {
+            font-weight: bold;
+        }
+        
+        #output em {
+            font-style: italic;
+        }
+        
+        #output del {
+            text-decoration: line-through;
+        }
+        
+        button {
+            background: #0066cc;
+            color: white;
+            border: none;
+            padding: 10px 20px;
+            border-radius: 4px;
+            cursor: pointer;
+            font-size: 16px;
+            margin-top: 10px;
+        }
+        
+        button:hover {
+            background: #0052a3;
+        }
+        
+        .header {
+            text-align: center;
+            margin-bottom: 30px;
+        }
+        
+        .label {
+            font-weight: bold;
+            margin-bottom: 10px;
+            color: #555;
+        }
+        
+        @media (max-width: 768px) {
+            .container {
+                grid-template-columns: 1fr;
+            }
+        }
+    </style>
+</head>
+<body>
+    <div class="header">
+        <h1>Markdown to HTML Converter</h1>
+    </div>
+    
+    <div class="container">
+        <div class="panel">
+            <div class="label">Markdown Input</div>
+            <textarea id="input" placeholder="Type your markdown here..."># Welcome to Markdown Converter
+
+## Features
+
+This converter supports:
+
+- **Bold text** and *italic text*
+- [Links](https://example.com)
+- `inline code`
+- ~~strikethrough~~
+
+### Lists
+
+1. Ordered lists
+2. Like this one
+3. With numbers
+
+- Unordered lists
+- Use dashes
+- Or asterisks
+
+### Code Blocks
+
+```
+function example() {
+    return "Hello World";
+}
+```
+
+### Blockquotes
+
+> This is a blockquote
+> It can span multiple lines
+
+---
+
+### Images
+
+![Alt text](https://via.placeholder.com/150)
+
+**Try editing this text!**</textarea>
+        </div>
+        
+        <div class="panel">
+            <div class="label">HTML Output</div>
+            <div id="output"></div>
+        </div>
+    </div>
+
+    <script src="/markdown_to_html.js"></script>
+    <script>
+        const input = document.getElementById('input');
+        const output = document.getElementById('output');
+        
+        function convert() {
+            // Clear previous output
+            output.innerHTML = '';
+            
+            // Convert and render
+            const markdown = input.value;
+            renderMarkdown(output, markdown);
+        }
+        
+        // Convert on input
+        input.addEventListener('input', convert);
+        
+        // Initial conversion
+        convert();
+    </script>
+</body>
+</html>
--- a/seobeo/seobeo.h	Tue Dec 23 14:00:37 2025 -0800
+++ b/seobeo/seobeo.h	Tue Dec 23 15:18:46 2025 -0800
@@ -8,6 +8,11 @@
  * Library for starting TCP, UDP server and serving static file or path.
  */
 
+// Define DIRECTORY before any includes to enable directory operations in dowa.h
+#ifndef DIRECTORY
+#define DIRECTORY
+#endif
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
--- a/seobeo/seobeo_internal.h	Tue Dec 23 14:00:37 2025 -0800
+++ b/seobeo/seobeo_internal.h	Tue Dec 23 15:18:46 2025 -0800
@@ -5,6 +5,9 @@
 #include <openssl/ssl.h> 
 #include <openssl/err.h>
 
+#ifndef DIRECTORY
+#define DIRECTORY
+#endif
 #include "dowa/dowa.h"
 
 typedef enum {