diff options
author | Aaron Bentley <abentley@panoramicfeedback.com> | 2006-04-06 14:06:13 -0400 |
---|---|---|
committer | Aaron Bentley <abentley@panoramicfeedback.com> | 2006-04-06 14:06:13 -0400 |
commit | b7622887a499a851c7016560143e7a4332bb901d (patch) | |
tree | 951a7bf1016573b44d1249801dbd8fa50c21f027 /libbe/restconvert.py | |
parent | d63c1b07b8eed0c1b8822ab03ad2d953df0b6f69 (diff) | |
parent | 64ea14acca6f6420ea17c0c2126a71de2c3ef91d (diff) | |
download | bugseverywhere-b7622887a499a851c7016560143e7a4332bb901d.tar.gz |
Merge from upstream
Diffstat (limited to 'libbe/restconvert.py')
-rw-r--r-- | libbe/restconvert.py | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/libbe/restconvert.py b/libbe/restconvert.py new file mode 100644 index 0000000..f93fcf6 --- /dev/null +++ b/libbe/restconvert.py @@ -0,0 +1,108 @@ +import re +from StringIO import StringIO +from docutils import nodes +from docutils.statemachine import StringList +from docutils.core import publish_file +from docutils.parsers import rst +from docutils.parsers.rst import directives +from docutils.parsers.rst.states import Inliner, MarkupMismatch, unescape +from elementtree import ElementTree + + +def rest_xml(rest): + warnings = StringIO() + parser = rst.Parser(inliner=HelpLinkInliner()) + xmltext = publish_file(rest, writer_name="html", parser=parser, + settings_overrides={"warning_stream": warnings, + "halt_level": 5}) + warnings.seek(0) + return ElementTree.parse(StringIO(xmltext)).getroot(), warnings.read() + +class HelpLinkInliner(Inliner): + def __init__(self, roles=None): + Inliner.__init__(self, roles) + regex = re.compile('\[([^|]*)\|([^]]*)\]') + self.implicit_dispatch.append((regex, self.help_reference)) + + def parse(self, *args, **kwargs): + self.more_messages = [] + nodes, messages = Inliner.parse(self, *args, **kwargs) + return nodes, (messages + self.more_messages) + + def help_reference(self, match, lineno): + from wizardhelp.controllers import iter_help_pages + text,link = match.groups() + rawtext = match.group(0) + text, link, rawtext = [unescape(f, 1) for f in (text, link, rawtext)] + if link not in list(iter_help_pages()): + msg = self.reporter.warning('Broken link to "%s".' % link, + line=lineno) + self.more_messages.append(msg) + ref = "/help/%s/" % link + unescaped = text + node = nodes.reference(rawtext, text, refuri=ref) + node.set_class("helplink") + return [node] + + +def rst_directive(name=None, required_args=0, optional_args=0, + final_arg_ws=False, options=None, content='forbidden'): + """Decorator that simplifies creating ReST directives + + All arguments are optional. Name is, by default, determined from the + function name. + + The possible values for content are 'forbidden', 'allowed' (but not + required), and 'required' (a warning will be generated if not present). + """ + content_rules = {'forbidden': (False, False), 'allowed': (True, False), + 'required': (True, True)} + content_allowed, content_required = content_rules[content] + + def decorator_factory(func): + my_name = name + if my_name is None: + my_name = func.__name__ + + def decorator(name, arguments, options, content, lineno, + content_offset, block_text, state, state_machine): + warn = state_machine.reporter.warning + if not content and content_required: + warn = state_machine.reporter.warning + warning = warn('%s is empty' % my_name, + nodes.literal_block(block_text, block_text), + line=lineno) + return [warning] + return func(name, arguments, options, content, lineno, + content_offset, block_text, state, state_machine) + + decorator.arguments = (required_args, optional_args, final_arg_ws) + decorator.options = options + decorator.content = content_allowed + directives.register_directive(my_name, decorator) + return decorator + return decorator_factory + + +@rst_directive(required_args=1, final_arg_ws=True, content='required') +def foldout(name, arguments, options, content, lineno, content_offset, + block_text, state, state_machine): + """\ + Generate a foldout section. + + On the ReST side, this merely involves marking the items with suitable + classes. A Kid match rule will be used to insert the appropriate + Javascript magic. + """ + text = '\n'.join(content) + foldout_title = nodes.paragraph([arguments[0]]) + foldout_title.set_class('foldout-title') + state.nested_parse(StringList([arguments[0]]), 0, foldout_title) + foldout_body = nodes.compound(text) + foldout_body.set_class('foldout-body') + state.nested_parse(content, content_offset, foldout_body) + foldout = nodes.compound(text) + foldout += foldout_title + foldout += foldout_body + foldout.set_class('foldout') + return [foldout] |