aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/notYetAnotherWiki.lua
diff options
context:
space:
mode:
Diffstat (limited to 'notYetAnotherWiki.lua')
-rwxr-xr-xnotYetAnotherWiki.lua1018
1 files changed, 841 insertions, 177 deletions
diff --git a/notYetAnotherWiki.lua b/notYetAnotherWiki.lua
index da88a52..f53691b 100755
--- a/notYetAnotherWiki.lua
+++ b/notYetAnotherWiki.lua
@@ -1,37 +1,74 @@
1#!/usr/bin/env luajit 1#!/usr/bin/env luajit
2 2
3-- 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. 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 lcmark = require("lcmark") -- https://github.com/jgm/lcmark 6 Normally I define functions and globals at the top, but here I'm interleaving them.
7]]
6 8
9local Lunamark = require("lunamark") -- https://github.com/jgm/lunamark
10local Lpeg = require("lpeg") -- https://www.inf.puc-rio.br/~roberto/lpeg/lpeg.html Lunamark uses this, so we can to.
11local RE = require("re") -- Part of lpeg. https://www.inf.puc-rio.br/~roberto/lpeg/re.html
7 12
8 13
14---------------------------------------------------------------------------------
9-- Some global data. 15-- Some global data.
10local globalData = { 16
11 ['_'] = ' ', ['dlr'] = '$', 17local GlobalMetaData = {
12 ['devuanCinnabarDark'] = '#310202', ['devuanCinnabarLight'] = '#510505', 18 dlr = '$', perc = '%', dot = '.',
13 ['devuanDarkPurpyDark'] = '#33313b', ['devuanDarkPurpyLight'] = '#3c3a45', 19 devuanCinnabarDark = '#310202', devuanCinnabarLight = '#510505',
14 ['devuanDeepSeaDark'] = '#132f40', ['devuanDeepSeaLight'] = '#1a4562', 20 devuanDarkPurpyDark = '#33313b', devuanDarkPurpyLight = '#3c3a45',
15 ['devuanSaphireDark'] = '#004489', ['devuanSaphireLight'] = '#00509f', 21 devuanDeepSeaDark = '#132f40', devuanDeepSeaLight = '#1a4562',
16 ['karenPurple'] = '#8800ff', ['onefangPurple'] = '#cc00ff', 22 devuanSaphireDark = '#004489', devuanSaphireLight = '#00509f',
17 favicon = 'nYAW_icon.png', logo = 'nYAW.png', header = '', --menu = '', 23 devuanDevuanDark = '#000000', devuanDevuanLight = '#ffffff',
18 history = '', footer = 'Powered by <a href="https://sledjhamr.org/cgit/notYetAnotherWiki/about/">notYetAnotherWiki</a> version 0.0. &nbsp;', 24 -- HTML link colours. Naturally HTML5 deprecated the simple version, replacing it with less simple CSS.
25 -- <body> has alink, link, vlink; CSS has active, link, visited, and hover.
26 devuanDevuanalink = '#03a4ff', devuanDevuanlink = '#0076b6', devuanDevuanvlink = '#6aa4db', devuanDevuanhlink = '#03a4ff',
27 devuanSDevuanalink = '#98c3db', devuanSDevuanlink = '#ffffff', devuanSDevuanvlink = '#ffffff', devuanSDevuanhlink = '#98c3db',
28 karenPurple = '#8800ff', onefangPurple = '#cc00ff', onefangGreen = '#42ff00',
29 PinkFloyd = '#AA00AA', DeepPurple = '#220022', -- From an ancient site of mine, which went from PinkFloyd to DeepPurple as a background gradient.
30 favicon = 'nYAW_icon.png', logo = 'nYAW.png',
19} 31}
20local Sites, Files, Subs = {}, {}, {}
21 32
33local Files, Subs, xLinks = {}, {}, {}
34local Context = {} -- Coz can't otherwise pass context through to the deeper Lunamark functions I'm overriding.
35
36local Template = ''
37local h = io.open("default.template", 'r')
38if nil ~= h then
39 Template = h:read('*a')
40 h:close()
41else
42 print('oops! No such file ' .. 'default.template')
43end
22 44
23 45
46---------------------------------------------------------------------------------
24-- Useful functions, part 0. 47-- Useful functions, part 0.
25 48
26-- A simple table.subtable = subtable wont work, you end up with a reference so that changes to the later get applaid to the former. 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.
27local copyTable = function(t, strip) 50local derefiTable = function(t, strip)
28 local argh = {} 51 local argh = {}
29 for l, y in ipairs(t) do if (l ~= y.name) and strip then table.insert(argh, y) end end 52 for l, y in ipairs(t) do if (l ~= y.name) and strip then table.insert(argh, y) end end
30 return argh 53 return argh
31end 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
32 60
33 61
34-- String together the bits array into a path string. 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
35local stringBits = function(l) 72local stringBits = function(l)
36 local bits = {} 73 local bits = {}
37 local last = 1 74 local last = 1
@@ -45,258 +82,885 @@ local stringBits = function(l)
45end 82end
46 83
47 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
48 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
176 end
177 end
178 end
179 end
180 return metadata
181end
182
183
184
185local commonLinky = function(l, body, u, url, beg, en, beg0, en0, bump)
186 if nil == url then
187-- print('OOPS! unknown linky - @' .. l .. '\t\t\t' .. string.sub(body, beg - 9, en) .. ' ' .. string.sub(body, en + 1, en0))
188 else
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)
201 end
202 return beg, en, body, here
203end
204
205
206
207---------------------------------------------------------------------------------
49-- Actually start doing things. 208-- Actually start doing things.
50 209
51-- Scan the subdirectories looking for .md files. 210-- Create the base of everything.md here, so it gets picked up as usual in the file scan.
52local directory = arg[1] 211h = io.open('everything.md', 'w')
53if nil == directory then directory = '.' end 212if nil ~= h then
54if '.' ~= directory then 213 h:close()
55 for l in io.popen('find . -name "*.md" -type f,l -printf "%P\n"'):lines() do 214else
56 Files[string.gsub(l, '%.md$', '')] = {} 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
57 end 258 end
58end 259end
59-- Can add in a distant directory to, for putting it's results in the current directory. 260
60for l in io.popen('find ' .. directory .. ' -name "*.md" -type f,l -printf "%P\n"'):lines() do 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
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)
292 end
293
294 end
295 end
296 end
297end
298
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
357
358 if nil ~= url then
359 if ('pub/' == string.sub(url, 1, 4)) then
360-- FIXME? - evil hack?
361 url = 'Foswiki/' .. url
362--print('FOSWIKI HTM ' .. url)
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))
373 else
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]=]
384 end
385
386 writeString(l .. '_NEW', body)
387 elseif 'PmWiki' == string.sub(l, 1, 6) then
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
441 end
442
443 writeString(l .. '_NEW', body)
444 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')
448 end
449end
450
451if '.' ~= Folder then
452 for l in io.popen('find -L . -name "*.md" -type f,l -printf "%P\n"'):lines() do
453 toFile(string.gsub(l, '%.md$', ''))
454 end
455end
456
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
61 local n = string.gsub(l, '%.md$', '') 459 local n = string.gsub(l, '%.md$', '')
62 if nil == Files[n] then Files[n] = {} end 460 if nil == Files[n] then toFile(n) end
63end 461end
64 462
65-- Gotta figure out all the files and subs first. File and sub metadata comes along for the ride. 463
66Subs[''] = {files = {}, subs = {}, bits = {}} 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 = {}
67for name, file in pairs(Files) do 466for name, file in pairs(Files) do
68 local bitter, path = '', '' 467 local bitter, path = '', ''
69 local bits, bit = stringBits(name) 468 local bits, bit = file.bits, file.bit
70 local ln = #bits 469 local ln = #bits
470 local body, metadata = '', {}
71 471
72 -- Go through our bits, construct Subs with bits. 472 -- Go through our bits, construct Subs with bits.
73 Files[name].bits = bits
74 Files[name].bit = bit
75 if ln > 0 then bitter = bits[1] end 473 if ln > 0 then bitter = bits[1] end
76 if '' ~= bitter then Subs[''].subs[bitter] = bitter end -- "bitter end" was entirely by accident, I'm keeping it. B-) 474 if '' ~= bitter then Subs[''].subs[bitter] = bitter end -- "bitter end" was entirely by accident, I'm keeping it. B-)
77 for i, d in ipairs(bits) do 475 for i, d in ipairs(bits) do
78 if '' ~= path then path = path .. '/' end 476 if '' ~= path then path = path .. '/' end
79 path = path .. d 477 path = path .. d
80 if nil == Subs[path] then Subs[path] = {files = {}, subs = {}} end 478 toSub(path)
81 if i < ln then Subs[path].subs[bits[i + 1]] = bits[i + 1] end 479 if i < ln then
82 Subs[path].bits = copyTable(bits, true) 480 Subs[path].subs[bits[i + 1]] = bits[i + 1]
83 if i < ln then table.remove(Subs[path].bits, #bits) end 481 table.remove(Subs[path].bits, #bits)
482 end
84 end 483 end
85 484
86 -- Start the file parsing here, coz we need it's metadata. 485 if '.md' == string.sub(name, -3, -1) then
87 print('Parsing ' .. name .. '.md') 486 -- This is a metadata only file, no content, stash the matadata.
88 local h = io.open(name .. '.md', 'r') 487
89-- TODO - should bail here on error? 488 metadata = readMdMd(name, metadata)
90 if nil ~= h then file.cm = h:read('*a') ; h:close() else print('oops! No such name ' .. name) end 489 if '.md' == name then toSub(path, 'metadata', metadata)
91 -- Convert the CommonMark to HTML, including the metadata. 490 elseif '/.md' == string.sub(name, -4, -1) then toSub(path, 'metadata', metadata)
92 local body, metadata, err = lcmark.convert(file.cm, "html", {smart = true, yaml_metadata = true, columns = 0}) 491-- else toFile(string.sub(name, 1, -4), 'metadata', metadata)
93 if nil == body then print('oops! ' .. err) 492 else NewMeta[string.sub(name, 1, -4)] = metadata -- Coz we can't add to Files here.
94 elseif '' == body then 493 end
95 -- This is a metadata only file, no content, stash the matadata in it's directory.
96 Subs[path].metadata = metadata
97 Files[name] = nil 494 Files[name] = nil
98 else
99 -- Ordinary md file, stash it's metadata and parsed body.
100 file.metadata = metadata
101 file.body = body
102 table.insert(Subs[path].files, bit)
103 end 495 end
104end 496end
105 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
504end
505
506-- Fix up subs now we have all the file bits.
507for name, file in pairs(Files) do
508 if '.md' ~= string.sub(name, -3, -1) then
509 table.insert(Subs[file.path].files, file.bit)
510 end
511end
512
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
525end
106 526
107 527
528---------------------------------------------------------------------------------
108-- These functions assume the above file and sub scan has completed. 529-- These functions assume the above file and sub scan has completed.
109 530
110-- Which page in this directory should we show? 531-- Which page in this folder should we show?
111-- NOTE - only looking for the .md files we scanned for before, any stray HTML, html, HTM, atd htm files will get ignored. 532-- NOTE - only looking for the .md files we scanned for before, any stray HTML, html, HTM, and htm files will get ignored.
112local whichPage = function(f) 533local whichPage = function(f)
113 local fl = '' 534 local fl = ''
114 if (nil ~= Subs[f]) and (nil ~= Subs[f].files) then 535 if nil ~= Subs[f] then
115 if 1 == #(Subs[f].files) then fl = Subs[f].files[1] .. '.HTML' else 536 if nil ~= Subs[f].whichPage then return Subs[f].whichPage end
116 -- Standard files to search for. 537 if nil ~= Subs[f].files then
117 for i, v in ipairs{'about', 'readme', 'index', 'homepage', 'mainpage', 'webhome'} do 538 if 1 == #(Subs[f].files) then fl = Subs[f].files[1] else
118 for j, w in ipairs(Subs[f].files) do 539 -- Standard files to search for.
119 if v == string.lower(w) then 540 for i, v in ipairs{'about', 'readme', 'index', 'homepage', 'mainpage', 'webhome'} do
120 fl = v .. '.HTML' 541 for j, w in ipairs(Subs[f].files) do
121 break 542 if v == string.lower(w) then
543 fl = w
544 break
545 end
122 end 546 end
547 if '' ~= fl then break end
123 end 548 end
124 if '' ~= fl then break 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
125 end 551 end
126 -- If nothing else, just grab the first one.
127 if ('' == fl) and (nil ~= Subs[f].files[1]) then fl = Subs[f].files[1] end
128 end 552 end
129 end 553 end
554 if '' ~= fl then fl = fl .. '.HTML' ; Subs[f].whichPage = fl end
130 return fl 555 return fl
131end 556end
132 557
133 558
134-- Calculate a link from the source directory to the destination directory. 559-- Figure out the original title and link for the original wiki.
560local whichWiki = function(metadata)
561 local title, link = '', ''
562 if 'PmWiki' == metadata.ogWiki then
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.
135local linkFrom = function(source, dest) 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
136 local depth = 0 582 local depth = 0
137 local link = '' 583 local lnk = ''
138 if source ~= dest then 584 if source ~= dest then
139 for i, v in ipairs(Subs[source].bits) do 585 if nil == Subs[source] then
140 if v ~= Subs[dest].bits[i] then 586-- print('!!!! No idea where to find source ' .. source)
141 depth = i 587 return 'DUNNO'
142 break 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'
143 end 595 end
144 end 596 end
145 depth = #(Subs[source].bits) - depth 597 local s = Subs[source].bits
146 depth = depth + 1 598 local d = Subs[dest].bits
147 link = string.rep('../', depth) 599 local sl = #s
148 if (0 == depth) or (depth > #(Subs[dest].bits)) then 600 local dl = #d
149 for i, v in ipairs(Subs[dest].bits) do 601
150 if i >= depth then 602 if 0 == dl then
151 if '' ~= link then link = link .. '/' end 603 depth = sl
152 link = link .. Subs[dest].bits[i] 604 else
605 for i, v in ipairs(s) do
606 if (nil == d[i]) or (v ~= d[i]) then
607 depth = i
608 break
153 end 609 end
154 end 610 end
155 end 611 end
612 -- depth is where they DON'T match.
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
156 end 617 end
157 return link 618 return lnk
158end 619end
159 620
160 621
161 622
623---------------------------------------------------------------------------------
162-- More of this actually doing things nonsense. 624-- More of this actually doing things nonsense.
163 625
164-- Loop through the files we found and actually create their HTML files. 626-- Create an "everything" page, for URL links to every file.HTML.
627local Bdy = '# All the pages\n\n| page | original page | last edited UTC | \n| --------- | ------- | --------------- | '
628Pages = {}
165for name, file in pairs(Files) do 629for name, file in pairs(Files) do
166 local path, result = '', '' 630 local metadata = derefTable(Files[name].metadata, true)
167 local body, metadata = Files[name].body, Files[name].metadata 631 if ('everything' ~= name) then
168 local bits, bit = Files[name].bits, Files[name].bit 632 local ln, fw, pw, ts = 'DUNNO', '', '', ''
169 local ln = #bits 633 local title, link = whichWiki(metadata)
170 634 link = string.gsub(link, 'https://', 'HTTPS://') -- Prevent this one from being converted.
171 path = table.concat(bits, '/', 1, ln) 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 .. ' |')
172 641
173 if '' ~= body then 642 -- Track our external links.
174 -- Continue the parsing and conversion. Start by turning our parsed body into something the lcmark template system can grock. 643 if (nil ~= metadata.ogBase) and (nil ~= metadata.ogFile) then
175 local bod, err = lcmark.compile_template(body) 644 local n = metadata.ogBase
176 if nil == bod then print('oops! ' .. err) else 645 if 'PmWiki' == metadata.ogWiki then n = n .. '.' else n = n .. '/' end
177 local templateFile = metadata.template 646 xLinks[n .. metadata.ogFile] = file.path
178 if nil == templateFile then templateFile = 'default' end
179 file.template = templateFile .. '.template'
180 end 647 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)
181 662
182 -- Copy any metadata found in parent directories. 663
183 local pth = '' 664-- Loop through Subs, doing whichPage and inheritance.
184 for i, d in ipairs(bits) do 665-- It gets to testing/even/deeper BEFORE it gets to testing/even sometimes. So sort them.
185 if '' ~= pth then pth = pth .. '/' end 666SUBS = {}
186 pth = pth .. d 667for name, sub in pairs(Subs) do
187 if nil ~= Subs[pth] then 668 table.insert(SUBS, sub)
188 if nil ~= Subs[pth].metadata then 669end
189 for m, x in pairs(Subs[pth].metadata) do 670table.sort(SUBS, function(a, b) return (string.lower(a.path) < string.lower(b.path)) end)
190 if nil == metadata[m] then 671for n, sub in pairs(SUBS) do
191 metadata[m] = x 672 local name = sub.path
192 end 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
193 end 685 end
194 end 686 end
195 end 687 end
196 end 688 end
197 -- Root directory needs to be handled separately, for now. 689 end
198 if nil ~= Subs[''].metadata then 690end
199 for m, x in pairs(Subs[''].metadata) do if nil == metadata[m] then metadata[m] = x end end 691
692-- Files inheritance.
693for name, file in pairs(Files) do
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
200 end 700 end
701 end
702end
201 703
202 for m, x in pairs(globalData) do if nil == metadata[m] then metadata[m] = x end end
203 704
204 -- Inherit these images from most recent parent directory that defines them. 705---------------------------------------------------------------------------------
205 for n, y in ipairs{'favicon', 'logo'} do 706-- Setup the lunarmark stuff.
206 local pith = '' 707local LunamarkOpts = {
207 if nil ~= metadata[y] then 708 layout='compact',
208 local pth = '' 709-- This list is copied from the lunamark source code, until I discover a way to discover it. The descriptions are useful to.
209 for m, x in ipairs(bits) do 710 containers=false, -- Put sections in containers (e.g. div or section tags)
210 if '' ~= pth then pth = pth .. '/' end 711 slides=false, -- Like containers, but do not nest them
211 pth = pth .. x 712 startnum=true, -- Start number of an ordered list is significant
212 if (nil ~= Subs[pth].metadata) and (nil ~= Subs[pth].metadata[y]) then pith = pth end 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'
753 else
754 url = link .. '/' .. string.sub(url, 7) .. '.HTML'
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
213 end 768 end
214 if ('' == pith) and (nil ~= Subs[''].metadata) and (nil ~= Subs[''].metadata[y]) then pith = pth end 769 local md
215 if '' == pith then metadata[y] = linkFrom(path, pith) .. globalData[y] 770 if ('fos' == string.sub(p, 9, 11)) or ('Fos' == string.sub(p, 1, 3)) then
216 else metadata[y] = linkFrom(path, pith) .. metadata[y] 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
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
217 end 799 end
218 end 800 end
219 end 801 end
802 end
803 return url
804end
220 805
221 -- Figure out this pages header links. 806function Writer.header(s, level)
222 metadata.header = '' 807 local text = Lunamark.util.rope_to_string(s)
223 for i, f in pairs(Subs[path].subs) do 808-- FIXME - Work around a bug in Lunamark?
224 local pth = path 809 text = RE.gsub(text, "{[\\]}", "")
225 if '' ~= path then pth = path .. '/' end 810 return '<h' .. level .. ' id="' .. RE.gsub(text, '{[ ]}', '_') .. '">' .. text .. ' <a style="font-size: 0.42em;" href="#top">🔼</a></h' .. level .. '>'
226 local fl = whichPage(pth .. f) 811end
227-- if '' == fl then 812local OgWriterLink = Writer.link -- So we can call the original from within mine, we are just changing the URL.
228-- metadata.header = metadata.header .. f .. ' &nbsp; ' 813function Writer.link(lab, url, tit)
229-- else 814 return OgWriterLink(lab, lunaLinky(url), tit)
230 metadata.header = metadata.header .. '<a href="' .. f .. '/' .. fl .. '">' .. f .. '</a> &nbsp; ' 815end
231-- end 816local OgWriterImage = Writer.image
232 end 817function Writer.image(lab, url, tit)
818 return OgWriterImage(lab, lunaLinky(url), tit)
819end
820
821local Parse = Lunamark.reader.markdown.new(Writer, LunamarkOpts)
233 822
234 -- Figure out this pages menu links.
235 metadata.menu = ''
236 if nil ~= Subs[path].files then table.sort(Subs[path].files) end
237 for i, f in ipairs(Subs[path].files) do
238 if name == f then
239 metadata.menu = metadata.menu .. '<p>' .. f .. '</p>'
240 else
241 metadata.menu = metadata.menu .. '<p><a href="' .. f .. '.HTML">' .. f .. '</a></p>'
242 end
243 end
244 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
245 -- Figure out this pages trail links. 833 -- Figure out this pages trail links.
834 metadata.home = linkFrom(file.path, '') .. Subs[''].whichPage
246 metadata.trail = '' 835 metadata.trail = ''
247 for i, b in ipairs(bits) do 836 for i, b in ipairs(bits) do
837 local p = table.concat(bits, '/', 1, i)
248 if i < #bits then 838 if i < #bits then
249 metadata.trail = metadata.trail .. '<a href="' .. linkFrom(path, table.concat(bits, '/', 1, i)) .. whichPage(b) .. '">' .. b .. '</a> &nbsp; ' 839 metadata.trail = metadata.trail .. '<a href="' .. linkFrom(file.path, p) .. Subs[p].whichPage .. '">' .. b .. '</a> &nbsp; &#x1f463; '
250 linkFrom(path, table.concat(bits, '/', 1, i)) 840 linkFrom(file.path, table.concat(bits, '/', 1, i))
251 else 841 else
252 metadata.trail = metadata.trail .. b .. ' &nbsp; ' 842 metadata.trail = metadata.trail .. ' ' .. b
253 end 843 end
254 end 844 end
255-- if '' == metadata.trail then metadata.trail = '<a href="' .. string.rep('../', ln) .. '/' .. whichPage('') .. '">home</a> &nbsp; ' end
256
257 -- Figure out this pages footer links.
258 if nil ~= metadata.pagehistory then metadata.history = '<p>Page&nbsp;<a href="' .. metadata.pagehistory .. '">history</a></p>' end
259 if nil ~= metadata.sourcecode then metadata.footer = '<a href="' .. metadata.sourcecode .. '">source code</a> &nbsp; &nbsp; ' .. metadata.footer end
260 if nil ~= metadata.feedatom then metadata.footer = '<a href="' .. metadata.feedatom .. '">atom feed</a> &nbsp; &nbsp; ' .. metadata.footer end
261 if metadata.footer ~= globalData.footer then metadata.footer = 'Web site ' .. metadata.footer end
262 metadata.footer = '<p>' .. metadata.footer .. '</p>'
263 845
264 -- Apply the template to the body. 846 -- Figure out this pages header links.
265 metadata.body = lcmark.apply_template(bod, metadata) 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
266 860
267 -- Put it all in the template. 861 -- Figure out this pages menu links.
268 local tm = '' 862 metadata.menu = ''
269 if nil ~= file.template then 863 if nil == metadata.title then metadata.title = bit end
270 local h = io.open(file.template, 'r') 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
271 if nil ~= h then 865 for i, f in ipairs(Subs[file.path].files) do
272 tm = tm .. h:read('*a') 866 local title, url = nil, nil
273 h:close() 867 if '' == file.path then
868 title = Files[f].metadata.title
869 url = Files[f].metadata.URL
274 else 870 else
275 print('oops! No such file ' .. file.template) 871 title = Files[file.path .. '/' .. f].metadata.title
872 url = Files[file.path .. '/' .. f].metadata.URL
276 end 873 end
277 874 if nil == title then title = f end
278-- TODO - Um not sure why this is here AND at the top of the loop. Here makes more sense. 875 if bit == f then
279 local template, err = lcmark.compile_template(tm) 876 metadata.menu = metadata.menu .. '<p>' .. title .. '</p>'
280 if nil == template then print('oops! ' .. err) else 877 for j, g in ipairs(file.headers) do
281 result = lcmark.apply_template(template, metadata) 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
282 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
283 else 913 else
284 result = body 914 temp = '/' .. name .. '.md'
285 end 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)
286 958
287 -- Write the file. 959 -- Write the file.
288 if '' ~= result then 960 if '' ~= result then
289 local base = name .. '.HTML' 961-- print('From ' .. name .. '.md -> ' .. base)
290 print('From ' .. name .. '.md -> ' .. base) 962 writeString(name .. '.HTML', result)
291 local a, e = io.open(base, 'w')
292 if nil == a then print('Could not open ' .. base .. ' - ' .. e) else
293 a:write(result)
294 a:close()
295 end
296 end 963 end
297
298 else
299 print('')
300 end 964 end
301end 965end
302 966