From 64ea14acca6f6420ea17c0c2126a71de2c3ef91d Mon Sep 17 00:00:00 2001 From: Aaron Bentley Date: Thu, 6 Apr 2006 14:05:47 -0400 Subject: Add ReST support to web front end --- libbe/restconvert.py | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 libbe/restconvert.py (limited to 'libbe') 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] -- cgit