view MoinMoin/converter/mediawiki_in.py @ 1882:cba57aaf5bc1

use triple double-quotes for docstrings
author Thomas Waldmann <tw AT waldmann-edv DOT de>
date Sat, 22 Dec 2012 01:03:16 +0100
parents 90eb2ea82c32
children 286e315935ae
line wrap: on
line source
# Copyright: 2000-2002 Juergen Hermann <jh@web.de>
# Copyright: 2006-2008 MoinMoin:ThomasWaldmann
# Copyright: 2007 MoinMoin:ReimarBauer
# Copyright: 2008-2010 MoinMoin:BastianBlank
# Copyright: 2010 MoinMoin:DmitryAndreev
# License: GNU GPL v2 (or any later version), see LICENSE.txt for details.

"""
MoinMoin - Media Wiki input converter
"""


from __future__ import absolute_import, division

import re

from werkzeug import url_encode

from MoinMoin import log
logging = log.getLogger(__name__)

from MoinMoin import config
from MoinMoin.util.iri import Iri
from MoinMoin.util.tree import html, moin_page, xlink

from ._args import Arguments
from ._args_wiki import parse as parse_arguments
from ._wiki_macro import ConverterMacro
from ._util import decode_data, normalize_split_text, _Iter, _Stack


class _TableArguments(object):
    rules = r'''
    (?:
        (?P<arg>
            (?:
                (?P<key> [-\w]+)
                =
            )?
            (?:
                (?P<value_u> [-\w]+)
                |
                "
                (?P<value_q1> .*?)
                (?<!\\)"
                |
                '
                (?P<value_q2> .*?)
                (?<!\\)'
            )
        )
    )
    '''
    _re = re.compile(rules, re.X)

    map_keys = {
        'colspan': 'number-columns-spanned',
        'rowspan': 'number-rows-spanned',
    }

    def arg_repl(self, args, arg, key=None, value_u=None, value_q1=None, value_q2=None):
        key = self.map_keys.get(key, key)
        value = (value_u or value_q1 or value_q2).decode('unicode-escape')

        if key:
            args.keyword[key] = value
        else:
            args.positional.append(value)

    def number_columns_spanned_repl(self, args, number_columns_spanned):
        args.keyword['number-columns-spanned'] = int(number_columns_spanned)

    def number_rows_spanned_repl(self, args, number_rows_spanned):
        args.keyword['number-rows-spanned'] = int(number_rows_spanned)

    def __call__(self, input):
        args = Arguments()

        for match in self._re.finditer(input):
            data = dict(((str(k), v) for k, v in match.groupdict().iteritems() if v is not None))
            getattr(self, '{0}_repl'.format(match.lastgroup))(args, **data)

        return args


class Converter(ConverterMacro):
    @classmethod
    def factory(cls, input, output, **kw):
        return cls()

    def __call__(self, data, contenttype=None, arguments=None):
        text = decode_data(data, contenttype)
        content = normalize_split_text(text)
        iter_content = _Iter(content)
        self.preprocessor = self.Mediawiki_preprocessor()
        body = self.parse_block(iter_content, arguments)
        root = moin_page.page(children=(body, ))

        return root

    block_comment = r"""
        (?P<comment>
            ^ \#\#
        )
    """

    def block_comment_repl(self, _iter_content, stack, comment):
        # A comment also ends anything
        stack.clear()

    block_head = r"""
        (?P<head>
            ^
            \s*
            (?P<head_head> =+ )
            \s*
            (?P<head_text> .*? )
            \s*
            (?P=head_head)
            \s*
            $
        )
    """

    def block_head_repl(self, _iter_content, stack, head, head_head, head_text):
        stack.clear()

        attrib = {moin_page.outline_level: str(len(head_head))}
        element = moin_page.h(attrib=attrib, children=[head_text])
        stack.top_append(element)

    block_line = r'(?P<line> ^ \s* $ )'
    # empty line that separates paragraphs

    def block_line_repl(self, _iter_content, stack, line):
        stack.clear()

    block_separator = r'(?P<separator> ^ \s* -{4,} \s* $ )'

    def block_separator_repl(self, _iter_content, stack, separator):
        stack.clear()
        stack.top_append(moin_page.separator())

    block_table = r"""
        ^
        (?P<table>
            \{\|
            \s*
            (?P<table_args> .*?)
        )
        $
    """

    table_end = r"""
        ^
        (?P<table_end>
        \|\}
        \s*
        )
        $
    """

    def block_table_lines(self, iter_content):
        """Unescaping generator for the lines in a table block"""
        for line in iter_content:
            match = self.table_end_re.match(line)
            if match:
                return
            yield line

    def block_table_repl(self, iter_content, stack, table, table_args=''):
        stack.clear()
        # TODO: table attributes
        elem = moin_page.table()
        stack.push(elem)
        if table_args:
            table_args = _TableArguments()(table_args)
            for key, value in table_args.keyword.iteritems():
                attrib = elem.attrib
                if key in ('class', 'style', 'number-columns-spanned', 'number-rows-spanned'):
                    attrib[moin_page(key)] = value

        element = moin_page.table_body()
        stack.push(element)
        lines = _Iter(self.block_table_lines(iter_content), startno=iter_content.lineno)
        element = moin_page.table_row()
        stack.push(element)
        preprocessor_status = []
        for line in lines:
            m = self.tablerow_re.match(line)
            if not m:
                return
            if m.group('newrow'):
                stack.pop_name('table-row')
                element = moin_page.table_row()
                stack.push(element)
            cells = m.group('cells')
            if cells:
                cells = cells.split('||')
                for cell in cells:
                    if stack.top_check('table-cell'):
                        stack.pop()

                    cell = re.split(r'\s*\|\s*', cell)
                    element = moin_page.table_cell()
                    if len(cell) > 1:
                        cell_args = _TableArguments()(cell[0])
                        for key, value in cell_args.keyword.iteritems():
                            attrib = element.attrib
                            if key in ('class', 'style', 'number-columns-spanned', 'number-rows-spanned'):
                                attrib[moin_page(key)] = value
                        cell = cell[1]
                    else:
                        cell = cell[0]
                    stack.push(element)
                    self.preprocessor.push()
                    self.parse_inline(cell, stack, self.inline_re)
                    preprocessor_status = self.preprocessor.pop()
            elif m.group('text'):
                self.preprocessor.push(preprocessor_status)
                self.parse_inline('\n{0}'.format(m.group('text')), stack, self.inline_re)
                preprocessor_status = self.preprocessor.pop()
        stack.pop_name('table')

    block_text = r'(?P<text> .+ )'

    def block_text_repl(self, _iter_content, stack, text):
        if stack.top_check('table', 'table-body', 'list'):
            stack.clear()

        if stack.top_check('body', 'list-item-body'):
            element = moin_page.p()
            stack.push(element)
        # If we are in a paragraph already, don't loose the whitespace
        else:
            stack.top_append('\n')
        self.parse_inline(text, stack, self.inline_re)

    indent = r"""
        ^
        (?P<indent> [*#:]* )
        (?P<list_begin>
            (?P<list_definition> ;
            )
            \s*
            |
            (?P<list_numbers> \# )
            \s+
            |
            (?P<list_bullet> \* )
            \s+
            |
            (?P<list_none> \: )
            \s+
        )
        (?P<text> .*? )
        $
    """

    def indent_iter(self, iter_content, line, level, is_list):
        yield line

        while True:
            line = iter_content.next()

            match = self.indent_re.match(line)

            new_level = 0
            if not match:
                if is_list:
                    iter_content.push(line)
                    return
                else:
                    yield line
                    break

            if match.group('indent'):
                new_level = len(match.group('indent'))

            if match.group('list_begin') or level != new_level:
                iter_content.push(line)
                return

            yield match.group('text')

    def indent_repl(self, iter_content, stack, line,
            indent, text, list_begin=None, list_definition=None,
            list_definition_text=None, list_numbers=None,
            list_bullet=None,
            list_none=None):

        level = len(indent)
        list_type = 'unordered', 'none'
        if list_begin:
            if list_definition:
                list_type = 'definition', None
            elif list_numbers:
                list_type = 'ordered', None
            elif list_bullet:
                list_type = 'unordered', None
            elif list_none:
                list_type = None, None

        element_use = None
        while len(stack) > 1:
            cur = stack.top()
            if cur.tag.name == 'list-item-body':
                if level > cur.level:
                    element_use = cur
                    break
            if cur.tag.name == 'list':
                if level >= cur.level and list_type == cur.list_type:
                    element_use = cur
                    break
            stack.pop()

        if not element_use:
            element_use = stack.top()
        if list_begin:
            if element_use.tag.name != 'list':
                attrib = {}
                if not list_definition:
                    attrib[moin_page.item_label_generate] = list_type[0]
                if list_type[1]:
                    attrib[moin_page.list_style_type] = list_type[1]
                element = moin_page.list(attrib=attrib)
                element.level, element.list_type = level, list_type
                stack.push(element)

            stack.push(moin_page.list_item())
            if list_definition:
                element_label = moin_page.list_item_label()
                stack.top_append(element_label)
                new_stack = _Stack(element_label, iter_content=iter_content)
                # TODO: definition list doesn't work,
                #       if definition of the term on the next line
                splited_text = text.split(':')
                list_definition_text=splited_text.pop(0)
                text = ':'.join(splited_text)

                self.parse_inline(list_definition_text, new_stack, self.inline_re)

            element_body = moin_page.list_item_body()
            element_body.level, element_body.type = level, type

            stack.push(element_body)
            new_stack = _Stack(element_body, iter_content=iter_content)
        else:
            new_stack = stack
            level = 0

        is_list = list_begin
        iter = _Iter(self.indent_iter(iter_content, text, level, is_list), startno=iter_content.lineno)
        for line in iter:
            match = self.block_re.match(line)
            it = iter
            # XXX: Hack to allow nowiki to ignore the list identation
            if match.lastgroup == 'table' or match.lastgroup == 'nowiki':
                it = iter_content
            self._apply(match, 'block', it, new_stack)

    inline_comment = r"""
        (?P<comment>
            (?P<comment_begin>
                (^|(?<=\s))
                /\*
                \s+
            )
            |
            (?P<comment_end>
                \s+
                \*/
                (?=\s)
            )
        )
    """

    def inline_comment_repl(self, stack, comment, comment_begin=None, comment_end=None):
        # TODO
        pass

    inline_emphstrong = r"""
        (?P<emphstrong>
            '{2,6}
            (?=
                [^']+
                (?P<emphstrong_follow>
                    '{2,3}
                    (?!')
                )
            )?
        )
    """

    def inline_emphstrong_repl(self, stack, emphstrong, emphstrong_follow=''):
        if len(emphstrong) == 5:
            if stack.top_check('emphasis'):
                stack.pop()
                if stack.top_check('strong'):
                    stack.pop()
                else:
                    stack.push(moin_page.strong())
            elif stack.top_check('strong'):
                if stack.top_check('strong'):
                    stack.pop()
                else:
                    stack.push(moin_page.strong())
            else:
                if len(emphstrong_follow) == 3:
                    stack.push(moin_page.emphasis())
                    stack.push(moin_page.strong())
                else:
                    stack.push(moin_page.strong())
                    stack.push(moin_page.emphasis())
        elif len(emphstrong) == 3:
            if stack.top_check('strong'):
                stack.pop()
            else:
                stack.push(moin_page.strong())
        elif len(emphstrong) == 2:
            if stack.top_check('emphasis'):
                stack.pop()
            else:
                stack.push(moin_page.emphasis())

    inline_entity = r"""
        (?P<entity>
            &
            (?:
               # symbolic entity, like &uuml;
               [0-9a-zA-Z]{2,6}
               |
               # numeric decimal entities, like &#42;
               \#\d{1,5}
               |
               # numeric hexadecimal entities, like &#x42;
               \#x[0-9a-fA-F]{1,6}
           )
           ;
       )
    """

    def inline_entity_repl(self, stack, entity):
        if entity[1] == '#':
            if entity[2] == 'x':
                c = int(entity[3:-1], 16)
            else:
                c = int(entity[2:-1], 10)
            c = unichr(c)
        else:
            from htmlentitydefs import name2codepoint
            c = unichr(name2codepoint.get(entity[1:-1], 0xfffe))
        stack.top_append(c)

    inline_blockquote = r"""
        (?P<blockquote>
            (?P<blockquote_begin>
            \<blockquote.*?\>
            )
            |
            (?P<blockquote_end>
            \<\/blockquote\>
            )
        )
    """

    def inline_blockquote_repl(self, stack, blockquote, blockquote_begin=None, blockquote_end=None):
        if blockquote_begin is not None:
            stack.push(moin_page.blockquote())
        elif blockquote_end is not None:
            stack.pop()

    inline_footnote = r"""
        (?P<footnote>
            (?P<footnote_begin>
            \<ref.*?\>
            )
            |
            (?P<footnote_end>
            \<\/ref\>
            )
        )
    """

    def inline_footnote_repl(self, stack, footnote, footnote_begin=None, footnote_text=None, footnote_end=None, footnote_start=None):
        #stack.top_check('emphasis'):
        if footnote_begin is not None:
            stack.push(moin_page.note(attrib={moin_page.note_class: 'footnote'}))
            stack.push(moin_page.note_body())
        elif footnote_end is not None:
            stack.pop()
            stack.pop()

    inline_strike = r"""
        (?P<strike>
           (?P<strike_begin>
           \<del\>
           |
           \<s\>
           )
           |
           (?P<strike_end>
           \<\/del\>
           |
           \<\/s\>
           )
        )
    """

    def inline_strike_repl(self, stack, strike, strike_begin=None, strike_end=None):
        if strike_begin is not None:
            attrib = {moin_page.text_decoration: 'line-through'}
            stack.push(moin_page.span(attrib=attrib))
        elif strike_end is not None:
            stack.pop()

    inline_subscript = r"""
        (?P<subscript>
            <sub>
            (?P<subscript_text> .*? )
            </sub>
        )
    """

    def inline_subscript_repl(self, stack, subscript, subscript_text):
        attrib = {moin_page.baseline_shift: 'sub'}
        elem = moin_page.span(attrib=attrib, children=[subscript_text])
        stack.top_append(elem)

    inline_superscript = r"""
        (?P<superscript>
            <sup>
            (?P<superscript_text> .*? )
            </sup>
        )
    """

    def inline_superscript_repl(self, stack, superscript, superscript_text):
        attrib = {moin_page.baseline_shift: 'super'}
        elem = moin_page.span(attrib=attrib, children=[superscript_text])
        stack.top_append(elem)

    inline_underline = r"""
        (?P<underline>
            \<u\>
            |
            \<\/u\>
        )
    """

    def inline_underline_repl(self, stack, underline):
        if not stack.top_check('span'):
            attrib = {moin_page.text_decoration: 'underline'}
            stack.push(moin_page.span(attrib=attrib))
        else:
            stack.pop()

    inline_link = r"""
        (?P<link>
            \[\[
            \s*
            (
                (?P<link_url>
                    [a-zA-Z0-9+.-]+
                    :
                    [^|]+?
                )
                |
                (?P<link_item> [^|]+? )
            )
            \s*
            (?P<link_args>
                (
                [|]
                \s*
                [^|]*?
                \s*
                )*
            )?
            \]\]
            |
            \[
            \s*
            (?P<external_link_url>
                    (%(uri_schemes)s)
                    :
                    [^ ]*
            )
            \s*
            (?P<alt_text> [^\]]*? )
            \s*
            \]
        )
    """ % dict(uri_schemes='|'.join(config.uri_schemes))

    def parse_args(self, input):
        """
        Parses media wiki arguments, this is taken from _args_wiki > parse function. The primary difference
        being that mediawiki breaks on pipes whereas the default parser breaks on spaces. Apart from that
        this parser also supports a few extra characters such as "<, >, ., /", mostly for URL linking

        :param input: can be like a|b|c=f|something else caption|g='long caption'|link=http://google.com
        :return Arguments instance
        """
        parse_rules = r'''
        (?:
            (?P<key>[\w-]+)=    # Matches 'key=' part of the string, optional
        )?
        (?:
            (?P<unquote_val>[-\w\s:\./<>]+) # Unquoted value, intended to break after a |
            |
            # Matches quoted values with every character, breaks after the quote
            "(?P<dquote_val>.*?)(?<!\\)"    # Quoted value with double quotes
            |
            '(?P<squote_val>.*?)(?<!\\)'    # Quoted value with single quotes
        )
        '''
        parse_re = re.compile(parse_rules, re.X | re.U)
        ret = Arguments()
        for match in parse_re.finditer(input):
            key = match.group('key')
            value = match.group('unquote_val') or match.group('squote_val') or match.group('dquote_val')
            if key:
                ret.keyword[key] = value
            else:
                ret.positional.append(value)
        return ret

    def inline_link_repl(self, stack, link, link_url=None, link_item=None,
                            link_args=u'', external_link_url=None, alt_text=u''):
        """Handle all kinds of links."""
        link_text = ''
        link_args_list = []
        # Remove the first pipe/space, example of link_args : |arg1|arg2 or " arg1 arg2"
        parsed_args = self.parse_args(link_args[1:])
        query = None
        if parsed_args.keyword:
            query = url_encode(parsed_args.keyword, charset=config.charset, encode_keys=True)
        # Take the last of positional parameters as link_text(caption)
        if parsed_args.positional:
            link_text = parsed_args.positional.pop()
        if link_item is not None:
            if '#' in link_item:
                path, fragment = link_item.rsplit('#', 1)
            else:
                path, fragment = link_item, None
            target = Iri(scheme='wiki.local', path=path, query=query, fragment=fragment)
            text = link_item
        else:
            if link_url and len(link_url.split(':')) > 0 and link_url.split(':')[0] == 'File':
                object_item = ':'.join(link_url.split(':')[1:])
                args = parsed_args.keyword
                if object_item is not None:
                    if 'do' not in args:
                        # by default, we want the item's get url for transclusion of raw data:
                        args['do'] = 'get'
                    query = url_encode(args, charset=config.charset, encode_keys=True)
                    target = Iri(scheme='wiki.local', path=object_item, query=query, fragment=None)
                    text = object_item
                else:
                    target = Iri(scheme='wiki.local', path=object_url)
                    text = object_url

                if not link_text:
                    link_text = text
                attrib = {xlink.href: target}
                attrib[moin_page.alt] = link_text

                element = moin_page.object(attrib)
                stack.push(element)
                if link_text:
                    self.preprocessor.push()
                    self.parse_inline(link_text, stack, self.inlinedesc_re)
                    self.preprocessor.pop()
                else:
                    stack.top_append(text)
                stack.pop()
                return
            target = Iri(scheme='wiki.local', path=link_url)
            text = link_url
        if external_link_url:
            target = Iri(external_link_url)
            text = alt_text
        element = moin_page.a(attrib={xlink.href: target})
        stack.push(element)
        if link_text:
            self.preprocessor.push()
            self.parse_inline(link_text, stack, self.inlinedesc_re)
            self.preprocessor.pop()
        else:
            stack.top_append(text)
        stack.pop()

    inline_breakline = r"""
        (?P<breakline>
            \<br\ \/\>
        )
    """

    def inline_breakline_repl(self, stack, breakline):
        stack.top_append(moin_page.line_break())

    inline_nowiki = r"""
        (?P<nowiki>
            <nowiki>
            (?P<nowiki_text> .*? )
            </nowiki>
            |
            <pre>
            (?P<nowiki_text_pre> .*? )
            </pre>
            |
            <code>
            (?P<nowiki_text_code> .*? )
            </code>
            |
            <tt>
            (?P<nowiki_text_tt> .*? )
            </tt>
        )
    """

    def inline_nowiki_repl(self, stack, nowiki, nowiki_text=None,
            nowiki_text_pre=None, pre_args='',
            nowiki_text_code=None, nowiki_text_tt=None):
        text = None

        if nowiki_text is not None:
            text = nowiki_text
            stack.top_append(moin_page.code(children=[text]))
        elif nowiki_text_code is not None:
            text = nowiki_text_code
            stack.top_append(moin_page.code(children=[text]))
        elif nowiki_text_tt is not None:
            text = nowiki_text_tt
            stack.top_append(moin_page.code(children=[text]))
        # Remove empty backtick nowiki samples
        elif nowiki_text_pre:
            # TODO: pre_args parsing
            text = nowiki_text_pre
            stack.top_append(moin_page.blockcode(children=[text]))
        else:
            return

    table = block_table

    tablerow = r"""
        ^
        [|!]
        (?P<tablerow>
            (?P<caption> \+.* )
            |
            (?P<newrow> \-\s* )
            |
            (?P<cells> .* )
        )
        |
        (?P<text> .* )
        $
    """
    # Block elements
    block = (
        block_line,
        block_table,
        block_comment,
        block_head,
        block_separator,
       # block_macro,
       # block_nowiki,
        block_text,
    )
    block_re = re.compile('|'.join(block), re.X | re.U | re.M)

    indent_re = re.compile(indent, re.X)

    inline = (
        inline_link,
        inline_breakline,
        inline_blockquote,
        #inline_macro,
        inline_nowiki,
        #inline_object,
        inline_emphstrong,
        inline_comment,
        inline_footnote,
        #inline_size,
        inline_strike,
        inline_subscript,
        inline_superscript,
        inline_underline,
        inline_entity,
    )
    inline_re = re.compile('|'.join(inline), re.X | re.U)

    inlinedesc = (
        #inline_macro,
        inline_breakline,
        inline_nowiki,
        inline_emphstrong,
    )
    inlinedesc_re = re.compile('|'.join(inlinedesc), re.X | re.U)

    # Nowiki end
    #nowiki_end_re = re.compile(nowiki_end, re.X)

    # Table
    table_re = re.compile(table, re.X | re.U)
    table_end_re = re.compile(table_end, re.X)

    # Table row
    tablerow_re = re.compile(tablerow, re.X | re.U)

    class Mediawiki_preprocessor(object):

        class Preprocessor_tag(object):
            def __init__(self, name='', text='', tag='', status=True):
                self.tag_name = name
                self.tag = tag
                self.text = [text]
                self.status = status

        all_tags = [
            'br',
            'blockquote'
            'del',
            'pre',
            'code',
            'tt',
            'nowiki',
            'ref',
            's',
            'sub',
            'sup',
            ]

        nowiki_tags = [
            'pre',
            'code',
            'tt',
            'nowiki',
            ]

        block_tags = [
            'blockquote',
            ]

        def __init__(self):
            self.opened_tags = []
            self.nowiki = False
            self.nowiki_tag = ''
            self._stack = []

        def push(self, status=[]):
            self._stack.append(self.opened_tags)
            self.opened_tags = status
            if self.opened_tags:
                if self.opened_tags[-1].tag_name in self.nowiki_tags:
                    self.nowiki = True
                    self.nowiki_tag = self.opened_tags[-1].tag_name
                else:
                    self.nowiki = False
                    self.nowiki_tag = ''

        def pop(self):
            if len(self._stack):
                self.opened_tags = self._stack.pop()
            else:
                self.opened_tags = []
            if self.opened_tags:
                if self.opened_tags[-1].tag_name in self.nowiki_tags:
                    self.nowiki = True
                    self.nowiki_tag = self.opened_tags[-1].tag_name
                else:
                    self.nowiki = False
                    self.nowiki_tag = ''
            return self.opened_tags

        def __call__(self, line, tags=[]):
            tags = tags or self.opened_tags
            match = re.match(r"(.*?)(\<.*\>.*)|(.*)", line)
            if match:
                pre_text = match.group(1) or match.group(3)
                # text may be None
                if pre_text:
                    if len(tags):
                        tags[-1].text.append(pre_text)
                    else:
                        post_line = [pre_text]
                else:
                    post_line = []
                next_text = match.group(2)
                while next_text:
                    match = re.match(r"<\s*([^>]*)>(?:(.*?)(<[^>]*>.*)|(.*))", next_text)
                    if match:
                        tag = match.group(1)
                        next_text = match.group(3)
                        text = match.group(2) or match.group(4)
                        if not text:
                            text = ''
                        tag_match = re.match(r"/\s*(.*)", tag)
                        status = not tag_match
                        if tag_match:
                            tag_name = tag_match.group(1).split(' ')[0]
                        else:
                            tag_name = tag.split(' ')[0]
                        if not tag_name in self.all_tags or re.match(r'.*/\s*$', tag)\
                                or self.nowiki and (status or tag_name != self.nowiki_tag):
                            if not len(tags):
                                post_line.append('<{0}>'.format(tag))
                                post_line.append(text)
                            else:
                                tags[-1].text.append('<{0}>'.format(tag))
                                tags[-1].text.append(text)
                        else:
                            if not status:
                                if self.nowiki:
                                    if tag_name == self.nowiki_tag:
                                        self.nowiki_tag = ''
                                        self.nowiki = False
                                if tag_name in [t.tag_name for t in tags]:
                                    open_tags = []
                                    tmp_line = ''
                                    close_tag = self.Preprocessor_tag()
                                    while tag_name != close_tag.tag_name:
                                        close_tag = tags.pop()
                                        tmp_line = '<{0}>{1}{2}</{3}>'.format(close_tag.tag, ''.join(close_tag.text), tmp_line, close_tag.tag_name)
                                        if not len(tags):
                                            post_line.append(tmp_line)
                                        else:
                                            tags[-1].text.append(tmp_line)
                                        open_tags.append(close_tag)
                                    open_tags = open_tags[:-1]
                                    if not len(tags):
                                        post_line.append(text)
                                    else:
                                        tags[-1].text.append(text)
                                    if open_tags:
                                        for t in open_tags[:-1].reverse():
                                            t.text = ''
                                            tags.append(t)
                            else:
                                if tag_name in self.nowiki_tags:
                                    self.nowiki = True
                                    self.nowiki_tag = tag_name
                                tags.append(self.Preprocessor_tag(tag_name, text, tag))
                    else:
                        post_line.append(next_text)
                        break
                return ''.join(post_line)
            self.opened_tags = tags

    def _apply(self, match, prefix, *args):
        """
        Call the _repl method for the last matched group with the given prefix.
        """
        data = dict(((str(k), v) for k, v in match.groupdict().iteritems() if v is not None))
        func = '{0}_{1}_repl'.format(prefix, match.lastgroup)
        #logging.debug("calling %s(%r, %r)" % (func, args, data))
        getattr(self, func)(*args, **data)

    def parse_block(self, iter_content, arguments):
        attrib = {}
        if arguments:
            for key, value in arguments.keyword.iteritems():
                if key in ('style', ):
                    attrib[moin_page(key)] = value
                elif key == '_old':
                    attrib[moin_page.class_] = value.replace('/', ' ')

        body = moin_page.body(attrib=attrib)

        stack = _Stack(body, iter_content=iter_content)

        for line in iter_content:
            match = self.indent_re.match(line)
            if match:
                data = dict(((str(k), v) for k, v in match.groupdict().iteritems() if v is not None))
                self.indent_repl(iter_content, stack, line, **data)
            else:
                self.indent_repl(iter_content, stack, line, '', line)

        return body

    def parse_inline(self, text, stack, inline_re):
        """Recognize inline elements within the given text"""
        lines = text.split('\n')
        text = []
        for line in lines:
            text.append(self.preprocessor(line))
        text = '\n'.join(text)
        pos = 0
        for match in inline_re.finditer(text):
            # Handle leading text
            stack.top_append_ifnotempty(text[pos:match.start()])
            pos = match.end()

            self._apply(match, 'inline', stack)

        # Handle trailing text
        stack.top_append_ifnotempty(text[pos:])


from . import default_registry
from MoinMoin.util.mime import Type, type_moin_document
default_registry.register(Converter.factory, Type('x-moin/format;name=mediawiki'), type_moin_document)
default_registry.register(Converter.factory, Type('text/x-mediawiki'), type_moin_document)