cross platform gui lib for lua
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

265 lines
6.2 KiB

  1. #!/usr/bin/env lua
  2. function message(msg, ...)
  3. io.stderr:write(string.format(msg .. "\n", ...))
  4. end
  5. function error(msg, ...)
  6. message("error: " .. msg, ...)
  7. return nil
  8. end
  9. function fatal(msg, ...)
  10. message("fatal: " .. msg, ...)
  11. os.exit(1)
  12. end
  13. if arg[1] == "-h" or arg[1] == "--help" or #arg < 1 then
  14. message("Usage: %s file1 [file2...] > output.md", arg[0])
  15. os.exit(1)
  16. end
  17. function basename(name)
  18. name = string.match(name, "([^/]+)$")
  19. name = string.match(name, "^([^.]+)")
  20. return name
  21. end
  22. function read_one_block(fn, tbl, i)
  23. local what = string.match(tbl[i], "^%s*/?%*%*%*%s+(%S+)%s*$")
  24. if what == nil then
  25. return error("invalid syntax in file %s line %s", fn, i)
  26. end
  27. what = string.lower(what)
  28. i = i + 1
  29. local res = {}
  30. while (not string.match(tbl[i], "^%s*%*%*%*")) and (not string.match(tbl[i], "^%s*%*/")) do
  31. local k, v = string.match(tbl[i], "^%s*%*%s*(%w+):%s*(%S.*)%s*$")
  32. if k then
  33. res[string.lower(k)] = v
  34. else
  35. local v = string.match(tbl[i], "^%s*%*%s*(%S.*)%s*$")
  36. if v then
  37. res['desc'] = (res['desc'] and (res['desc'] .. " ") or "") .. v
  38. end
  39. end
  40. i = i + 1
  41. end
  42. return what, res, i
  43. end
  44. function read_file(name)
  45. local tbl = {}
  46. local file, err
  47. if name == "-" then
  48. file = io.stdin
  49. else
  50. file, err = io.open(name, "r")
  51. if err then error(err) end
  52. end
  53. for l in file:lines() do
  54. tbl[#tbl+1] = l
  55. end
  56. if name ~= "-" then
  57. file:close()
  58. end
  59. return tbl
  60. end
  61. function collect_data(filename, res)
  62. local f = read_file(filename)
  63. res = res or {}
  64. local module = basename(filename)
  65. local l = 1
  66. while l <= #f do
  67. if (string.match(f[l], "^%s*/?%*%*%* ")) then
  68. local what, tbl, nl = read_one_block(filename, f, l)
  69. if what == "module" then
  70. module = tbl.name
  71. if tbl.desc then
  72. res[module] = res[module] or {}
  73. res[module].desc = tbl.desc
  74. end
  75. elseif what == "intro" then
  76. if tbl.desc then
  77. res[1] = tbl.desc
  78. end
  79. else
  80. res[module] = res[module] or {}
  81. if tbl.object then
  82. res[module].object = res[module].object or {}
  83. t = nil
  84. for _, o in ipairs(res[module].object) do
  85. if o.name == tbl.object then
  86. t = o
  87. end
  88. end
  89. if not t then
  90. t = { object = { name = tbl.object } }
  91. res[module].object[#res[module].object + 1] = t
  92. end
  93. tbl.object = nil
  94. t[what] = t[what] or {}
  95. t[what][#t[what] + 1] = tbl
  96. else
  97. res[module][what] = res[module][what] or {}
  98. t = res[module][what]
  99. t[#t+1] = tbl
  100. end
  101. end
  102. l = nl
  103. else
  104. l = l + 1
  105. end
  106. end
  107. return res
  108. end
  109. function outf(str, ...)
  110. print(string.format(str, ...))
  111. end
  112. function output_functions(func)
  113. if not func then return end
  114. outf("<h2 id=\"functions\">Functions</h2>")
  115. for _, f in ipairs(func) do
  116. outf("<h3 id=\"func_%s\">%s</h3>", f.name, f.name)
  117. outf("<code>%s</code>", f.signature)
  118. if f.desc then outf("<p>%s</p>", f.desc) end
  119. end
  120. end
  121. function output_objects(obj)
  122. if not obj then return end
  123. outf("<h2 id=\"objects\">Objects</h2>")
  124. for _, o in ipairs(obj) do
  125. outf("<h3 id=\"obj_%s\">%s</h3>", o.name, o.name)
  126. if o.desc then outf("<p>%s</p>", o.desc) end
  127. if o.constructor then
  128. outf("<h4>Constructors</h4>")
  129. outf("<dl>")
  130. for _, c in ipairs(o.constructor) do
  131. outf("<dt>%s</dt>", c.name)
  132. outf("<dd><code>%s</code>", c.signature)
  133. if c.desc then outf("<br/>%s", c.desc) end
  134. outf("</dd>")
  135. end
  136. outf("</dl>")
  137. end
  138. if o.property then
  139. outf("<h4>Properties</h4>")
  140. outf("<dl>")
  141. for _, p in ipairs(o.property) do
  142. outf("<dt>%s</dt>", p.name)
  143. if p.desc then outf("<dd>%s</dd>", p.desc) end
  144. end
  145. outf("</dl>")
  146. end
  147. if o.method then
  148. outf("<h4>Methods</h4>")
  149. outf("<dl>")
  150. for _, m in ipairs(o.method) do
  151. outf("<dt>%s</dt>", m.name)
  152. outf("<dd><code>%s</code>", m.signature)
  153. if m.desc then outf("<br/>%s", m.desc) end
  154. outf("</dd>")
  155. end
  156. outf("</dl>")
  157. end
  158. end
  159. end
  160. function sorted_keys(tbl)
  161. local res = {}
  162. for k, _ in pairs(tbl) do
  163. if type(k) == "string" then
  164. res[#res+1] = k
  165. end
  166. end
  167. table.sort(res)
  168. return res
  169. end
  170. function output_toc(modules)
  171. local ind = " "
  172. outf("<h1>Table of contents</h1>\n")
  173. outf("<ul class=\"toc\">")
  174. for _, mod in ipairs(sorted_keys(modules)) do
  175. desc = modules[mod]
  176. outf("<li><a href=\"#mod_%s\">Module %s</a>", mod, mod)
  177. outf("<ul>")
  178. if desc["function"] then
  179. outf("<li><a href=\"#functions\">Functions</a>")
  180. outf("<ul>")
  181. for _, f in ipairs(desc['function']) do
  182. outf("<li><a href=\"#func_%s\">%s</a>", f.name, f.name)
  183. end
  184. outf("</ul></li>")
  185. end
  186. if desc["object"] then
  187. outf("<li><a href=\"#objects\">Objects</a>")
  188. outf("<ul>")
  189. for _, f in ipairs(desc['object']) do
  190. outf("<li><a href=\"#obj_%s\">%s</a>", f.name, f.name)
  191. end
  192. outf("</ul></li>")
  193. end
  194. outf("</ul></li>")
  195. end
  196. outf("</ul>\n")
  197. end
  198. function output_stylesheet()
  199. outf[[<style type="text/css">
  200. body { font-family: sans; font-size: 12pt; margin-left: 50pt; }
  201. h4 { color: #666; font-size: 14pt; font-weight: bolder; margin-left: -20pt; }
  202. h3 { color: #666; font-size: 16pt; font-weight: bolder; margin-left: -30pt; }
  203. h2 { color: #666; font-size: 18pt; font-weight: bolder; margin-left: -40pt; }
  204. h1 { color: #666; font-size: 20pt; font-weight: bolder; margin-left: -50pt; }
  205. h1.title { color: #666; font-size: 24pt; }
  206. dt { color: #444; font-family: monospace; font-weight: bolder; }
  207. ul.toc { margin-left: -10pt; }
  208. ul.toc a { color: #444; text-decoration: none; }
  209. ul.toc a:hover { color: #000; text-decoration: underline; }
  210. </style>]]
  211. end
  212. function output(modules, title)
  213. outf("<html><head><title>%s</title>", title)
  214. output_stylesheet()
  215. outf("</head><body>")
  216. if title then
  217. outf("<h1 class=\"title\">%s</h1>", title)
  218. end
  219. if modules[1] then
  220. outf("<p>%s</p>", modules[1])
  221. end
  222. output_toc(modules)
  223. for _, mod in ipairs(sorted_keys(modules)) do
  224. desc = modules[mod]
  225. outf("<h1 id=\"mod_%s\">Module %s</h1>", mod, mod)
  226. if desc.desc then
  227. outf("<p>%s</p>", desc.desc)
  228. end
  229. output_functions(desc['function'])
  230. output_objects(desc['object'])
  231. end
  232. outf("</body></html>")
  233. end
  234. modules = {}
  235. for i = 2, #arg do
  236. modules = collect_data(arg[i], modules)
  237. end
  238. for mname, module in pairs(modules) do
  239. if type(module) == "table" then
  240. for lname, list in pairs(module) do
  241. table.sort(list, function(e1, e2) return e1.name < e2.name end)
  242. end
  243. end
  244. end
  245. output(modules, arg[1])