makemd.py 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. import sys
  4. import os.path as path
  5. import os
  6. import xml.etree.ElementTree as ET
  7. input_list = []
  8. for arg in sys.argv[1:]:
  9. if not path.exists(arg):
  10. exit("path {} doesn't exist".format(arg))
  11. elif path.isdir(arg):
  12. input_list += filter(path.isfile, [path.join(arg, f) for f in os.listdir(arg)])
  13. else: # assuming is a file
  14. input_list.append(arg)
  15. if len(input_list) < 1:
  16. print 'usage: makemd.py <classes.xml>'
  17. sys.exit(0)
  18. def validate_tag(elem, tag):
  19. if elem.tag != tag:
  20. print "Tag mismatch, expected '" + tag + "', got " + elem.tag
  21. sys.exit(255)
  22. class_names = []
  23. classes = {}
  24. def make_class_list(class_list, columns):
  25. f = open('class_list.md', 'wb')
  26. prev = 0
  27. col_max = len(class_list) / columns + 1
  28. col_count = 0
  29. row_count = 0
  30. last_initial = ''
  31. fit_columns = []
  32. for n in range(0, columns):
  33. fit_columns += [[]]
  34. indexers = []
  35. last_initial = ''
  36. idx = 0
  37. for n in class_list:
  38. col = idx / col_max
  39. if col >= columns:
  40. col = columns - 1
  41. fit_columns[col] += [n]
  42. idx += 1
  43. if n[:1] != last_initial:
  44. indexers += [n]
  45. last_initial = n[:1]
  46. row_max = 0
  47. f.write("\n")
  48. for n in range(0, columns):
  49. if len(fit_columns[n]) > row_max:
  50. row_max = len(fit_columns[n])
  51. f.write("| ")
  52. for n in range(0, columns):
  53. f.write(" | |")
  54. f.write("\n")
  55. f.write("| ")
  56. for n in range(0, columns):
  57. f.write(" --- | ------- |")
  58. f.write("\n")
  59. for r in range(0, row_max):
  60. s = '| '
  61. for c in range(0, columns):
  62. if r >= len(fit_columns[c]):
  63. continue
  64. classname = fit_columns[c][r]
  65. initial = classname[0]
  66. if classname in indexers:
  67. s += '**' + initial + '** | '
  68. else:
  69. s += ' | '
  70. s += '[' + classname + '](class_' + classname.lower() + ') | '
  71. s += '\n'
  72. f.write(s)
  73. f.close()
  74. def dokuize_text(txt):
  75. return txt
  76. def dokuize_text(text):
  77. pos = 0
  78. while True:
  79. pos = text.find('[', pos)
  80. if pos == -1:
  81. break
  82. endq_pos = text.find(']', pos + 1)
  83. if endq_pos == -1:
  84. break
  85. pre_text = text[:pos]
  86. post_text = text[endq_pos + 1:]
  87. tag_text = text[pos + 1:endq_pos]
  88. if tag_text in class_names:
  89. tag_text = make_type(tag_text)
  90. else:
  91. # command
  92. cmd = tag_text
  93. space_pos = tag_text.find(' ')
  94. if cmd.find('html') == 0:
  95. cmd = tag_text[:space_pos]
  96. param = tag_text[space_pos + 1:]
  97. tag_text = '<' + param + '>'
  98. elif cmd.find('method') == 0:
  99. cmd = tag_text[:space_pos]
  100. param = tag_text[space_pos + 1:]
  101. if param.find('.') != -1:
  102. (class_param, method_param) = param.split('.')
  103. tag_text = '[' + class_param + '.' + method_param.replace("_", "&#95;") + '](' + class_param.lower() + '#' \
  104. + method_param + ')'
  105. else:
  106. tag_text = '[' + param.replace("_", "&#95;") + '](#' + param + ')'
  107. elif cmd.find('image=') == 0:
  108. tag_text = '![](' + cmd[6:] + ')'
  109. elif cmd.find('url=') == 0:
  110. tag_text = '[' + cmd[4:] + '](' + cmd[4:]
  111. elif cmd == '/url':
  112. tag_text = ')'
  113. elif cmd == 'center':
  114. tag_text = ''
  115. elif cmd == '/center':
  116. tag_text = ''
  117. elif cmd == 'br':
  118. tag_text = '\n'
  119. elif cmd == 'i' or cmd == '/i':
  120. tag_text = '_'
  121. elif cmd == 'b' or cmd == '/b':
  122. tag_text = '**'
  123. elif cmd == 'u' or cmd == '/u':
  124. tag_text = '__'
  125. else:
  126. tag_text = '[' + tag_text + ']'
  127. text = pre_text + tag_text + post_text
  128. pos = len(pre_text) + len(tag_text)
  129. # tnode = ET.SubElement(parent,"div")
  130. # tnode.text=text
  131. return text
  132. def make_type(t):
  133. global class_names
  134. if t in class_names:
  135. return '[' + t + '](class_' + t.lower() + ')'
  136. return t
  137. def make_method(
  138. f,
  139. name,
  140. m,
  141. declare,
  142. event=False,
  143. ):
  144. s = ' * '
  145. ret_type = 'void'
  146. args = list(m)
  147. mdata = {}
  148. mdata['argidx'] = []
  149. for a in args:
  150. if a.tag == 'return':
  151. idx = -1
  152. elif a.tag == 'argument':
  153. idx = int(a.attrib['index'])
  154. else:
  155. continue
  156. mdata['argidx'].append(idx)
  157. mdata[idx] = a
  158. if not event:
  159. if -1 in mdata['argidx']:
  160. s += make_type(mdata[-1].attrib['type'])
  161. else:
  162. s += 'void'
  163. s += ' '
  164. if declare:
  165. # span.attrib["class"]="funcdecl"
  166. # a=ET.SubElement(span,"a")
  167. # a.attrib["name"]=name+"_"+m.attrib["name"]
  168. # a.text=name+"::"+m.attrib["name"]
  169. s += ' **' + m.attrib['name'].replace("_", "&#95;") + '** '
  170. else:
  171. s += ' **[' + m.attrib['name'].replace("_", "&#95;") + '](#' + m.attrib['name'] + ')** '
  172. s += ' **(**'
  173. argfound = False
  174. for a in mdata['argidx']:
  175. arg = mdata[a]
  176. if a < 0:
  177. continue
  178. if a > 0:
  179. s += ', '
  180. else:
  181. s += ' '
  182. s += make_type(arg.attrib['type'])
  183. if 'name' in arg.attrib:
  184. s += ' ' + arg.attrib['name']
  185. else:
  186. s += ' arg' + str(a)
  187. if 'default' in arg.attrib:
  188. s += '=' + arg.attrib['default']
  189. argfound = True
  190. if argfound:
  191. s += ' '
  192. s += ' **)**'
  193. if 'qualifiers' in m.attrib:
  194. s += ' ' + m.attrib['qualifiers']
  195. f.write(s + '\n')
  196. def make_doku_class(node):
  197. name = node.attrib['name']
  198. f = open("class_" + name.lower() + '.md', 'wb')
  199. f.write('# ' + name + ' \n')
  200. if 'inherits' in node.attrib:
  201. inh = node.attrib['inherits'].strip()
  202. f.write('####**Inherits:** ' + make_type(inh) + '\n')
  203. if 'category' in node.attrib:
  204. f.write('####**Category:** ' + node.attrib['category'].strip()
  205. + '\n')
  206. briefd = node.find('brief_description')
  207. if briefd != None:
  208. f.write('\n### Brief Description \n')
  209. f.write(dokuize_text(briefd.text.strip()) + '\n')
  210. methods = node.find('methods')
  211. if methods != None and len(list(methods)) > 0:
  212. f.write('\n### Member Functions \n')
  213. for m in list(methods):
  214. make_method(f, node.attrib['name'], m, False)
  215. events = node.find('signals')
  216. if events != None and len(list(events)) > 0:
  217. f.write('\n### Signals \n')
  218. for m in list(events):
  219. make_method(f, node.attrib['name'], m, True, True)
  220. d = m.find('description')
  221. if d == None or d.text.strip() == '':
  222. continue
  223. f.write('\n')
  224. f.write(dokuize_text(d.text.strip()))
  225. f.write('\n')
  226. members = node.find('members')
  227. if members != None and len(list(members)) > 0:
  228. f.write('\n### Member Variables \n')
  229. for c in list(members):
  230. s = ' * '
  231. s += make_type(c.attrib['type']) + ' '
  232. s += '**' + c.attrib['name'] + '**'
  233. if c.text.strip() != '':
  234. s += ' - ' + c.text.strip()
  235. f.write(s + '\n')
  236. constants = node.find('constants')
  237. if constants != None and len(list(constants)) > 0:
  238. f.write('\n### Numeric Constants \n')
  239. for c in list(constants):
  240. s = ' * '
  241. s += '**' + c.attrib['name'] + '**'
  242. if 'value' in c.attrib:
  243. s += ' = **' + c.attrib['value'] + '**'
  244. if c.text.strip() != '':
  245. s += ' - ' + c.text.strip()
  246. f.write(s + '\n')
  247. descr = node.find('description')
  248. if descr != None and descr.text.strip() != '':
  249. f.write('\n### Description \n')
  250. f.write(dokuize_text(descr.text.strip()) + '\n')
  251. methods = node.find('methods')
  252. if methods != None and len(list(methods)) > 0:
  253. f.write('\n### Member Function Description \n')
  254. for m in list(methods):
  255. d = m.find('description')
  256. if d == None or d.text.strip() == '':
  257. continue
  258. f.write('\n#### <a name="' + m.attrib['name'] + '">' + m.attrib['name'] + '</a>\n')
  259. make_method(f, node.attrib['name'], m, True)
  260. f.write('\n')
  261. f.write(dokuize_text(d.text.strip()))
  262. f.write('\n')
  263. f.close()
  264. for file in input_list:
  265. tree = ET.parse(file)
  266. doc = tree.getroot()
  267. if 'version' not in doc.attrib:
  268. print "Version missing from 'doc'"
  269. sys.exit(255)
  270. version = doc.attrib['version']
  271. class_name = doc.attrib['name']
  272. if class_name in class_names:
  273. continue
  274. class_names.append(class_name)
  275. classes[class_name] = doc
  276. class_names.sort()
  277. make_class_list(class_names, 2)
  278. for cn in class_names:
  279. c = classes[cn]
  280. make_doku_class(c)