diff options
author | Jo-Philipp Wich <jow@openwrt.org> | 2015-01-28 22:27:46 +0100 |
---|---|---|
committer | Jo-Philipp Wich <jow@openwrt.org> | 2015-01-28 22:28:04 +0100 |
commit | c669c01cea36ce09b64a53dc0e597d27411e9c88 (patch) | |
tree | f17a7dc0ba0646743fb760204b9fa925e9efa451 /build | |
parent | e6e74b712fe6fd87cb19e89203e4ef45d7459458 (diff) |
build: add modified luadoc for use with LuCI sources
Signed-off-by: Jo-Philipp Wich <jow@openwrt.org>
Diffstat (limited to 'build')
-rwxr-xr-x | build/luadoc/doc.lua | 126 | ||||
-rw-r--r-- | build/luadoc/luadoc/config.lua | 34 | ||||
-rw-r--r-- | build/luadoc/luadoc/doclet/debug.lua | 46 | ||||
-rw-r--r-- | build/luadoc/luadoc/doclet/formatter.lua | 84 | ||||
-rw-r--r-- | build/luadoc/luadoc/doclet/html.lua | 275 | ||||
-rw-r--r-- | build/luadoc/luadoc/doclet/html/constant.lp | 28 | ||||
-rw-r--r-- | build/luadoc/luadoc/doclet/html/file.lp | 112 | ||||
-rw-r--r-- | build/luadoc/luadoc/doclet/html/function.lp | 64 | ||||
-rw-r--r-- | build/luadoc/luadoc/doclet/html/index.lp | 67 | ||||
-rw-r--r-- | build/luadoc/luadoc/doclet/html/luadoc.css | 285 | ||||
-rw-r--r-- | build/luadoc/luadoc/doclet/html/menu.lp | 55 | ||||
-rw-r--r-- | build/luadoc/luadoc/doclet/html/module.lp | 155 | ||||
-rw-r--r-- | build/luadoc/luadoc/doclet/html/table.lp | 15 | ||||
-rw-r--r-- | build/luadoc/luadoc/doclet/raw.lua | 12 | ||||
-rw-r--r-- | build/luadoc/luadoc/init.lua | 50 | ||||
-rw-r--r-- | build/luadoc/luadoc/lp.lua | 130 | ||||
-rw-r--r-- | build/luadoc/luadoc/taglet/standard.lua | 567 | ||||
-rw-r--r-- | build/luadoc/luadoc/taglet/standard/tags.lua | 191 | ||||
-rw-r--r-- | build/luadoc/luadoc/util.lua | 201 | ||||
-rwxr-xr-x | build/makedocs.sh | 16 |
20 files changed, 2511 insertions, 2 deletions
diff --git a/build/luadoc/doc.lua b/build/luadoc/doc.lua new file mode 100755 index 000000000..383dde29c --- /dev/null +++ b/build/luadoc/doc.lua @@ -0,0 +1,126 @@ +#!/usr/bin/env lua +------------------------------------------------------------------------------- +-- LuaDoc launcher. +-- @release $Id: luadoc.lua.in,v 1.1 2008/02/17 06:42:51 jasonsantos Exp $ +------------------------------------------------------------------------------- + +--local source = debug.getinfo(1).source or "" +--local mypath = source:match("@(.+)/[^/]+") + +--package.path = package.path .. ";" .. mypath .. "/?.lua;" .. mypath .. "/?/init.lua" + +require "luadoc.init" + +------------------------------------------------------------------------------- +-- Print version number. + +local function print_version () + print (string.format("%s\n%s\n%s", + luadoc._VERSION, + luadoc._DESCRIPTION, + luadoc._COPYRIGHT)) +end + +------------------------------------------------------------------------------- +-- Print usage message. + +local function print_help () + print ("Usage: "..arg[0]..[[ [options|files] +Generate documentation from files. Available options are: + -d path output directory path + -t path template directory path + -h, --help print this help and exit + --noindexpage do not generate global index page + --nofiles do not generate documentation for files + --nomodules do not generate documentation for modules + --doclet doclet_module doclet module to generate output + --taglet taglet_module taglet module to parse input code + -q, --quiet suppress all normal output + -v, --version print version information]]) +end + +local function off_messages (arg, i, options) + options.verbose = nil +end + +------------------------------------------------------------------------------- +-- Process options. TODO: use getopts. +-- @class table +-- @name OPTIONS + +local OPTIONS = { + d = function (arg, i, options) + local dir = arg[i+1] + if string.sub (dir, -2) ~= "/" then + dir = dir..'/' + end + options.output_dir = dir + return 1 + end, + t = function (arg, i, options) + local dir = arg[i+1] + if string.sub (dir, -2) ~= "/" then + dir = dir..'/' + end + options.template_dir = dir + return 1 + end, + h = print_help, + help = print_help, + q = off_messages, + quiet = off_messages, + v = print_version, + version = print_version, + doclet = function (arg, i, options) + options.doclet = arg[i+1] + return 1 + end, + taglet = function (arg, i, options) + options.taglet = arg[i+1] + return 1 + end, +} + +------------------------------------------------------------------------------- + +local function process_options (arg) + local files = {} + local options = require "luadoc.config" + local i = 1 + while i <= #arg do + local argi = arg[i] + if string.sub (argi, 1, 1) ~= '-' then + table.insert (files, argi) + else + local opt = string.sub (argi, 2) + if string.sub (opt, 1, 1) == '-' then + opt = string.gsub (opt, "%-", "") + end + if OPTIONS[opt] then + if OPTIONS[opt] (arg, i, options) then + i = i + 1 + end + else + options[opt] = 1 + end + end + i = i+1 + end + return files, options +end + +------------------------------------------------------------------------------- +-- Main function. Process command-line parameters and call luadoc processor. + +function main (arg) + -- Process options + local argc = #arg + if argc < 1 then + print_help () + return + end + local files, options = process_options (arg) + return luadoc.main(files, options) +end + +main(arg) diff --git a/build/luadoc/luadoc/config.lua b/build/luadoc/luadoc/config.lua new file mode 100644 index 000000000..9e4b9de3c --- /dev/null +++ b/build/luadoc/luadoc/config.lua @@ -0,0 +1,34 @@ +------------------------------------------------------------------------------- +-- LuaDoc configuration file. This file contains the default options for +-- luadoc operation. These options can be overriden by the command line tool +-- @see luadoc.print_help +-- @release $Id: config.lua,v 1.6 2007/04/18 14:28:39 tomas Exp $ +------------------------------------------------------------------------------- + +module "luadoc.config" + +------------------------------------------------------------------------------- +-- Default options +-- @class table +-- @name default_options +-- @field output_dir default output directory for generated documentation, used +-- by several doclets +-- @field taglet parser used to analyze source code input +-- @field doclet documentation generator +-- @field template_dir directory with documentation templates, used by the html +-- doclet +-- @field verbose command line tool configuration to output processing +-- information + +local default_options = { + output_dir = "", + taglet = "luadoc.taglet.standard", + doclet = "luadoc.doclet.html", + -- TODO: find a way to define doclet specific options + template_dir = "luadoc/doclet/html/", + nomodules = false, + nofiles = false, + verbose = true, +} + +return default_options diff --git a/build/luadoc/luadoc/doclet/debug.lua b/build/luadoc/luadoc/doclet/debug.lua new file mode 100644 index 000000000..0b75f84cb --- /dev/null +++ b/build/luadoc/luadoc/doclet/debug.lua @@ -0,0 +1,46 @@ +----------------------------------------------------------------- +-- LuaDoc debugging facilities. +-- @release $Id: debug.lua,v 1.3 2007/04/18 14:28:39 tomas Exp $ +----------------------------------------------------------------- + +module "luadoc.doclet.debug" + +function printline() + print(string.rep('-', 79)) +end + +----------------------------------------------------------------- +-- Print debug information about document +-- @param doc Table with the structured documentation. + +function start (doc) + print("Files:") + for _, filepath in ipairs(doc.files) do + print('\t', filepath) + end + printline() + + print("Modules:") + for _, modulename in ipairs(doc.modules) do + print('\t', modulename) + end + printline() + + for i, v in pairs(doc.files) do + print('\t', i, v) + end + printline() + for i, v in pairs(doc.files[doc.files[1]]) do + print(i, v) + end + + printline() + for i, v in pairs(doc.files[doc.files[1]].doc[1]) do + print(i, v) + end + printline() + print("Params") + for i, v in pairs(doc.files[doc.files[1]].doc[1].param) do + print(i, v) + end +end diff --git a/build/luadoc/luadoc/doclet/formatter.lua b/build/luadoc/luadoc/doclet/formatter.lua new file mode 100644 index 000000000..2d725389c --- /dev/null +++ b/build/luadoc/luadoc/doclet/formatter.lua @@ -0,0 +1,84 @@ +------------------------------------------------------------------------------- +-- Doclet to format source code according to LuaDoc standard tags. This doclet +-- (re)write .lua files adding missing standard tags. Texts are formatted to +-- 80 columns and function parameters are added based on code analysis. +-- +-- @release $Id: formatter.lua,v 1.5 2007/04/18 14:28:39 tomas Exp $ +------------------------------------------------------------------------------- + +local util = require "luadoc.util" +local assert, ipairs, pairs, type = assert, ipairs, pairs, type +local string = require"string" +local table = require"table" + +module "luadoc.doclet.formatter" + +options = { + output_dir = "./", +} + +------------------------------------------------------------------------------- +-- Assembly the output filename for an input file. +-- TODO: change the name of this function +function out_file (filename) + local h = filename + h = options.output_dir..h + return h +end + +------------------------------------------------------------------------------- +-- Generate a new lua file for each input lua file. If the user does not +-- specify a different output directory input files will be rewritten. +-- @param doc documentation table + +function start (doc) + local todo = "<TODO>" + + -- Process files + for i, file_doc in ipairs(doc.files) do + -- assembly the filename + local filename = out_file(file_doc.name) + luadoc.logger:info(string.format("generating file `%s'", filename)) + + -- TODO: confirm file overwrite + local f = posix.open(filename, "w") + assert(f, string.format("could not open `%s' for writing", filename)) + + for _, block in ipairs(file_doc.doc) do + + -- write reorganized comments + f:write(string.rep("-", 80).."\n") + + -- description + f:write(util.comment(util.wrap(block.description, 77))) + f:write("\n") + + if block.class == "function" then + -- parameters + table.foreachi(block.param, function (_, param_name) + f:write(util.comment(util.wrap(string.format("@param %s %s", param_name, block.param[param_name] or todo), 77))) + f:write("\n") + end) + + -- return + if type(block.ret) == "table" then + table.foreachi(block.ret, function (_, ret) + f:write(util.comment(util.wrap(string.format("@return %s", ret), 77)).."\n") + end) + else + f:write(util.comment(util.wrap(string.format("@return %s", block.ret or todo), 77)).."\n") + end + end + + -- TODO: usage + -- TODO: see + + -- write code + for _, line in ipairs(block.code) do + f:write(line.."\n") + end + end + + f:close() + end +end diff --git a/build/luadoc/luadoc/doclet/html.lua b/build/luadoc/luadoc/doclet/html.lua new file mode 100644 index 000000000..e77fb7441 --- /dev/null +++ b/build/luadoc/luadoc/doclet/html.lua @@ -0,0 +1,275 @@ +------------------------------------------------------------------------------- +-- Doclet that generates HTML output. This doclet generates a set of html files +-- based on a group of templates. The main templates are: +-- <ul> +-- <li>index.lp: index of modules and files;</li> +-- <li>file.lp: documentation for a lua file;</li> +-- <li>module.lp: documentation for a lua module;</li> +-- <li>function.lp: documentation for a lua function. This is a +-- sub-template used by the others.</li> +-- </ul> +-- +-- @release $Id: html.lua,v 1.29 2007/12/21 17:50:48 tomas Exp $ +------------------------------------------------------------------------------- + +local assert, getfenv, ipairs, loadstring, pairs, setfenv, tostring, tonumber, type = assert, getfenv, ipairs, loadstring, pairs, setfenv, tostring, tonumber, type +local io = require"io" +local posix = require "nixio.fs" +local lp = require "luadoc.lp" +local luadoc = require"luadoc" +local package = package +local string = require"string" +local table = require"table" + +module "luadoc.doclet.html" + +------------------------------------------------------------------------------- +-- Looks for a file `name' in given path. Removed from compat-5.1 +-- @param path String with the path. +-- @param name String with the name to look for. +-- @return String with the complete path of the file found +-- or nil in case the file is not found. + +local function search (path, name) + for c in string.gfind(path, "[^;]+") do + c = string.gsub(c, "%?", name) + local f = io.open(c) + if f then -- file exist? + f:close() + return c + end + end + return nil -- file not found +end + +------------------------------------------------------------------------------- +-- Include the result of a lp template into the current stream. + +function include (template, env) + -- template_dir is relative to package.path + local templatepath = options.template_dir .. template + + -- search using package.path (modified to search .lp instead of .lua + local search_path = string.gsub(package.path, "%.lua", "") + local templatepath = search(search_path, templatepath) + assert(templatepath, string.format("template `%s' not found", template)) + + env = env or {} + env.table = table + env.io = io + env.lp = lp + env.ipairs = ipairs + env.tonumber = tonumber + env.tostring = tostring + env.type = type + env.luadoc = luadoc + env.options = options + + return lp.include(templatepath, env) +end + +------------------------------------------------------------------------------- +-- Returns a link to a html file, appending "../" to the link to make it right. +-- @param html Name of the html file to link to +-- @return link to the html file + +function link (html, from) + local h = html + from = from or "" + string.gsub(from, "/", function () h = "../" .. h end) + return h +end + +------------------------------------------------------------------------------- +-- Returns the name of the html file to be generated from a module. +-- Files with "lua" or "luadoc" extensions are replaced by "html" extension. +-- @param modulename Name of the module to be processed, may be a .lua file or +-- a .luadoc file. +-- @return name of the generated html file for the module + +function module_link (modulename, doc, from) + -- TODO: replace "." by "/" to create directories? + -- TODO: how to deal with module names with "/"? + assert(modulename) + assert(doc) + from = from or "" + + if doc.modules[modulename] == nil then +-- logger:error(string.format("unresolved reference to module `%s'", modulename)) + return + end + + local href = "modules/" .. modulename .. ".html" + string.gsub(from, "/", function () href = "../" .. href end) + return href +end + +------------------------------------------------------------------------------- +-- Returns the name of the html file to be generated from a lua(doc) file. +-- Files with "lua" or "luadoc" extensions are replaced by "html" extension. +-- @param to Name of the file to be processed, may be a .lua file or +-- a .luadoc file. +-- @param from path of where am I, based on this we append ..'s to the +-- beginning of path +-- @return name of the generated html file + +function file_link (to, from) + assert(to) + from = from or "" + + local href = to + href = string.gsub(href, "lua$", "html") + href = string.gsub(href, "luadoc$", "html") + href = "files/" .. href + string.gsub(from, "/", function () href = "../" .. href end) + return href +end + +------------------------------------------------------------------------------- +-- Returns a link to a function or to a table +-- @param fname name of the function or table to link to. +-- @param doc documentation table +-- @param kind String specying the kinf of element to link ("functions" or "tables"). + +function link_to (fname, doc, module_doc, file_doc, from, kind) + assert(fname) + assert(doc) + from = from or "" + kind = kind or "functions" + + if file_doc then + for _, func_name in pairs(file_doc[kind]) do + if func_name == fname then + return file_link(file_doc.name, from) .. "#" .. fname + end + end + end + + if module_doc and module_doc[kind] then + for func_name, tbl in pairs(module_doc[kind]) do + if func_name == fname then + return "#" .. fname + end + end + end + + local _, _, modulename, fname = string.find(fname, "^(.-)[%.%:]?([^%.%:]*)$") + assert(fname) + + -- if fname does not specify a module, use the module_doc + if string.len(modulename) == 0 and module_doc then + modulename = module_doc.name + end + + local module_doc = doc.modules[modulename] + if not module_doc then +-- logger:error(string.format("unresolved reference to function `%s': module `%s' not found", fname, modulename)) + return + end + + for _, func_name in pairs(module_doc[kind]) do + if func_name == fname then + return module_link(modulename, doc, from) .. "#" .. fname + end + end + +-- logger:error(string.format("unresolved reference to function `%s' of module `%s'", fname, modulename)) +end + +------------------------------------------------------------------------------- +-- Make a link to a file, module or function + +function symbol_link (symbol, doc, module_doc, file_doc, from) + assert(symbol) + assert(doc) + + local href = +-- file_link(symbol, from) or + module_link(symbol, doc, from) or + link_to(symbol, doc, module_doc, file_doc, from, "functions") or + link_to(symbol, doc, module_doc, file_doc, from, "tables") + + if not href then + logger:error(string.format("unresolved reference to symbol `%s'", symbol)) + end + + return href or "" +end + +------------------------------------------------------------------------------- +-- Assembly the output filename for an input file. +-- TODO: change the name of this function +function out_file (filename) + local h = filename + h = string.gsub(h, "lua$", "html") + h = string.gsub(h, "luadoc$", "html") + h = "files/" .. h +-- h = options.output_dir .. string.gsub (h, "^.-([%w_]+%.html)$", "%1") + h = options.output_dir .. h + return h +end + +------------------------------------------------------------------------------- +-- Assembly the output filename for a module. +-- TODO: change the name of this function +function out_module (modulename) + local h = modulename .. ".html" + h = "modules/" .. h + h = options.output_dir .. h + return h +end + +----------------------------------------------------------------- +-- Generate the output. +-- @param doc Table with the structured documentation. + +function start (doc) + -- Generate index file + if (#doc.files > 0 or #doc.modules > 0) and (not options.noindexpage) then + local filename = options.output_dir.."index.html" + logger:info(string.format("generating file `%s'", filename)) + local f = posix.open(filename, "w") + assert(f, string.format("could not open `%s' for writing", filename)) + io.output(f) + include("index.lp", { doc = doc }) + f:close() + end + + -- Process modules + if not options.nomodules then + for _, modulename in ipairs(doc.modules) do + local module_doc = doc.modules[modulename] + -- assembly the filename + local filename = out_module(modulename) + logger:info(string.format("generating file `%s'", filename)) + + local f = posix.open(filename, "w") + assert(f, string.format("could not open `%s' for writing", filename)) + io.output(f) + include("module.lp", { doc = doc, module_doc = module_doc }) + f:close() + end + end + + -- Process files + if not options.nofiles then + for _, filepath in ipairs(doc.files) do + local file_doc = doc.files[filepath] + -- assembly the filename + local filename = out_file(file_doc.name) + logger:info(string.format("generating file `%s'", filename)) + + local f = posix.open(filename, "w") + assert(f, string.format("could not open `%s' for writing", filename)) + io.output(f) + include("file.lp", { doc = doc, file_doc = file_doc} ) + f:close() + end + end + + -- copy extra files + local f = posix.open(options.output_dir.."luadoc.css", "w") + io.output(f) + include("luadoc.css") + f:close() +end diff --git a/build/luadoc/luadoc/doclet/html/constant.lp b/build/luadoc/luadoc/doclet/html/constant.lp new file mode 100644 index 000000000..2e35392ad --- /dev/null +++ b/build/luadoc/luadoc/doclet/html/constant.lp @@ -0,0 +1,28 @@ +<% +if module_doc then + from = "modules/"..module_doc.name +elseif file_doc then + from = "files/.."..file_doc.name +else + from = "" +end +%> + +<dt><%=const.private and "local " or ""%><a name="<%=const.name%>"></a><strong><%=const.name:gsub(".+%.","")%></strong></dt> +<dd> +<%=const.description or ""%> + +<%if type(const.see) == "string" then %> +<h3>See also:</h3> + <a href="<%=const.see%>"><%=const.see%></a> +<%elseif type(const.see) == "table" and #const.see > 0 then %> +<h3>See also:</h3> +<ul> + <%for i = 1, #const.see do%> + <li><a href="<%=luadoc.doclet.html.symbol_link(const.see[i], doc, module_doc, file_doc, from)%>"> + <%=const.see[i]:gsub(".+%.","")%> + </a> + <%end%> +</ul +<%end%> +</dd> diff --git a/build/luadoc/luadoc/doclet/html/file.lp b/build/luadoc/luadoc/doclet/html/file.lp new file mode 100644 index 000000000..68f486404 --- /dev/null +++ b/build/luadoc/luadoc/doclet/html/file.lp @@ -0,0 +1,112 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html> +<head> + <title>Reference</title> + <link rel="stylesheet" href="<%=luadoc.doclet.html.link('luadoc.css', 'files/'..file_doc.name)%>" type="text/css" /> + <!--meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/--> +</head> + +<body> +<div id="container"> + +<div id="product"> + <div id="product_logo"></div> + <div id="product_name"><big><b></b></big></div> + <div id="product_description"></div> +</div> <!-- id="product" --> + +<div id="main"> + +<div id="navigation"> +<%=luadoc.doclet.html.include("menu.lp", { doc=doc, file_doc=file_doc })%> + +</div> <!-- id="navigation" --> + +<div id="content"> + +<h1>File <code><%=file_doc.name%></code></h1> + +<%if file_doc.description then%> +<p><%=file_doc.description%></p> +<%end%> +<%if file_doc.author then%> +<p><b><%= #file_doc.author>1 and "Authors" or "Author" %>:</b> +<table class="authors_list"> +<%for _, author in ipairs(file_doc.author) do%> + <tr><td class="name"><%= author %></td></tr> +<%end%> +</table> +</p> +<%end%> +<%if file_doc.copyright then%> +<p>Copyright ©<%=file_doc.copyright%></p> +<%end%> +<%if file_doc.release then%> +<p><small><b>Release:</b> <%=file_doc.release%></small></p> +<%end%> + +<%if #file_doc.functions > 0 then%> +<h2>Functions</h2> +<table class="function_list"> +<%for _, func_name in ipairs(file_doc.functions) do + local func_data = file_doc.functions[func_name]%> + <tr> + <td class="name" nowrap><%=func_data.private and "local " or ""%><a href="#<%=func_name%>"><%=func_name%></a> (<%=table.concat(func_data.param or {}, ", ")%>)</td> + <td class="summary"><%=func_data.summary%></td> + </tr> +<%end%> +</table> +<%end%> + + +<%if #file_doc.tables > 0 then%> +<h2>Tables</h2> +<table class="table_list"> +<%for _, tab_name in ipairs(file_doc.tables) do%> + <tr> + <td class="name" nowrap><a href="#<%=tab_name%>"><%=tab_name%></a></td> + <td class="summary"><%=file_doc.tables[tab_name].summary%></td> + </tr> +<%end%> +</table> +<%end%> + + +<br/> +<br/> + + + +<%if #file_doc.functions > 0 then%> +<h2><a name="functions"></a>Functions</h2> +<dl class="function"> +<%for _, func_name in ipairs(file_doc.functions) do%> +<%=luadoc.doclet.html.include("function.lp", { doc=doc, file_doc=file_doc, func=file_doc.functions[func_name] })%> +<%end%> +</dl> +<%end%> + + +<%if #file_doc.tables > 0 then%> +<h2><a name="tables"></a>Tables</h2> +<dl class="table"> +<%for _, tab_name in ipairs(file_doc.tables) do%> +<%=luadoc.doclet.html.include("table.lp", { doc=doc, file_doc=file_doc, tab=file_doc.tables[tab_name] })%> +<%end%> +</dl> +<%end%> + + + +</div> <!-- id="content" --> + +</div> <!-- id="main" --> + +<div id="about"> + <p><a href="http://validator.w3.org/check?uri=referer"><img src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0!" height="31" width="88" /></a></p> +</div> <!-- id="about" --> + +</div> <!-- id="container" --> +</body> +</html> diff --git a/build/luadoc/luadoc/doclet/html/function.lp b/build/luadoc/luadoc/doclet/html/function.lp new file mode 100644 index 000000000..29d403e00 --- /dev/null +++ b/build/luadoc/luadoc/doclet/html/function.lp @@ -0,0 +1,64 @@ +<% +if module_doc then + from = "modules/"..module_doc.name +elseif file_doc then + from = "files/.."..file_doc.name +else + from = "" +end +%> + +<dt><%=func.private and "local " or ""%><a name="<%=func.name%>"></a><strong><%=func.printname%></strong> (<%=table.concat(func.param or {}, ", ")%>)</dt> +<dd> +<%=func.description or ""%> + +<%if type(func.param) == "table" and #func.param > 0 then%> +<h3>Parameters</h3> +<ul> + <%for p = 1, #func.param do%> + <li> + <%=func.param[p]%>: <%=func.param[func.param[p]] or ""%> + </li> + <%end%> +</ul> +<%end%> + + +<%if type(func.usage) == "string" then%> +<h3>Usage:</h3> +<%=func.usage%> +<%elseif type(func.usage) == "table" then%> +<h3>Usage</h3> +<ul> + <%for _, usage in ipairs(func.usage) do%> + <li><%= usage %> + <%end%> +</ul> +<%end%> + +<%if type(func.ret) == "string" then%> +<h3>Return value:</h3> +<%=func.ret%> +<%elseif type(func.ret) == "table" then%> +<h3>Return values:</h3> +<ol> + <%for _, ret in ipairs(func.ret) do%> + <li><%= ret %> + <%end%> +</ol> +<%end%> + +<%if type(func.see) == "string" then %> +<h3>See also:</h3> + <a href="<%=func.see%>"><%=func.see%></a> +<%elseif type(func.see) == "table" and #func.see > 0 then %> +<h3>See also:</h3> +<ul> + <%for i = 1, #func.see do%> + <li><a href="<%=luadoc.doclet.html.symbol_link(func.see[i], doc, module_doc, file_doc, from)%>"> + <%=(oop and func.see[i]:gsub("%.",":") or func.see[i]:gsub(".+%.",""))%> + </a> + <%end%> +</ul> +<%end%> +</dd> diff --git a/build/luadoc/luadoc/doclet/html/index.lp b/build/luadoc/luadoc/doclet/html/index.lp new file mode 100644 index 000000000..b4b9f5c3b --- /dev/null +++ b/build/luadoc/luadoc/doclet/html/index.lp @@ -0,0 +1,67 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html> +<head> + <title>Reference</title> + <link rel="stylesheet" href="<%=luadoc.doclet.html.link("luadoc.css")%>" type="text/css" /> + <!--meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/--> +</head> + +<body> +<div id="container"> + +<div id="product"> + <div id="product_logo"></div> + <div id="product_name"><big><b></b></big></div> + <div id="product_description"></div> +</div> <!-- id="product" --> + +<div id="main"> + +<div id="navigation"> +<%=luadoc.doclet.html.include("menu.lp", { doc=doc })%> + +</div> <!-- id="navigation" --> + +<div id="content"> + + +<%if not options.nomodules and #doc.modules > 0 then%> +<h2>Modules</h2> +<table class="module_list"> +<!--<tr><td colspan="2">Modules</td></tr>--> +<%for _, modulename in ipairs(doc.modules) do%> + <tr> + <td class="name"><a href="<%=luadoc.doclet.html.module_link(modulename, doc)%>"><%=modulename%></a></td> + <td class="summary"><%=doc.modules[modulename].summary%></td> + </tr> +<%end%> +</table> +<%end%> + + + +<%if not options.nofiles and #doc.files > 0 then%> +<h2>Files</h2> +<table class="file_list"> +<!--<tr><td colspan="2">Files</td></tr>--> +<%for _, filepath in ipairs(doc.files) do%> + <tr> + <td class="name"><a href="<%=luadoc.doclet.html.file_link(filepath)%>"><%=filepath%></a></td> + <td class="summary"></td> + </tr> +<%end%> +</table> +<%end%> + +</div> <!-- id="content" --> + +</div> <!-- id="main" --> + +<div id="about"> + <p><a href="http://validator.w3.org/check?uri=referer"><img src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0!" height="31" width="88" /></a></p> +</div> <!-- id="about" --> + +</div> <!-- id="container" --> +</body> +</html> diff --git a/build/luadoc/luadoc/doclet/html/luadoc.css b/build/luadoc/luadoc/doclet/html/luadoc.css new file mode 100644 index 000000000..f9f974951 --- /dev/null +++ b/build/luadoc/luadoc/doclet/html/luadoc.css @@ -0,0 +1,285 @@ +body { + margin-left: 1em; + margin-right: 1em; + font-family: arial, helvetica, geneva, sans-serif; + background-color:#ffffff; margin:0px; +} + +code { + font-family: "Andale Mono", monospace; +} + +tt { + font-family: "Andale Mono", monospace; +} + +body, td, th { font-size: 11pt; } + +h1, h2, h3, h4 { margin-left: 0em; } + +textarea, pre, tt { font-size:10pt; } +body, td, th { color:#000000; } +small { font-size:0.85em; } +h1 { font-size:1.5em; } +h2 { font-size:1.25em; } +h3 { font-size:1.15em; } +h4 { font-size:1.06em; } + +a:link { font-weight:bold; color: #004080; text-decoration: none; } +a:visited { font-weight:bold; color: #006699; text-decoration: none; } +a:link:hover { text-decoration:underline; } +hr { color:#cccccc } +img { border-width: 0px; } + + +h3 { padding: 1em 0 0.5em; } + +p { margin-left: 1em; } + +p.name { + font-family: "Andale Mono", monospace; + padding-top: 1em; + margin-left: 0em; +} + +blockquote { margin-left: 3em; } + +pre.example { + background-color: rgb(245, 245, 245); + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-style: solid; + border-right-style: solid; + border-bottom-style: solid; + border-left-style: solid; + border-top-color: silver; + border-right-color: silver; + border-bottom-color: silver; + border-left-color: silver; + padding: 1em; + margin-left: 1em; + margin-right: 1em; + font-family: "Andale Mono", monospace; + font-size: smaller; +} + + +hr { + margin-left: 0em; + background: #00007f; + border: 0px; + height: 1px; +} + +ul { list-style-type: disc; } + +table.index { border: 1px #00007f; } +table.index td { text-align: left; vertical-align: top; } +table.index ul { padding-top: 0em; margin-top: 0em; } + +table { + border: 1px solid black; + border-collapse: collapse; + margin: 1em auto; +} +th { + border: 1px solid black; + padding: 0.5em; +} +td { + border: 1px solid black; + padding: 0.5em; +} +div.header, div.footer { margin-left: 0em; } + +#container +{ + margin-left: 1em; + margin-right: 1em; + background-color: #f0f0f0; +} + +#product +{ + text-align: center; + border-bottom: 1px solid #cccccc; + background-color: #ffffff; +} + +#product big { + font-size: 2em; +} + +#product_logo +{ +} + +#product_name +{ +} + +#product_description +{ +} + +#main +{ + background-color: #f0f0f0; + border-left: 2px solid #cccccc; +} + +#navigation +{ + float: left; + width: 18em; + margin: 0; + vertical-align: top; + background-color: #f0f0f0; + overflow:visible; +} + +#navigation h1 { + background-color:#e7e7e7; + font-size:1.1em; + color:#000000; + text-align:left; + margin:0px; + padding:0.2em; + border-top:1px solid #dddddd; + border-bottom:1px solid #dddddd; +} + +#navigation ul +{ + font-size:1em; + list-style-type: none; + padding: 0; + margin: 1px; +} + +#navigation li +{ + text-indent: -1em; + margin: 0em 0em 0em 0.5em; + display: block; + padding: 3px 0px 0px 12px; +} + +#navigation li li a +{ + padding: 0px 3px 0px -1em; +} + +#content +{ + margin-left: 18em; + padding: 1em; + border-left: 2px solid #cccccc; + border-right: 2px solid #cccccc; + background-color: #ffffff; +} + +#about +{ + clear: both; + margin: 0; + padding: 5px; + border-top: 2px solid #cccccc; + background-color: #ffffff; +} + +@media print { + body { + font: 12pt "Times New Roman", "TimeNR", Times, serif; + } + a { font-weight:bold; color: #004080; text-decoration: underline; } + + #main
{
background-color: #ffffff;
border-left: 0px;
}
+ #container
{
margin-left: 2%;
margin-right: 2%;
background-color: #ffffff;
} + + #content
{
margin-left: 0px;
padding: 1em;
border-left: 0px;
border-right: 0px;
background-color: #ffffff;
} + + #navigation
{
display: none; + } + pre.example { + font-family: "Andale Mono", monospace; + font-size: 10pt; + page-break-inside: avoid; + } +} + +table.module_list td +{ + border-width: 1px; + padding: 3px; + border-style: solid; + border-color: #cccccc; +} +table.module_list td.name { background-color: #f0f0f0; } +table.module_list td.summary { width: 100%; } + +table.file_list +{ + border-width: 1px; + border-style: solid; + border-color: #cccccc; + border-collapse: collapse; +} +table.file_list td +{ + border-width: 1px; + padding: 3px; + border-style: solid; + border-color: #cccccc; +} +table.file_list td.name { background-color: #f0f0f0; } +table.file_list td.summary { width: 100%; } + + +table.function_list +{ + border-width: 1px; + border-style: solid; + border-color: #cccccc; + border-collapse: collapse; +} +table.function_list td +{ + border-width: 1px; + padding: 3px; + border-style: solid; + border-color: #cccccc; +} +table.function_list td.name { background-color: #f0f0f0; } +table.function_list td.summary { width: 100%; } + + +table.table_list +{ + border-width: 1px; + border-style: solid; + border-color: #cccccc; + border-collapse: collapse; +} +table.table_list td +{ + border-width: 1px; + padding: 3px; + border-style: solid; + border-color: #cccccc; +} +table.table_list td.name { background-color: #f0f0f0; } +table.table_list td.summary { width: 100%; } + +dl.function dt {border-top: 1px solid #ccc; padding-top: 1em;} +dl.function dd {padding: 0.5em 0;} +dl.function h3 {margin: 0; font-size: medium;} + +dl.table dt {border-top: 1px solid #ccc; padding-top: 1em;} +dl.table dd {padding-bottom: 1em;} +dl.table h3 {padding: 0; margin: 0; font-size: medium;} + +#TODO: make module_list, file_list, function_list, table_list inherit from a list + diff --git a/build/luadoc/luadoc/doclet/html/menu.lp b/build/luadoc/luadoc/doclet/html/menu.lp new file mode 100644 index 000000000..0fe365202 --- /dev/null +++ b/build/luadoc/luadoc/doclet/html/menu.lp @@ -0,0 +1,55 @@ +<% +if module_doc then + from = "modules/"..module_doc.name +elseif file_doc then + from = "files/.."..file_doc.name +else + from = "" +end +%> + +<h1>LuaDoc</h1> +<ul> + <%if not module_doc and not file_doc then%> + <li><strong>Index</strong></li> + <%else%> + <li><a href="<%=luadoc.doclet.html.link("index.html", from)%>">Index</a></li> + <%end%> +</ul> + + +<!-- Module list --> +<%if not options.nomodules and #doc.modules > 0 then%> +<h1>Modules</h1> +<ul> +<%for _, modulename in ipairs(doc.modules) do + if module_doc and module_doc.name == modulename then%> + <li><strong><%=modulename%></strong></li> + <%else%> + <li> + <a href="<%=luadoc.doclet.html.module_link(modulename, doc, from)%>"><%=modulename%></a> + </li> +<% end +end%> +</ul> +<%end%> + + +<!-- File list --> +<%if not options.nofiles and #doc.files > 0 then%> +<h1>Files</h1> +<ul> +<%for _, filepath in ipairs(doc.files) do + if file_doc and file_doc.name == filepath then%> + <li><strong><%=filepath%></strong></li> + <%else%> + <li> + <a href="<%=luadoc.doclet.html.file_link(filepath, from)%>"><%=filepath%></a> + </li> +<% end +end%> +</ul> +<%end%> + + + diff --git a/build/luadoc/luadoc/doclet/html/module.lp b/build/luadoc/luadoc/doclet/html/module.lp new file mode 100644 index 000000000..0798c1be0 --- /dev/null +++ b/build/luadoc/luadoc/doclet/html/module.lp @@ -0,0 +1,155 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html> +<head> + <title>Reference</title> + <link rel="stylesheet" href="<%=luadoc.doclet.html.link('luadoc.css', 'modules/'..module_doc.name)%>" type="text/css" /> + <!--meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/--> +</head> + +<body> +<div id="container"> + +<div id="product"> + <div id="product_logo"></div> + <div id="product_name"><big><b></b></big></div> + <div id="product_description"></div> +</div> <!-- id="product" --> + +<div id="main"> + +<div id="navigation"> +<%=luadoc.doclet.html.include("menu.lp", { doc=doc, module_doc=module_doc })%> +<% oop = not not ( module_doc.doc[1] and module_doc.doc[1].cstyle == "instance" ) %> + +</div><!-- id="navigation" --> + +<div id="content"> + +<h1><%=( oop and "Object Instance" or "Class" )%> <code><%=module_doc.name%></code></h1> + +<p><%=module_doc.description%></p> +<%if module_doc.author then%> +<p><b><%= #module_doc.author>1 and "Authors" or "Author" %>:</b> +<table class="authors_list"> +<%for _, author in ipairs(module_doc.author) do%> + <tr><td class="name"><%= author %></td></tr> +<%end%> +</table> +</p> +<%end%> +<%if module_doc.copyright then%> +<p>Copyright© <%=module_doc.copyright%></p> +<%end%> +<%if module_doc.release then%> +<p><small><b>Release:</b> <%=module_doc.release%></small></p> +<%end%> + +<%if #module_doc.constants > 0 then %> +<h2>Constants</h2> +<table class="function_list"> +<%for _, const_name in ipairs(module_doc.constants) do + local const_data = module_doc.constants[const_name]%> + <tr> + <td class="name" nowrap><code><%=const_data.private and "local " or ""%><%=(const_name:gsub(".+%.",""))%></code></td> + <td class="summary"><%=const_data.summary%></td> + </tr> +<%end%> +</table> +<%end%> + +<% local funcs = { }; if #module_doc.functions > 0 then %> +<h2>Functions</h2> +<table class="function_list"> +<% +for _, func_name in ipairs(module_doc.functions) do + funcs[#funcs+1] = func_name +end + +table.sort(funcs, function(a, b) + local func_data_a = module_doc.functions[a] + local func_data_b = module_doc.functions[b] + local x = func_data_a.sort or a + local y = func_data_b.sort or b + return x < y +end) + +for _, func_name in ipairs(funcs) do + local func_data = module_doc.functions[func_name] + + func_data.printname = func_name:gsub("^%d+#", "") + if oop then + func_data.printname = func_data.printname:gsub("%.", ":") + else + func_data.printname = func_data.printname:gsub("^.+%.", "") + end +%> + <tr> + <td class="name" nowrap><%=func_data.private and "local " or ""%><a href="#<%=func_name%>"><%=func_data.printname%></a> (<%=table.concat(module_doc.functions[func_name].param or {}, ", ")%>)</td> + <td class="summary"><%=module_doc.functions[func_name].summary%></td> + </tr> +<%end%> +</table> +<%end%> + + +<% local tabs = { }; if #module_doc.tables > 0 then%> +<h2>Tables</h2> +<table class="table_list"> +<% +for _, tab_name in ipairs(module_doc.tables) do + tabs[#tabs+1] = tab_name +end + +table.sort(tabs, function(a, b) + local tab_data_a = module_doc.tables[a] + local tab_data_b = module_doc.tables[b] + local x = tab_data_a.sort or a + local y = tab_data_b.sort or b + return x < y +end) + +for _, tab_name in ipairs(tabs) do +%> + <tr> + <td class="name" nowrap><a href="#<%=tab_name%>"><%=tab_name%></a></td> + <td class="summary"><%=module_doc.tables[tab_name].summary%></td> + </tr> +<%end%> +</table> +<%end%> + + +<br/> +<br/> + +<%if #module_doc.functions > 0 then%> +<h2><a name="functions"></a>Functions</h2> +<dl class="function"> +<%for _, func_name in ipairs(funcs) do%> +<%=luadoc.doclet.html.include("function.lp", { doc=doc, module_doc=module_doc, func=module_doc.functions[func_name], oop=oop })%> +<%end%> +</dl> +<%end%> + +<%if #module_doc.tables > 0 then%> +<h2><a name="tables"></a>Tables</h2> +<dl class="table"> +<%for _, tab_name in ipairs(tabs) do%> +<%=luadoc.doclet.html.include("table.lp", { doc=doc, module_doc=module_doc, tab=module_doc.tables[tab_name] })%> +<%end%> +</dl> +<%end%> + + +</div> <!-- id="content" --> + +</div> <!-- id="main" --> + +<div id="about"> + <p><a href="http://validator.w3.org/check?uri=referer"><img src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0!" height="31" width="88" /></a></p> +</div> <!-- id="about" --> + +</div> <!-- id="container" --> +</body> +</html> diff --git a/build/luadoc/luadoc/doclet/html/table.lp b/build/luadoc/luadoc/doclet/html/table.lp new file mode 100644 index 000000000..5cd023953 --- /dev/null +++ b/build/luadoc/luadoc/doclet/html/table.lp @@ -0,0 +1,15 @@ +<dt><a name="<%=tab.name%>"></a><strong><%=tab.name%></strong></dt> +<dd><%=tab.description%> + +<%if type(tab.field) == "table" and #tab.field > 0 then%> +<em>Fields</em> +<ul> + <%for p = 1, #tab.field do%> + <li> + <%=tab.field[p]%>: <%=tab.field[tab.field[p]] or ""%> + </li> + <%end%> +</ul> +<%end%> + +</dd> diff --git a/build/luadoc/luadoc/doclet/raw.lua b/build/luadoc/luadoc/doclet/raw.lua new file mode 100644 index 000000000..1e880b883 --- /dev/null +++ b/build/luadoc/luadoc/doclet/raw.lua @@ -0,0 +1,12 @@ +----------------------------------------------------------------- +-- @release $Id: raw.lua,v 1.5 2007/04/18 14:28:39 tomas Exp $ +----------------------------------------------------------------- + +module "luadoc.doclet.raw" + +----------------------------------------------------------------- +-- Generate the output. +-- @param doc Table with the structured documentation. + +function start (doc) +end diff --git a/build/luadoc/luadoc/init.lua b/build/luadoc/luadoc/init.lua new file mode 100644 index 000000000..649515de6 --- /dev/null +++ b/build/luadoc/luadoc/init.lua @@ -0,0 +1,50 @@ +------------------------------------------------------------------------------- +-- LuaDoc main function. +-- @release $Id: init.lua,v 1.4 2008/02/17 06:42:51 jasonsantos Exp $ +------------------------------------------------------------------------------- + +local require = require + +local util = require "luadoc.util" + +logger = {} + +module ("luadoc") + +------------------------------------------------------------------------------- +-- LuaDoc version number. + +_COPYRIGHT = "Copyright (c) 2003-2007 The Kepler Project" +_DESCRIPTION = "Documentation Generator Tool for the Lua language" +_VERSION = "LuaDoc 3.0.1" + +------------------------------------------------------------------------------- +-- Main function +-- @see luadoc.doclet.html, luadoc.doclet.formatter, luadoc.doclet.raw +-- @see luadoc.taglet.standard + +function main (files, options) + logger = util.loadlogengine(options) + + -- load config file + if options.config ~= nil then + -- load specified config file + dofile(options.config) + else + -- load default config file + require("luadoc.config") + end + + local taglet = require(options.taglet) + local doclet = require(options.doclet) + + -- analyze input + taglet.options = options + taglet.logger = logger + local doc = taglet.start(files) + + -- generate output + doclet.options = options + doclet.logger = logger + doclet.start(doc) +end diff --git a/build/luadoc/luadoc/lp.lua b/build/luadoc/luadoc/lp.lua new file mode 100644 index 000000000..adf84f9f0 --- /dev/null +++ b/build/luadoc/luadoc/lp.lua @@ -0,0 +1,130 @@ +---------------------------------------------------------------------------- +-- Lua Pages Template Preprocessor. +-- +-- @release $Id: lp.lua,v 1.7 2007/04/18 14:28:39 tomas Exp $ +---------------------------------------------------------------------------- + +local assert, error, getfenv, loadstring, setfenv = assert, error, getfenv, loadstring, setfenv +local find, format, gsub, strsub = string.find, string.format, string.gsub, string.sub +local concat, tinsert = table.concat, table.insert +local open = io.open + +module (...) + +---------------------------------------------------------------------------- +-- function to do output +local outfunc = "io.write" +-- accepts the old expression field: `$| <Lua expression> |$' +local compatmode = true + +-- +-- Builds a piece of Lua code which outputs the (part of the) given string. +-- @param s String. +-- @param i Number with the initial position in the string. +-- @param f Number with the final position in the string (default == -1). +-- @return String with the correspondent Lua code which outputs the part of the string. +-- +local function out (s, i, f) + s = strsub(s, i, f or -1) + if s == "" then return s end + -- we could use `%q' here, but this way we have better control + s = gsub(s, "([\\\n\'])", "\\%1") + -- substitute '\r' by '\'+'r' and let `loadstring' reconstruct it + s = gsub(s, "\r", "\\r") + return format(" %s('%s'); ", outfunc, s) +end + + +---------------------------------------------------------------------------- +-- Translate the template to Lua code. +-- @param s String to translate. +-- @return String with translated code. +---------------------------------------------------------------------------- +function translate (s) + if compatmode then + s = gsub(s, "$|(.-)|%$", "<?lua = %1 ?>") + s = gsub(s, "<!%-%-$$(.-)$$%-%->", "<?lua %1 ?>") + end + s = gsub(s, "<%%(.-)%%>", "<?lua %1 ?>") + local res = {} + local start = 1 -- start of untranslated part in `s' + while true do + local ip, fp, target, exp, code = find(s, "<%?(%w*)[ \t]*(=?)(.-)%?>", start) + if not ip then break end + tinsert(res, out(s, start, ip-1)) + if target ~= "" and target ~= "lua" then + -- not for Lua; pass whole instruction to the output + tinsert(res, out(s, ip, fp)) + else + if exp == "=" then -- expression? + tinsert(res, format(" %s(%s);", outfunc, code)) + else -- command + tinsert(res, format(" %s ", code)) + end + end + start = fp + 1 + end + tinsert(res, out(s, start)) + return concat(res) +end + + +---------------------------------------------------------------------------- +-- Defines the name of the output function. +-- @param f String with the name of the function which produces output. + +function setoutfunc (f) + outfunc = f +end + +---------------------------------------------------------------------------- +-- Turns on or off the compatibility with old CGILua 3.X behavior. +-- @param c Boolean indicating if the compatibility mode should be used. + +function setcompatmode (c) + compatmode = c +end + +---------------------------------------------------------------------------- +-- Internal compilation cache. + +local cache = {} + +---------------------------------------------------------------------------- +-- Translates a template into a Lua function. +-- Does NOT execute the resulting function. +-- Uses a cache of templates. +-- @param string String with the template to be translated. +-- @param chunkname String with the name of the chunk, for debugging purposes. +-- @return Function with the resulting translation. + +function compile (string, chunkname) + local f, err = cache[string] + if f then return f end + f, err = loadstring (translate (string), chunkname) + if not f then error (err, 3) end + cache[string] = f + return f +end + +---------------------------------------------------------------------------- +-- Translates and executes a template in a given file. +-- The translation creates a Lua function which will be executed in an +-- optionally given environment. +-- @param filename String with the name of the file containing the template. +-- @param env Table with the environment to run the resulting function. + +function include (filename, env) + -- read the whole contents of the file + local fh = assert (open (filename)) + local src = fh:read("*a") + fh:close() + -- translates the file into a function + local prog = compile (src, '@'..filename) + local _env + if env then + _env = getfenv (prog) + setfenv (prog, env) + end + prog () +end diff --git a/build/luadoc/luadoc/taglet/standard.lua b/build/luadoc/luadoc/taglet/standard.lua new file mode 100644 index 000000000..ef925f8c7 --- /dev/null +++ b/build/luadoc/luadoc/taglet/standard.lua @@ -0,0 +1,567 @@ +------------------------------------------------------------------------------- +-- @release $Id: standard.lua,v 1.39 2007/12/21 17:50:48 tomas Exp $ +------------------------------------------------------------------------------- + +local assert, pairs, tostring, type = assert, pairs, tostring, type +local io = require "io" +local posix = require "nixio.fs" +local luadoc = require "luadoc" +local util = require "luadoc.util" +local tags = require "luadoc.taglet.standard.tags" +local string = require "string" +local table = require "table" + +module 'luadoc.taglet.standard' + +------------------------------------------------------------------------------- +-- Creates an iterator for an array base on a class type. +-- @param t array to iterate over +-- @param class name of the class to iterate over + +function class_iterator (t, class) + return function () + local i = 1 + return function () + while t[i] and t[i].class ~= class do + i = i + 1 + end + local v = t[i] + i = i + 1 + return v + end + end +end + +-- Patterns for function recognition +local identifiers_list_pattern = "%s*(.-)%s*" +local identifier_pattern = "[^%(%s]+" +local function_patterns = { + "^()%s*function%s*("..identifier_pattern..")%s*%("..identifiers_list_pattern.."%)", + "^%s*(local%s)%s*function%s*("..identifier_pattern..")%s*%("..identifiers_list_pattern.."%)", + "^()%s*("..identifier_pattern..")%s*%=%s*function%s*%("..identifiers_list_pattern.."%)", +} + +------------------------------------------------------------------------------- +-- Checks if the line contains a function definition +-- @param line string with line text +-- @return function information or nil if no function definition found + +local function check_function (line) + line = util.trim(line) + + local info = table.foreachi(function_patterns, function (_, pattern) + local r, _, l, id, param = string.find(line, pattern) + if r ~= nil then + return { + name = id, + private = (l == "local"), + param = { } --util.split("%s*,%s*", param), + } + end + end) + + -- TODO: remove these assert's? + if info ~= nil then + assert(info.name, "function name undefined") + assert(info.param, string.format("undefined parameter list for function `%s'", info.name)) + end + + return info +end + +------------------------------------------------------------------------------- +-- Checks if the line contains a module definition. +-- @param line string with line text +-- @param currentmodule module already found, if any +-- @return the name of the defined module, or nil if there is no module +-- definition + +local function check_module (line, currentmodule) + line = util.trim(line) + + -- module"x.y" + -- module'x.y' + -- module[[x.y]] + -- module("x.y") + -- module('x.y') + -- module([[x.y]]) + -- module(...) + + local r, _, modulename = string.find(line, "^module%s*[%s\"'(%[]+([^,\"')%]]+)") + if r then + -- found module definition + logger:debug(string.format("found module `%s'", modulename)) + return modulename + end + return currentmodule +end + +-- Patterns for constant recognition +local constant_patterns = { + "^()%s*([A-Z][A-Z0-9_]*)%s*=", + "^%s*(local%s)%s*([A-Z][A-Z0-9_]*)%s*=", +} + +------------------------------------------------------------------------------- +-- Checks if the line contains a constant definition +-- @param line string with line text +-- @return constant information or nil if no constant definition found + +local function check_constant (line) + line = util.trim(line) + + local info = table.foreachi(constant_patterns, function (_, pattern) + local r, _, l, id = string.find(line, pattern) + if r ~= nil then + return { + name = id, + private = (l == "local"), + } + end + end) + + -- TODO: remove these assert's? + if info ~= nil then + assert(info.name, "constant name undefined") + end + + return info +end + +------------------------------------------------------------------------------- +-- Extracts summary information from a description. The first sentence of each +-- doc comment should be a summary sentence, containing a concise but complete +-- description of the item. It is important to write crisp and informative +-- initial sentences that can stand on their own +-- @param description text with item description +-- @return summary string or nil if description is nil + +local function parse_summary (description) + -- summary is never nil... + description = description or "" + + -- append an " " at the end to make the pattern work in all cases + description = description.." " + + -- read until the first period followed by a space or tab + local summary = string.match(description, "(.-%.)[%s\t]") + + -- if pattern did not find the first sentence, summary is the whole description + summary = summary or description + + return summary +end + +------------------------------------------------------------------------------- +-- @param f file handle +-- @param line current line being parsed +-- @param modulename module already found, if any +-- @return current line +-- @return code block +-- @return modulename if found + +local function parse_code (f, line, modulename) + local code = {} + while line ~= nil do + if string.find(line, "^[\t ]*%-%-%-") then + -- reached another luadoc block, end this parsing + return line, code, modulename + else + -- look for a module definition + modulename = check_module(line, modulename) + + table.insert(code, line) + line = f:read() + end + end + -- reached end of file + return line, code, modulename +end + +------------------------------------------------------------------------------- +-- Parses the information inside a block comment +-- @param block block with comment field +-- @return block parameter + +local function parse_comment (block, first_line, modulename) + + -- get the first non-empty line of code + local code = table.foreachi(block.code, function(_, line) + if not util.line_empty(line) then + -- `local' declarations are ignored in two cases: + -- when the `nolocals' option is turned on; and + -- when the first block of a file is parsed (this is + -- necessary to avoid confusion between the top + -- local declarations and the `module' definition. + if (options.nolocals or first_line) and line:find"^%s*local" then + return + end + return line + end + end) + + -- parse first line of code + if code ~= nil then + local func_info = check_function(code) + local module_name = check_module(code) + local const_info = check_constant(code) + if func_info then + block.class = "function" + block.name = func_info.name + block.param = func_info.param + block.private = func_info.private + elseif const_info then + block.class = "constant" + block.name = const_info.name + block.private = const_info.private + elseif module_name then + block.class = "module" + block.name = module_name + block.param = {} + else + block.param = {} + end + else + -- TODO: comment without any code. Does this means we are dealing + -- with a file comment? + end + + -- parse @ tags + local currenttag = "description" + local currenttext + + table.foreachi(block.comment, function (_, line) + line = util.trim_comment(line) + + local r, _, tag, text = string.find(line, "@([_%w%.]+)%s+(.*)") + if r ~= nil then + -- found new tag, add previous one, and start a new one + -- TODO: what to do with invalid tags? issue an error? or log a warning? + tags.handle(currenttag, block, currenttext) + + currenttag = tag + currenttext = text + else + currenttext = util.concat(currenttext, "\n" .. line) + assert(string.sub(currenttext, 1, 1) ~= " ", string.format("`%s', `%s'", currenttext, line)) + end + end) + tags.handle(currenttag, block, currenttext) + + -- extracts summary information from the description + block.summary = parse_summary(block.description) + assert(string.sub(block.description, 1, 1) ~= " ", string.format("`%s'", block.description)) + + if block.name and block.class == "module" then + modulename = block.name + end + + return block, modulename +end + +------------------------------------------------------------------------------- +-- Parses a block of comment, started with ---. Read until the next block of +-- comment. +-- @param f file handle +-- @param line being parsed +-- @param modulename module already found, if any +-- @return line +-- @return block parsed +-- @return modulename if found + +local function parse_block (f, line, modulename, first) + local multiline = not not (line and line:match("%[%[")) + local block = { + comment = {}, + code = {}, + } + + while line ~= nil do + if (multiline == true and string.find(line, "%]%]") ~= nil) or + (multiline == false and string.find(line, "^[\t ]*%-%-") == nil) then + -- reached end of comment, read the code below it + -- TODO: allow empty lines + line, block.code, modulename = parse_code(f, line, modulename) + + -- parse information in block comment + block, modulename = parse_comment(block, first, modulename) + + return line, block, modulename + else + table.insert(block.comment, line) + line = f:read() + end + end + -- reached end of file + + -- parse information in block comment + block, modulename = parse_comment(block, first, modulename) + + return line, block, modulename +end + +------------------------------------------------------------------------------- +-- Parses a file documented following luadoc format. +-- @param filepath full path of file to parse +-- @param doc table with documentation +-- @return table with documentation + +function parse_file (filepath, doc, handle, prev_line, prev_block, prev_modname) + local blocks = { prev_block } + local modulename = prev_modname + + -- read each line + local f = handle or io.open(filepath, "r") + local i = 1 + local line = prev_line or f:read() + local first = true + while line ~= nil do + + if string.find(line, "^[\t ]*%-%-%-") then + -- reached a luadoc block + local block, newmodname + line, block, newmodname = parse_block(f, line, modulename, first) + + if modulename and newmodname and newmodname ~= modulename then + doc = parse_file( nil, doc, f, line, block, newmodname ) + else + table.insert(blocks, block) + modulename = newmodname + end + else + -- look for a module definition + local newmodname = check_module(line, modulename) + + if modulename and newmodname and newmodname ~= modulename then + parse_file( nil, doc, f ) + else + modulename = newmodname + end + + -- TODO: keep beginning of file somewhere + + line = f:read() + end + first = false + i = i + 1 + end + + if not handle then + f:close() + end + + if filepath then + -- store blocks in file hierarchy + assert(doc.files[filepath] == nil, string.format("doc for file `%s' already defined", filepath)) + table.insert(doc.files, filepath) + doc.files[filepath] = { + type = "file", + name = filepath, + doc = blocks, + -- functions = class_iterator(blocks, "function"), + -- tables = class_iterator(blocks, "table"), + } + -- + local first = doc.files[filepath].doc[1] + if first and modulename then + doc.files[filepath].author = first.author + doc.files[filepath].copyright = first.copyright + doc.files[filepath].description = first.description + doc.files[filepath].release = first.release + doc.files[filepath].summary = first.summary + end + end + + -- if module definition is found, store in module hierarchy + if modulename ~= nil then + if modulename == "..." then + assert( filepath, "Can't determine name for virtual module from filepatch" ) + modulename = string.gsub (filepath, "%.lua$", "") + modulename = string.gsub (modulename, "/", ".") + end + if doc.modules[modulename] ~= nil then + -- module is already defined, just add the blocks + table.foreachi(blocks, function (_, v) + table.insert(doc.modules[modulename].doc, v) + end) + else + -- TODO: put this in a different module + table.insert(doc.modules, modulename) + doc.modules[modulename] = { + type = "module", + name = modulename, + doc = blocks, +-- functions = class_iterator(blocks, "function"), +-- tables = class_iterator(blocks, "table"), + author = first and first.author, + copyright = first and first.copyright, + description = "", + release = first and first.release, + summary = "", + } + + -- find module description + for m in class_iterator(blocks, "module")() do + doc.modules[modulename].description = util.concat( + doc.modules[modulename].description, + m.description) + doc.modules[modulename].summary = util.concat( + doc.modules[modulename].summary, + m.summary) + if m.author then + doc.modules[modulename].author = m.author + end + if m.copyright then + doc.modules[modulename].copyright = m.copyright + end + if m.release then + doc.modules[modulename].release = m.release + end + if m.name then + doc.modules[modulename].name = m.name + end + end + doc.modules[modulename].description = doc.modules[modulename].description or (first and first.description) or "" + doc.modules[modulename].summary = doc.modules[modulename].summary or (first and first.summary) or "" + end + + -- make functions table + doc.modules[modulename].functions = {} + for f in class_iterator(blocks, "function")() do + if f and f.name then + table.insert(doc.modules[modulename].functions, f.name) + doc.modules[modulename].functions[f.name] = f + end + end + + -- make tables table + doc.modules[modulename].tables = {} + for t in class_iterator(blocks, "table")() do + if t and t.name then + table.insert(doc.modules[modulename].tables, t.name) + doc.modules[modulename].tables[t.name] = t + end + end + + -- make constants table + doc.modules[modulename].constants = {} + for c in class_iterator(blocks, "constant")() do + if c and c.name then + table.insert(doc.modules[modulename].constants, c.name) + doc.modules[modulename].constants[c.name] = c + end + end + end + + if filepath then + -- make functions table + doc.files[filepath].functions = {} + for f in class_iterator(blocks, "function")() do + if f and f.name then + table.insert(doc.files[filepath].functions, f.name) + doc.files[filepath].functions[f.name] = f + end + end + + -- make tables table + doc.files[filepath].tables = {} + for t in class_iterator(blocks, "table")() do + if t and t.name then + table.insert(doc.files[filepath].tables, t.name) + doc.files[filepath].tables[t.name] = t + end + end + end + + return doc +end + +------------------------------------------------------------------------------- +-- Checks if the file is terminated by ".lua" or ".luadoc" and calls the +-- function that does the actual parsing +-- @param filepath full path of the file to parse +-- @param doc table with documentation +-- @return table with documentation +-- @see parse_file + +function file (filepath, doc) + local patterns = { "%.lua$", "%.luadoc$" } + local valid = table.foreachi(patterns, function (_, pattern) + if string.find(filepath, pattern) ~= nil then + return true + end + end) + + if valid then + logger:info(string.format("processing file `%s'", filepath)) + doc = parse_file(filepath, doc) + end + + return doc +end + +------------------------------------------------------------------------------- +-- Recursively iterates through a directory, parsing each file +-- @param path directory to search +-- @param doc table with documentation +-- @return table with documentation + +function directory (path, doc) + for f in posix.dir(path) do + local fullpath = path .. "/" .. f + local attr = posix.stat(fullpath) + assert(attr, string.format("error stating file `%s'", fullpath)) + + if attr.type == "reg" then + doc = file(fullpath, doc) + elseif attr.type == "dir" and f ~= "." and f ~= ".." then + doc = directory(fullpath, doc) + end + end + return doc +end + +-- Recursively sorts the documentation table +local function recsort (tab) + table.sort (tab) + -- sort list of functions by name alphabetically + for f, doc in pairs(tab) do + if doc.functions then + table.sort(doc.functions) + end + if doc.tables then + table.sort(doc.tables) + end + end +end + +------------------------------------------------------------------------------- + +function start (files, doc) + assert(files, "file list not specified") + + -- Create an empty document, or use the given one + doc = doc or { + files = {}, + modules = {}, + } + assert(doc.files, "undefined `files' field") + assert(doc.modules, "undefined `modules' field") + + table.foreachi(files, function (_, path) + local attr = posix.stat(path) + assert(attr, string.format("error stating path `%s'", path)) + + if attr.type == "reg" then + doc = file(path, doc) + elseif attr.type == "dir" then + doc = directory(path, doc) + end + end) + + -- order arrays alphabetically + recsort(doc.files) + recsort(doc.modules) + + return doc +end diff --git a/build/luadoc/luadoc/taglet/standard/tags.lua b/build/luadoc/luadoc/taglet/standard/tags.lua new file mode 100644 index 000000000..e9d035483 --- /dev/null +++ b/build/luadoc/luadoc/taglet/standard/tags.lua @@ -0,0 +1,191 @@ +------------------------------------------------------------------------------- +-- Handlers for several tags +-- @release $Id: tags.lua,v 1.8 2007/09/05 12:39:09 tomas Exp $ +------------------------------------------------------------------------------- + +local luadoc = require "luadoc" +local util = require "luadoc.util" +local string = require "string" +local table = require "table" +local assert, type, tostring, tonumber = assert, type, tostring, tonumber + +module "luadoc.taglet.standard.tags" + +------------------------------------------------------------------------------- + +local function author (tag, block, text) + block[tag] = block[tag] or {} + if not text then + luadoc.logger:warn("author `name' not defined [["..text.."]]: skipping") + return + end + table.insert (block[tag], text) +end + +------------------------------------------------------------------------------- +-- Set the class of a comment block. Classes can be "module", "function", +-- "table". The first two classes are automatic, extracted from the source code + +local function class (tag, block, text) + block[tag] = text +end + +------------------------------------------------------------------------------- + +local function cstyle (tag, block, text) + block[tag] = text +end + +------------------------------------------------------------------------------- + +local function sort (tag, block, text) + block[tag] = tonumber(text) or 0 +end + +------------------------------------------------------------------------------- + +local function copyright (tag, block, text) + block[tag] = text +end + +------------------------------------------------------------------------------- + +local function description (tag, block, text) + block[tag] = text +end + +------------------------------------------------------------------------------- + +local function field (tag, block, text) + if block["class"] ~= "table" then + luadoc.logger:warn("documenting `field' for block that is not a `table'") + end + block[tag] = block[tag] or {} + + local _, _, name, desc = string.find(text, "^([_%w%.]+)%s+(.*)") + assert(name, "field name not defined") + + table.insert(block[tag], name) + block[tag][name] = desc +end + +------------------------------------------------------------------------------- +-- Set the name of the comment block. If the block already has a name, issue +-- an error and do not change the previous value + +local function name (tag, block, text) + if block[tag] and block[tag] ~= text then + luadoc.logger:error(string.format("block name conflict: `%s' -> `%s'", block[tag], text)) + end + + block[tag] = text +end + +------------------------------------------------------------------------------- +-- Processes a parameter documentation. +-- @param tag String with the name of the tag (it must be "param" always). +-- @param block Table with previous information about the block. +-- @param text String with the current line beeing processed. + +local function param (tag, block, text) + block[tag] = block[tag] or {} + -- TODO: make this pattern more flexible, accepting empty descriptions + local _, _, name, desc = string.find(text, "^([_%w%.]+)%s+(.*)") + if not name then + luadoc.logger:warn("parameter `name' not defined [["..text.."]]: skipping") + return + end + local i = table.foreachi(block[tag], function (i, v) + if v == name then + return i + end + end) + if i == nil then + luadoc.logger:warn(string.format("documenting undefined parameter `%s'", name)) + table.insert(block[tag], name) + end + block[tag][name] = desc +end + +------------------------------------------------------------------------------- + +local function release (tag, block, text) + block[tag] = text +end + +------------------------------------------------------------------------------- + +local function ret (tag, block, text) + tag = "ret" + if type(block[tag]) == "string" then + block[tag] = { block[tag], text } + elseif type(block[tag]) == "table" then + table.insert(block[tag], text) + else + block[tag] = text + end +end + +------------------------------------------------------------------------------- +-- @see ret + +local function see (tag, block, text) + -- see is always an array + block[tag] = block[tag] or {} + + -- remove trailing "." + text = string.gsub(text, "(.*)%.$", "%1") + + local s = util.split("%s*,%s*", text) + + table.foreachi(s, function (_, v) + table.insert(block[tag], v) + end) +end + +------------------------------------------------------------------------------- +-- @see ret + +local function usage (tag, block, text) + if type(block[tag]) == "string" then + block[tag] = { block[tag], text } + elseif type(block[tag]) == "table" then + table.insert(block[tag], text) + else + block[tag] = text + end +end + +------------------------------------------------------------------------------- + +local handlers = {} +handlers["author"] = author +handlers["class"] = class +handlers["cstyle"] = cstyle +handlers["copyright"] = copyright +handlers["description"] = description +handlers["field"] = field +handlers["name"] = name +handlers["param"] = param +handlers["release"] = release +handlers["return"] = ret +handlers["see"] = see +handlers["sort"] = sort +handlers["usage"] = usage + +------------------------------------------------------------------------------- + +function handle (tag, block, text) + if not handlers[tag] then + luadoc.logger:error(string.format("undefined handler for tag `%s'", tag)) + return + end + + if text then + text = text:gsub("`([^\n]-)`", "<code>%1</code>") + text = text:gsub("`(.-)`", "<pre>%1</pre>") + end + +-- assert(handlers[tag], string.format("undefined handler for tag `%s'", tag)) + return handlers[tag](tag, block, text) +end diff --git a/build/luadoc/luadoc/util.lua b/build/luadoc/luadoc/util.lua new file mode 100644 index 000000000..e1058d590 --- /dev/null +++ b/build/luadoc/luadoc/util.lua @@ -0,0 +1,201 @@ +------------------------------------------------------------------------------- +-- General utilities. +-- @release $Id: util.lua,v 1.16 2008/02/17 06:42:51 jasonsantos Exp $ +------------------------------------------------------------------------------- + +local posix = require "nixio.fs" +local type, table, string, io, assert, tostring, setmetatable, pcall = type, table, string, io, assert, tostring, setmetatable, pcall + +------------------------------------------------------------------------------- +-- Module with several utilities that could not fit in a specific module + +module "luadoc.util" + +------------------------------------------------------------------------------- +-- Removes spaces from the begining and end of a given string +-- @param s string to be trimmed +-- @return trimmed string + +function trim (s) + return (string.gsub(s, "^%s*(.-)%s*$", "%1")) +end + +------------------------------------------------------------------------------- +-- Removes spaces from the begining and end of a given string, considering the +-- string is inside a lua comment. +-- @param s string to be trimmed +-- @return trimmed string +-- @see trim +-- @see string.gsub + +function trim_comment (s) + s = string.gsub(s, "^%s*%-%-+%[%[(.*)$", "%1") + s = string.gsub(s, "^%s*%-%-+(.*)$", "%1") + return s +end + +------------------------------------------------------------------------------- +-- Checks if a given line is empty +-- @param line string with a line +-- @return true if line is empty, false otherwise + +function line_empty (line) + return (string.len(trim(line)) == 0) +end + +------------------------------------------------------------------------------- +-- Appends two string, but if the first one is nil, use to second one +-- @param str1 first string, can be nil +-- @param str2 second string +-- @return str1 .. " " .. str2, or str2 if str1 is nil + +function concat (str1, str2) + if str1 == nil or string.len(str1) == 0 then + return str2 + else + return str1 .. " " .. str2 + end +end + +------------------------------------------------------------------------------- +-- Split text into a list consisting of the strings in text, +-- separated by strings matching delim (which may be a pattern). +-- @param delim if delim is "" then action is the same as %s+ except that +-- field 1 may be preceeded by leading whitespace +-- @usage split(",%s*", "Anna, Bob, Charlie,Dolores") +-- @usage split(""," x y") gives {"x","y"} +-- @usage split("%s+"," x y") gives {"", "x","y"} +-- @return array with strings +-- @see table.concat + +function split(delim, text) + local list = {} + if string.len(text) > 0 then + delim = delim or "" + local pos = 1 + -- if delim matches empty string then it would give an endless loop + if string.find("", delim, 1) and delim ~= "" then + error("delim matches empty string!") + end + local first, last + while 1 do + if delim ~= "" then + first, last = string.find(text, delim, pos) + else + first, last = string.find(text, "%s+", pos) + if first == 1 then + pos = last+1 + first, last = string.find(text, "%s+", pos) + end + end + if first then -- found? + table.insert(list, string.sub(text, pos, first-1)) + pos = last+1 + else + table.insert(list, string.sub(text, pos)) + break + end + end + end + return list +end + +------------------------------------------------------------------------------- +-- Comments a paragraph. +-- @param text text to comment with "--", may contain several lines +-- @return commented text + +function comment (text) + text = string.gsub(text, "\n", "\n-- ") + return "-- " .. text +end + +------------------------------------------------------------------------------- +-- Wrap a string into a paragraph. +-- @param s string to wrap +-- @param w width to wrap to [80] +-- @param i1 indent of first line [0] +-- @param i2 indent of subsequent lines [0] +-- @return wrapped paragraph + +function wrap(s, w, i1, i2) + w = w or 80 + i1 = i1 or 0 + i2 = i2 or 0 + assert(i1 < w and i2 < w, "the indents must be less than the line width") + s = string.rep(" ", i1) .. s + local lstart, len = 1, string.len(s) + while len - lstart > w do + local i = lstart + w + while i > lstart and string.sub(s, i, i) ~= " " do i = i - 1 end + local j = i + while j > lstart and string.sub(s, j, j) == " " do j = j - 1 end + s = string.sub(s, 1, j) .. "\n" .. string.rep(" ", i2) .. + string.sub(s, i + 1, -1) + local change = i2 + 1 - (i - j) + lstart = j + change + len = len + change + end + return s +end + +------------------------------------------------------------------------------- +-- Opens a file, creating the directories if necessary +-- @param filename full path of the file to open (or create) +-- @param mode mode of opening +-- @return file handle + +function posix.open (filename, mode) + local f = io.open(filename, mode) + if f == nil then + filename = string.gsub(filename, "\\", "/") + local dir = "" + for d in string.gfind(filename, ".-/") do + dir = dir .. d + posix.mkdir(dir) + end + f = io.open(filename, mode) + end + return f +end + + +---------------------------------------------------------------------------------- +-- Creates a Logger with LuaLogging, if present. Otherwise, creates a mock logger. +-- @param options a table with options for the logging mechanism +-- @return logger object that will implement log methods + +function loadlogengine(options) + local logenabled = pcall(function() + require "logging" + require "logging.console" + end) + + local logging = logenabled and logging + + if logenabled then + if options.filelog then + logger = logging.file("luadoc.log") -- use this to get a file log + else + logger = logging.console("[%level] %message\n") + end + + if options.verbose then + logger:setLevel(logging.INFO) + else + logger:setLevel(logging.WARN) + end + + else + noop = {__index=function(...) + return function(...) + -- noop + end + end} + + logger = {} + setmetatable(logger, noop) + end + + return logger +end diff --git a/build/makedocs.sh b/build/makedocs.sh index 2f7f57345..a9fc760e7 100755 --- a/build/makedocs.sh +++ b/build/makedocs.sh @@ -1,2 +1,14 @@ -luadoc -d $2 --no-files $(for f in $(find $1 -name '*.lua' -type f); do if grep -q -- "@return" $f; then echo $f; fi; done) -echo API-Documentation was created in $2. +#!/bin/bash + +topdir=$(pwd) + +[ -f "$topdir/build/makedocs.sh" -a -n "$1" ] || { + echo "Please execute as ./build/makedocs.sh [output directory]" >&2 + exit 1 +} + +( + cd "$topdir/build/luadoc/" + find "$topdir/libs/" "$topdir/modules/" -type f -name '*.lua' -or -name '*.luadoc' | \ + xargs grep -l '@return' | xargs ./doc.lua --no-files -d "$1" +) |