changeset 271:186df6f00a36

Fixed rst loading. In my branch, the plugin interface will be more sensible. imported from: moin--main--1.5--patch-274
author Alexander Schremmer <alex@alexanderweb.de.tla>
date Fri, 02 Dec 2005 15:21:43 +0000
parents 9eccf657b834
children d35743ee9865
files MoinMoin/parser/rst.py contrib/rst_parser/rst.py
diffstat 2 files changed, 553 insertions(+), 543 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/parser/rst.py	Fri Dec 02 15:21:43 2005 +0000
@@ -0,0 +1,553 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin - ReStructured Text Parser
+
+    @copyright: 2004 by Matthew Gilbert <gilbert AT voxmea DOT net>
+        and by Alexander Schremmer <alex AT alexanderweb DOT de>
+    @license: GNU GPL, see COPYING for details.
+
+    REQUIRES docutils 0.3.3 or later
+"""
+
+import re
+import new
+import StringIO
+import __builtin__
+import sys
+import copy
+import types
+
+# docutils imports are below
+import MoinMoin.parser.wiki
+from MoinMoin.Page import Page
+
+Dependencies = [] # this parser just depends on the raw text
+
+# --- make docutils safe by overriding all module-scoped names related to IO ---
+
+# TODO: Add an error message to dummyOpen so that the user knows what they did
+# requested an unsupported feature of docutils in MoinMoin.
+def dummyOpen(x, y=None, z=None): return
+
+class dummyIO(StringIO.StringIO):
+    def __init__(self, destination=None, destination_path=None,
+                 encoding=None, error_handler='', autoclose=1,
+                 handle_io_errors=1, source_path=None):
+        StringIO.StringIO.__init__(self)
+
+class dummyUrllib2:
+    def urlopen(a):
+        return StringIO.StringIO()
+    urlopen = staticmethod(urlopen)
+
+# # # All docutils imports must be contained below here
+try:
+    import docutils
+    from docutils.core import publish_parts
+    from docutils.writers import html4css1
+    from docutils.nodes import fully_normalize_name, reference
+    from docutils.parsers import rst
+    from docutils.parsers.rst import directives, roles
+# # # All docutils imports must be contained above here
+
+    ErrorParser = None # used in the case of missing docutils
+    docutils.io.FileOutput = docutils.io.FileInput = dummyIO
+except ImportError:
+    # we need to workaround this totally broken plugin interface that does
+    # not allow us to raise exceptions
+    class ErrorParser:
+        caching = 0
+        Dependencies = Dependencies # copy dependencies from module-scope
+
+        def __init__(self, raw, request, **kw):
+            self.raw = raw
+            self.request = request
+    
+        def format(self, formatter):
+            _ = self.request.getText
+            from MoinMoin.parser import plain
+            self.request.write(formatter.sysmsg(1) +
+                               formatter.rawHTML(_('Rendering of reStructured text is not possible, ''please'' install docutils.')) +
+                               formatter.sysmsg(0))
+            plain.Parser(self.raw, self.request).format(formatter)
+    
+    # Create a pseudo docutils environment
+    docutils = html4css1 = dummyUrllib2()
+    html4css1.HTMLTranslator = html4css1.Writer = object
+
+def safe_import(name, globals = None, locals = None, fromlist = None):
+    mod = __builtin__.__import__(name, globals, locals, fromlist)
+    if mod:
+        mod.open = dummyOpen
+        mod.urllib2 = dummyUrllib2
+    return mod
+
+# Go through and change all docutils modules to use a dummyOpen and dummyUrllib2
+# module. Also make sure that any docutils imported modules also get the dummy
+# implementations.
+for i in sys.modules.keys():
+    if i.startswith('docutils') and sys.modules[i]:
+        sys.modules[i].open = dummyOpen
+        sys.modules[i].urllib2 = dummyUrllib2
+        sys.modules[i].__import__ = safe_import
+
+# --- End of dummy-code --------------------------------------------------------
+
+def html_escape_unicode(node):
+    # Find Python function that does this for me. string.encode('ascii',
+    # 'xmlcharrefreplace') only 2.3 and above.
+    for i in node:
+        if ord(i) > 127:
+            node = node.replace(i, '&#%d;' % (ord(i)))
+    return node
+
+class MoinWriter(html4css1.Writer):
+
+    config_section = 'MoinMoin writer'
+    config_section_dependencies = ('writers',)
+
+    #"""Final translated form of `document`."""
+    output = None
+
+    def wiki_resolver(self, node):
+        """
+            Normally an unknown reference would be an error in an reST document.
+            However, this is how new documents are created in the wiki. This
+            passes on unknown references to eventually be handled by the
+            MoinMoin formatter.
+        """
+        if len(node['ids']) != 0:
+            # If the node has id then its probably an internal link. Let
+            # docutils generate an error.
+            return False
+        node['refuri'] = node['name']
+        del node['refname']
+        node.resolved = 1
+        self.nodes.append(node)
+        return True
+
+    wiki_resolver.priority = 001
+
+    def __init__(self, formatter, request):
+        html4css1.Writer.__init__(self)
+        self.formatter = formatter
+        self.request = request
+        # Add our wiki unknown_reference_resolver to our list of functions to
+        # run when a target isn't found
+        self.unknown_reference_resolvers = [self.wiki_resolver]
+        # We create a new parser to process MoinMoin wiki style links in the
+        # reST.
+        self.wikiparser = MoinMoin.parser.wiki.Parser('', self.request)
+        self.wikiparser.formatter = self.formatter
+        self.wikiparser.hilite_re = None
+        self.nodes = []
+
+    def translate(self):
+        visitor = MoinTranslator(self.document,
+                                 self.formatter,
+                                 self.request,
+                                 self.wikiparser,
+                                 self)
+        self.document.walkabout(visitor)
+        self.visitor = visitor
+        self.output = html_escape_unicode(visitor.astext())
+
+
+class Parser:
+    caching = 1
+    Dependencies = Dependencies # copy dependencies from module-scope
+
+    def __init__(self, raw, request, **kw):
+        self.raw = raw
+        self.request = request
+        self.form = request.form
+
+    def format(self, formatter):
+        # Create our simple parser
+        parser = MoinDirectives(self.request)
+
+        parts = publish_parts(
+            source = self.raw,
+            writer = MoinWriter(formatter, self.request),
+            settings_overrides = {
+                'halt_level': 5,
+                'traceback': True,
+                'file_insertion_enabled': 0,
+                'raw_enabled': 0,
+                'stylesheet_path': '',
+            }
+        )
+
+        text = ''
+        if parts['title']:
+            text += formatter.rawHTML('<h2>' + parts['title'] + '</h2>')
+        # If there is only one subtitle then it is held in parts['subtitle'].
+        # However, if there is more than one subtitle then this is empty and
+        # fragment contains all of the subtitles.
+        if parts['subtitle']:
+            text += formatter.rawHTML('<h3>' + parts['subtitle'] + '</h3>')
+        if parts['docinfo']:
+            text += parts['docinfo']
+        text += parts['fragment']
+        self.request.write(html_escape_unicode(text))
+
+class RawHTMLList(list):
+    """
+        RawHTMLList catches all html appended to internal HTMLTranslator lists.
+        It passes the HTML through the MoinMoin rawHTML formatter to strip 
+        markup when necessary. This is to support other formatting outputs
+        (such as ?action=format&mimetype=text/plain).
+    """
+    
+    def __init__(self, formatter):
+        self.formatter = formatter
+        
+    def append(self, text):
+        f = sys._getframe()
+        if f.f_back.f_code.co_filename.endswith('html4css1.py'):
+            if isinstance(text, types.StringType) or isinstance(text, types.UnicodeType):
+                text = self.formatter.rawHTML(text)
+        list.append(self, text)
+
+class MoinTranslator(html4css1.HTMLTranslator):
+
+    def __init__(self, document, formatter, request, parser, writer):
+        html4css1.HTMLTranslator.__init__(self, document)
+        self.formatter = formatter
+        self.request = request
+        # MMG: Using our own writer when needed. Save the old one to restore
+        # after the page has been processed by the html4css1 parser.
+        self.original_write, self.request.write = self.request.write, self.capture_wiki_formatting
+        self.wikiparser = parser
+        self.wikiparser.request = request
+        # MoinMoin likes to start the initial headers at level 3 and the title
+        # gets level 2, so to comply with their styles, we do here also.
+        # TODO: Could this be fixed by passing this value in settings_overrides?
+        self.initial_header_level = 3
+        # Temporary place for wiki returned markup. This will be filled when
+        # replacing the default writer with the capture_wiki_formatting
+        # function (see visit_image for an example).
+        self.wiki_text = ''
+        self.setup_wiki_handlers()
+        
+        # Make all internal lists RawHTMLLists, see RawHTMLList class
+        # comment for more information.
+        for i in self.__dict__:
+            if isinstance(getattr(self, i), types.ListType):
+                setattr(self, i, RawHTMLList(formatter))
+
+    def depart_docinfo(self, node):
+        """
+            depart_docinfo assigns a new list to self.body, we need to re-make that
+            into a RawHTMLList.
+        """
+        html4css1.HTMLTranslator.depart_docinfo(self, node)
+        self.body = RawHTMLList(self.formatter)
+
+    def capture_wiki_formatting(self, text):
+        """
+            Captures MoinMoin generated markup to the instance variable
+            wiki_text.
+        """
+        # For some reason getting empty strings here which of course overwrites
+        # what we really want (this is called multiple times per MoinMoin
+        # format call, which I don't understand).
+        self.wiki_text += text
+
+    def process_wiki_text(self, text):
+        """
+            This sequence is repeated numerous times, so its captured as a
+            single call here. Its important that wiki_text is blanked before we
+            make the format call. format will call request.write which we've
+            hooked to capture_wiki_formatting. If wiki_text is not blanked
+            before a call to request.write we will get the old markup as well as
+            the newly generated markup.
+
+            TODO: Could implement this as a list so that it acts as a stack. I
+            don't like having to remember to blank wiki_text.
+        """
+        self.wiki_text = ''
+        self.wikiparser.raw = text
+        self.wikiparser.format(self.formatter)
+
+    def add_wiki_markup(self):
+        """
+            Place holder in case this becomes more elaborate someday. For now it
+            only appends the MoinMoin generated markup to the html body and
+            raises SkipNode.
+        """
+        self.body.append(self.wiki_text)
+        self.wiki_text = ''
+        raise docutils.nodes.SkipNode
+
+    def astext(self):
+        self.request.write = self.original_write
+        return html4css1.HTMLTranslator.astext(self)
+
+    def process_inline(self, node, uri_string):
+        """
+            Process the "inline:" link scheme. This can either come from
+            visit_reference or from visit_image. The uri_string changes
+            depending on the caller. The uri is passed to MoinMoin to handle the
+            inline link. If it is an image, the src line is extracted and passed
+            to the html4css1 writer to allow the reST image attributes.
+            Otherwise, the html from MoinMoin is inserted into the reST document
+            and SkipNode is raised.
+        """
+        self.process_wiki_text(node[uri_string])
+        # Only pass the src and alt parts to the writer. The reST writer
+        # inserts its own tags so we don't need the MoinMoin html markup.
+        src = re.search('src="([^"]+)"', self.wiki_text)
+        if src:
+            node['uri'] = src.groups()[0]
+            if not 'alt' in node.attributes:
+                alt = re.search('alt="([^"]*)"', self.wiki_text)
+                if alt:
+                    node['alt'] = alt.groups()[0]
+        else:
+            # Image doesn't exist yet for the page so just use what's
+            # returned from MoinMoin verbatim
+            self.add_wiki_markup()
+
+    def process_wiki_target(self, target):
+        self.process_wiki_text(target)
+        # MMG: May need a call to fixup_wiki_formatting here but I
+        # don't think so.
+        self.add_wiki_markup()
+
+    def fixup_wiki_formatting(self, text):
+        replacement = {'<p>': '', '</p>': '', '\n': '', '> ': '>'}
+        for src, dst in replacement.items():
+            text = text.replace(src, dst)
+        # Everything seems to have a space ending the text block. We want to
+        # get rid of this
+        if text and text[-1] == ' ':
+            text = text[:-1]
+        return text
+
+    def visit_reference(self, node):
+        """
+            Pass links to MoinMoin to get the correct wiki space url. Extract
+            the url and pass it on to the html4css1 writer to handle. Inline
+            images are also handled by visit_image. Not sure what the "drawing:"
+            link scheme is used for, so for now it is handled here.
+
+            Also included here is a hack to allow MoinMoin macros. This routine
+            checks for a link which starts with "[[". This link is passed to the
+            MoinMoin formatter and the resulting markup is inserted into the
+            document in the place of the original link reference.
+        """
+        moin_link_schemes = ('wiki:', 'attachment:', 'drawing:', '[[',
+                             'inline:')
+
+        if 'refuri' in node.attributes:
+            target = None
+            refuri = node['refuri']
+
+            # MMG: Fix this line
+            if [scheme for scheme in moin_link_schemes if
+                    refuri.lstrip().startswith(scheme)]:
+                # For a macro, We want the actuall text from the user in target,
+                # not the fully normalized version that is contained in refuri.
+                if refuri.startswith('[['):
+                    target = node['name']
+                else:
+                    target = refuri
+            # TODO: Figure out the following two elif's and comment
+            # appropriately.
+            # The node should have a whitespace normalized name if the docutlis
+            # reStructuredText parser would normally fully normalize the name.
+            elif ('name' in node.attributes and
+                  fully_normalize_name(node['name']) == refuri):
+                target = ':%s:' % (node['name'])
+            # If its not a uri containing a ':' then its probably destined for
+            # wiki space.
+            elif ':' not in refuri:
+                target = ':%s:' % (refuri)
+
+            if target:
+                if target.startswith('inline:'):
+                    self.process_inline(node, 'refuri')
+                elif target.startswith('[[') and target.endswith(']]'):
+                    self.process_wiki_target(target)
+                else:
+                    # Not a macro or inline so hopefully its a link. Put the target in
+                    # brackets so that MoinMoin knows its a link. Extract the
+                    # href, if it exists, and let docutils handle it from there.
+                    # If there is no href just add whatever MoinMoin returned.
+                    node_text = node.astext().replace('\n', ' ')
+                    self.process_wiki_text('[%s %s]' % (target, node_text))
+                    href = re.search('href="([^"]+)"', self.wiki_text)
+                    if href:
+                        # dirty hack in order to undo the HTML entity quoting
+                        node['refuri'] = href.groups()[0].replace("&amp;", "&")
+                    else:
+                        self.wiki_text = self.fixup_wiki_formatting(self.wiki_text)
+                        self.add_wiki_markup()
+        html4css1.HTMLTranslator.visit_reference(self, node)
+
+    def visit_image(self, node):
+        """
+            Need to intervene in the case of inline images. We need MoinMoin to
+            give us the actual src line to the image and then we can feed this
+            to the default html4css1 writer. NOTE: Since the writer can't "open"
+            this image the scale attribute doesn't work without directly
+            specifying the height or width (or both).
+
+            TODO: Need to handle figures similarly.
+        """
+        uri = node['uri'].lstrip()
+        prefix = ''          # assume no prefix
+        if ':' in uri:
+            prefix = uri.split(':',1)[0]
+        # if prefix isn't URL, try to display in page
+        if not prefix.lower() in ('file', 'http', 'https', 'ftp'):
+            # no prefix given, so fake "inline:"
+            if not prefix:
+                node['uri'] = 'inline:' + uri
+            self.process_inline(node, 'uri')
+        html4css1.HTMLTranslator.visit_image(self, node)
+
+    def create_wiki_functor(self, moin_func):
+        moin_callable = getattr(self.formatter, moin_func)
+        def visit_func(self, node):
+            self.wiki_text = ''
+            self.request.write(moin_callable(1))
+            self.body.append(self.wiki_text)
+        def depart_func(self, node):
+            self.wiki_text = ''
+            self.request.write(moin_callable(0))
+            self.body.append(self.wiki_text)
+        return visit_func, depart_func
+
+    def setup_wiki_handlers(self):
+        """
+            Have the MoinMoin formatter handle markup when it makes sense. These
+            are portions of the document that do not contain reST specific
+            markup. This allows these portions of the document to look
+            consistent with other wiki pages.
+
+            Setup dispatch routines to handle basic document markup. The
+            hanlders dict is the html4css1 handler name followed by the wiki
+            handler name.
+        """
+        handlers = {
+            # Text Markup
+            'emphasis': 'emphasis',
+            'strong': 'strong',
+            'literal': 'code',
+            # Blocks
+            'literal_block': 'preformatted',
+            # Simple Lists
+            'bullet_list': 'bullet_list',
+            'list_item': 'listitem',
+            # Definition List
+            'definition_list': 'definition_list',
+            # Admonitions
+            'warning': 'highlight'
+        }
+        for rest_func, moin_func in handlers.items():
+            visit_func, depart_func = self.create_wiki_functor(moin_func)
+            visit_func = new.instancemethod(visit_func, self, MoinTranslator)
+            depart_func = new.instancemethod(depart_func, self, MoinTranslator)
+            setattr(self, 'visit_%s' % (rest_func), visit_func)
+            setattr(self, 'depart_%s' % (rest_func), depart_func)
+
+    # Enumerated list takes an extra paramter so we handle this differently
+    def visit_enumerated_list(self, node):
+        self.wiki_text = ''
+        self.request.write(self.formatter.number_list(1, start=node.get('start', None)))
+        self.body.append(self.wiki_text)
+
+    def depart_enumerated_list(self, node):
+        self.wiki_text = ''
+        self.request.write(self.formatter.number_list(0))
+        self.body.append(self.wiki_text)
+
+
+class MoinDirectives:
+    """
+        Class to handle all custom directive handling. This code is called as
+        part of the parsing stage.
+    """
+
+    def __init__(self, request):
+        self.request = request
+
+        # include MoinMoin pages
+        directives.register_directive('include', self.include)
+
+        # used for MoinMoin macros
+        directives.register_directive('macro', self.macro)
+
+        # disallow a few directives in order to prevent XSS
+        # for directive in ('meta', 'include', 'raw'):
+        for directive in ('meta', 'raw'):
+            directives.register_directive(directive, None)
+
+        # disable the raw role
+        roles._roles['raw'] = None
+
+        # As a quick fix for infinite includes we only allow a fixed number of
+        # includes per page
+        self.num_includes = 0
+        self.max_includes = 10
+
+    # Handle the include directive rather than letting the default docutils
+    # parser handle it. This allows the inclusion of MoinMoin pages instead of
+    # something from the filesystem.
+    def include(self, name, arguments, options, content, lineno,
+                content_offset, block_text, state, state_machine):
+        # content contains the included file name
+
+        _ = self.request.getText
+
+        # Limit the number of documents that can be included
+        if self.num_includes < self.max_includes:
+            self.num_includes += 1
+        else:
+            lines = [_("**Maximum number of allowed includes exceeded**")]
+            state_machine.insert_input(lines, 'MoinDirectives')
+            return
+
+        if len(content):
+            page = Page(page_name = content[0], request = self.request)
+            if page.exists():
+                text = page.get_raw_body()
+                lines = text.split('\n')
+                # Remove the "#format rst" line
+                if lines[0].startswith("#format"):
+                    del lines[0]
+            else:
+                lines = [_("**Could not find the referenced page: %s**") % (content[0],)]
+            # Insert the text from the included document and then continue
+            # parsing
+            state_machine.insert_input(lines, 'MoinDirectives')
+        return
+
+    include.content = True
+
+    # Add additional macro directive.
+    # This allows MoinMoin macros to be used either by using the directive
+    # directly or by using the substitution syntax. Much cleaner than using the
+    # reference hack (`[[SomeMacro]]`_). This however simply adds a node to the
+    # document tree which is a reference, but through a much better user
+    # interface.
+    def macro(self, name, arguments, options, content, lineno,
+                content_offset, block_text, state, state_machine):
+        # content contains macro to be called
+        if len(content):
+            # Allow either with or without brackets
+            if content[0].startswith('[['):
+                macro = content[0]
+            else:
+                macro = '[[%s]]' % content[0]
+            ref = reference(macro, refuri = macro)
+            ref['name'] = macro
+            return [ref]
+        return
+
+    macro.content = True
+
+if ErrorParser: # fixup in case of missing docutils
+    Parser = ErrorParser
--- a/contrib/rst_parser/rst.py	Fri Dec 02 14:13:05 2005 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,543 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-    MoinMoin - ReStructured Text Parser
-
-    @copyright: 2004 by Matthew Gilbert <gilbert AT voxmea DOT net>
-        and by Alexander Schremmer <alex AT alexanderweb DOT de>
-    @license: GNU GPL, see COPYING for details.
-
-    REQUIRES docutils 0.3.3 or later
-
-    TODO: importing this module must not crash due to missing dependencies,
-          like a not installed docutils (or similar). Moin does import the
-          module e.g. when using inline:abc.txt, just to see if it supports
-          the .txt extension. If it crashes then, attachment inlining will
-          not work AT ALL in moin.
-          So the imports should be moved to a function that is invoked when
-          the parser is invoked to parse rst, not on module import.
-          Maybe also add code that can "pseudo parse" rst when docutils is
-          missing, e.g. use plain text parser. Or give some error msg that
-          docutils is missing.
-
-          See also:
-          http://moinmoin.wikiwikiweb.de/ErrorHandlingInPlugins#head-4d50f5e8a2b5b1629e63693954a5354f1d3269d0
-          
-          Moved to contrib/ until this is fixed.
-"""
-
-import re
-import new
-import StringIO
-import __builtin__
-import sys
-import copy
-import types
-
-# docutils imports are below
-import MoinMoin.parser.wiki
-from MoinMoin.Page import Page
-
-Dependencies = [] # this parser just depends on the raw text
-
-# --- make docutils safe by overriding all module-scoped names related to IO ---
-
-# TODO: Add an error message to dummyOpen so that the user knows what they did
-# requested an unsupported feature of docutils in MoinMoin.
-def dummyOpen(x, y=None, z=None): return
-
-class dummyIO(StringIO.StringIO):
-    def __init__(self, destination=None, destination_path=None,
-                 encoding=None, error_handler='', autoclose=1,
-                 handle_io_errors=1, source_path=None):
-        StringIO.StringIO.__init__(self)
-
-class dummyUrllib2:
-    def urlopen(a):
-        return StringIO.StringIO()
-    urlopen = staticmethod(urlopen)
-
-# # # All docutils imports must be contained below here
-import docutils
-from docutils.core import publish_parts
-from docutils.writers import html4css1
-from docutils.nodes import fully_normalize_name, reference
-from docutils.parsers import rst
-from docutils.parsers.rst import directives, roles
-# # # All docutils imports must be contained above here
-
-def safe_import(name, globals = None, locals = None, fromlist = None):
-    mod = __builtin__.__import__(name, globals, locals, fromlist)
-    if mod:
-        mod.open = dummyOpen
-        mod.urllib2 = dummyUrllib2
-    return mod
-
-# Go through and change all docutils modules to use a dummyOpen and dummyUrllib2
-# module. Also make sure that any docutils imported modules also get the dummy
-# implementations.
-for i in sys.modules.keys():
-    if i.startswith('docutils') and sys.modules[i]:
-        sys.modules[i].open = dummyOpen
-        sys.modules[i].urllib2 = dummyUrllib2
-        sys.modules[i].__import__ = safe_import
-
-docutils.io.FileOutput = docutils.io.FileInput = dummyIO
-
-# --- End of dummy-code --------------------------------------------------------
-
-def html_escape_unicode(node):
-    # Find Python function that does this for me. string.encode('ascii',
-    # 'xmlcharrefreplace') only 2.3 and above.
-    for i in node:
-        if ord(i) > 127:
-            node = node.replace(i, '&#%d;' % (ord(i)))
-    return node
-
-class MoinWriter(html4css1.Writer):
-
-    config_section = 'MoinMoin writer'
-    config_section_dependencies = ('writers',)
-
-    #"""Final translated form of `document`."""
-    output = None
-
-    def wiki_resolver(self, node):
-        """
-            Normally an unknown reference would be an error in an reST document.
-            However, this is how new documents are created in the wiki. This
-            passes on unknown references to eventually be handled by the
-            MoinMoin formatter.
-        """
-        if len(node['ids']) != 0:
-            # If the node has id then its probably an internal link. Let
-            # docutils generate an error.
-            return False
-        node['refuri'] = node['name']
-        del node['refname']
-        node.resolved = 1
-        self.nodes.append(node)
-        return True
-
-    wiki_resolver.priority = 001
-
-    def __init__(self, formatter, request):
-        html4css1.Writer.__init__(self)
-        self.formatter = formatter
-        self.request = request
-        # Add our wiki unknown_reference_resolver to our list of functions to
-        # run when a target isn't found
-        self.unknown_reference_resolvers = [self.wiki_resolver]
-        # We create a new parser to process MoinMoin wiki style links in the
-        # reST.
-        self.wikiparser = MoinMoin.parser.wiki.Parser('', self.request)
-        self.wikiparser.formatter = self.formatter
-        self.wikiparser.hilite_re = None
-        self.nodes = []
-
-    def translate(self):
-        visitor = MoinTranslator(self.document,
-                                 self.formatter,
-                                 self.request,
-                                 self.wikiparser,
-                                 self)
-        self.document.walkabout(visitor)
-        self.visitor = visitor
-        self.output = html_escape_unicode(visitor.astext())
-
-
-class Parser:
-    caching = 1
-    Dependencies = Dependencies # copy dependencies from module-scope
-
-    def __init__(self, raw, request, **kw):
-        self.raw = raw
-        self.request = request
-        self.form = request.form
-
-    def format(self, formatter):
-        # Create our simple parser
-        parser = MoinDirectives(self.request)
-
-        parts = publish_parts(
-            source = self.raw,
-            writer = MoinWriter(formatter, self.request),
-            settings_overrides = {
-                'halt_level': 5,
-                'traceback': True,
-                'file_insertion_enabled': 0,
-                'raw_enabled': 0,
-                'stylesheet_path': '',
-            }
-        )
-
-        text = ''
-        if parts['title']:
-            text += formatter.rawHTML('<h2>' + parts['title'] + '</h2>')
-        # If there is only one subtitle then it is held in parts['subtitle'].
-        # However, if there is more than one subtitle then this is empty and
-        # fragment contains all of the subtitles.
-        if parts['subtitle']:
-            text += formatter.rawHTML('<h3>' + parts['subtitle'] + '</h3>')
-        if parts['docinfo']:
-            text += parts['docinfo']
-        text += parts['fragment']
-        self.request.write(html_escape_unicode(text))
-
-class RawHTMLList(list):
-    """
-        RawHTMLList catches all html appended to internal HTMLTranslator lists.
-        It passes the HTML through the MoinMoin rawHTML formatter to strip 
-        markup when necessary. This is to support other formatting outputs
-        (such as ?action=format&mimetype=text/plain).
-    """
-    
-    def __init__(self, formatter):
-        self.formatter = formatter
-        
-    def append(self, text):
-        f = sys._getframe()
-        if f.f_back.f_code.co_filename.endswith('html4css1.py'):
-            if isinstance(text, types.StringType) or isinstance(text, types.UnicodeType):
-                text = self.formatter.rawHTML(text)
-        list.append(self, text)
-
-class MoinTranslator(html4css1.HTMLTranslator):
-
-    def __init__(self, document, formatter, request, parser, writer):
-        html4css1.HTMLTranslator.__init__(self, document)
-        self.formatter = formatter
-        self.request = request
-        # MMG: Using our own writer when needed. Save the old one to restore
-        # after the page has been processed by the html4css1 parser.
-        self.original_write, self.request.write = self.request.write, self.capture_wiki_formatting
-        self.wikiparser = parser
-        self.wikiparser.request = request
-        # MoinMoin likes to start the initial headers at level 3 and the title
-        # gets level 2, so to comply with their styles, we do here also.
-        # TODO: Could this be fixed by passing this value in settings_overrides?
-        self.initial_header_level = 3
-        # Temporary place for wiki returned markup. This will be filled when
-        # replacing the default writer with the capture_wiki_formatting
-        # function (see visit_image for an example).
-        self.wiki_text = ''
-        self.setup_wiki_handlers()
-        
-        # Make all internal lists RawHTMLLists, see RawHTMLList class
-        # comment for more information.
-        for i in self.__dict__:
-            if isinstance(getattr(self, i), types.ListType):
-                setattr(self, i, RawHTMLList(formatter))
-
-    def depart_docinfo(self, node):
-        """
-            depart_docinfo assigns a new list to self.body, we need to re-make that
-            into a RawHTMLList.
-        """
-        html4css1.HTMLTranslator.depart_docinfo(self, node)
-        self.body = RawHTMLList(self.formatter)
-
-    def capture_wiki_formatting(self, text):
-        """
-            Captures MoinMoin generated markup to the instance variable
-            wiki_text.
-        """
-        # For some reason getting empty strings here which of course overwrites
-        # what we really want (this is called multiple times per MoinMoin
-        # format call, which I don't understand).
-        self.wiki_text += text
-
-    def process_wiki_text(self, text):
-        """
-            This sequence is repeated numerous times, so its captured as a
-            single call here. Its important that wiki_text is blanked before we
-            make the format call. format will call request.write which we've
-            hooked to capture_wiki_formatting. If wiki_text is not blanked
-            before a call to request.write we will get the old markup as well as
-            the newly generated markup.
-
-            TODO: Could implement this as a list so that it acts as a stack. I
-            don't like having to remember to blank wiki_text.
-        """
-        self.wiki_text = ''
-        self.wikiparser.raw = text
-        self.wikiparser.format(self.formatter)
-
-    def add_wiki_markup(self):
-        """
-            Place holder in case this becomes more elaborate someday. For now it
-            only appends the MoinMoin generated markup to the html body and
-            raises SkipNode.
-        """
-        self.body.append(self.wiki_text)
-        self.wiki_text = ''
-        raise docutils.nodes.SkipNode
-
-    def astext(self):
-        self.request.write = self.original_write
-        return html4css1.HTMLTranslator.astext(self)
-
-    def process_inline(self, node, uri_string):
-        """
-            Process the "inline:" link scheme. This can either come from
-            visit_reference or from visit_image. The uri_string changes
-            depending on the caller. The uri is passed to MoinMoin to handle the
-            inline link. If it is an image, the src line is extracted and passed
-            to the html4css1 writer to allow the reST image attributes.
-            Otherwise, the html from MoinMoin is inserted into the reST document
-            and SkipNode is raised.
-        """
-        self.process_wiki_text(node[uri_string])
-        # Only pass the src and alt parts to the writer. The reST writer
-        # inserts its own tags so we don't need the MoinMoin html markup.
-        src = re.search('src="([^"]+)"', self.wiki_text)
-        if src:
-            node['uri'] = src.groups()[0]
-            if not 'alt' in node.attributes:
-                alt = re.search('alt="([^"]*)"', self.wiki_text)
-                if alt:
-                    node['alt'] = alt.groups()[0]
-        else:
-            # Image doesn't exist yet for the page so just use what's
-            # returned from MoinMoin verbatim
-            self.add_wiki_markup()
-
-    def process_wiki_target(self, target):
-        self.process_wiki_text(target)
-        # MMG: May need a call to fixup_wiki_formatting here but I
-        # don't think so.
-        self.add_wiki_markup()
-
-    def fixup_wiki_formatting(self, text):
-        replacement = {'<p>': '', '</p>': '', '\n': '', '> ': '>'}
-        for src, dst in replacement.items():
-            text = text.replace(src, dst)
-        # Everything seems to have a space ending the text block. We want to
-        # get rid of this
-        if text and text[-1] == ' ':
-            text = text[:-1]
-        return text
-
-    def visit_reference(self, node):
-        """
-            Pass links to MoinMoin to get the correct wiki space url. Extract
-            the url and pass it on to the html4css1 writer to handle. Inline
-            images are also handled by visit_image. Not sure what the "drawing:"
-            link scheme is used for, so for now it is handled here.
-
-            Also included here is a hack to allow MoinMoin macros. This routine
-            checks for a link which starts with "[[". This link is passed to the
-            MoinMoin formatter and the resulting markup is inserted into the
-            document in the place of the original link reference.
-        """
-        moin_link_schemes = ('wiki:', 'attachment:', 'drawing:', '[[',
-                             'inline:')
-
-        if 'refuri' in node.attributes:
-            target = None
-            refuri = node['refuri']
-
-            # MMG: Fix this line
-            if [scheme for scheme in moin_link_schemes if
-                    refuri.lstrip().startswith(scheme)]:
-                # For a macro, We want the actuall text from the user in target,
-                # not the fully normalized version that is contained in refuri.
-                if refuri.startswith('[['):
-                    target = node['name']
-                else:
-                    target = refuri
-            # TODO: Figure out the following two elif's and comment
-            # appropriately.
-            # The node should have a whitespace normalized name if the docutlis
-            # reStructuredText parser would normally fully normalize the name.
-            elif ('name' in node.attributes and
-                  fully_normalize_name(node['name']) == refuri):
-                target = ':%s:' % (node['name'])
-            # If its not a uri containing a ':' then its probably destined for
-            # wiki space.
-            elif ':' not in refuri:
-                target = ':%s:' % (refuri)
-
-            if target:
-                if target.startswith('inline:'):
-                    self.process_inline(node, 'refuri')
-                elif target.startswith('[[') and target.endswith(']]'):
-                    self.process_wiki_target(target)
-                else:
-                    # Not a macro or inline so hopefully its a link. Put the target in
-                    # brackets so that MoinMoin knows its a link. Extract the
-                    # href, if it exists, and let docutils handle it from there.
-                    # If there is no href just add whatever MoinMoin returned.
-                    node_text = node.astext().replace('\n', ' ')
-                    self.process_wiki_text('[%s %s]' % (target, node_text))
-                    href = re.search('href="([^"]+)"', self.wiki_text)
-                    if href:
-                        # dirty hack in order to undo the HTML entity quoting
-                        node['refuri'] = href.groups()[0].replace("&amp;", "&")
-                    else:
-                        self.wiki_text = self.fixup_wiki_formatting(self.wiki_text)
-                        self.add_wiki_markup()
-        html4css1.HTMLTranslator.visit_reference(self, node)
-
-    def visit_image(self, node):
-        """
-            Need to intervene in the case of inline images. We need MoinMoin to
-            give us the actual src line to the image and then we can feed this
-            to the default html4css1 writer. NOTE: Since the writer can't "open"
-            this image the scale attribute doesn't work without directly
-            specifying the height or width (or both).
-
-            TODO: Need to handle figures similarly.
-        """
-        uri = node['uri'].lstrip()
-        prefix = ''          # assume no prefix
-        if ':' in uri:
-            prefix = uri.split(':',1)[0]
-        # if prefix isn't URL, try to display in page
-        if not prefix.lower() in ('file', 'http', 'https', 'ftp'):
-            # no prefix given, so fake "inline:"
-            if not prefix:
-                node['uri'] = 'inline:' + uri
-            self.process_inline(node, 'uri')
-        html4css1.HTMLTranslator.visit_image(self, node)
-
-    def create_wiki_functor(self, moin_func):
-        moin_callable = getattr(self.formatter, moin_func)
-        def visit_func(self, node):
-            self.wiki_text = ''
-            self.request.write(moin_callable(1))
-            self.body.append(self.wiki_text)
-        def depart_func(self, node):
-            self.wiki_text = ''
-            self.request.write(moin_callable(0))
-            self.body.append(self.wiki_text)
-        return visit_func, depart_func
-
-    def setup_wiki_handlers(self):
-        """
-            Have the MoinMoin formatter handle markup when it makes sense. These
-            are portions of the document that do not contain reST specific
-            markup. This allows these portions of the document to look
-            consistent with other wiki pages.
-
-            Setup dispatch routines to handle basic document markup. The
-            hanlders dict is the html4css1 handler name followed by the wiki
-            handler name.
-        """
-        handlers = {
-            # Text Markup
-            'emphasis': 'emphasis',
-            'strong': 'strong',
-            'literal': 'code',
-            # Blocks
-            'literal_block': 'preformatted',
-            # Simple Lists
-            'bullet_list': 'bullet_list',
-            'list_item': 'listitem',
-            # Definition List
-            'definition_list': 'definition_list',
-            # Admonitions
-            'warning': 'highlight'
-        }
-        for rest_func, moin_func in handlers.items():
-            visit_func, depart_func = self.create_wiki_functor(moin_func)
-            visit_func = new.instancemethod(visit_func, self, MoinTranslator)
-            depart_func = new.instancemethod(depart_func, self, MoinTranslator)
-            setattr(self, 'visit_%s' % (rest_func), visit_func)
-            setattr(self, 'depart_%s' % (rest_func), depart_func)
-
-    # Enumerated list takes an extra paramter so we handle this differently
-    def visit_enumerated_list(self, node):
-        self.wiki_text = ''
-        self.request.write(self.formatter.number_list(1, start=node.get('start', None)))
-        self.body.append(self.wiki_text)
-
-    def depart_enumerated_list(self, node):
-        self.wiki_text = ''
-        self.request.write(self.formatter.number_list(0))
-        self.body.append(self.wiki_text)
-
-
-class MoinDirectives:
-    """
-        Class to handle all custom directive handling. This code is called as
-        part of the parsing stage.
-    """
-
-    def __init__(self, request):
-        self.request = request
-
-        # include MoinMoin pages
-        directives.register_directive('include', self.include)
-
-        # used for MoinMoin macros
-        directives.register_directive('macro', self.macro)
-
-        # disallow a few directives in order to prevent XSS
-        # for directive in ('meta', 'include', 'raw'):
-        for directive in ('meta', 'raw'):
-            directives.register_directive(directive, None)
-
-        # disable the raw role
-        roles._roles['raw'] = None
-
-        # As a quick fix for infinite includes we only allow a fixed number of
-        # includes per page
-        self.num_includes = 0
-        self.max_includes = 10
-
-    # Handle the include directive rather than letting the default docutils
-    # parser handle it. This allows the inclusion of MoinMoin pages instead of
-    # something from the filesystem.
-    def include(self, name, arguments, options, content, lineno,
-                content_offset, block_text, state, state_machine):
-        # content contains the included file name
-
-        _ = self.request.getText
-
-        # Limit the number of documents that can be included
-        if self.num_includes < self.max_includes:
-            self.num_includes += 1
-        else:
-            lines = [_("**Maximum number of allowed includes exceeded**")]
-            state_machine.insert_input(lines, 'MoinDirectives')
-            return
-
-        if len(content):
-            page = Page(page_name = content[0], request = self.request)
-            if page.exists():
-                text = page.get_raw_body()
-                lines = text.split('\n')
-                # Remove the "#format rst" line
-                if lines[0].startswith("#format"):
-                    del lines[0]
-            else:
-                lines = [_("**Could not find the referenced page: %s**") % (content[0],)]
-            # Insert the text from the included document and then continue
-            # parsing
-            state_machine.insert_input(lines, 'MoinDirectives')
-        return
-
-    include.content = True
-
-    # Add additional macro directive.
-    # This allows MoinMoin macros to be used either by using the directive
-    # directly or by using the substitution syntax. Much cleaner than using the
-    # reference hack (`[[SomeMacro]]`_). This however simply adds a node to the
-    # document tree which is a reference, but through a much better user
-    # interface.
-    def macro(self, name, arguments, options, content, lineno,
-                content_offset, block_text, state, state_machine):
-        # content contains macro to be called
-        if len(content):
-            # Allow either with or without brackets
-            if content[0].startswith('[['):
-                macro = content[0]
-            else:
-                macro = '[[%s]]' % content[0]
-            ref = reference(macro, refuri = macro)
-            ref['name'] = macro
-            return [ref]
-        return
-
-    macro.content = True
-