webmcp
view framework/bin/autodoc.lua @ 395:ae1a66bb6b7d
Fixed error in autodoc documentation of <db_handle>:quote_binary(...)
| author | jbe | 
|---|---|
| date | Wed Dec 09 05:23:42 2015 +0100 (2015-12-09) | 
| parents | ed910089a0c5 | 
| children | 
 line source
     1 #!/usr/bin/env lua
     3 local args = {...}
     5 if not args[1] or string.match(args[1], "^%-") then
     6   print("Usage: autodoc.lua srcdir/ > documentation.html")
     7   os.exit(1)
     8 end
    10 local entries = {}
    12 for idx, srcdir in ipairs(args) do
    13   local find_proc = io.popen('find "' .. srcdir .. '" -name \\*.lua', "r")
    14   for filename in find_proc:lines() do
    15     local synopsis, comment, source
    16     local mode
    17     local function reset()
    18       synopsis, comment, source = {}, {}, {}
    19       mode = "idle"
    20     end
    21     reset()
    22     local function strip(tbl)
    23       while true do
    24         local line = tbl[#tbl]
    25         if line and string.find(line, "^%s*$") then
    26           tbl[#tbl] = nil
    27         else
    28           break
    29         end
    30       end
    31       if #tbl > 0 then
    32         local min_indent = math.huge
    33         for idx, line in ipairs(tbl) do
    34           local spaces = string.match(line, "^(%s*)")
    35           if min_indent > #spaces then
    36             min_indent = #spaces
    37           end
    38         end
    39         local pattern_parts = { "^" }
    40         for i = 1, min_indent do
    41           pattern_parts[#pattern_parts+1] = "%s"
    42         end
    43         pattern_parts[#pattern_parts+1] = "(.-)%s*$"
    44         local pattern = table.concat(pattern_parts)
    45         for idx, line in ipairs(tbl) do
    46           tbl[idx] = string.match(line, pattern)
    47         end
    48       end
    49     end
    50     local function entry_done()
    51       if #synopsis > 0 then
    52         strip(synopsis)
    53         strip(comment)
    54         strip(source)
    55         local stripped_synopsis = {}
    56         for idx, line in ipairs(synopsis) do
    57           local stripped_line = string.match(line, "^(.-)%-%-") or line
    58           stripped_line = string.match(stripped_line, "^(.-)%s*$")
    59           stripped_synopsis[#stripped_synopsis+1] = stripped_line
    60         end
    61         local concatted_synopsis = string.gsub(
    62           table.concat(stripped_synopsis, " "), "[%s]+", " "
    63         )
    64         local func_call = string.match(
    65           concatted_synopsis, "^[A-Za-z0-9_,. ]+= ?(.-) ?$"
    66         )
    67         if not func_call then
    68           func_call = string.match(
    69             concatted_synopsis,
    70             "^ ?for[A-Za-z0-9_, ]+in (.-) ? do[ %.]+end ?$"
    71           )
    72         end
    73         if not func_call then
    74           func_call = string.match(concatted_synopsis, "^ ?(.-) ?$")
    75         end
    76         func_call = string.gsub(
    77           func_call,
    78           "^([^({]*)([({]).*[,;].*[,;].*[,;].*([)}])$",
    79           function(base, open, close)
    80             return base .. open .. " ... " .. close
    81           end
    82         )
    83         if entries[func_call] then
    84           error("Multiple occurrences of: " .. func_call)
    85         end
    86         entries[func_call] = {
    87           func_call   = func_call,
    88           synopsis    = synopsis,
    89           comment     = comment,
    90           source      = source
    91         }
    92       end
    93       reset()
    94     end
    95     for line in io.lines(filename) do
    96       local function add_to(tbl)
    97         if #tbl > 0 or not string.match(line, "^%s*$") then
    98           tbl[#tbl+1] = line
    99         end
   100       end
   101       if mode == "idle" then
   102         if string.find(line, "^%s*%-%-%[%[%-%-%s*$") then
   103           mode = "synopsis"
   104         end
   105       elseif mode == "synopsis" then
   106         if string.find(line, "^%s*$") and #synopsis > 0 then
   107           mode = "comment"
   108         elseif string.find(line, "^%s*%-%-]]%-%-%s*$") then
   109           mode = "source"
   110         else
   111           add_to(synopsis)
   112         end
   113       elseif mode == "comment" then
   114         if string.find(line, "^%s*%-%-]]%-%-%s*$") then
   115           mode = "source"
   116         else
   117           add_to(comment)
   118         end
   119       elseif mode == "source" then
   120         if string.find(line, "^%s*%-%-//%-%-%s*$") then
   121           entry_done()
   122         else
   123           add_to(source)
   124         end
   125       end
   126     end
   127     entry_done()
   128   end
   129   find_proc:close()
   130 end
   133 function output(...)
   134   return io.stdout:write(...)
   135 end
   137 function encode(text)
   138   return (
   139     string.gsub(
   140       text, '[<>&"]',
   141       function(char)
   142         if char == '<' then
   143           return "<"
   144         elseif char == '>' then
   145           return ">"
   146         elseif char == '&' then
   147           return "&"
   148         elseif char == '"' then
   149           return """
   150         end
   151       end
   152     )
   153   )
   154 end
   156 function output_lines(tbl)
   157   for idx, line in ipairs(tbl) do
   158     if idx == 1 then
   159       output('<pre>')
   160     end
   161     local command, comment = string.match(line, "^(.-)(%-%-.*)$")
   162     if command then
   163       output(
   164         encode(command),
   165         '<span class="autodoc_comment_tail">', encode(comment), '</span>'
   166       )
   167     else
   168       output(encode(line))
   169     end
   170     if idx == #tbl then
   171       output('</pre>')
   172     end
   173     output('\n')
   174   end
   175 end
   177 keys = {}
   178 for key in pairs(entries) do
   179   keys[#keys+1] = key
   180 end
   181 table.sort(keys)
   182 for idx, key in ipairs(keys) do
   183   local entry = entries[key]
   184   local m1, m2 = string.match(key, "<?([A-Za-z0-9_]*)>?([A-Za-z0-9_.:]+)")
   185   local anchor = m1 .. m2
   186   output('<li id="', anchor, '" class="autodoc_entry">\n')
   187   output('  <div class="short_synopsis" onclick="toggleSection(\'', anchor, '\')">\n')
   188   output('    ', encode(entry.func_call), '\n')
   189   output('  </div>\n')
   190   output('  <div id="autodoc_details_', anchor, '" class="autodoc_details" style="display: none;">\n')
   191   output('    <div class="autodoc_synopsis">\n')
   192   output_lines(entry.synopsis)
   193   output('    </div>\n')
   194   output('    <div class="autodoc_comment">')
   195   for idx, line in ipairs(entry.comment) do
   196     output(encode(line))
   197     if idx < #entry.comment then
   198       output('<br/>')
   199     end
   200   end
   201   output('</div>\n')
   202   output('    <div class="autodoc_source">\n')
   203   output_lines(entry.source)
   204   output('    </div>\n')
   205   output('  </div>\n')
   206   output('</li>\n')
   207 end
