lepture/mistune

Block parse contents of a block plugin

hellocode808 opened this issue · 3 comments

I'm trying to write a plugin that renders tabs:

{tabs}

{tab Title 1}
**Content 1**

- Eggs
- Carrots
- Milk
{/tab}
{/tabs}

The plugin code:

TABS_PATTERN = r'(?sm){tabs}(?P<tabs_content>.*?){/tabs}'
TAB_PATTERN = r'(?sm){tab\s+(?P<tab_title>.+?)}(?P<tab_content>.*?)\s*{/tab}'

def parse_block_tabs(block, m, state):
    text = m.group('tabs_content')
    state.append_token({'type': 'tabs', 'text': text})
    return m.end() + 1

def parse_block_tab(block, m, state):
    title = m.group("tab_title")
    text = m.group('tab_content')
    state.append_token(
        {
            'type': 'tab',
            'text': text,
            'attrs': {
                'title': title
            }
        }
    )
    return m.end() + 1

def render_block_tabs(renderer, text):
    return '<ul class="tabs">' + text + '</ul>'

def render_block_tab(renderer, text, title):
    return '<li data-title="' + title + '">' + text + '</li>'

def tabs(md):
    md.block.register(
        'tabs', TABS_PATTERN, parse_block_tabs, before="paragraph"
    )
    if md.renderer and md.renderer.NAME == 'html':
        md.renderer.register('tabs', render_block_tabs)

def tab(md):
    md.block.register('tab', TAB_PATTERN, parse_block_tab, before="paragraph")
    if md.renderer and md.renderer.NAME == 'html':
        md.renderer.register('tab', render_block_tab)

Is there a way to employ the block parser after parsing with parse_block_tabs? In the docs I only found the option 'text': text to use the inline parser. I want all elements, inline and block, to be rendered - in my example the list and {tab} is not parsed.

Why not use directives? You can create a custom directive for tabs: https://mistune.lepture.com/en/latest/directives.html

That sounds like a good option! A syntax like this for example, inspired by PyMdown Extensions:

.. tab::
    :title: Title 1
    Content 1
.. tab::
    :title: Title 2
    Content 2

"Consecutive tabs will automatically be grouped. " - but how to implement this? I think in the parsing of the directive there needs to be a check if the preceding tokens are part of a tab set (or if not, start a new tab set). For that, access to the token tree would be needed. Any pointers on that or is there a simpler way I am not seeing?

@hellocode808 I suggest you to built it upon v3 (current master code). https://pypi.org/project/mistune/3.0.0rc4/

It supports RST-styled directives and fenced-styled directives. If you want to group your tabs, you can rerun the tokens in before_render_hooks.


BTW, I do offer paid work to write plugins and directives: https://github.com/sponsors/lepture/sponsorships?tier_id=220664