Sal
Peter Hoffmann
Python Developer, Conference Speaker, Mountaineer

Mistune 3 wikilink inline parser

Extending Mistune 3 to parse inline wikilinks.

Mistune 3 has changed it's internal structure and extension mechanisms.

The mistune advanced documentation has some examples how to create and register inline patterns. After some iterations I came up with the following solution to render wiki links:

import re  
from typing import TYPE_CHECKING, Match  
  
if TYPE_CHECKING:  
    from mistune import Markdown  
    from mistune.core import BaseRenderer, InlineState  
    from mistune.inline_parser import InlineParser  
  
  
def parse_wikilink(inline: "InlineParser", m: Match[str], state: "InlineState") -> int:  
    """Parse wikilink syntax [[page title]] or [[page title|display text]]"""  
    page_title = m.group('page').strip()  
    display_text = m.group('display')  
      
    # Use display text if provided, otherwise use page title  
    if display_text is not None:  
        text = display_text.strip()  
    else:  
        text = page_title  
      
    # Create a wikilink token  
    state.append_token({  
        "type": "wikilink",  
        "children": [{"type": "text", "raw": text}],  
        "attrs": {  
            "page": page_title,  
            "display": text  
        }  
    })  
      
    return m.end()  
  
def render_wikilink_html(renderer: "BaseRenderer", children: str, page: str, display: str) -> str:  
    """Render wikilink as HTML anchor tag"""  
    url_page = page.replace(' ', '_')  
    return f'<a href="/wiki/{url_page}" class="wikilink">{children}</a>'  
  
def wikilink_plugin(md: "Markdown") -> None:  
    """Plugin function to add wikilink support to mistune"""  
    # Use named groups
    WIKILINK_PATTERN = r'\[\[(?P<page>[^|\]]+)(?:\|(?P<display>[^\]]+))?\]\]'  
    md.inline.register("wikilink", WIKILINK_PATTERN, parse_wikilink, before="link")  
      
    if md.renderer and md.renderer.NAME == "html":  
        md.renderer.register("wikilink", render_wikilink_html)
  
# Usage example  
if __name__ == "__main__":  
    from mistune import create_markdown  
      
    # Create markdown parser with the wikilink plugin  
    md = create_markdown(plugins=[wikilink_plugin])  
      
    # Test examples  
    text1 = "Check out [[Main Page]] for more info."  
    text2 = "Visit [[Installation Guide|the installation guide]] to get started."  
    text3 = "Multiple links: [[Page One]] and [[Page Two|Custom Text]]."  
      
    print("Example 1:")  
    print(md(text1))  
    # Output: <p>Check out <a href="/wiki/Main_Page" class="wikilink">Main Page</a> for more info.</p>  
      
    print("\nExample 2:")  
    print(md(text2))  
    # Output: <p>Visit <a href="/wiki/Installation_Guide" class="wikilink">the installation guide</a> to get started.</p>  
      
    print("\nExample 3:")  
    print(md(text3))  
    # Output: <p>Multiple links: <a href="/wiki/Page_One" class="wikilink">Page One</a> and <a href="/wiki/Page_Two" class="wikilink">Custom Text</a>.</p>