10 Commits

Author SHA1 Message Date
murat 3f2380e6a2 initial readme 2026-06-18 10:24:46 +03:00
murat 28a973991f BREAKING CHANGES(sitecontents and title): pageContent and pageTitle shortcodes 2026-06-18 10:02:39 +03:00
murat 9ae0960750 feat(shortcodes): list.item.<option> shortcodes 2026-06-18 09:40:10 +03:00
murat a98460360c fix(public directory): not deleting old files
fixed by deleting all html files in the public directory
2026-06-17 17:15:35 +03:00
murat 5fbe2da916 feat: use the html file named same as the md file for template if exists
known bug: /public/ directory doesn't cleaned before recreating html
files
2026-06-17 17:05:26 +03:00
murat e74d70af1b feat(options): draft control 2026-06-16 21:29:25 +03:00
murat fcc6ef114a chore: remove unused variables 2026-06-16 21:05:21 +03:00
murat 87bbceb647 chore: update <br> cleanup 2026-06-16 20:55:46 +03:00
murat 1aa5380836 feat(styling): paragraphs 2026-06-16 20:53:14 +03:00
murat 6e1659d542 chore: removing <br> tags around the block elements 2026-06-16 19:39:28 +03:00
2 changed files with 220 additions and 102 deletions
+20
View File
@@ -1,2 +1,22 @@
# luago # luago
Static website generator written in Lua Static website generator written in Lua
> Still in development
> Please don't use for production yet
> There are a lot of work to do
## what it does
- reads .md files in that directory and create html files
- transforms basic markdown syntax to html styling
### features
- read all md files
- check if index.md and index.html files are exists (if not stop with error)
- read options section on every md file
- clear public/ directory and create if not exists
- create html files using same name template html file
- if there are no html file for that md file, use index.html
- {{pageContent}}, {{pageTitle}} and {{list:}}-{{:list}} shortcodes
- list.item.<option> shortcode inside list shortcode
luago name
: **lua** + **hugo** (can't thing of anything better)
+119 -21
View File
@@ -12,20 +12,32 @@ for file in lfs.dir(currentDir) do
-- ignore "." and ".." files -- ignore "." and ".." files
if not(file:sub(1,2) == ".." or file:sub(1,1) == '.') then if not(file:sub(1,2) == ".." or file:sub(1,1) == '.') then
local filePath = currentDir .. '/' .. file local filePath = currentDir .. '/' .. file
-- match file names ending with ".md"
if file:match("index.md") then haveIndexmd = true end if file:match("index.md") then haveIndexmd = true end
if file:match("index.html") then haveIndexhtml = true end if file:match("index.html") then haveIndexhtml = true end
-- match file names ending with ".md"
if file:match("%.md$") then if file:match("%.md$") then
markdownFileCount = markdownFileCount + 1 markdownFileCount = markdownFileCount + 1
markdownFiles[markdownFileCount] = { markdownFiles[markdownFileCount] = {
options = {}, options = {},
filePath = filePath, filePath = filePath,
fileName = file:sub(1, file:len()-3), fileName = file:sub(1, file:len()-3),
content = "" content = "",
hasHtml = false
} }
end end
end end
end end
-- check html files with same name as the md files
for file in lfs.dir(currentDir) do
if file:match("%.html$") then
for index, value in ipairs(markdownFiles) do
if file:match(value.fileName .. ".html") then
markdownFiles[index].hasHtml = true
print(value.fileName .. "file has a html template file.")
end
end
end
end
-- stop the program if "index.html" or "index.md" doesn't exist -- stop the program if "index.html" or "index.md" doesn't exist
if (not(haveIndexhtml) and not(haveIndexmd)) then return print("Can't find index.html or index.md!") end if (not(haveIndexhtml) and not(haveIndexmd)) then return print("Can't find index.html or index.md!") end
@@ -51,7 +63,7 @@ for index, file in ipairs(markdownFiles) do
end end
-- fill options table -- fill options table
for i, value in ipairs(lines) do for _, value in ipairs(lines) do
if value:sub(value:len(), value:len()) == "\n" then if value:sub(value:len(), value:len()) == "\n" then
value = value:sub(1, value:find("\n")-1) value = value:sub(1, value:find("\n")-1)
end end
@@ -73,7 +85,7 @@ for index, file in ipairs(markdownFiles) do
end end
-- replace markdownFiles.content with md file content -- replace markdownFiles.content with md file content
for index, value in ipairs(markdownFiles) do for index, _ in ipairs(markdownFiles) do
local f = io.open(markdownFiles[index].filePath) local f = io.open(markdownFiles[index].filePath)
if f then if f then
local content = f:read("*a") local content = f:read("*a")
@@ -87,7 +99,7 @@ for index, value in ipairs(markdownFiles) do
end end
end end
for index, value in ipairs(markdownFiles) do for index, _ in ipairs(markdownFiles) do
print("---------------") print("---------------")
-- print file path with index -- print file path with index
print(index .. ': ' .. markdownFiles[index].filePath) print(index .. ': ' .. markdownFiles[index].filePath)
@@ -109,19 +121,23 @@ end
-- get index.html content -- get index.html content
local indexFile = io.open("index.html"):read("*all") local indexFile = io.open("index.html"):read("*all")
local siteName
local siteTitle
-- remove and create "public/" directory -- delete html files and create "public/" directory
lfs.rmdir("public") for file in lfs.dir(currentDir .. "/public") do
if file:match("%.html$") then
os.remove(currentDir .. "/public/" .. file)
end
end
lfs.mkdir("public") lfs.mkdir("public")
for index, value in ipairs(markdownFiles) do for index, _ in ipairs(markdownFiles) do
if markdownFiles[index].options["draft"] ~= "yes" then
local workDir = lfs.currentdir() local workDir = lfs.currentdir()
-- create html file for that md file -- create html file for that md file
local htmlFile = io.open(workDir .. "/public/" .. markdownFiles[index].fileName .. ".html", 'w') local htmlFile = io.open(workDir .. "/public/" .. markdownFiles[index].fileName .. ".html", 'w')
if htmlFile then if htmlFile then
local content = indexFile local content = indexFile
if markdownFiles[index].hasHtml then content = io.open(markdownFiles[index].fileName .. ".html"):read("*all") end
-- STYLING -- STYLING
local function styleLists(s) local function styleLists(s)
@@ -160,6 +176,37 @@ for index, value in ipairs(markdownFiles) do
return table.concat(result, "\n") return table.concat(result, "\n")
end end
local function styleParagraph(s)
local lines = {}
for line in (s .. "\n"):gmatch("([^\n]*)\n") do
table.insert(lines, line)
end
local result = {}
local pLines = {}
local function flushP()
if #pLines > 0 then
table.insert(result, "<p>" .. table.concat(pLines, "\n") .. "</p>")
pLines = {}
end
end
for _, line in ipairs(lines) do
local isBlock = line:match("^<") or line:match("^#")
local isEmpty = line:match("^%s*$")
if isBlock or isEmpty then
flushP()
table.insert(result, line)
else
table.insert(pLines, line)
end
end
flushP()
return table.concat(result, "\n")
end
local function styling(s) local function styling(s)
-- blockquote -- blockquote
local lines = {} local lines = {}
@@ -170,8 +217,23 @@ for index, value in ipairs(markdownFiles) do
s = table.concat(lines, "\n") s = table.concat(lines, "\n")
-- lists -- lists
s = styleLists(s) s = styleLists(s)
-- paragraph
s = styleParagraph(s)
s = s:gsub("<p></p>", "")
-- line breaks -- line breaks
s = s:gsub("\r?\n", "<br>") s = s:gsub("\r?\n", "<br>")
-- remove <br> tags around block elements
local blockTags = { "ul", "ol", "li", "blockquote", "p",
"h1", "h2", "h3", "h4", "h5", "h6", "hr" }
for _, tag in ipairs(blockTags) do
s = s:gsub("(</" .. tag .. ">)<br>", "%1")
s = s:gsub("<br>(</" .. tag .. ">)", "%1")
s = s:gsub("(<" .. tag .. ">)<br>", "%1")
s = s:gsub("<br>(<" .. tag .. ">)", "%1")
end
-- self-closing hr
s = s:gsub("(<hr>)<br>", "%1")
s = s:gsub("<br>(<hr>)", "%1")
-- headers -- headers
s = s:gsub("######%s*(.-)%s*<br>", "<h6>%1</h6>") s = s:gsub("######%s*(.-)%s*<br>", "<h6>%1</h6>")
s = s:gsub("#####%s*(.-)%s*<br>", "<h5>%1</h5>") s = s:gsub("#####%s*(.-)%s*<br>", "<h5>%1</h5>")
@@ -193,25 +255,61 @@ for index, value in ipairs(markdownFiles) do
s = s:gsub("`(.-)`", "<code>%1</code>") s = s:gsub("`(.-)`", "<code>%1</code>")
-- horizontal rule -- horizontal rule
s = s:gsub("%-%-%-", "<hr>") s = s:gsub("%-%-%-", "<hr>")
-- TODO: p for normal text
return s return s
end end
markdownFiles[index].content = styling(markdownFiles[index].content) markdownFiles[index].content = styling(markdownFiles[index].content)
-- replace <!-- sitecontents --> with markdown file content -- start_idx, end_idx = c
local start_idx, end_idx = content:find("<!-- sitecontents -->", 1, true) -- {{pageContent}} shortcode
content = content:gsub("{{pageContent}}", markdownFiles[index].content)
-- {{pageTitle}} shortcode
content = content:gsub("{{pageTitle}}", markdownFiles[index].options["title"])
local start_idx, end_idx
-- list shortcodes
while content:find("{{list:}}", 1, true) do
start_idx, end_idx = content:find("{{list:}}")
if start_idx and end_idx then if start_idx and end_idx then
local first = content:sub(1, start_idx - 1) local first = content:sub(1, start_idx - 1)
local second = content:sub(end_idx + 1) local second = content:sub(end_idx + 1)
content = first .. markdownFiles[index].content .. second if second:find("{{:list}}", 1, true) then
start_idx, end_idx = second:find("{{:list}}")
if start_idx and end_idx then
local shortcode = second:sub(1, start_idx - 1)
local third = second:sub(end_idx + 1)
local function formatShortcode(element)
local dir = markdownFiles[index].filePath:match("(.*)/[^/]+%.md$")
local results = {}
for mdfile in lfs.dir(dir) do
if mdfile:match("%.md$") and mdfile ~= markdownFiles[index].fileName .. ".md" then
local fileName = mdfile:match("(.-)%.md$")
for i, _ in ipairs(markdownFiles) do
if markdownFiles[i].fileName == fileName then
local copy = element
-- replace items starting with list.item.
for option in copy:gmatch("{{list%.item%.(.-)}}") do
local value = markdownFiles[i].options[option]
if value then
copy = copy:gsub("{{list%.item%." .. option .. "}}", value)
end
end
table.insert(results, copy)
end
end
end
end
return table.concat(results, "\n")
end
shortcode = formatShortcode(shortcode)
content = first .. shortcode .. third
end
end end
while content:find("<!-- title -->", 1, true) do
start_idx, end_idx = content:find("<!-- title -->", 1, true)
if start_idx and end_idx then
local first = content:sub(1, start_idx - 1)
local second = content:sub(end_idx + 1)
content = first .. markdownFiles[index].options["title"] .. second
end end
end end
@@ -221,4 +319,4 @@ for index, value in ipairs(markdownFiles) do
print("Error: Cannot create html file for " .. markdownFiles[index].filePath) print("Error: Cannot create html file for " .. markdownFiles[index].filePath)
end end
end end
end