webmcp
view framework/bin/autodoc.lua @ 233:827c44692141
Allow setting certain global variables in autoloader
| author | jbe | 
|---|---|
| date | Sat Feb 28 23:28:41 2015 +0100 (2015-02-28) | 
| parents | e81669ae2e4d | 
| children | 46ff54bbd10e | 
 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   output('<li class="autodoc_entry">\n')
   185   output(
   186     '  <div class="short_synopsis"',
   187     ' onclick="document.getElementById(\'autodoc_details_',
   188     idx,
   189     '\').style.display = document.getElementById(\'autodoc_details_',
   190     idx,
   191     '\').style.display ? \'\' : \'none\';">\n'
   192   )
   193   output('    ', encode(entry.func_call), '\n')
   194   output('  </div>\n')
   195   output(
   196     '  <div id="autodoc_details_',
   197     idx,
   198     '" class="autodoc_details" style="display: none;">\n'
   199   )
   200   output('    <div class="autodoc_synopsis">\n')
   201   output_lines(entry.synopsis)
   202   output('    </div>\n')
   203   output('    <div class="autodoc_comment">')
   204   for idx, line in ipairs(entry.comment) do
   205     output(encode(line))
   206     if idx < #entry.comment then
   207       output('<br/>')
   208     end
   209   end
   210   output('    </div>\n')
   211   output('    <div class="autodoc_source">\n')
   212   output_lines(entry.source)
   213   output('    </div>\n')
   214   output('  </div>\n')
   215   output('</li>\n')
   216 end
