aboutsummaryrefslogtreecommitdiff
path: root/makespec.py
blob: c7b90b542c73a4051621134a07780c52b2e945d8 (plain)
  1. #!/usr/bin/env python3
  2. import re
  3. import sys
  4. from subprocess import *
  5. if len(sys.argv) == 3:
  6. specfile = sys.argv[1]
  7. specformat = sys.argv[2]
  8. if not (specformat in ["html", "markdown"]):
  9. sys.stderr.write("Format must be html or markdown\n")
  10. exit(1)
  11. else:
  12. sys.stderr.write("Usage: makespec.py SPECFILE [html|markdown]\n")
  13. exit(1)
  14. def toIdentifier(s):
  15. return re.sub(r'\s+', '-', re.sub(r'\W+', ' ', s.strip().lower()))
  16. def pipe_through_prog(prog, text):
  17. p1 = Popen(prog.split(), stdout=PIPE, stdin=PIPE, stderr=PIPE)
  18. [result, err] = p1.communicate(input=text.encode('utf-8'))
  19. return [p1.returncode, result.decode('utf-8'), err]
  20. def replaceAnchor(match):
  21. refs.append("[{0}]: #{1}".format(match.group(1), match.group(2)))
  22. if specformat == "html":
  23. return '<a id="{1}" href="#{1}" class="definition">{0}</a>'.format(match.group(1), match.group(2))
  24. else:
  25. return match.group(0)
  26. stage = 0
  27. example = 0
  28. section = ""
  29. sections = []
  30. mdlines = []
  31. refs = []
  32. lastnum = []
  33. finishedMeta = False
  34. yamllines = []
  35. with open(specfile, 'r', encoding='utf-8') as spec:
  36. for ln in spec:
  37. if not finishedMeta:
  38. yamllines.append(ln)
  39. if re.match(r'^\.\.\.$', ln):
  40. finishedMeta = True
  41. elif re.match(r'^\.$', ln):
  42. if stage == 0:
  43. example += 1
  44. mdlines.append("\n<div class=\"example\" id=\"example-{0}\" data-section=\"{1}\">\n".format(example, section))
  45. mdlines.append("<div class=\"examplenum\"><a href=\"#example-{0}\">Example {0}</a>&nbsp;&nbsp;<a class=\"dingus\" title=\"open in interactive dingus\">(interact)</a></div>\n\n".format(example))
  46. mdlines.append("````````````````````````````````````````````````````````` markdown\n")
  47. stage = 1
  48. elif stage == 1:
  49. mdlines.append("`````````````````````````````````````````````````````````\n\n")
  50. mdlines.append("````````````````````````````````````````````````````````` html\n")
  51. stage = 2
  52. elif stage == 2:
  53. mdlines.append("`````````````````````````````````````````````````````````\n\n")
  54. mdlines.append("</div>\n")
  55. stage = 0
  56. else:
  57. sys.stderr.out("Encountered unknown stage {0}\n".format(stage))
  58. sys.exit(1)
  59. else:
  60. if stage == 0:
  61. match = re.match(r'^(#{1,6}) *(.*)', ln)
  62. if match:
  63. section = match.group(2)
  64. lastlevel = len(lastnum)
  65. level = len(match.group(1))
  66. if re.search(r'{-}$', section):
  67. section = re.sub(r' *{-} *$', '', section)
  68. number = ''
  69. else:
  70. if lastlevel == level:
  71. lastnum[level - 1] = lastnum[level - 1] + 1
  72. elif lastlevel < level:
  73. while len(lastnum) < level:
  74. lastnum.append(1)
  75. else: # lastlevel > level
  76. lastnum = lastnum[0:level]
  77. lastnum[level - 1] = lastnum[level - 1] + 1
  78. number = '.'.join([str(x) for x in lastnum])
  79. ident = toIdentifier(section)
  80. sections.append(dict(level=level,
  81. contents=section,
  82. ident=ident,
  83. number=number))
  84. refs.append("[{0}]: #{1}".format(section, ident))
  85. else:
  86. ln = re.sub(r'\[([^]]*)\]\(@([^)]*)\)', replaceAnchor, ln)
  87. else:
  88. ln = re.sub(r' ', '␣', ln)
  89. mdlines.append(ln)
  90. mdtext = ''.join(mdlines) + '\n\n' + '\n'.join(refs) + '\n'
  91. if specformat == "markdown":
  92. sys.stdout.write(mdtext)
  93. elif specformat == "html":
  94. toclines = []
  95. for section in sections:
  96. indent = ' ' * (section['level'] - 1)
  97. toclines.append(indent + '* [' + section['number'] + ' ' +
  98. section['contents'] + '](#' + section['ident'] + ')')
  99. toc = '<div id="TOC">\n\n' + '\n'.join(toclines) + '\n\n</div>\n\n'
  100. yaml = ''.join(yamllines) + '\n'
  101. prog = "pandoc -s -S --no-highlight --number-sections --template template.html"
  102. [retcode, result, err] = pipe_through_prog(prog, yaml + toc + mdtext)
  103. if retcode == 0:
  104. result = re.sub(r'␣', '<span class="space"> </span>', result)
  105. sys.stdout.write(result)
  106. else:
  107. sys.stderr.write("Error converting markdown version of spec:\n")
  108. sys.stderr.write(err)
  109. exit(1)
  110. exit(0)