#!/usr/bin/env luajit -- Read the README file for what this is all about. If there is no README or similar, then you can find the link to the source below. local lcmark = require("lcmark") -- https://github.com/jgm/lcmark -- Some global data. local globalData = { ['_'] = ' ', ['dlr'] = '$', ['devuanCinnabarDark'] = '#310202', ['devuanCinnabarLight'] = '#510505', ['devuanDarkPurpyDark'] = '#33313b', ['devuanDarkPurpyLight'] = '#3c3a45', ['devuanDeepSeaDark'] = '#132f40', ['devuanDeepSeaLight'] = '#1a4562', ['devuanSaphireDark'] = '#004489', ['devuanSaphireLight'] = '#00509f', ['karenPurple'] = '#8800ff', ['onefangPurple'] = '#cc00ff', favicon = 'nYAW_icon.png', logo = 'nYAW.png', header = '', home = '', --menu = '', history = '', footer = 'Powered by notYetAnotherWiki version 0.0.  ', } local Sites, Files, Subs = {}, {}, {} -- Useful functions, part 0. -- A simple table.subtable = subtable wont work, you end up with a reference so that changes to the later get applaid to the former. local copyTable = function(t, strip) local argh = {} for l, y in ipairs(t) do if (l ~= y.name) and strip then table.insert(argh, y) end end return argh end -- String together the bits array into a path string. local stringBits = function(l) local bits = {} local last = 1 for j = 1, #l do if '/' == string.sub(l, j, j) then table.insert(bits, string.sub(l, last, j - 1)) last = j + 1 end end return bits, string.sub(l, last) end -- Actually start doing things. -- Scan the subdirectories looking for .md files. local directory = arg[1] if nil == directory then directory = '.' end if '.' ~= directory then for l in io.popen('find . -name "*.md" -type f,l -printf "%P\n"'):lines() do Files[string.gsub(l, '%.md$', '')] = {} end end -- Can add in a distant directory to, for putting it's results in the current directory. for l in io.popen('find ' .. directory .. ' -name "*.md" -type f,l -printf "%P\n"'):lines() do local n = string.gsub(l, '%.md$', '') if nil == Files[n] then Files[n] = {} end end -- Gotta figure out all the files and subs first. File and sub metadata comes along for the ride. Subs[''] = {files = {}, subs = {}, bits = {}} for name, file in pairs(Files) do local bitter, path = '', '' local bits, bit = stringBits(name) local ln = #bits -- Go through our bits, construct Subs with bits. Files[name].bits = bits Files[name].bit = bit if ln > 0 then bitter = bits[1] end if '' ~= bitter then Subs[''].subs[bitter] = bitter end -- "bitter end" was entirely by accident, I'm keeping it. B-) for i, d in ipairs(bits) do if '' ~= path then path = path .. '/' end path = path .. d if nil == Subs[path] then Subs[path] = {files = {}, subs = {}} end if i < ln then Subs[path].subs[bits[i + 1]] = bits[i + 1] end Subs[path].bits = copyTable(bits, true) if i < ln then table.remove(Subs[path].bits, #bits) end end -- Start the file parsing here, coz we need it's metadata. -- print('Parsing ' .. name .. '.md') local h = io.open(name .. '.md', 'r') -- TODO - should bail here on error? if nil ~= h then file.cm = h:read('*a') ; h:close() else print('oops! No such name ' .. name) end -- Convert the CommonMark to HTML, including the metadata. local body, metadata, err = lcmark.convert(file.cm, "html", {smart = true, yaml_metadata = true, columns = 0}) if nil == body then print('oops! ' .. err) elseif '' == body then -- This is a metadata only file, no content, stash the matadata in it's directory. Subs[path].metadata = metadata Files[name] = nil else -- Ordinary md file, stash it's metadata and parsed body. file.metadata = metadata file.body = body table.insert(Subs[path].files, bit) end end -- These functions assume the above file and sub scan has completed. -- Which page in this directory should we show? -- NOTE - only looking for the .md files we scanned for before, any stray HTML, html, HTM, and htm files will get ignored. local whichPage = function(f) local fl = '' if (nil ~= Subs[f]) and (nil ~= Subs[f].files) then if 1 == #(Subs[f].files) then fl = Subs[f].files[1] else -- Standard files to search for. for i, v in ipairs{'about', 'readme', 'index', 'homepage', 'mainpage', 'webhome'} do for j, w in ipairs(Subs[f].files) do if v == string.lower(w) then fl = w break end end if '' ~= fl then break end end -- If nothing else, just grab the first one. if ('' == fl) and (nil ~= Subs[f].files[1]) then fl = Subs[f].files[1] end end end if '' ~= fl then fl = fl .. '.HTML' end return fl end -- Calculate a link from the source directory to the destination directory. local linkFrom = function(source, dest) local depth = 0 local link = '' if source ~= dest then for i, v in ipairs(Subs[source].bits) do if v ~= Subs[dest].bits[i] then depth = i break end end depth = #(Subs[source].bits) - depth depth = depth + 1 link = string.rep('../', depth) if (0 == depth) or (depth > #(Subs[dest].bits)) then for i, v in ipairs(Subs[dest].bits) do if i >= depth then if '' ~= link then link = link .. '/' end link = link .. Subs[dest].bits[i] end end end end return link end -- More of this actually doing things nonsense. -- Loop through the files we found and actually create their HTML files. for name, file in pairs(Files) do local path, result = '', '' local body, metadata = Files[name].body, Files[name].metadata local bits, bit = Files[name].bits, Files[name].bit local ln = #bits path = table.concat(bits, '/', 1, ln) if '' ~= body then -- Continue the parsing and conversion. Start by turning our parsed body into something the lcmark template system can grock. local bod, err = lcmark.compile_template(body) if nil == bod then print('oops! ' .. err) else local templateFile = metadata.template if nil == templateFile then templateFile = 'default' end file.template = templateFile .. '.template' end -- Copy any metadata found in parent directories. local pth = '' for i, d in ipairs(bits) do if '' ~= pth then pth = pth .. '/' end pth = pth .. d if nil ~= Subs[pth] then if nil ~= Subs[pth].metadata then for m, x in pairs(Subs[pth].metadata) do if nil == metadata[m] then metadata[m] = x end end end end end -- Root directory needs to be handled separately, for now. if nil ~= Subs[''].metadata then for m, x in pairs(Subs[''].metadata) do if nil == metadata[m] then metadata[m] = x end end end for m, x in pairs(globalData) do if nil == metadata[m] then metadata[m] = x end end -- Inherit these images from most recent parent directory that defines them. for n, y in ipairs{'favicon', 'logo'} do local pith = '' if nil ~= metadata[y] then local pth, found = '', false if (nil ~= Subs[''].metadata) and (nil ~= Subs[''].metadata[y]) then pith = '' ; found = true end for m, x in ipairs(bits) do if '' ~= pth then pth = pth .. '/' end pth = pth .. x if (nil ~= Subs[pth].metadata) and (nil ~= Subs[pth].metadata[y]) then pith = pth ; found = true end end if found then metadata[y] = linkFrom(path, pith) .. metadata[y] else metadata[y] = linkFrom(path, pith) .. globalData[y] end end end -- Figure out this pages header links. metadata.header = '' subs = {} for i, f in pairs(Subs[path].subs) do table.insert(subs, f) end table.sort(subs, function(a, b) return (string.lower(a) < string.lower(b)) end) for i, f in ipairs(subs) do local pth = path if '' ~= path then pth = path .. '/' end local fl = whichPage(pth .. f) metadata.header = metadata.header .. '' .. f .. '   ' end -- Figure out this pages menu links. metadata.menu = '' if nil == metadata.title then metadata.title = metadata.pagetitle end if nil == metadata.title then metadata.title = bit end for i, f in ipairs(Subs[path].files) do local title, url = nil, nil if '' == path then title = Files[f].metadata.title url = Files[f].metadata.URL else title = Files[path .. '/' .. f].metadata.title url = Files[path .. '/' .. f].metadata.URL end if nil == title then title = f end if bit == f then metadata.menu = metadata.menu .. '

' .. title .. '

' else if nil ~= url then metadata.menu = metadata.menu .. '

' .. title .. ' ☝

' else metadata.menu = metadata.menu .. '

' .. title .. '

' end end end -- Figure out this pages trail links. metadata.home = linkFrom(path, '') .. whichPage('') metadata.trail = '' for i, b in ipairs(bits) do if i < #bits then metadata.trail = metadata.trail .. '' .. b .. ' 👣   ' linkFrom(path, table.concat(bits, '/', 1, i)) else metadata.trail = metadata.trail .. b .. '   ' end end -- if '' == metadata.trail then metadata.trail = 'home   ' end -- Figure out this pages footer links. if nil ~= metadata.pagehistory then metadata.history = '

Page history

' end if nil ~= metadata.sourcecode then metadata.footer = 'source code     ' .. metadata.footer end if nil ~= metadata.feedatom then metadata.footer = 'atom feed     ' .. metadata.footer end if metadata.footer ~= globalData.footer then metadata.footer = 'Web site ' .. metadata.footer end metadata.footer = '

' .. metadata.footer .. '

' -- Apply the template to the body. metadata.body = lcmark.apply_template(bod, metadata) -- Put it all in the template. local tm = '' if nil ~= file.template then local h = io.open(file.template, 'r') if nil ~= h then tm = tm .. h:read('*a') h:close() else print('oops! No such file ' .. file.template) end -- TODO - Um not sure why this is here AND at the top of the loop. Here makes more sense. local template, err = lcmark.compile_template(tm) if nil == template then print('oops! ' .. err) else result = lcmark.apply_template(template, metadata) end else result = body end -- Write the file. if '' ~= result then local base = name .. '.HTML' -- print('From ' .. name .. '.md -> ' .. base) local a, e = io.open(base, 'w') if nil == a then print('Could not open ' .. base .. ' - ' .. e) else a:write(result) a:close() end end else print('') end end