-- local l = require("pandoc.logging") local read = pandoc.read assert(#arg == 2, "\n" .. "[ERROR] usage: pandoc lua sitemap.lua ") local index_file, output_file = table.unpack(arg) local node_len = 1 local node_list, node_map = {}, {} local function collect (fp) local f = assert(io.open(fp), "\n" .. "[ERROR] could not open " .. fp .. " for reading.") table.insert(node_list, fp) node_map[fp] = { order = #node_list, nodes = {} } if fp:len() > node_len then node_len = fp:len() end -- track node len local data = f:read("a") f:close() local visited = {} read(data):walk({ Link = function (link) if not link.target:find(".%.md$") then return end local f = io.open(link.target) if f == nil then return else f:close() end if visited[link.target] then return end visited[link.target] = true table.insert(node_map[fp]["nodes"], link.target) if not node_map[link.target] then collect(link.target) end end }) end collect(index_file) local L = { L = "<", R = ">", NW = ",", N = "-", NE = ".", W = "|", X = " ", E = "|", SW = "'", S = "-", SE = "'", } local arm_a, arm_b = {}, {} for i,_ in ipairs(node_list) do arm_a[i], arm_b[i] = {}, {} end local arm_row_len = 1 for _,node in ipairs(node_list) do local node_a = node_map[node] for _,node in ipairs(node_a["nodes"]) do local a, b = node_a["order"], node_map[node]["order"] local i_a, i_b = math.min(a,b), math.max(a,b) local arm = a < b and arm_a or arm_b -- find the first free column local col = 1 while true do for i=i_a,i_b do local cell = arm[i][col] if cell ~= nil and cell ~= L.X then col = col + 1 goto continue end end break ::continue:: end col = col == 1 and 2 or col if col > arm_row_len then arm_row_len = col end -- track row len -- layout starting row local row_a = arm[i_a] if row_a[1] == nil or row_a[1] == L.X then row_a[1] = a < b and L.N or L.L end for i=2,col-1 do if row_a[i] == nil or row_a[i] == L.X then row_a[i] = L.N end end row_a[col] = a < b and L.NW or L.NE -- layout rows between start and end for i=i_a+1,i_b-1 do local row_i = arm[i] for j=1,col-1 do if row_i[j] == nil then row_i[j] = L.X end end row_i[col] = L.W end -- layout ending row local row_b = arm[i_b] if row_b[1] == nil or row_b[1] == L.X then row_b[1] = a < b and L.R or L.S end for i=2,col-1 do if row_b[i] == nil or row_b[i] == L.X then row_b[i] = L.S end end row_b[col] = a < b and L.SW or L.SE end end -- construct data lines local lines = {} table.insert(lines, "
") table.insert(lines, "
") table.insert(lines, "

sitemap

") table.insert(lines, "
") table.insert(lines, "
")

for i,node in ipairs(node_list) do
  local line = {}
  local node_padded = ("%-"..node_len.."s"):format(node)
  local node_anchor = node_padded:gsub("(.+)%.md", "%1")
  local row_a, row_b = arm_a[i], arm_b[i]

  -- reverse arm a row
  for j=1,#row_a//2 do
    row_a[j], row_a[#row_a-j+1] = row_a[#row_a-j+1], row_a[j]
  end

  table.insert(line, (("%"..arm_row_len.."s"):format(table.concat(row_a))))
  table.insert(line, ((" %s "):format(node_anchor)))
  table.insert(line, (table.concat(row_b)))
  table.insert(lines, table.concat(line))
end
table.insert(lines, "
") table.insert(lines, "
") local data = table.concat(lines, "\n") -- read existing data from output_file local f = io.open(output_file) local data_old if f then data_old = f:read("a"); f:close() end -- write to output_file if no output_file yet or data changed if not data_old or data ~= data_old then local f = assert(io.open(output_file, "w"), "\n" .. "[ERROR] could not open " .. output_file .. " for writing.") f:write(data) f:close() end