build: add modified luadoc for use with LuCI sources

Signed-off-by: Jo-Philipp Wich <jow@openwrt.org>
This commit is contained in:
Jo-Philipp Wich 2015-01-28 22:27:46 +01:00
parent e6e74b712f
commit c669c01cea
20 changed files with 2511 additions and 2 deletions

126
build/luadoc/doc.lua Executable file
View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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>

View file

@ -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 &copy;<%=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>&nbsp;(<%=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>

View file

@ -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>&nbsp;(<%=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>

View file

@ -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>

View file

@ -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

View file

@ -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%>

View file

@ -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&copy; <%=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>&nbsp;(<%=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>

View file

@ -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>

View file

@ -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

View file

@ -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

130
build/luadoc/luadoc/lp.lua Normal file
View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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"
)