From 671e18febd45bba01d3d29db7a544d25d1b36a3b Mon Sep 17 00:00:00 2001
From: venomade ' .. c .. ""
+ return "\x00CODE" .. #code_stash .. "\x00"
+ end)
+
+ -- bold + italic ***text***
+ s = s:gsub("%*%*%*(.-)%*%*%*", "%1")
+ -- bold **text**
+ s = s:gsub("%*%*(.-)%*%*", "%1")
+ -- italic *text*
+ s = s:gsub("%*(.-)%*", "%1")
+
+ -- links [text](url)
+ s = s:gsub("%[(.-)%]%((.-)%)", function(txt, url)
+ -- internal anchor links start with #
+ if url:sub(1,1) == "#" then
+ return '' .. txt .. ""
+ end
+ return '' .. txt .. ""
+ end)
+
+ -- restore code spans
+ s = s:gsub("\x00CODE(%d+)\x00", function(n)
+ return code_stash[tonumber(n)]
+ end)
+
+ return s
+end
+
+-- ── Syntax highlighting for code blocks ──────────────────────────────────────
+-- Simple but good-enough token colouring for lua, c, sh, and text.
+
+local SH_KEYWORDS = {
+ ["if"]=1,["then"]=1,["else"]=1,["elif"]=1,["fi"]=1,
+ ["for"]=1,["while"]=1,["do"]=1,["done"]=1,["case"]=1,
+ ["esac"]=1,["in"]=1,["function"]=1,["return"]=1,
+ ["local"]=1,["export"]=1,["echo"]=1,["exit"]=1,
+}
+
+local LUA_KEYWORDS = {
+ ["and"]=1,["break"]=1,["do"]=1,["else"]=1,["elseif"]=1,
+ ["end"]=1,["false"]=1,["for"]=1,["function"]=1,["goto"]=1,
+ ["if"]=1,["in"]=1,["local"]=1,["nil"]=1,["not"]=1,
+ ["or"]=1,["repeat"]=1,["return"]=1,["then"]=1,["true"]=1,
+ ["until"]=1,["while"]=1,
+}
+
+local C_KEYWORDS = {
+ ["auto"]=1,["break"]=1,["case"]=1,["char"]=1,["const"]=1,
+ ["continue"]=1,["default"]=1,["do"]=1,["double"]=1,["else"]=1,
+ ["enum"]=1,["extern"]=1,["float"]=1,["for"]=1,["goto"]=1,
+ ["if"]=1,["inline"]=1,["int"]=1,["long"]=1,["register"]=1,
+ ["return"]=1,["short"]=1,["signed"]=1,["sizeof"]=1,["static"]=1,
+ ["struct"]=1,["switch"]=1,["typedef"]=1,["union"]=1,["unsigned"]=1,
+ ["void"]=1,["volatile"]=1,["while"]=1,["NULL"]=1,["true"]=1,["false"]=1,
+}
+
+local function hl_lua(code)
+ local out = {}
+ local i, n = 1, #code
+ while i <= n do
+ local ch = code:sub(i,i)
+ -- single-line comment
+ if code:sub(i,i+1) == "--" then
+ local rest = escape_html(code:sub(i))
+ out[#out+1] = '' .. rest .. ""
+ break
+ -- long string / comment stubs not handled — treated as unknown
+ elseif ch == '"' or ch == "'" then
+ local q, j = ch, i+1
+ while j <= n do
+ local c = code:sub(j,j)
+ if c == "\\" then j=j+2 elseif c==q then j=j+1; break else j=j+1 end
+ end
+ out[#out+1] = ''..escape_html(code:sub(i,j-1))..""
+ i=j
+ elseif ch:match("%d") then
+ local j=i
+ while j<=n and code:sub(j,j):match("[%d%.xXa-fA-F]") do j=j+1 end
+ out[#out+1]=''..escape_html(code:sub(i,j-1))..""
+ i=j
+ elseif ch:match("[%a_]") then
+ local j=i
+ while j<=n and code:sub(j,j):match("[%w_]") do j=j+1 end
+ local word=code:sub(i,j-1)
+ if LUA_KEYWORDS[word] then
+ out[#out+1]=''..word..""
+ else
+ out[#out+1]=escape_html(word)
+ end
+ i=j
+ else
+ out[#out+1]=escape_html(ch); i=i+1
+ end
+ end
+ return table.concat(out)
+end
+
+local function hl_c(code)
+ local out = {}
+ local i, n = 1, #code
+ while i <= n do
+ local ch = code:sub(i,i)
+ if code:sub(i,i+1) == "//" then
+ out[#out+1]=''..escape_html(code:sub(i))..""; break
+ elseif ch == '"' or ch == "'" then
+ local q,j=ch,i+1
+ while j<=n do
+ local c=code:sub(j,j)
+ if c=="\\" then j=j+2 elseif c==q then j=j+1;break else j=j+1 end
+ end
+ out[#out+1]=''..escape_html(code:sub(i,j-1))..""; i=j
+ elseif ch:match("%d") then
+ local j=i
+ while j<=n and code:sub(j,j):match("[%d%.xXuUlL]") do j=j+1 end
+ out[#out+1]=''..escape_html(code:sub(i,j-1))..""; i=j
+ elseif ch:match("[%a_]") then
+ local j=i
+ while j<=n and code:sub(j,j):match("[%w_]") do j=j+1 end
+ local word=code:sub(i,j-1)
+ if C_KEYWORDS[word] then
+ out[#out+1]=''..word..""
+ else
+ out[#out+1]=escape_html(word)
+ end
+ i=j
+ else
+ out[#out+1]=escape_html(ch); i=i+1
+ end
+ end
+ return table.concat(out)
+end
+
+local function hl_sh(code)
+ local out = {}
+ local i,n=1,#code
+ while i<=n do
+ local ch=code:sub(i,i)
+ if ch=="#" then
+ out[#out+1]=''..escape_html(code:sub(i))..""; break
+ elseif ch=='"' or ch=="'" then
+ local q,j=ch,i+1
+ while j<=n do
+ local c=code:sub(j,j)
+ if ch=='"' and c=="\\" then j=j+2 elseif c==q then j=j+1;break else j=j+1 end
+ end
+ out[#out+1]=''..escape_html(code:sub(i,j-1))..""; i=j
+ elseif ch=="$" then
+ out[#out+1]='$'; i=i+1
+ elseif ch:match("[%a_]") then
+ local j=i
+ while j<=n and code:sub(j,j):match("[%w_]") do j=j+1 end
+ local word=code:sub(i,j-1)
+ if SH_KEYWORDS[word] then
+ out[#out+1]=''..word..""
+ else
+ out[#out+1]=escape_html(word)
+ end
+ i=j
+ else
+ out[#out+1]=escape_html(ch); i=i+1
+ end
+ end
+ return table.concat(out)
+end
+
+local highlighters = { lua=hl_lua, c=hl_c, sh=hl_sh, bash=hl_sh, zsh=hl_sh }
+
+local function highlight_code(lang, code)
+ local hl = lang and highlighters[lang:lower()]
+ if hl then
+ -- highlight line by line
+ local lines = {}
+ for line in (code .. "\n"):gmatch("([^\n]*)\n") do
+ lines[#lines+1] = hl(line)
+ end
+ return table.concat(lines, "\n")
+ end
+ return escape_html(code)
+end
+
+-- ── Block-level Markdown parser ───────────────────────────────────────────────
+
+local function parse_md(src)
+ local lines = {}
+ for ln in (src .. "\n"):gmatch("([^\n]*)\n") do
+ lines[#lines+1] = ln
+ end
+
+ local out = {}
+ local toc = {} -- {level, text, slug}
+ local i = 1
+ local in_list = false
+ local in_para = false
+
+ local function close_para()
+ if in_para then out[#out+1] = "
'
+ .. body
+ .. "" + goto continue + end + + -- table | col | col | + if line:match("^|") then + close_all() + local tbl_lines = {} + while i <= #lines and lines[i]:match("^|") do + tbl_lines[#tbl_lines+1] = lines[i] + i = i + 1 + end + out[#out+1] = '" .. inline_md(table.concat(bq_lines, " ")) .. "
| " .. inline_md(cell:match("^%s*(.-)%s*$")) .. " | " + end + out[#out+1] = "
|---|
| " .. inline_md(cell:match("^%s*(.-)%s*$")) .. " | " + end + out[#out+1] = "
" + in_para = true + else + out[#out+1] = " " + end + out[#out+1] = inline_md(line) + i = i + 1 + + ::continue:: + end + + close_all() + return table.concat(out, "\n"), toc +end + +-- ── TOC sidebar HTML ────────────────────────────────────────────────────────── + +local function build_sidebar(toc) + local out = {} + out[#out+1] = '' + return table.concat(out, "\n") +end + +-- ── Full HTML template ──────────────────────────────────────────────────────── + +local function build_html(title, sidebar_html, body_html) + return string.format([[ + +
+ + +