185 lines
5.1 KiB
Python
185 lines
5.1 KiB
Python
|
import py
|
||
|
from py.__.rest import rst
|
||
|
from py.xml import html
|
||
|
|
||
|
class RestTransformer(object):
|
||
|
def __init__(self, tree):
|
||
|
self.tree = tree
|
||
|
self._titledepths = {}
|
||
|
self._listmarkers = []
|
||
|
|
||
|
def parse(self, handler):
|
||
|
handler.startDocument()
|
||
|
self.parse_nodes(self.tree.children, handler)
|
||
|
handler.endDocument()
|
||
|
|
||
|
def parse_nodes(self, nodes, handler):
|
||
|
for node in nodes:
|
||
|
name = node.__class__.__name__
|
||
|
if name == 'Rest':
|
||
|
continue
|
||
|
getattr(self, 'handle_%s' % (name,))(node, handler)
|
||
|
|
||
|
def handle_Title(self, node, handler):
|
||
|
depthkey = (node.abovechar, node.belowchar)
|
||
|
if depthkey not in self._titledepths:
|
||
|
if not self._titledepths:
|
||
|
depth = 1
|
||
|
else:
|
||
|
depth = max(self._titledepths.values()) + 1
|
||
|
self._titledepths[depthkey] = depth
|
||
|
else:
|
||
|
depth = self._titledepths[depthkey]
|
||
|
handler.startTitle(depth)
|
||
|
self.parse_nodes(node.children, handler)
|
||
|
handler.endTitle(depth)
|
||
|
|
||
|
def handle_ListItem(self, node, handler):
|
||
|
# XXX oomph...
|
||
|
startlist = False
|
||
|
c = node.parent.children
|
||
|
nodeindex = c.index(node)
|
||
|
if nodeindex == 0:
|
||
|
startlist = True
|
||
|
else:
|
||
|
prev = c[nodeindex - 1]
|
||
|
if not isinstance(prev, rst.ListItem):
|
||
|
startlist = True
|
||
|
elif prev.indent < node.indent:
|
||
|
startlist = True
|
||
|
endlist = False
|
||
|
if nodeindex == len(c) - 1:
|
||
|
endlist = True
|
||
|
else:
|
||
|
next = c[nodeindex + 1]
|
||
|
if not isinstance(next, rst.ListItem):
|
||
|
endlist = True
|
||
|
elif next.indent < node.indent:
|
||
|
endlist = True
|
||
|
type = isinstance(node, rst.OrderedListItem) and 'o' or 'u'
|
||
|
handler.startListItem('u', startlist)
|
||
|
self.parse_nodes(node.children, handler)
|
||
|
handler.endListItem('u', endlist)
|
||
|
|
||
|
def handle_Transition(self, node, handler):
|
||
|
handler.handleTransition()
|
||
|
|
||
|
def handle_Paragraph(self, node, handler):
|
||
|
handler.startParagraph()
|
||
|
self.parse_nodes(node.children, handler)
|
||
|
handler.endParagraph()
|
||
|
|
||
|
def handle_SubParagraph(self, node, handler):
|
||
|
handler.startSubParagraph()
|
||
|
self.parse_nodes(node.children, handler)
|
||
|
handler.endSubParagraph()
|
||
|
|
||
|
def handle_LiteralBlock(self, node, handler):
|
||
|
handler.handleLiteralBlock(node._text)
|
||
|
|
||
|
def handle_Text(self, node, handler):
|
||
|
handler.handleText(node._text)
|
||
|
|
||
|
def handle_Em(self, node, handler):
|
||
|
handler.handleEm(node._text)
|
||
|
|
||
|
def handle_Strong(self, node, handler):
|
||
|
handler.handleStrong(node._text)
|
||
|
|
||
|
def handle_Quote(self, node, handler):
|
||
|
handler.handleQuote(node._text)
|
||
|
|
||
|
def handle_Link(self, node, handler):
|
||
|
handler.handleLink(node._text, node.target)
|
||
|
|
||
|
def entitize(txt):
|
||
|
for char, repl in (('&', 'amp'), ('>', 'gt'), ('<', 'lt'), ('"', 'quot'),
|
||
|
("'", 'apos')):
|
||
|
txt = txt.replace(char, '&%s;' % (repl,))
|
||
|
return txt
|
||
|
|
||
|
class HTMLHandler(object):
|
||
|
def __init__(self, title='untitled rest document'):
|
||
|
self.title = title
|
||
|
self.root = None
|
||
|
self.tagstack = []
|
||
|
self._currlist = None
|
||
|
|
||
|
def startDocument(self):
|
||
|
h = html.html()
|
||
|
self.head = head = html.head()
|
||
|
self.title = title = html.title(self.title)
|
||
|
self._push(h)
|
||
|
h.append(head)
|
||
|
h.append(title)
|
||
|
self.body = body = html.body()
|
||
|
self._push(body)
|
||
|
|
||
|
def endDocument(self):
|
||
|
self._pop() # body
|
||
|
self._pop() # html
|
||
|
|
||
|
def startTitle(self, depth):
|
||
|
h = getattr(html, 'h%s' % (depth,))()
|
||
|
self._push(h)
|
||
|
|
||
|
def endTitle(self, depth):
|
||
|
self._pop()
|
||
|
|
||
|
def startParagraph(self):
|
||
|
self._push(html.p())
|
||
|
|
||
|
def endParagraph(self):
|
||
|
self._pop()
|
||
|
|
||
|
def startSubParagraph(self):
|
||
|
self._push(html.p(**{'class': 'sub'}))
|
||
|
|
||
|
def endSubParagraph(self):
|
||
|
self._pop()
|
||
|
|
||
|
def handleLiteralBlock(self, text):
|
||
|
pre = html.pre(text)
|
||
|
if self.tagstack:
|
||
|
self.tagstack[-1].append(pre)
|
||
|
else:
|
||
|
self.root = pre
|
||
|
|
||
|
def handleText(self, text):
|
||
|
self.tagstack[-1].append(text)
|
||
|
|
||
|
def handleEm(self, text):
|
||
|
self.tagstack[-1].append(html.em(text))
|
||
|
|
||
|
def handleStrong(self, text):
|
||
|
self.tagstack[-1].append(html.strong(text))
|
||
|
|
||
|
def startListItem(self, type, startlist):
|
||
|
if startlist:
|
||
|
nodename = type == 'o' and 'ol' or 'ul'
|
||
|
self._push(getattr(html, nodename)())
|
||
|
self._push(html.li())
|
||
|
|
||
|
def endListItem(self, type, closelist):
|
||
|
self._pop()
|
||
|
if closelist:
|
||
|
self._pop()
|
||
|
|
||
|
def handleLink(self, text, target):
|
||
|
self.tagstack[-1].append(html.a(text, href=target))
|
||
|
|
||
|
def _push(self, el):
|
||
|
if self.tagstack:
|
||
|
self.tagstack[-1].append(el)
|
||
|
else:
|
||
|
self.root = el
|
||
|
self.tagstack.append(el)
|
||
|
|
||
|
def _pop(self):
|
||
|
self.tagstack.pop()
|
||
|
|
||
|
def _html(self):
|
||
|
return self.root.unicode()
|
||
|
html = property(_html)
|
||
|
|