diff --git a/generasitio.lua b/generasitio.lua new file mode 100644 index 0000000..c8078eb --- /dev/null +++ b/generasitio.lua @@ -0,0 +1,488 @@ +meta = { + domain = "compudanzas.net", + title = "compudanzas", + description = "explorations of computing at a human scale", + fecha = os.date("%Y-%m-%d") +} + +webdir = "webtest" -- web output directory +gemdir = "gemtest" -- gemini output directory +templates = { + webEn = { + header = { path = "pageheader.html", template = ""}, + footer = { path = "pagefooter.html", template = ""}, + incoming = { path = "pageincoming.html", template = ""} + }, + gemEn = { + header = { path = "pageheader.gmi", template = ""}, + footer = { path = "pagefooter.gmi", template = ""}, + incoming = { path = "pageincoming.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 = {} } + + -- convert one line at a time + local count = 1 + for line in f:lines() do + -- the output line: + local out = { gem = line, web = nil} + + if count == 1 then -- extract title + pagemeta.ptitle = string.match(line, "^#+%s*(.-)$") + elseif count == 2 then -- language + if line == "" then + pagemeta.lang = "en,es-MX" -- default + else + pagemeta.lang, pagemeta.trlang, pagemeta.trname = string.match("^lang=(.-)%s(.-)->(.-)$") + 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 + -- TODO create nav + local title, level = getHeader( line ) + + local close = closeTags() + out.web = string.format("%s%s ",close,level,title,level) + + elseif string.match( line, "^>") then -- BLOCKQUOTE + local close = closeTags() + out.web = string.format("%s%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 + + -- set templates + pagemeta.outs.web.templates = templates.webEn + pagemeta.outs.gem.templates = templates.gemEn + + -- fill templates and write results + for key, out in pairs(pagemeta.outs) do + local fo = assert( io.open( out.path, "w" ) ) + fo:write( fillTemplate(out.templates.header.template, pagemeta) ) + fo:write( table.concat( lines[key],"\n" )) -- content + fo:write( "\n" ) + fo:close() + end + + -- close source file + f:close() + end +end + +function secondPass() -- write incoming links and footer + + for name,page in pairs(pages) do + local pagemeta = page + + local doIncoming = true + if #pagemeta.incoming > 0 then + local gemlines = {} + local weblines = { "
" } + + -- 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 = "", + } + 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") + 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 ) + + end + gmofiles:close() + index:close() +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("diff --git a/templates/pageheader.gmi b/templates/pageheader.gmi new file mode 100644 index 0000000..00b41b0 --- /dev/null +++ b/templates/pageheader.gmi @@ -0,0 +1,2 @@ +# {ptitle} + diff --git a/templates/pageheader.html b/templates/pageheader.html new file mode 100644 index 0000000..0cc7c10 --- /dev/null +++ b/templates/pageheader.html @@ -0,0 +1,29 @@ + + +
+ + + + + + + + + + + + + + + +
+ +