webmcp
view framework/bin/autodoc.lua @ 2:72860d232f32
Version 1.0.2
Fixed bug with explicit garbage collection (requests > 256kB caused an error)
Views prefixed with an underscore can't be called externally
ui.paginate now displays the last page, if the selected page number is too high.
Fixed bug with explicit garbage collection (requests > 256kB caused an error)
Views prefixed with an underscore can't be called externally
ui.paginate now displays the last page, if the selected page number is too high.
author | jbe/bsw |
---|---|
date | Thu Dec 10 12:00:00 2009 +0100 (2009-12-10) |
parents | 9fdfb27f8e67 |
children | 3d43a5cf17c1 |
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)
80 return base .. "{ ... }"
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, "r") 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