From: Jo-Philipp Wich Date: Wed, 23 Jul 2008 13:27:25 +0000 (+0000) Subject: * luci: add modified luadoc source to contrib X-Git-Tag: 0.8.0~589 X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fluci.git;a=commitdiff_plain;h=7b60b141d872e1cae79325057771dc49a6085d81 * luci: add modified luadoc source to contrib --- diff --git a/contrib/luadoc/lua/luadoc/config.lua b/contrib/luadoc/lua/luadoc/config.lua new file mode 100644 index 000000000..9e4b9de3c --- /dev/null +++ b/contrib/luadoc/lua/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/contrib/luadoc/lua/luadoc/doclet/debug.lua b/contrib/luadoc/lua/luadoc/doclet/debug.lua new file mode 100644 index 000000000..0b75f84cb --- /dev/null +++ b/contrib/luadoc/lua/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/contrib/luadoc/lua/luadoc/doclet/formatter.lua b/contrib/luadoc/lua/luadoc/doclet/formatter.lua new file mode 100644 index 000000000..af070d54b --- /dev/null +++ b/contrib/luadoc/lua/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 = "" + + -- 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 = lfs.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/contrib/luadoc/lua/luadoc/doclet/html.lua b/contrib/luadoc/lua/luadoc/doclet/html.lua new file mode 100644 index 000000000..b736a9ddf --- /dev/null +++ b/contrib/luadoc/lua/luadoc/doclet/html.lua @@ -0,0 +1,267 @@ +------------------------------------------------------------------------------- +-- Doclet that generates HTML output. This doclet generates a set of html files +-- based on a group of templates. The main templates are: +-- +-- +-- @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 lfs = require "lfs" +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 + + 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 = lfs.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 = lfs.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 = lfs.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 = lfs.open(options.output_dir.."luadoc.css", "w") + io.output(f) + include("luadoc.css") + f:close() +end diff --git a/contrib/luadoc/lua/luadoc/doclet/html/file.lp b/contrib/luadoc/lua/luadoc/doclet/html/file.lp new file mode 100644 index 000000000..67926b4a7 --- /dev/null +++ b/contrib/luadoc/lua/luadoc/doclet/html/file.lp @@ -0,0 +1,112 @@ + + + + Reference + + + + + +
+ +
+ +
+
+
+ +
+ + + +
+ +

File <%=file_doc.name%>

+ +<%if file_doc.description then%> +

<%=file_doc.description%>

+<%end%> +<%if file_doc.author then%> +

<%= #file_doc.author>1 and "Authors" or "Author" %>: + +<%for _, author in ipairs(file_doc.author) do%> + +<%end%> +
<%= author %>
+

+<%end%> +<%if file_doc.copyright then%> +

Copyright ©<%=file_doc.copyright%>

+<%end%> +<%if file_doc.release then%> +

Release: <%=file_doc.release%>

+<%end%> + +<%if #file_doc.functions > 0 then%> +

Functions

+ +<%for _, func_name in ipairs(file_doc.functions) do + local func_data = file_doc.functions[func_name]%> + + + + +<%end%> +
<%=func_data.private and "local " or ""%><%=func_name%> (<%=table.concat(func_data.param, ", ")%>)<%=func_data.summary%>
+<%end%> + + +<%if #file_doc.tables > 0 then%> +

Tables

+ +<%for _, tab_name in ipairs(file_doc.tables) do%> + + + + +<%end%> +
<%=tab_name%><%=file_doc.tables[tab_name].summary%>
+<%end%> + + +
+
+ + + +<%if #file_doc.functions > 0 then%> +

Functions

+
+<%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%> +
+<%end%> + + +<%if #file_doc.tables > 0 then%> +

Tables

+
+<%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%> +
+<%end%> + + + +
+ +
+ +
+

Valid XHTML 1.0!

+
+ +
+ + diff --git a/contrib/luadoc/lua/luadoc/doclet/html/function.lp b/contrib/luadoc/lua/luadoc/doclet/html/function.lp new file mode 100644 index 000000000..aa0e25b14 --- /dev/null +++ b/contrib/luadoc/lua/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 +%> + +
<%=func.private and "local " or ""%><%=func.name%> (<%=table.concat(func.param, ", ")%>)
+
+<%=func.description or ""%> + +<%if type(func.param) == "table" and #func.param > 0 then%> +

Parameters

+
    + <%for p = 1, #func.param do%> +
  • + <%=func.param[p]%>: <%=func.param[func.param[p]] or ""%> +
  • + <%end%> +
+<%end%> + + +<%if type(func.usage) == "string" then%> +

Usage:

+<%=func.usage%> +<%elseif type(func.usage) == "table" then%> +

Usage

+
    + <%for _, usage in ipairs(func.usage) do%> +
  • <%= usage %> + <%end%> +
+<%end%> + +<%if type(func.ret) == "string" then%> +

Return value:

+<%=func.ret%> +<%elseif type(func.ret) == "table" then%> +

Return values:

+
    + <%for _, ret in ipairs(func.ret) do%> +
  1. <%= ret %> + <%end%> +
+<%end%> + +<%if type(func.see) == "string" then %> +

See also:

+ <%=func.see%> +<%elseif type(func.see) == "table" and #func.see > 0 then %> +

See also:

+ +<%end%> +
diff --git a/contrib/luadoc/lua/luadoc/doclet/html/index.lp b/contrib/luadoc/lua/luadoc/doclet/html/index.lp new file mode 100644 index 000000000..b4b9f5c3b --- /dev/null +++ b/contrib/luadoc/lua/luadoc/doclet/html/index.lp @@ -0,0 +1,67 @@ + + + + Reference + " type="text/css" /> + + + + +
+ +
+ +
+
+
+ +
+ + + +
+ + +<%if not options.nomodules and #doc.modules > 0 then%> +

Modules

+ + +<%for _, modulename in ipairs(doc.modules) do%> + + + + +<%end%> +
<%=modulename%><%=doc.modules[modulename].summary%>
+<%end%> + + + +<%if not options.nofiles and #doc.files > 0 then%> +

Files

+ + +<%for _, filepath in ipairs(doc.files) do%> + + + + +<%end%> +
<%=filepath%>
+<%end%> + +
+ +
+ +
+

Valid XHTML 1.0!

+
+ +
+ + diff --git a/contrib/luadoc/lua/luadoc/doclet/html/luadoc.css b/contrib/luadoc/lua/luadoc/doclet/html/luadoc.css new file mode 100644 index 000000000..bc0f98a5a --- /dev/null +++ b/contrib/luadoc/lua/luadoc/doclet/html/luadoc.css @@ -0,0 +1,286 @@ +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-top: 1em; } + +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-left: auto; + margin-right: 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-bottom: 1em;} +dl.function h3 {padding: 0; 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/contrib/luadoc/lua/luadoc/doclet/html/menu.lp b/contrib/luadoc/lua/luadoc/doclet/html/menu.lp new file mode 100644 index 000000000..0fe365202 --- /dev/null +++ b/contrib/luadoc/lua/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 +%> + +

LuaDoc

+ + + + +<%if not options.nomodules and #doc.modules > 0 then%> +

Modules

+ +<%end%> + + + +<%if not options.nofiles and #doc.files > 0 then%> +

Files

+ +<%end%> + + + diff --git a/contrib/luadoc/lua/luadoc/doclet/html/module.lp b/contrib/luadoc/lua/luadoc/doclet/html/module.lp new file mode 100644 index 000000000..6dca9a9ad --- /dev/null +++ b/contrib/luadoc/lua/luadoc/doclet/html/module.lp @@ -0,0 +1,108 @@ + + + + Reference + + + + + +
+ +
+ +
+
+
+ +
+ + + +
+ +

Module <%=module_doc.name%>

+ +

<%=module_doc.description%>

+<%if module_doc.author then%> +

<%= #module_doc.author>1 and "Authors" or "Author" %>: + +<%for _, author in ipairs(module_doc.author) do%> + +<%end%> +
<%= author %>
+

+<%end%> +<%if module_doc.copyright then%> +

Copyright© <%=module_doc.copyright%>

+<%end%> +<%if module_doc.release then%> +

Release: <%=module_doc.release%>

+<%end%> + +<%if #module_doc.functions > 0 then%> +

Functions

+ +<%for _, func_name in ipairs(module_doc.functions) do + local func_data = module_doc.functions[func_name]%> + + + + +<%end%> +
<%=func_data.private and "local " or ""%><%=func_name%> (<%=table.concat(module_doc.functions[func_name].param, ", ")%>)<%=module_doc.functions[func_name].summary%>
+<%end%> + + +<%if #module_doc.tables > 0 then%> +

Tables

+ +<%for _, tab_name in ipairs(module_doc.tables) do%> + + + + +<%end%> +
<%=tab_name%><%=module_doc.tables[tab_name].summary%>
+<%end%> + + +
+
+ + +<%if #module_doc.functions > 0 then%> +

Functions

+
+<%for _, func_name in ipairs(module_doc.functions) do%> +<%=luadoc.doclet.html.include("function.lp", { doc=doc, module_doc=module_doc, func=module_doc.functions[func_name] })%> +<%end%> +
+<%end%> + + +<%if #module_doc.tables > 0 then%> +

Tables

+
+<%for _, tab_name in ipairs(module_doc.tables) do%> +<%=luadoc.doclet.html.include("table.lp", { doc=doc, module_doc=module_doc, tab=module_doc.tables[tab_name] })%> +<%end%> +
+<%end%> + + +
+ +
+ +
+

Valid XHTML 1.0!

+
+ +
+ + diff --git a/contrib/luadoc/lua/luadoc/doclet/html/table.lp b/contrib/luadoc/lua/luadoc/doclet/html/table.lp new file mode 100644 index 000000000..5cd023953 --- /dev/null +++ b/contrib/luadoc/lua/luadoc/doclet/html/table.lp @@ -0,0 +1,15 @@ +
<%=tab.name%>
+
<%=tab.description%> + +<%if type(tab.field) == "table" and #tab.field > 0 then%> +Fields +
    + <%for p = 1, #tab.field do%> +
  • + <%=tab.field[p]%>: <%=tab.field[tab.field[p]] or ""%> +
  • + <%end%> +
+<%end%> + +
diff --git a/contrib/luadoc/lua/luadoc/doclet/raw.lua b/contrib/luadoc/lua/luadoc/doclet/raw.lua new file mode 100644 index 000000000..1e880b883 --- /dev/null +++ b/contrib/luadoc/lua/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/contrib/luadoc/lua/luadoc/init.lua b/contrib/luadoc/lua/luadoc/init.lua new file mode 100644 index 000000000..649515de6 --- /dev/null +++ b/contrib/luadoc/lua/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/contrib/luadoc/lua/luadoc/lp.lua b/contrib/luadoc/lua/luadoc/lp.lua new file mode 100644 index 000000000..adf84f9f0 --- /dev/null +++ b/contrib/luadoc/lua/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: `$| |$' +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, "$|(.-)|%$", "") + s = gsub(s, "", "") + end + s = gsub(s, "<%%(.-)%%>", "") + 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/contrib/luadoc/lua/luadoc/taglet/standard.lua b/contrib/luadoc/lua/luadoc/taglet/standard.lua new file mode 100644 index 000000000..144755e6b --- /dev/null +++ b/contrib/luadoc/lua/luadoc/taglet/standard.lua @@ -0,0 +1,493 @@ +------------------------------------------------------------------------------- +-- @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 lfs = require "lfs" +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 + +------------------------------------------------------------------------------- +-- 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) + + -- 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) + if func_info then + block.class = "function" + block.name = func_info.name + block.param = func_info.param + block.private = func_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, 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)) + + return block +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 block = { + comment = {}, + code = {}, + } + + while line ~= nil do + if 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 = parse_comment(block, first) + + 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 = parse_comment(block, first) + + 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) + local blocks = {} + local modulename = nil + + -- read each line + local f = io.open(filepath, "r") + local i = 1 + local line = f:read() + local first = true + while line ~= nil do + if string.find(line, "^[\t ]*%-%-%-") then + -- reached a luadoc block + local block + line, block, modulename = parse_block(f, line, modulename, first) + table.insert(blocks, block) + else + -- look for a module definition + modulename = check_module(line, modulename) + + -- TODO: keep beginning of file somewhere + + line = f:read() + end + first = false + i = i + 1 + end + f:close() + -- 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 + + -- if module definition is found, store in module hierarchy + if modulename ~= nil then + if modulename == "..." then + 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 + end + + -- 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 + + 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 lfs.dir(path) do + local fullpath = path .. "/" .. f + local attr = lfs.attributes(fullpath) + assert(attr, string.format("error stating file `%s'", fullpath)) + + if attr.mode == "file" then + doc = file(fullpath, doc) + elseif attr.mode == "directory" 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 = lfs.attributes(path) + assert(attr, string.format("error stating path `%s'", path)) + + if attr.mode == "file" then + doc = file(path, doc) + elseif attr.mode == "directory" then + doc = directory(path, doc) + end + end) + + -- order arrays alphabetically + recsort(doc.files) + recsort(doc.modules) + + return doc +end diff --git a/contrib/luadoc/lua/luadoc/taglet/standard/tags.lua b/contrib/luadoc/lua/luadoc/taglet/standard/tags.lua new file mode 100644 index 000000000..980514c5f --- /dev/null +++ b/contrib/luadoc/lua/luadoc/taglet/standard/tags.lua @@ -0,0 +1,171 @@ +------------------------------------------------------------------------------- +-- 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 = assert, type, tostring + +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 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["copyright"] = copyright +handlers["description"] = description +handlers["field"] = field +handlers["name"] = name +handlers["param"] = param +handlers["release"] = release +handlers["return"] = ret +handlers["see"] = see +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 +-- assert(handlers[tag], string.format("undefined handler for tag `%s'", tag)) + return handlers[tag](tag, block, text) +end diff --git a/contrib/luadoc/lua/luadoc/util.lua b/contrib/luadoc/lua/luadoc/util.lua new file mode 100644 index 000000000..e51e2e5df --- /dev/null +++ b/contrib/luadoc/lua/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 lfs = require "lfs" +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, "%-%-+(.*)$", "%1") + return trim(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 lfs.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 + lfs.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 +