parsav  docpage.t at [b9cf14c14b]

File render/docpage.t artifact 97c704e199 part of check-in b9cf14c14b


-- vim: ft=terra
local page = lib.srv.convo.page
local pstr = lib.mem.ptr(int8)
local pref = lib.mem.ref(int8)
local P = lib.str.plit
local R = lib.str.lit

local topics = lib.util.keys(data.doc)
local topicidxt = {}
table.sort(topics) -- because deterministic builds are good
local branches = {}
for i,k in pairs(topics) do
	topicidxt[k] = i
	local par = data.doc[k].meta.parent
	if par then
		branches[par] = branches[par] or {}
		local br = branches[par]
		br[#br+1] = k
	end
end

local struct pgpair {
	content:page name:pref title:pref
	priv:lib.store.powerset parent:intptr
}
local pages = symbol(pgpair[#topics])
local allpages = {}


for i,v in ipairs(topics) do
	local t = data.doc[v]
	local par = 0
	if t.meta.parent then par = topicidxt[t.meta.parent] end
	local restrict = symbol(lib.store.powerset)
	local setbits = quote restrict:clear() end
	if t.meta.priv then
		if type(t.meta.priv) ~= 'table' then t.meta.priv = {t.meta.priv} end
		for _,v in pairs(t.meta.priv) do
			setbits = quote [setbits]; (restrict.[v] << true) end
		end
	end
	allpages[i] = quote var [restrict]; [setbits] in pgpair {
		name = R(v);
		parent = par;
		priv = restrict;
		title = R(t.meta.title);
		content = page {
			title = ['documentation :: ' .. t.meta.title];
			body = [ t.text ];
			class = P'doc article';
			cache = true;
		};
	} end
end

local terra 
showpage(co: &lib.srv.convo, id: pref)
	var [pages] = array([allpages])
	for i=0,[pages.type.N] do
		if pages[i].name:cmp(id) then
			co:stdpage(pages[i].content)
			return
		end
	end -- else
	co:complain(404,'not found', 'no help article with that identifier is available')
end

local terra 
pushbranches(list: &lib.str.acc, idx: intptr, ps: lib.store.powerset): {}
	var [pages] = array([allpages])
	var started = false
	for i=0,[pages.type.N] do
		if pages[i].parent == idx+1 and (pages[i].priv:sz() == 0 or 
				(ps and pages[i].priv):sz() ~= 0) then
			if not started then
				started = true
				list:lpush('<ul>')
			end
			list:lpush('<li><a href="/doc/'):rpush(pages[i].name):lpush('">')
				:rpush(pages[i].title):lpush('</a>')
			pushbranches(list, i, ps)
			list:lpush('</li>')
		end
	end
	if started then list:lpush('</ul>') end
end

local terra 
render_docpage(co: &lib.srv.convo, pg: pref)
	var nullprivs: lib.store.powerset nullprivs:clear()
	if not pg then -- display index
		var list: lib.str.acc list:compose('<ul>')
		var [pages] = array([allpages])
		for i=0,[pages.type.N] do
			if pages[i].parent == 0 and (pages[i].priv:sz() == 0 or
				(co.aid ~= 0 and (co.who.rights.powers
					and pages[i].priv):sz() > 0)) then
				list:lpush('<li><a href="/doc/'):rpush(pages[i].name):lpush('">')
					:rpush(pages[i].title):lpush('</a>')
				if co.aid ~= 0 then
					pushbranches(&list, i, co.who.rights.powers)
				else
					pushbranches(&list, i, nullprivs)
				end
				list:lpush('</li>')
			end
		end
		list:lpush('</ul>')

		var bp = list:finalize()
		co:stdpage(page {
			title = 'documentation';
			body = bp;
			class = P'doc listing';
			cache = false;
		})
		bp:free()
	else showpage(co, pg) end
end

return render_docpage