Skip to content

Commit

Permalink
fix: wikilink re-implemented as inline parser not plugin
Browse files Browse the repository at this point in the history
The problem that was brought up in #144 was that [[Wikilinks]] were
half-rendered in code blocks. This is fixed. Some extra steps were
necessary to make sure that [[Wikilinks|with title]] are rendered
correct when in a table.
  • Loading branch information
redimp committed Oct 9, 2024
1 parent 12d3c00 commit 32299d0
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 64 deletions.
34 changes: 0 additions & 34 deletions otterwiki/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,39 +40,6 @@ def page_view_htmlcontent_postprocess(self, html, page):
"""


class WikiLinkPlugin:
"""This plugin preprocesses links in the [[WikiLink]] style."""

wiki_link_outer = re.compile(
r'\[\['
r'([^\]]+)'
r'\]\](?!\])' # [[ # ... # ]]
)
wiki_link_inner = re.compile(r'([^\|]+)\|?(.*)')

@hookimpl
def renderer_markdown_preprocess(self, md):
"""
Will turn
[[Page]]
[[Title|Link]]
into
[Page](/Page)
[Title](/Link)
"""
for m in self.wiki_link_outer.finditer(md):
title, link = self.wiki_link_inner.findall(m.group(1))[0]
if link == '':
link = title
if not link.startswith("/"):
link = f"/{link}"
# quote link (and just in case someone encoded already: unquote)
link = urllib.parse.quote(urllib.parse.unquote(link), safe="/#")
md = md.replace(m.group(0), f'[{title}]({link})')

return md


# pluggy doesn't by default handle chaining the output of one plugin into
# another, so this is a small utility function to do this.
# this utility function will chain the result of each hook into the first
Expand All @@ -88,5 +55,4 @@ def chain_hooks(hook_name, value, *args, **kwargs):
# addition to the utility function above.
plugin_manager = pluggy.PluginManager("otterwiki")
plugin_manager.add_hookspecs(OtterWikiPluginSpec)
plugin_manager.register(WikiLinkPlugin())
plugin_manager.load_setuptools_entrypoints("otterwiki")
2 changes: 2 additions & 0 deletions otterwiki/renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
plugin_fold,
plugin_math,
plugin_alerts,
plugin_wikilink,
)
from otterwiki.plugins import chain_hooks
from bs4 import BeautifulSoup
Expand Down Expand Up @@ -197,6 +198,7 @@ def __init__(self):
plugin_fold,
plugin_math,
plugin_alerts,
plugin_wikilink,
],
)
self.lastword = re.compile(r"([a-zA-Z_0-9\.]+)$")
Expand Down
64 changes: 64 additions & 0 deletions otterwiki/renderer_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from mistune.inline_parser import LINK_LABEL
from mistune.util import unikey, ESCAPE_TEXT
import urllib.parse

__all__ = ['plugin_task_lists', 'plugin_footnotes']

Expand Down Expand Up @@ -559,6 +560,68 @@ def __call__(self, md):
)


class mistunePluginWikiLink:
"""This plugin preprocesses links in the [[WikiLink]] style."""

PIPE_REPLACEMENT="\ufeff"

WIKI_LINK = (
r"\[\[(([^|\]#]+)(?:#[^\]]*)?(?:(\|)([^\]]+))?)\]\]"
)
WIKI_LINK_RE = re.compile(WIKI_LINK)
WIKI_LINK_MOD = (
r"\[\[(([^"+PIPE_REPLACEMENT+r"\]#]+)(?:#[^\]]*)?(?:("+PIPE_REPLACEMENT+r")([^\]]+))?)\]\]"
)
WIKI_LINK_MOD_RE = re.compile(WIKI_LINK_MOD)

def parse_wikilink(self, inline, m, state):
title, link = m.group(2), m.group(4) or ""

if link == '':
link = title
if not link.startswith("/"):
link = f"/{link}"
# quote link (and just in case someone encoded already: unquote)
link = urllib.parse.quote(urllib.parse.unquote(link), safe="/#")

return "wikilink", inline.render(title, state), link

def render_html_wikilink(self, text, link):
return '<a href="'+ link +'">' + text + '</a>'

def replace_wikilinks(self, match):
if match.group(3) and len(match.group(3)):
return "[["+match.group(2)+"%"+match.group(4)+"]]"
return "[["+match.group(2)+"]]"

def before_parse(self, md, s, state):
def replace(match):
if match.group(3) and len(match.group(3)):
return "[["+match.group(2)+self.PIPE_REPLACEMENT+match.group(4)+"]]"
return "[["+match.group(2)+"]]"
s = self.WIKI_LINK_RE.sub(replace, s)
return s, state

def after_render(self, md, s, state):
def replace(match):
if match.group(3) and len(match.group(3)):
return "[["+match.group(2)+"|"+match.group(4)+"]]"
return "[["+match.group(2)+"]]"
s = self.WIKI_LINK_MOD_RE.sub(replace, s)
return s

def __call__(self, md):
md.before_parse_hooks.append(self.before_parse)
md.after_render_hooks.append(self.after_render)

md.inline.register_rule('wikilink', self.WIKI_LINK_MOD, self.parse_wikilink)

md.inline.rules.append('wikilink')

if md.renderer.NAME == 'html':
md.renderer.register('wikilink', self.render_html_wikilink)


plugin_task_lists = mistunePluginTaskLists()
plugin_footnotes = mistunePluginFootnotes()
plugin_mark = mistunePluginMark()
Expand All @@ -567,3 +630,4 @@ def __call__(self, md):
plugin_fold = mistunePluginFold()
plugin_math = mistunePluginMath()
plugin_alerts = mistunePluginAlerts()
plugin_wikilink = mistunePluginWikiLink()
31 changes: 1 addition & 30 deletions tests/test_renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
# vim: set et ts=8 sts=4 sw=4 ai:

import pytest
from otterwiki.plugins import WikiLinkPlugin
from otterwiki.renderer import render, clean_html


Expand Down Expand Up @@ -122,40 +121,12 @@ def test_wiki_link_in_table(req_ctx):
[[Paul|people/Paul]]
"""
html, _ = render.markdown(text)
print(html)
assert '<td><a href="/people/John">people/John</a></td>' in html
assert '<a href="/people/Paul">Paul</a>' in html
assert '<td><a href="/people/Mary">Mary</a></td>' in html


def test_preprocess_wiki_links():
plugin = WikiLinkPlugin()
md = plugin.renderer_markdown_preprocess(
"""
[[Page]]
[[Title|Link]]
[[Text with space|Link with space]]
"""
)
assert '[Page](/Page)' in md
assert '[Title](/Link)' in md
assert '[Page](/Page)' == plugin.renderer_markdown_preprocess("[[Page]]")
assert '[Title](/Link)' == plugin.renderer_markdown_preprocess("[[Title|Link]]")
assert (
'[Text with space](/Link%20with%20space)'
== plugin.renderer_markdown_preprocess("[[Text with space|Link with space]]")
)
assert (
'[Text with space](/Link%20with%20space)'
== plugin.renderer_markdown_preprocess(
"[[Text with space|Link%20with%20space]]"
)
)
# make sure fragment identifier of the URL survived the parser
assert '[Random#Title](/Random#Title)' == plugin.renderer_markdown_preprocess(
"[[Random#Title]]"
)


def test_table_align():
text = """
| left th | center th | right th |
Expand Down

0 comments on commit 32299d0

Please sign in to comment.