meta = { domain = "compudanzas.net", title = "compudanzas", description = "explorations of computing at a human scale", fecha = os.date("%Y-%m-%d") } webdir = "web" -- web output directory gemdir = "gem" -- gemini output directory templates = { webEn = { header = { path = "pageheader.html", template = ""}, footer = { path = "pagefooter.html", template = ""}, incoming = { path = "pageincoming.html", template = ""} }, webEs = { header = { path = "pageheader.html", template = ""}, footer = { path = "pagefooter_es.html", template = ""}, incoming = { path = "pageincoming_es.html", template = ""} }, gemEn = { header = { path = "pageheader.gmi", template = ""}, footer = { path = "pagefooter.gmi", template = ""}, incoming = { path = "pageincoming.gmi", template = ""} }, gemEs = { header = { path = "pageheader.gmi", template = ""}, footer = { path = "pagefooter_es.gmi", template = ""}, incoming = { path = "pageincoming_es.gmi", template = ""} }, } pages = {} function slugify( s ) return (string.gsub( s, "%s", "_" )) end function spacify( s ) -- opposite of slugify (?) return (string.gsub( s, "_", " ")) end function fillTemplate( template, pagemeta ) return ( string.gsub( template, "({.-})", function (key) local var = string.sub(key,2,-2) -- remove { } return meta[var] or pagemeta[var] end) ) end function getHeader( line ) -- returns title, level local head, title = string.match(line,"^(#+)%s*(.-)$") return title, #head end function getLink( line ) -- returns dest, text return string.match( line, "^=>%s*(%S-)%s+(.-)$") end function isImagePath( text ) return text:match(".jpg$") or text:match(".gif$") or text:match(".png$") end function sanitize( line ) -- replace relevant html entities return line:gsub("<","<"):gsub(">",">") end function closeTags() local close = "" if flags.list then close = "\n" flags.list = false elseif flags.p then close = "
\n" flags.p = false elseif flags.gallery then close = "\n" flags.gallery = false end return close end function insertIncoming( pagename, incomingname ) if incomingname == "pages" then return false end local incoming = pages[pagename].incoming for i = 1, #incoming do if incoming[i] == incomingname then return false end end table.insert( incoming, incomingname) return true end function firstPass() -- load templates for _,t in pairs(templates) do -- read templates for k,subtemp in pairs( t ) do local f = assert(io.open(string.format("templates/%s",subtemp.path),"r")) subtemp.template = f:read("a") f:close() end end -- for each page: -- convert gmo to gmi and html -- and calculate incoming links for name,page in pairs(pages) do local pagemeta = pages[name] local gmopath = string.format("src/%s.gmo", pagemeta.slug) -- open file local f = assert( io.open(gmopath, "r") ) -- initialize flags flags = { list = false, pre = false , p = false, gallery = false } -- table to store the lines to write to file local lines = { web = {}, gem = {} } local navlines = { "%s %s
", ttext, weblink ) pagemeta.gemtranslation = string.format( "%s\n%s\n", ttext, gemlink) end end elseif count == 3 then -- obtain page description pagemeta.pdescription,n = string.gsub(line,"[{}]","") end if count <=2 then goto nextline end -- skip normal processing for the first lines -- CONVERT LINES if string.match( line, "^```") then -- preformated if flags.pre then out.web = "" else out.web = "" end flags.pre = not flags.pre goto insert -- skip more checks end if flags.pre then out.web = sanitize( line ) goto insert end if string.match( line, "^%+") then -- + append html out.gem = nil out.web = string.sub(line,3) -- remove "+ " elseif string.match( line, "^&") then -- & append gemtext out.gem = string.sub(line,3) -- remove "& " elseif string.match( line, "^$") then -- empty line out.web = closeTags() elseif string.match( line, "^#+") then -- HEADERS local title, level = getHeader( line ) -- add h1 to navigation if level==1 then table.insert(navlines,string.format("
%s", close, string.sub(line,3)) elseif string.match( line, "^%*") then -- LIST ITEMS local li = string.format("
%s", webline)
flags.p = true
else
out.web = string.format("
\n%s",webline)
end
-- gem
local gemlinks = {}
local gemline = string.gsub( line, "{(.-)}", function (wikiname)
table.insert(gemlinks, string.format("=> ./%s.gmi %s",pages[wikiname].slug, wikiname))
return wikiname
end)
out.gem = gemline
-- append links if there were any
if #gemlinks > 0 then
out.gem = out.gem.."\n"..table.concat(gemlinks,"\n")
end
end -- paragraphs
::insert:: -- insert line in table
for k,l in pairs(out) do
if l ~= nil then
table.insert( lines[k], l )
end
end
-- skip incoming links calculation if
mode if flags.pre then goto nextline end -- calculate incoming links from outgoing for outname in string.gmatch( line, "{([^ ]?.-[^ ]?)}" ) do insertIncoming( outname, name ) end ::nextline:: count = count + 1 end -- end for line in f:lines() -- finalize html local close = closeTags() if isPre then table.insert( lines.web, "" ) elseif close~="" then table.insert( lines.web, close ) end table.insert( navlines, "
" } -- format list of incoming links for i = 1, #pagemeta.incoming do name = pagemeta.incoming[i] slug = pages[name].slug table.insert( gemlines, string.format("=> ./%s.gmi %s",slug,name) ) table.insert( weblines, string.format("%s ",slug,name) ) end table.insert(weblines,"
") page.gemincoming = table.concat( gemlines, "\n" ) page.webincoming = table.concat( weblines ) else doIncoming = false print( string.format("{%s} is an orphan!", name) ) end -- fill incoming and footer templates and write results for key, out in pairs(pagemeta.outs) do local fo = assert( io.open( out.path, "a" ) ) if doIncoming then fo:write( fillTemplate(out.templates.incoming.template, pagemeta) ) end fo:write( fillTemplate(out.templates.footer.template, pagemeta) ) fo:close() end end end function initPageMetadata( name ) -- return a table with metadata local meta = { incoming = {}, slug = slugify(name), name = name, ptitle = "", pdescription = "", updatedate = "", navcontent = "", gemincoming = "", webincoming = "", gemtranslation = "", webtranslation = "" } meta.outs = { web = { path = string.format("%s/%s.html", webdir, meta.slug) }, gem = { path = string.format("%s/%s.gmi", gemdir, meta.slug) } } -- get update date for file local stat = io.popen(string.format("stat -c %%y src/%s.gmo", meta.slug),"r") local dat = stat:read("l") stat:close() meta.updatedate = string.sub(dat, 1, 10) -- YYYY-MM-DD return meta end function genIndex() local indexpath = "src/pages.gmo" -- initialize and open index file os.execute(string.format("cp templates/index.gmi %s",indexpath)) local index = assert( io.open(indexpath,"a" ) ) -- get gmo files in chronological order local gmofiles = io.popen("ls -t src/*gmo") local count = 0 for filename in gmofiles:lines() do local basename = string.sub(filename, 5, -5) -- remove src/ and .gmo local name = spacify(basename) -- create an entry for each file local entry = string.format("=> ./%s.gmi {%s}\n", basename, name) index:write(entry) -- also initialize each name in the pages table -- initialize page metadata pages[ name ] = initPageMetadata( name ) count = count + 1 end gmofiles:close() index:close() return count end function genLog() -- generate the following log files: -- * twtxt gemini and web -- * atom feed gemini and web -- * gmo log -- * gmisub local logsrc = assert( io.open( "src/log.txt", "r" ) ) local logs = { gemtw = { path = string.format("%s/tw.txt",gemdir), head="templates/twheader.txt" }, webtw = { path = string.format("%s/tw.txt",webdir), head="templates/twheader.txt" }, gmolog = { path = "src/log.gmo", head="templates/logheader.gmi" }, gematom = { path = string.format("%s/atom.xml",gemdir), head="templates/gematomheader.txt" }, webatom = { path = string.format("%s/atom.xml",webdir), head="templates/webatomheader.txt" }, gemfeed = { path = string.format("%s/feed.gmi",gemdir), head="templates/feedheader.gmi" } } -- create and open logs for _,log in pairs(logs) do os.execute(string.format("cp %s %s",log.head,log.path)) log.f = assert( io.open( log.path, "a" ) ) end logs.gematom.f:write(string.format("