aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/notYetAnotherWiki.lua
diff options
context:
space:
mode:
Diffstat (limited to 'notYetAnotherWiki.lua')
-rwxr-xr-xnotYetAnotherWiki.lua1058
1 files changed, 918 insertions, 140 deletions
diff --git a/notYetAnotherWiki.lua b/notYetAnotherWiki.lua
index 0ee0f10..f53691b 100755
--- a/notYetAnotherWiki.lua
+++ b/notYetAnotherWiki.lua
@@ -1,189 +1,967 @@
1#!/usr/bin/env luajit 1#!/usr/bin/env luajit
2 2
3local lcmark = require("lcmark") 3--[[ Read the README file for what this is all about.
4 If there is no README or similar, then you can find the link to the source below.
4 5
5local globalData = {version = '-0.1', header = '', footer = '', menu = '', ['_'] = ' ', ['dlr'] = '$'} 6 Normally I define functions and globals at the top, but here I'm interleaving them.
6local site = {} 7]]
7 8
8local createHTML = function(cm, file) 9local Lunamark = require("lunamark") -- https://github.com/jgm/lunamark
9-- cm = string.gsub(cm, '. ', '.  ') 10local Lpeg = require("lpeg") -- https://www.inf.puc-rio.br/~roberto/lpeg/lpeg.html Lunamark uses this, so we can to.
10 if (nil ~= file) and ('' ~= file) then io.write('Parsing ' .. file .. ' -> ') end 11local RE = require("re") -- Part of lpeg. https://www.inf.puc-rio.br/~roberto/lpeg/re.html
11 local result = '' 12
12 local body, metadata, err = lcmark.convert(cm, "html", {smart = true, yaml_metadata = true, columns = 0}) 13
13 14---------------------------------------------------------------------------------
14 if nil == body then print('oops! ' .. err) else 15-- Some global data.
15 local bod, err = lcmark.compile_template(body) 16
16 if nil == bod then print('oops! ' .. err) else 17local GlobalMetaData = {
17 local templateFile = metadata.template 18 dlr = '$', perc = '%', dot = '.',
18 if nil == file then 19 devuanCinnabarDark = '#310202', devuanCinnabarLight = '#510505',
19 templateFile = nil 20 devuanDarkPurpyDark = '#33313b', devuanDarkPurpyLight = '#3c3a45',
20 else 21 devuanDeepSeaDark = '#132f40', devuanDeepSeaLight = '#1a4562',
21 if nil == templateFile then templateFile = 'default' end 22 devuanSaphireDark = '#004489', devuanSaphireLight = '#00509f',
22 templateFile = templateFile .. '.template' 23 devuanDevuanDark = '#000000', devuanDevuanLight = '#ffffff',
23 for k, v in pairs(globalData) do 24 -- HTML link colours. Naturally HTML5 deprecated the simple version, replacing it with less simple CSS.
24 if nill == metadata[k] then metadata[k] = v else print('metadata already has ' .. k) end 25 -- <body> has alink, link, vlink; CSS has active, link, visited, and hover.
25 end 26 devuanDevuanalink = '#03a4ff', devuanDevuanlink = '#0076b6', devuanDevuanvlink = '#6aa4db', devuanDevuanhlink = '#03a4ff',
26 end 27 devuanSDevuanalink = '#98c3db', devuanSDevuanlink = '#ffffff', devuanSDevuanvlink = '#ffffff', devuanSDevuanhlink = '#98c3db',
27 28 karenPurple = '#8800ff', onefangPurple = '#cc00ff', onefangGreen = '#42ff00',
28 if nil ~= file then 29 PinkFloyd = '#AA00AA', DeepPurple = '#220022', -- From an ancient site of mine, which went from PinkFloyd to DeepPurple as a background gradient.
29 local depth = 0 30 favicon = 'nYAW_icon.png', logo = 'nYAW.png',
30 local base = '' 31}
31 for p in string.gmatch(file, '(%w+)/') do 32
32 depth = depth + 1 33local Files, Subs, xLinks = {}, {}, {}
33 base = p 34local Context = {} -- Coz can't otherwise pass context through to the deeper Lunamark functions I'm overriding.
34 end 35
35 local path = string.sub(file, 1, #base) 36local Template = ''
36 37local h = io.open("default.template", 'r')
37 metadata.header = '' 38if nil ~= h then
38 metadata.menu = '' 39 Template = h:read('*a')
39 local trl = {} 40 h:close()
40 metadata.trail = '' 41else
41 local dir = site[''] 42 print('oops! No such file ' .. 'default.template')
42 local dr, pdr, tr = '', '', '' 43end
43 while nil ~= dir.subs do 44
44 local old = dir 45
45 for m, x in pairs(dir.subs) do 46---------------------------------------------------------------------------------
46 if x == string.sub(file, 1, #x) then 47-- Useful functions, part 0.
47 pdr = pdr .. '/' .. m 48
48 tr = tr .. '../' 49-- A simple table.subtable = subtable wont work, you end up with a reference so that changes to the later get applied to the former.
49 dr = m 50local derefiTable = function(t, strip)
50 dir = site[dr] 51 local argh = {}
51 table.insert(trl, '">' .. m .. '</a> &#x1f463;') 52 for l, y in ipairs(t) do if (l ~= y.name) and strip then table.insert(argh, y) end end
52 break 53 return argh
53 end 54end
55local derefTable = function(t, strip)
56 local argh = {}
57 for l, y in pairs(t) do argh[l] = y end
58 return argh
59end
60
61
62local writeString = function(base, body)
63 local a, e = io.open(base, 'w')
64 if nil == a then print('Could not open ' .. base .. ' - ' .. e) else
65 a:write(body)
66 a:close()
67 end
68end
69
70
71-- String together the bits array into a path string. Or the other way around. lol
72local stringBits = function(l)
73 local bits = {}
74 local last = 1
75 for j = 1, #l do
76 if '/' == string.sub(l, j, j) then
77 table.insert(bits, string.sub(l, last, j - 1))
78 last = j + 1
79 end
80 end
81 return bits, string.sub(l, last)
82end
83
84
85-- Put a value into the Files or Subs table, creating things if needed.
86local toFile = function(name, key, value)
87 if nil == Files[name] then
88 local bits, bit = stringBits(name)
89 local path = ''
90 Files[name] = {}
91 Files[name].headers = {}
92 Files[name].bits = bits
93 Files[name].bit = bit
94 for i, d in ipairs(bits) do
95 if '' ~= path then path = path .. '/' end
96 path = path .. d
97 end
98 Files[name].path = path
99-- Files[name].body = ''
100 if ("Foswiki" == bits[1]) or ("PmWiki" == bits[1]) then Files[name].ogWiki = bits[1] end
101 end
102 if nil ~= key then Files[name][key] = value end
103 for i, v in ipairs{'metadata', 'bits', } do
104 if nil == Files[name][v] then Files[name][v] = {} end
105 end
106 -- Open the files and do the initial cleanups.
107 local body = ''
108 if '.md' ~= string.sub(name, -3, -1) then
109 h = io.open(name .. '.md', 'r')
110 if nil ~= h then
111-- print('Parsing ' .. name .. '.md')
112 Context = Files[name]
113 body = h:read('*a') ; h:close()
114 -- Deal with my typical double spaced sentence endings, and other things.
115 local result = RE.compile( [=[{~
116 (
117 {[.?!]{" "}} -> '%1&nbsp;' / -- '&nbsp;' gets turned into hex 0xA0 by parse(). So feed it another metadata token that gets translated to &nbsp;. Seems we now skip this issue.
118 {[\\]{['"|$]}} -> '%2' / -- Do the same for fixing the \' \" \| etc mess pandoc left.
119 {"[ ]{.foswikiGrayFG}" } -> '' / -- Coz Foswiki sucks. No idea why the next thing didn't catch it.
120 {"[" {([^]])+} "]{.foswiki" {([^FG}])+} "FG}" } -> "<span style='color: %3;'>%2</span>" /
121 {"::: {."[A-Za-z_. ]+"}"} -> '' /
122 {":::"} -> '' /
123 {"-noComment-"} -> ' -- ' /
124 {"| bgcolor=#" {([^ ])+} " " } -> "| <span style='background: #%2;'> bgcolor=#%2 </span> " / -- Deal with debdog's color table.
125 {"[" {([^]])+} ']{style="color: ' {([^}])+} "}" } -> "<span style='color: %3;'>%2</span>" /
126 {"[" {([^]])+} "]{style='color: " {([^}])+} "}" } -> "<span style='color: %3;'>%2</span>" /
127 {"{#"[A-Za-z_]+"}"} -> '' /
128 {"### [[edit](/bin/edit/Main/" {([^%nl])+} } -> '' /
129 {"#"+ " " {([^%nl])+} } -> header /
130 .
131 )* ~}]=], { header = function(a) table.insert(Context.headers, a); return a end } ):match(body)
132 body = result
133-- {"<!--".*"-->"} -> '' /
134-- {"[$]"} -> '$dlr$' / -- Replace $, coz otherwise it confuses things later.
135 body = RE.gsub(body, '{[$]}', '$dlr$')
136-- {"[%]"} -> '$perc$' / -- Gotta be done after the %1's above. otherwise screws things up when included above.
137-- body = RE.gsub(body, '{[%]}', '$perc$') -- Coz otherwise stray % trip up the capture part.
138 end
139 Files[name].body = body
140 end
141end
142local toSub = function(name, key, value)
143 if nil == Subs[name] then
144 local bits, bit = stringBits(name)
145 local path = ''
146 Subs[name] = {}
147 table.insert(bits, bit)
148 Subs[name].bits = bits
149 Subs[name].bit = bit
150 for i, d in ipairs(bits) do
151 if '' ~= path then path = path .. '/' end
152 path = path .. d
153 end
154 Subs[name].path = path
155 end
156 if nil ~= key then Subs[name][key] = value end
157 for i, v in ipairs{'metadata', 'bits', 'files', 'subs'} do
158 if nil == Subs[name][v] then Subs[name][v] = {} end
159 end
160end
161
162
163
164local readMdMd = function(name, metadata)
165 local h1 = io.open(name .. '.md')
166 if nil == h1 then
167-- print('Could not open ' .. name .. '.md')
168 return {}
169 else
170 for l in h1:lines() do
171 for k, v in string.gmatch(l, "(%w+)%s*=%s*(.+)") do
172 if nil == v then
173 print(name .. ' ' .. k)
174 else
175 metadata[k] = v
54 end 176 end
55 if old == dir then break end
56 end
57 table.remove(trl)
58 for m, x in ipairs(trl) do
59 tr = string.sub(tr, 4)
60 trl[m] = '&nbsp;<a href="' .. tr .. x
61 end 177 end
62 metadata.trail = table.concat(trl) 178 end
179 end
180 return metadata
181end
63 182
64 if nil ~= dir.files then 183
65 local l = {} 184
66 for m, x in pairs(dir.files) do table.insert(l, {m = m; x = x}) end 185local commonLinky = function(l, body, u, url, beg, en, beg0, en0, bump)
67 table.sort(l, function(a, b) return (a.m <= b.m) end) 186 if nil == url then
68 for m, x in ipairs(l) do 187-- print('OOPS! unknown linky - @' .. l .. '\t\t\t' .. string.sub(body, beg - 9, en) .. ' ' .. string.sub(body, en + 1, en0))
69 metadata.menu = metadata.menu .. '<p><a href="' .. string.sub(x.x, 1 + #pdr) .. '.HTML">' .. x.m .. '</a></p>\n' 188 else
70 end 189 local md = readMdMd(url, {})
190-- if nil ~= md then
191 if nil ~= md.realURL then url = md.realURL end
192-- end
193 body = string.sub(body, 1, beg - bump) .. url .. string.sub(body, en0 + 1)
194 here = here + string.len(url)
195 end
196 if 1 == bump then
197 here = here + 1
198 beg, en = RE.find(body, [['https://fos.wiki.devuan.org/']], here)
199 else
200 beg, en = RE.find(body, [["'https://wiki.devuan.org/"]], here)
71 end 201 end
72 if nil ~= dir.subs then 202 return beg, en, body, here
73 local l = {} 203end
74 for m, x in pairs(dir.subs) do table.insert(l, {m = m; x = x}) end 204
75 table.sort(l, function(a, b) return (a.m <= b.m) end) 205
76 for m, x in pairs(l) do 206
77 metadata.header = metadata.header .. '<a href="' .. string.sub(x.x, 1 + #pdr) .. '">' .. x.m .. '</a> &nbsp; ' 207---------------------------------------------------------------------------------
208-- Actually start doing things.
209
210-- Create the base of everything.md here, so it gets picked up as usual in the file scan.
211h = io.open('everything.md', 'w')
212if nil ~= h then
213 h:close()
214else
215 print("Can't open everything.md for writing.")
216end
217
218-- Scan the sub folders looking for our files.
219local Folder = arg[1]
220toSub('')
221if nil == Folder then Folder = '.' end
222--GlobalMetaData.root = Folder
223
224--[[ Sort out realURL for symlinked .md.md files.
225 realURL is the generic URL part for this page. By policy it points to whatever is the latest copy / symlink of the original download .md.md.
226 realURL starts out being the path to the downloaded file and friends.
227 If we make a symlink during SuckIt, then that gets updated to point to the place the symlink is in.
228 below we compare timestamps and select the latest version if there's more than one symlink.
229 For the "page symlinked" problem, this should work if realURL is kept updated.
230 For the "page copied" problem, this should work if realURL is kept updated, same as symlinked really, coz that's just another copy.
231 For the "page moved" problem, that'll be the most recent symlink, the old one still has it's symlink pointing to the download .md.md, which gets updated with the current realURL.
232 So when some external old URL points to someplace a page used to be, it's old symlink points to the up to date download .md.md, and we know where to go to find the page now.
233 A left over .md.md file should have a redirect .HTML page created for it.
234]]
235for l in io.popen('find -L ' .. Folder .. ' -name unsorted -prune -o -name "*.md.md" -xtype l -printf "%P\n"'):lines() do
236 local metadata = readMdMd(string.sub(l, 1, -4), {})
237 if nil == metadata.realURL then
238 metadata.realURL = string.sub(l, 1, -7)
239 else
240 if metadata.realURL ~= string.sub(l, 1, -7) then
241 metadata.realURL = string.sub(l, 1, -7)
242 -- If this already exists, compare the timestamps, most recent wins.
243 local time0 = io.popen('ls -l --time-style=+%s "' .. metadata.realURL .. '.md.md" | cut -d \' \' -f 6'):read('l')
244 local time1 = io.popen('ls -l --time-style=+%s "' .. l .. '" | cut -d \' \' -f 6'):read('l')
245 if time0 > time1 then metadata = nil end
246 else metadata = nil end
247 end
248
249 if nil ~= metadata then
250-- DUNNO if this writes to the original file, or overwrites the symlink.
251 local a, e = io.open(l, 'w')
252 if nil == a then print('Could not open ' .. l .. ' - ' .. e) else
253 for k, v in pairs(metadata) do
254 a:write(k .. '=' .. v .. '\n')
255 end
256 a:close()
257 end
258 end
259end
260
261-- Clean up unsorted.
262for l in io.popen('find -L ' .. Folder .. ' -name unsorted -prune -o -name "*.md" -a -not -name "*.md.md" -xtype l -printf "%P\n"'):lines() do
263 local tp = '_fos'
264 local metadata = readMdMd(l, {})
265 if nil ~= metadata then
266 if "PmWiki" == metadata.ogWiki then tp = '_pm' end
267 if nil ~= metadata.ogFile then
268 local unsort = 'unsorted/' .. metadata.ogFile
269 local a, e = io.open(unsort .. tp .. '.md' , 'r')
270 if nil ~= a then
271 a:close()
272 -- Keep the .md.md symlink, delete the rest.
273 os.execute('rm ' .. unsort .. tp .. '.HTML')
274 os.execute('rm ' .. unsort .. tp .. '.md')
275 a, e = io.open(unsort .. tp .. '.HTML', 'w')
276 if nil == a then print('Could not open ' .. unsort .. tp .. '.HTML' .. ' - ' .. e) else
277 local dst = string.sub(l, 1, -4) .. '.HTML'
278 local cnt = 1
279 for j = 1, #metadata.ogFile do
280 if '/' == string.sub(metadata.ogFile, j, j) then cnt = cnt + 1 end
78 end 281 end
282 dst = string.rep('../', cnt) .. dst
283 a:write(
284[=[<!DOCTYPE html>
285<html>
286 <head><meta http-equiv="refresh" content="0; url=]=] .. dst .. '"' .. [=[/></head>
287 <body><p>Click this if you don't get redirected to the real page - <a href="]=] .. dst .. '"' .. [=[>Redirect</a></p></body>
288</html>
289]=])
290 a:close()
291 print('REDIRECT ' .. unsort .. tp .. '.HTML \t-> ' .. dst)
79 end 292 end
293
80 end 294 end
295 end
296 end
297end
81 298
82 metadata.body = lcmark.apply_template(bod, metadata) 299-- Look for copied pages from the other wikis.
300for l in io.popen('find -L ' .. Folder .. ' -name "*.HTM" -type f,l -printf "%P\n"'):lines() do
301-- Only do this if .HTM is newer than .md, or .md doesn't exist.
302 local htime = io.popen("date -ur " .. l .. " +%s"):read('l')
303 local mtime = io.popen("date -ur " .. string.sub(l, 1, -4) .. "md +%s 2>/dev/null"):read('l')
304 if (nil == mtime) or (htime > mtime) then
305 print('pandoc converting ' .. l .. ' -> ' .. string.sub(l, 1, -4) .. 'md')
306os.execute('cp ' .. l .. ' ' .. l .. '_ORIGINAL0')
307 -- Open the HTM files and do the initial cleanups, then pandoc them.
308 h = io.open(l, 'r')
309 if nil ~= h then
310 local body = h:read('*a') ; h:close()
311writeString(l .. '_ORIGINAL1', body)
312 if 'Foswiki' == string.sub(l, 1, 7) then
313 -- Strip out the actual content.
314 local beg, en = RE.find(body, [['<div id="patternMainContents">']]) if nil ~= beg then body = string.sub(body, en + 1) end
315 beg, en = RE.find(body, [['<div class="patternContent">']]) if nil ~= beg then body = string.sub(body, en + 1) end
316 beg, en = RE.find(body, [['<div class="foswikiTopic">']]) if nil ~= beg then
317 if ' -- ' == string.sub(body, en + 1, en + 4) then
318 beg, en = RE.find(body, '[%nl]', en + 4)
319 body = string.sub(body, en + 1)
320 end
321 end
322 beg, en = RE.find(body, [['<div class="patternInfo">']]) if nil ~= beg then body = string.sub(body, 1, beg - 1) end
323-- beg, en = RE.find(body, [['<div class="foswikiForm foswikiFormStep">']]) if nil ~= beg then body = string.sub(body, 1, en + 1) end
324 beg, en = RE.find(body, [['<div class="foswikiAttachments foswikiFormStep" style="overflow:auto">']]) if nil ~= beg then body = string.sub(body, 1, beg - 1) end
325 beg, en = RE.find(body, [['<div class="foswikiSearchResultsPager">']]) if nil ~= beg then body = string.sub(body, 1, beg - 1) end
326 -- Some clean ups.
327 local result = RE.compile( [[{~
328 (
329 {'class="foswikiCurrentTopicLink"'} -> blank /
330 {'class="foswikiNewLink"'} -> blank /
331 {"<span class='foswikiSmall'><a href='/bin/edit/Main/" ([^;action=form])* ";action=form'>edit</a></span>"} -> blank /
332 {" -- "} -> '-noComment-' /
333-- {"-- " ([^%nl])* } -> blank /
334 {'<div class="foswikiTopic">'} -> blank /
335 {'rel="nofollow"'} -> blank / {"rel='nofollow'"} -> blank /
336 {"target='_blank'"} -> blank /
337 {"</div>" ([%nl])* } -> blank /
338-- {'style="' ([^"])+ '"'} -> blank / {"style='" ([^'])+ "'"} -> blank /
339 .
340 )* ~}]], { blank = function(a) return '' end } ):match(body)
341 body = result
342-- body = RE.gsub(body, [=[{"<!-- ".*"-->"}]=], '') -- FIXME
343 local here = 1
344 beg, en = RE.find(body, [['https://fos.wiki.devuan.org/']], here)
345 while nil ~= beg do
346 here = beg + 1
347 local beg0, en0
348 local url = nil
349 if '"' == string.sub(body, beg - 1, beg - 1) then
350 beg0, en0 = RE.find(body, [['"']], en)
351 url = string.sub(body, en + 1, en0 - 1)
352 end
353 if "'" == string.sub(body, beg - 1, beg - 1) then
354 beg0, en0 = RE.find(body, [["'"]], en)
355 url = string.sub(body, en + 1, en0)
356 end
83 357
84 local tm = '' 358 if nil ~= url then
85 if nil ~= templateFile then 359 if ('pub/' == string.sub(url, 1, 4)) then
86 local h = io.open(templateFile, 'r') 360-- FIXME? - evil hack?
87 if nil ~= h then 361 url = 'Foswiki/' .. url
88 tm = tm .. h:read('*a') 362--print('FOSWIKI HTM ' .. url)
89 h:close() 363 else
364 url = nil
365 end
366 end
367--print('HTM0 ' .. string.sub(body, beg, en + 84) .. ' \t\t')
368 beg, en, body, here = commonLinky(l, body, 'https://fos.wiki.devuan.org/', url, beg, en, beg0, en0, 1)
369--if nil ~= en then print('HTM1 ' .. string.sub(body, beg, en + 84) .. ' \t\t') end
370--[=[
371 if nil == url then
372 print('OOPS! unknown linky - @' .. l .. '\t\t\t' .. string.sub(body, beg - 9, en) .. ' ' .. string.sub(body, en + 1, en0))
90 else 373 else
91 print('oops! No such file ' .. templateFile) 374-- print(' linky - @' .. l .. '\t\t\t' .. string.sub(body, beg - 9, en) .. ' ' .. string.sub(body, en + 1, en0) .. ' -> ' .. url)
375 local md = readMdMd(url, {})
376-- if nil ~= md then
377 if nil ~= md.realURL then url = md.realURL end
378-- end
379 body = string.sub(body, 1, beg - 1) .. url .. string.sub(body, en0 + 1)
380 here = here + #url
381 end
382 beg, en = RE.find(body, [['https://fos.wiki.devuan.org/']], here)
383]=]
92 end 384 end
93 385
94 local template, err = lcmark.compile_template(tm) 386 writeString(l .. '_NEW', body)
95 if nil == template then print('oops! ' .. err) else 387 elseif 'PmWiki' == string.sub(l, 1, 6) then
96 result = lcmark.apply_template(template, metadata) 388 local beg, en = RE.find(body, [['<!--PageText-->']]) if nil ~= beg then body = string.sub(body, en + 2) end
389 beg, en = RE.find(body, [["div id='wikitext'>"]]) if nil ~= beg then body = string.sub(body, en + 2) end
390 beg, en = RE.find(body, [["<div id='printfoot'>"]]) if nil ~= beg then body = string.sub(body, 1, beg - (2 + 9)) end -- There's a </div> to get rid of to.
391 beg, en = RE.find(body, [['<!--HTMLFooter-->']]) if nil ~= beg then body = string.sub(body, 1, beg - 2) end
392 local result = RE.compile( [[{~
393 (
394 {"class='categorylink'"} -> blank /
395 {"class='createlink'"} -> blank /
396 {"class='createlinktext'"} -> blank /
397 {"class='escaped'"} -> blank /
398 {"class='diffmarkup'"} -> blank /
399 {"class='selflink'"} -> blank /
400 {"class='urllink'"} -> blank /
401 {"<div class='vspace'></div><hr /> <a class='wikilink' href='https://wiki.devuan.org?n=Profiles." .* ([%nl])* } -> blank /
402 {"<a class='selflink' href='https://wiki.devuan.org?n=Profiles." .* ([%nl])* } -> blank /
403 {"<div class='vspace'></div><hr />"} -> blank /
404 {"<div class='vspace'></div>"} -> blank /
405 {"class='wikilink'"} -> blank /
406 {'rel="nofollow"'} -> blank / {"rel='nofollow'"} -> blank /
407 {"target='_blank'"} -> blank /
408-- {'style="' ([^"])+ '"'} -> blank / {"style='" ([^'])+ "'"} -> blank /
409 {"<span class='hlt " {([a-z])+} "'></span><pre" } -> "<pre class='%2'" /
410 .
411 )* ~}]], { blank = function(a) return '' end } ):match(body)
412 body = result
413-- body = RE.gsub(body, [=["<a " {([^ >])+} " >"]=], "<a %1>")
414-- DONE? - <span class='hlt html'></span><pre style='background-color: #cc00ff;' class='escaped'> ... lines of HTML code ... </pre>
415-- most of the time I'll see <pre class='escaped'>
416-- My own looking glass has several.
417-- Foswiki <pre class='bash'>
418-- CommonMark->HTML ---lua <pre><code class="language-lua"> .............................. </code></pre>
419-- Seems to be the spec way of doing it.
420-- most of the time I'll see <pre><code>
421
422 here = 1
423 beg, en = RE.find(body, [["'https://wiki.devuan.org/"]], here)
424 while nil ~= beg do
425 here = beg + 1
426 local beg0, en0 = RE.find(body, [["'"]], en)
427-- FIXME? - This might be working around a bug elsewhere.
428 if "'" == string.sub(body, en0, en0) then en0 = en0 - 1 end
429 local url = string.sub(body, en + 1, en0)
430 if '?n=' == string.sub(url, 1, 3) then
431 url = string.sub(url, 4):gsub('[%a]+%.([%a-]+)', '%1_pm.HTML')
432 elseif ("'" == url) or ('uploads/' == string.sub(url, 1, 8)) then
433-- FIXME - evil hack? Yep, evil hack, need to know the depth of the source, which isn't here.
434 url = 'PmWiki/' .. url
435 else
436 url = nil
437 end
438--print('HTM0 ' .. string.sub(body, beg, en + 84) .. ' \t\t')
439 beg, en, body, here = commonLinky(l, body, "'https://wiki.devuan.org/", url, beg, en, beg0, en0, 0)
440--if nil ~= en then print('HTM1 ' .. string.sub(body, beg, en + 84) .. ' \t\t') end
97 end 441 end
98 else 442
99 result = body 443 writeString(l .. '_NEW', body)
100 end 444 end
101 end 445 end
446
447 ok, rslt, status = os.execute('pandoc --wrap=preserve -f html -t commonmark_x --self-contained ' .. l .. '_NEW' .. ' >' .. string.sub(l, 1, -4) .. 'md')
102 end 448 end
449end
103 450
104 if ('' ~= result) and (nil ~= file) then 451if '.' ~= Folder then
105 local base = string.gsub(file, '%.md$', '') 452 for l in io.popen('find -L . -name "*.md" -type f,l -printf "%P\n"'):lines() do
106 print(base .. '.HTML') 453 toFile(string.gsub(l, '%.md$', ''))
107 local a, e = io.open(base .. '.HTML', 'w') 454 end
108 if nil == a then print('Could not open ' .. base .. '.HTML - ' .. e) else 455end
109 a:write(result) 456
110 a:close() 457-- Can add in a distant folder to, for putting it's results in the current folder.
458for l in io.popen('find -L ' .. Folder .. ' -name "*.md" -type f,l -printf "%P\n"'):lines() do
459 local n = string.gsub(l, '%.md$', '')
460 if nil == Files[n] then toFile(n) end
461end
462
463
464-- Gotta figure out all the files and subs first. File and sub metadata comes along for the ride, coz we need them later.
465local NewMeta = {}
466for name, file in pairs(Files) do
467 local bitter, path = '', ''
468 local bits, bit = file.bits, file.bit
469 local ln = #bits
470 local body, metadata = '', {}
471
472 -- Go through our bits, construct Subs with bits.
473 if ln > 0 then bitter = bits[1] end
474 if '' ~= bitter then Subs[''].subs[bitter] = bitter end -- "bitter end" was entirely by accident, I'm keeping it. B-)
475 for i, d in ipairs(bits) do
476 if '' ~= path then path = path .. '/' end
477 path = path .. d
478 toSub(path)
479 if i < ln then
480 Subs[path].subs[bits[i + 1]] = bits[i + 1]
481 table.remove(Subs[path].bits, #bits)
111 end 482 end
112 else
113 print('')
114 end 483 end
115 return result 484
485 if '.md' == string.sub(name, -3, -1) then
486 -- This is a metadata only file, no content, stash the matadata.
487
488 metadata = readMdMd(name, metadata)
489 if '.md' == name then toSub(path, 'metadata', metadata)
490 elseif '/.md' == string.sub(name, -4, -1) then toSub(path, 'metadata', metadata)
491-- else toFile(string.sub(name, 1, -4), 'metadata', metadata)
492 else NewMeta[string.sub(name, 1, -4)] = metadata -- Coz we can't add to Files here.
493 end
494 Files[name] = nil
495 end
496end
497
498-- FIXED - Lua doesn't like modifying the thing you are pair()ing, like we want to do in the last loop.
499for name, file in pairs(NewMeta) do
500 if nil == Files[name] then toFile(name) end
501 for k, v in pairs(file) do
502 if nil == Files[name].metadata[k] then Files[name].metadata[k] = v end
503 end
116end 504end
117 505
118local directory = arg[1] 506-- Fix up subs now we have all the file bits.
119if nil == directory then directory = '.' end 507for name, file in pairs(Files) do
120local all = {} 508 if '.md' ~= string.sub(name, -3, -1) then
121if '.' ~= directory then 509 table.insert(Subs[file.path].files, file.bit)
122 for l in io.popen('find . -name "*.md" -type f,l -printf "%P\n"'):lines() do
123 all[l] = l
124 end 510 end
125end 511end
126for l in io.popen('find ' .. directory .. ' -name "*.md" -type f,l -printf "%P\n"'):lines() do 512
127 if nil == all[l] then all[l] = l end 513-- Find empty subs.
514for name, sub in pairs(Subs) do
515 if 0 == #sub.files then
516 print("EMPTY " .. name)
517 h = io.open(name .. '/index.md', 'w')
518 if nil ~= h then
519 h:write('This folder has no files.')
520 h:close()
521 else
522 print("Can't open " .. name .. '/index.md for writing.')
523 end
524 end
128end 525end
129 526
130for i, l in pairs(all) do
131 local dir = ''
132 local files, subs = {}, {}
133 local c, parent = 1, ''
134 527
135 for p in string.gmatch(l, '(%w+)/') do 528---------------------------------------------------------------------------------
136 if '' == dir then 529-- These functions assume the above file and sub scan has completed.
137 dir = p 530
138 if nil ~= site[dir] then 531-- Which page in this folder should we show?
139 subs = site[dir].subs 532-- NOTE - only looking for the .md files we scanned for before, any stray HTML, html, HTM, and htm files will get ignored.
140 files = site[dir].files 533local whichPage = function(f)
534 local fl = ''
535 if nil ~= Subs[f] then
536 if nil ~= Subs[f].whichPage then return Subs[f].whichPage end
537 if nil ~= Subs[f].files then
538 if 1 == #(Subs[f].files) then fl = Subs[f].files[1] else
539 -- Standard files to search for.
540 for i, v in ipairs{'about', 'readme', 'index', 'homepage', 'mainpage', 'webhome'} do
541 for j, w in ipairs(Subs[f].files) do
542 if v == string.lower(w) then
543 fl = w
544 break
545 end
546 end
547 if '' ~= fl then break end
548 end
549 -- If nothing else, just grab the first one.
550 if ('' == fl) and (nil ~= Subs[f].files[1]) then fl = Subs[f].files[1] end
141 end 551 end
142 end 552 end
553 end
554 if '' ~= fl then fl = fl .. '.HTML' ; Subs[f].whichPage = fl end
555 return fl
556end
557
143 558
144 local path = string.sub(l, 1, -1 - #(string.gsub(l, '.*/', ''))) 559-- Figure out the original title and link for the original wiki.
145 if nil ~= site[parent] then 560local whichWiki = function(metadata)
146 if nil == site[parent].subs then site[parent].subs = {} end 561 local title, link = '', ''
147 site[parent].subs[p] = path 562 if 'PmWiki' == metadata.ogWiki then
148 elseif 1 == c then subs[p] = path 563 title = metadata.ogBase .. '.' .. metadata.ogFile
564 link = metadata.ogURL .. '/?n=' .. metadata.ogBase .. '.' .. metadata.ogFile
565 end
566 if 'Foswiki' == metadata.ogWiki then
567 title = metadata.ogBase .. '/' .. metadata.ogFile
568 link = metadata.ogURL .. '/' .. metadata.ogBase .. '/' .. metadata.ogFile
569 end
570 return title, link
571end
572
573
574-- Calculate a link from the source folder to the destination folder.
575local linkFrom = function(source, dest)
576 -- Evil hacks!
577 if 'Profiles' == dest then dest = 'PmWiki/Profiles' end
578 if 'Onefang' == dest then dest = 'PmWiki/Onefang' end
579 if 'Tiki' == dest then dest = 'PmWiki/Tiki' end
580
581 if source == dest then return '' end
582 local depth = 0
583 local lnk = ''
584 if source ~= dest then
585 if nil == Subs[source] then
586-- print('!!!! No idea where to find source ' .. source)
587 return 'DUNNO'
588 end
589 if nil == Subs[dest] then
590 if dest == Subs[source].bit then
591 return ''
592 else
593-- print('!!!! No idea where to find dest ' .. dest .. ' from ' .. Subs[source].path .. ' / ' .. Subs[source].bit)
594 return 'DUNNO'
595 end
596 end
597 local s = Subs[source].bits
598 local d = Subs[dest].bits
599 local sl = #s
600 local dl = #d
601
602 if 0 == dl then
603 depth = sl
149 else 604 else
150 if ('' ~= parent) and (dir == parent) then subs[p] = path end 605 for i, v in ipairs(s) do
151 site[parent] = {subs = {[p] = path}} 606 if (nil == d[i]) or (v ~= d[i]) then
607 depth = i
608 break
609 end
610 end
152 end 611 end
153 c = c + #p + 1 612 -- depth is where they DON'T match.
154 parent = p 613 local m = depth - 1
614 if 0 > m then m = 0 end
615 lnk = string.rep('../', sl - m)
616 if 0 ~= (m + 1) then lnk = lnk .. table.concat(d, '/', m + 1, dl) end
155 end 617 end
618 return lnk
619end
620
621
622
623---------------------------------------------------------------------------------
624-- More of this actually doing things nonsense.
156 625
157 if (1 == c) and (nil ~= site[dir]) then 626-- Create an "everything" page, for URL links to every file.HTML.
158 subs = site[dir].subs 627local Bdy = '# All the pages\n\n| page | original page | last edited UTC | \n| --------- | ------- | --------------- | '
159 files = site[dir].files 628Pages = {}
629for name, file in pairs(Files) do
630 local metadata = derefTable(Files[name].metadata, true)
631 if ('everything' ~= name) then
632 local ln, fw, pw, ts = 'DUNNO', '', '', ''
633 local title, link = whichWiki(metadata)
634 link = string.gsub(link, 'https://', 'HTTPS://') -- Prevent this one from being converted.
635 if 'PmWiki' == metadata.ogWiki then pw = 'PmWiki [' .. title .. '](' .. link .. ')' end
636 if 'Foswiki' == metadata.ogWiki then fw = 'Foswiki [' .. title .. '](' .. link .. ')' end
637 if nil ~= metadata.timestamp then ts = metadata.timestamp end
638 if nil ~= file.bit then ln = file.bit
639 end
640 table.insert(Pages, '\n| [' .. name .. '](<' .. name .. '.HTML>) | ' .. fw .. ' ' .. pw .. ' | ' .. ts .. ' |')
641
642 -- Track our external links.
643 if (nil ~= metadata.ogBase) and (nil ~= metadata.ogFile) then
644 local n = metadata.ogBase
645 if 'PmWiki' == metadata.ogWiki then n = n .. '.' else n = n .. '/' end
646 xLinks[n .. metadata.ogFile] = file.path
647 end
160 end 648 end
649end
650table.sort(Pages, function(a, b) return (string.lower(a) < string.lower(b)) end)
651for i, f in ipairs(Pages) do
652 Bdy = Bdy .. f
653end
654h = io.open('everything.md', 'a+')
655if nil ~= h then
656 h:write(Bdy)
657 h:close()
658else
659 print("Can't open everything.md for writing.")
660end
661toFile('everything', 'body', Bdy)
161 662
162 local base = string.gsub(string.sub(l, c, -1), '%.md$', '') 663
163 if nil ~= site[parent] then site[parent].files[base] = string.sub(l, 1, -4) 664-- Loop through Subs, doing whichPage and inheritance.
164 elseif 1 == c then files[base] = string.sub(l, 1, -4) 665-- It gets to testing/even/deeper BEFORE it gets to testing/even sometimes. So sort them.
165 else 666SUBS = {}
166 if ('' ~= parent) and (dir == parent) then files[base] = string.sub(l, 1, -4) end 667for name, sub in pairs(Subs) do
167 site[parent] = {files = {[base] = string.sub(l, 1, -4)}} 668 table.insert(SUBS, sub)
669end
670table.sort(SUBS, function(a, b) return (string.lower(a.path) < string.lower(b.path)) end)
671for n, sub in pairs(SUBS) do
672 local name = sub.path
673 sub.whichPage = whichPage(name)
674 local metadata = sub.metadata
675 for i, s in pairs(sub.subs) do
676 local nm = i
677 if '' ~= name then nm = name .. '/' .. i end
678 for k, v in pairs(metadata) do
679 if nil == Subs[nm].metadata[k] then
680 if ('favicon' == k) or ('logo' == k) then
681 Subs[nm].metadata[k] = linkFrom(nm, name) .. v
682 else
683 if 'hidden' ~= k then -- Don't inherit hidden.
684 Subs[nm].metadata[k] = v
685 end
686 end
687 end
688 end
168 end 689 end
690end
169 691
170-- FIXME - still some minor bug somewhere, this fixes that, but causes other problems. Meh, I can live with excess empty subs tables. 692-- Files inheritance.
171-- if (nil ~= subs) and (0 == #subs) then subs = nil end 693for name, file in pairs(Files) do
172 site[dir] = {files = files, subs = subs} 694 if '' ~= file.body then
695 local mdata = Subs[file.path].metadata
696 for k, v in pairs(mdata) do
697 if nil == file.metadata[k] then
698 Files[name].metadata[k] = v
699 end
700 end
701 end
173end 702end
174 703
175for k, v in pairs(site) do 704
176 if nil ~= v.files then 705---------------------------------------------------------------------------------
177 for m, x in pairs(v.files) do 706-- Setup the lunarmark stuff.
178 local file = x .. '.md' 707local LunamarkOpts = {
179 local h = io.open(file, 'r') 708 layout='compact',
180 if nil ~= h then 709-- This list is copied from the lunamark source code, until I discover a way to discover it. The descriptions are useful to.
181 createHTML(h:read('*a'), file) 710 containers=false, -- Put sections in containers (e.g. div or section tags)
182 h:close() 711 slides=false, -- Like containers, but do not nest them
712 startnum=true, -- Start number of an ordered list is significant
713 smart=false, -- Smart typography (quotes, dashes, ellipses)
714 preserve_tabs=true, -- Don't expand tabs to spaces
715 notes=true, -- Footnotes
716 inline_notes=true, -- Inline footnotes
717 definition_lists=true, -- Definition lists
718 citations=true, -- Citations
719 citation_nbsps=true, -- Turn spacing into non-breaking spaces in citations
720 fenced_code_blocks=true, -- Fenced code blocks
721 lua_metadata=true, -- Lua metadata
722 pandoc_title_blocks=true, -- Pandoc style title blocks
723 hash_enumerators=true, -- may be used as ordered list enumerator
724 require_blank_before_blockquote=false,
725 require_blank_before_header=false,
726 require_blank_before_fenced_code_block=false,
727 fancy_lists=true, -- Pandoc style fancy lists
728 task_list=true, -- GitHub-Flavored Markdown task list
729 strikeout=true, -- Strike-through with double tildes
730 mark=true, -- Highlight with double equals
731 subscript=true, -- Subscripted text between tildes
732 superscript=true, -- Superscripted text between circumflexes
733 bracketed_spans=true, -- Spans with attributes
734 fenced_divs=true, -- Divs with attributes
735 raw_attribute=true, -- Raw pass-through on code elements
736 fenced_code_attributes=true, -- Fenced code block attributes
737 link_attributes=true, -- Link attributes
738 pipe_tables=true, -- PHP Markdown Extra pipe table support
739 table_captions=true, -- Table caption syntax extension
740 header_attributes=true, -- Header attributes
741 line_blocks=true, -- Line blocks
742 escaped_line_breaks=true, -- Pandoc-style escaped hard line breaks
743}
744local Writer = Lunamark.writer.html5.new(LunamarkOpts)
745-- Can override the various writer functions, there's something for each of the basic HTML elements.
746local lunaLinky = function(url) -- Fix up the links.
747 if ('https://wiki.devuan.org/' ~= url) and ('https://fos.wiki.devuan.org/' ~= url) then
748 -- TODO - This might be covering up a bug elsewhere.
749 if '/Main/' == string.sub(url, 1, 6) then
750 local link = linkFrom(Context.path, 'Foswiki/Main')
751 if '' == link then
752 url = string.sub(url, 7) .. '.HTML'
183 else 753 else
184 print('oops! No such file ' .. file) 754 url = link .. '/' .. string.sub(url, 7) .. '.HTML'
185 end 755 end
756 end
757 if '/System/' == string.sub(url, 1, 8) then
758 url = 'https://fos.wiki.devuan.org' .. url
759 end
760 for i, p in ipairs{'https://wiki.devuan.org/?n=', 'https://wiki.devuan.org?n=', 'PmWiki/uploads/', 'Foswiki/pub/', 'https://fos.wiki.devuan.org/'} do
761 if p == string.sub(url, 1, #p) then
762 local ur = string.sub(url, #p + 1)
763-- TODO - could probably replace some of this mess with RE.gsub() and friends. Meh, it works.
764 local f4, f5, tk1 = string.find(ur, '?', 1, true)
765 if fail ~= f4 then
766 local u = string.sub(ur, 1, f4 - 1)
767 ur = u
768 end
769 local md
770 if ('fos' == string.sub(p, 9, 11)) or ('Fos' == string.sub(p, 1, 3)) then
771 md = readMdMd('Foswiki/' .. ur .. '.md', {})
772 else
773 md = readMdMd('PmWiki/' .. string.gsub(ur, '%.', '/', 1) .. '.md', {})
774 end
775 if (nil ~= md) and (nil ~= md.realURL) then url = md.realURL end
186 776
777 if ('https://fos.wiki.devuan.org/bin/' ~= string.sub(url, 1, 32)) and ('https://fos.wiki.devuan.org/System/' ~= string.sub(url, 1, 35)) then
778 local xlnk = xLinks[string.gsub(ur, '%..*', '', 1)]
779 if nil == Context.path then
780 url = string.gsub(ur, '%.', '/', 1)
781 else
782 if nil == xlnk then xlnk = string.gsub(string.gsub(ur, '%..*', '', 1), '/.*', '', 1) end
783 if '' ~= Context.path then xlnk = linkFrom(Context.path, xlnk) end
784 if '/' == string.sub(xlnk, 1, 1) then xlnk = string.sub(xlnk, 2) end
785 if ('' ~= xlnk) and ('/' ~= string.sub(xlnk, -1)) then xlnk = xlnk .. '/' end
786 if 'DUNNO/' == xlnk then print('OOPS! page not found - @' .. Context.path .. ' / ' .. Context.bit .. '\t' .. url .. ' -> ' .. xlnk .. ' ' .. string.gsub(ur, '.*%.', '', 1) .. '.HTML') end
787 end
788-- if (nil ~= md) and (nil ~= md.realURL) then url = md.realURL
789-- else
790 url = xlnk .. string.gsub(ur, '.*%.', '', 1)
791-- end
792 if 'PmWiki/uploads/' == p then
793 url = '../../' .. p .. string.gsub(ur, '%.', '.', 1)
794 elseif 'Foswiki/pub/' == p then
795 url = '../../' .. p .. ur
796 else
797 url = url .. '.HTML'
798 end
799 end
800 end
187 end 801 end
188 end 802 end
803 return url
189end 804end
805
806function Writer.header(s, level)
807 local text = Lunamark.util.rope_to_string(s)
808-- FIXME - Work around a bug in Lunamark?
809 text = RE.gsub(text, "{[\\]}", "")
810 return '<h' .. level .. ' id="' .. RE.gsub(text, '{[ ]}', '_') .. '">' .. text .. ' <a style="font-size: 0.42em;" href="#top">🔼</a></h' .. level .. '>'
811end
812local OgWriterLink = Writer.link -- So we can call the original from within mine, we are just changing the URL.
813function Writer.link(lab, url, tit)
814 return OgWriterLink(lab, lunaLinky(url), tit)
815end
816local OgWriterImage = Writer.image
817function Writer.image(lab, url, tit)
818 return OgWriterImage(lab, lunaLinky(url), tit)
819end
820
821local Parse = Lunamark.reader.markdown.new(Writer, LunamarkOpts)
822
823
824---------------------------------------------------------------------------------
825-- Loop through the files we found and actually create their HTML files.
826for name, file in pairs(Files) do
827 local body, metadata = Files[name].body, derefTable(Files[name].metadata, true)
828 local bits, bit = Files[name].bits, Files[name].bit
829 local ln = #bits
830 local result = ''
831
832 if '' ~= body then
833 -- Figure out this pages trail links.
834 metadata.home = linkFrom(file.path, '') .. Subs[''].whichPage
835 metadata.trail = ''
836 for i, b in ipairs(bits) do
837 local p = table.concat(bits, '/', 1, i)
838 if i < #bits then
839 metadata.trail = metadata.trail .. '<a href="' .. linkFrom(file.path, p) .. Subs[p].whichPage .. '">' .. b .. '</a> &nbsp; &#x1f463; '
840 linkFrom(file.path, table.concat(bits, '/', 1, i))
841 else
842 metadata.trail = metadata.trail .. ' ' .. b
843 end
844 end
845
846 -- Figure out this pages header links.
847 metadata.header = ''
848 subs = {}
849 for i, f in pairs(Subs[file.path].subs) do
850 table.insert(subs, f)
851 end
852 table.sort(subs, function(a, b) return (string.lower(a) < string.lower(b)) end)
853 for i, f in ipairs(subs) do
854 local pth = file.path
855 if '' ~= file.path then pth = file.path .. '/' end
856 if 'true' ~= Subs[pth .. f].metadata.hidden then
857 metadata.header = metadata.header .. '<a href="' .. f .. '/' .. whichPage(pth .. f) .. '">' .. f .. '</a> &nbsp; &#128194; '
858 end
859 end
860
861 -- Figure out this pages menu links.
862 metadata.menu = ''
863 if nil == metadata.title then metadata.title = bit end
864 if nil ~= Subs[file.path].files then table.sort(Subs[file.path].files, function(a, b) return (string.lower(a) < string.lower(b)) end) end
865 for i, f in ipairs(Subs[file.path].files) do
866 local title, url = nil, nil
867 if '' == file.path then
868 title = Files[f].metadata.title
869 url = Files[f].metadata.URL
870 else
871 title = Files[file.path .. '/' .. f].metadata.title
872 url = Files[file.path .. '/' .. f].metadata.URL
873 end
874 if nil == title then title = f end
875 if bit == f then
876 metadata.menu = metadata.menu .. '<p>' .. title .. '</p>'
877 for j, g in ipairs(file.headers) do
878 local beg, en = RE.find(g, [['{']])
879 if nil ~= beg then
880 g = string.sub(g, 1, beg - 2)
881 end
882 local h = string.sub(RE.gsub(g, '{[#]}', ''), 2)
883 local l = string.len(g) - string.len(h)
884 g = h
885 h = RE.gsub(h, '{[ ]}', '&nbsp;')
886-- FIXME - Work around a bug in Lunamark?
887 g = RE.gsub(g, '{[\\]}', '')
888 h = RE.gsub(h, '{[\\]}', '')
889-- FIXME - if it's a linky, strip off the URL part. The Wiki audit has such things.
890 metadata.menu = metadata.menu .. '<p>' .. string.rep('&nbsp;', l) .. '<a style="font-size: 0.80em;" href="#' .. RE.gsub(g, '{[ ]}', '_') .. '">' .. h .. '</a></p>'
891 end
892 else
893 if nil ~= url then metadata.menu = metadata.menu .. '<p><a href="' .. url .. '">' .. title .. ' &#9757;</a></p>'
894 else
895 local pth = file.path
896 if '' ~= pth then pth = pth .. '/' end
897 -- Don't include any left over .md.md files, so don't do this if f.md doesn't exist.
898 local a, e = io.open(pth .. f .. '.md' , 'r')
899 if nil ~= a then
900 a:close()
901 metadata.menu = metadata.menu .. '<p><a href="' .. f .. '.HTML">' .. title .. '</a></p>'
902 end
903 end
904 end
905 end
906
907 -- Figure out this pages footer links.
908 local temp = ''
909 metadata.footer = ''
910 if nil == metadata.pagehistory then
911 if 'Foswiki' == metadata.ogWiki then metadata.pagehistory = metadata.ogURL .. '/bin/oops/' .. metadata.ogBase .. '/' .. metadata.ogFile .. '?template=oopshistory' end
912 if 'PmWiki' == metadata.ogWiki then metadata.pagehistory = metadata.ogURL .. '/?n=' .. metadata.ogBase .. '.' .. metadata.ogFile .. '?action=diff' end
913 else
914 temp = '/' .. name .. '.md'
915 end
916 if nil ~= metadata.pagehistory then metadata.history = '<p>Page&nbsp;<a href="' .. metadata.pagehistory .. temp .. '">history</a></p>' else
917 metadata.history = ''
918 end
919 if nil ~= metadata.sourcecode then metadata.footer = '<a href="' .. metadata.sourcecode .. '">source code</a>' end
920 if nil ~= metadata.feedatom then metadata.footer = '<a href="' .. metadata.feedatom .. '">atom feed<img src="feed-icon-14x14.png"></img></a> &nbsp; &nbsp; ' .. metadata.footer end
921 if metadata.footer ~= '' then metadata.footer = 'Web site ' .. metadata.footer end
922 -- Add a link to the original page.
923 if nil ~= metadata.ogURL then
924 local title, link = whichWiki(metadata)
925 link = string.gsub(link, 'https://', 'HTTPS://') -- Prevent this one from being converted.
926-- TODO - wrap "edit" in a link to actually edit it. PmWiki "?action=edit" Foswiki "https://fos.wiki.devuan.org/bit/edit/" .. page .. "?t=" .. 10 digit random number?
927 local edit = 'T'
928 if 'PmWiki' == metadata.ogWiki then edit = 'Maybe you can <a href="' .. link .. '?action=edit">edit</a> t' end
929-- if 'Foswiki' == metadata.ogWiki then edit = '' end
930 metadata.footer = edit .. 'he <a href="' .. link .. '">original page</a>. &nbsp; ' .. metadata.footer
931 end
932 metadata.footer = '<p>' .. metadata.footer .. '</p>'
933
934 -- Do our own metadata replacement, it's simple and works better.
935 local temp = Template
936 -- Toss the body in first, so the scan can deal with it to.
937 -- NOTE - this is where we actually parse the markup into HTML.
938 Context = file
939 body = RE.gsub(body, '{[%nl]^1[%a]+}[.]^1 ', '%1$dot$ ') -- Coz otherwise stray . trip up the list detection.
940 local bd, md = Parse(body) -- The md is a table of extracted metadata, not likely to be any, and we wont do anything with it.
941 bd = RE.gsub(bd, '{[%]}', '$perc$') -- Coz otherwise stray % trip up the capture part.
942 temp = RE.gsub(temp, '"$body$"', bd)
943 -- The actual metadata replacement.
944 result = RE.compile ('{~ ({[$][A-Za-z_]+[$]} -> meta / .)* ~}',
945 {
946 meta = function(a)
947 a = string.sub(a, 2, -2)
948 local md = metadata[a]
949 if nil == md then
950 md = GlobalMetaData[a]
951 if nil == md then
952 md = a
953 end
954 end
955 return md
956 end
957 } ):match(temp)
958
959 -- Write the file.
960 if '' ~= result then
961-- print('From ' .. name .. '.md -> ' .. base)
962 writeString(name .. '.HTML', result)
963 end
964 end
965end
966
967