------ generating HTML output --------- -- Although this can be generalized for outputting any format, since the template -- is language-agnostic, this implementation concentrates on HTML. -- This does the actual generation of HTML, and provides support functions in the ldoc -- table for the template -- -- A fair amount of the complexity comes from operating in two basic modes; first, where -- there is a number of modules (classic LuaDoc) or otherwise, where there is only one -- module and the index contains the documentation for that module. -- -- Like LuaDoc, LDoc puts similar kinds of documentation files in their own directories. -- So module docs go into 'modules/', scripts go into 'scripts/', and so forth. LDoc -- generalizes the idea of these project-level categories and in fact custom categories -- can be created (refered to as 'kinds' in the code) local List = require 'pl.List' local utils = require 'pl.utils' local path = require 'pl.path' local stringx = require 'pl.stringx' local template = require 'pl.template' local tablex = require 'pl.tablex' local OrderedMap = require 'pl.OrderedMap' local tools = require 'ldoc.tools' local markup = require 'ldoc.markup' local prettify = require 'ldoc.prettify' local doc = require 'ldoc.doc' local unpack = utils.unpack local html = {} local quit = utils.quit local function cleanup_whitespaces(text) local lines = stringx.splitlines(text) for i = 1, #lines do lines[i] = stringx.rstrip(lines[i]) end lines[#lines + 1] = "" -- Little trick: file should end with newline return table.concat(lines, "\n") end local function get_module_info(m) local info = OrderedMap() for tag in doc.module_info_tags() do local val = m.tags[tag] if type(val)=='table' then val = table.concat(val,',') end tag = stringx.title(tag) info:set(tag,val) end if #info:keys() > 0 then return info end end local escape_table = { ["'"] = "'", ["\""] = """, ["<"] = "<", [">"] = ">", ["&"] = "&" } function html.generate_output(ldoc, args, project) local check_directory, check_file, writefile = tools.check_directory, tools.check_file, tools.writefile local original_ldoc local function save_and_set_ldoc (set) if not set then return end if not original_ldoc then original_ldoc = tablex.copy(ldoc) end for s in set:iter() do local var,val = s:match('([^=]+)=(.+)') local num = tonumber(val) if num then val = num elseif val == 'true' then val = true elseif val == 'false' then val = false end print('setting',var,val) ldoc[var] = val end end local function restore_ldoc () if original_ldoc then ldoc = original_ldoc end end function ldoc.escape(str) return (str:gsub("['&<>\"]", escape_table)) end function ldoc.prettify(str) return prettify.code('lua','usage',str,0,false) end -- Item descriptions come from combining the summary and description fields function ldoc.descript(item) return tools.join(' ', item.summary, item.description) end function ldoc.module_name (mod) local name = mod.name if args.unqualified and (mod.type == 'module' or mod.type == 'classmod') then -- leave out package name = name:gsub('^.-%.','') elseif mod.type == 'topic' then if mod.display_name then name = mod.display_name else -- leave out md extension name = name:gsub('%..*$','') end end return name end -- this generates the internal module/function references function ldoc.href(see) if see.href then -- explict reference, e.g. to Lua manual return see.href elseif doc.Module:class_of(see) then return ldoc.ref_to_module(see) else return ldoc.ref_to_module(see.mod)..'#'..see.name end end -- this is either called from the 'root' (index or single module) or -- from the 'modules' etc directories. If we are in one of those directories, -- then linking to another kind is `../kind/name`; to the same kind is just `name`. -- If we are in the root, then it is `kind/name`. function ldoc.ref_to_module (mod) local base = "" -- default: same directory mod = mod or ldoc.module local kind, module = mod.kind, ldoc.module local name = mod.name -- default: name of module if not ldoc.single then if module then -- we are in kind/ if module.type ~= type then -- cross ref to ../kind/ base = "../"..kind.."/" end else -- we are in root: index base = kind..'/' end else -- single module if mod == ldoc.single then name = ldoc.output if not ldoc.root then base = '../' end elseif ldoc.root then -- ref to other kinds (like examples) base = kind..'/' else if module.type ~= type then -- cross ref to ../kind/ base = "../"..kind.."/" end end end return base..name..'.html' end function ldoc.include_file (file) local text,e = utils.readfile(file) if not text then quit("unable to include "..file) else return text end end -- these references are never from the index...? function ldoc.source_ref (fun) local modname = fun.module.name local pack,name = tools.split_dotted_name(modname) if not pack then name = modname end return (ldoc.single and "" or "../").."source/"..name..'.lua.html#'..fun.lineno end function ldoc.use_li(ls) if #ls > 1 then return '