|
@@ -9,9 +9,9 @@
|
|
|
:license: BSD, see LICENSE for more details.
|
|
|
"""
|
|
|
import logging
|
|
|
-import re
|
|
|
|
|
|
import mistune
|
|
|
+from mistune.plugins import plugin_strikethrough, plugin_url
|
|
|
from flask import url_for
|
|
|
from markupsafe import Markup
|
|
|
from pluggy import HookimplMarker
|
|
@@ -24,33 +24,30 @@ impl = HookimplMarker('flaskbb')
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
-_re_user = re.compile(r'@(\w+)', re.I)
|
|
|
+_re_user = r'(?i)@(\w+)'
|
|
|
|
|
|
|
|
|
-def userify(match):
|
|
|
- value = match.group(1)
|
|
|
- user = "<a href='{url}'>@{user}</a>".format(
|
|
|
- url=url_for("user.profile", username=value, _external=False),
|
|
|
- user=value
|
|
|
- )
|
|
|
- return user
|
|
|
+def parse_user_link(inline, match, state):
|
|
|
+ url = url_for("user.profile", username=match.group(1), _external=False)
|
|
|
+ return 'link', url, match.group(0)
|
|
|
|
|
|
|
|
|
-class FlaskBBRenderer(mistune.Renderer):
|
|
|
- """Markdown with some syntactic sugar, such as @user gettting linked
|
|
|
- to the user's profile.
|
|
|
- """
|
|
|
+def plugin_userify(md):
|
|
|
+ """Mistune plugin that transforms @username references to links."""
|
|
|
+ md.inline.register_rule('flaskbb_user_link', _re_user, parse_user_link)
|
|
|
+ md.inline.rules.append('flaskbb_user_link')
|
|
|
|
|
|
- def __init__(self, **kwargs):
|
|
|
- super(FlaskBBRenderer, self).__init__(**kwargs)
|
|
|
|
|
|
- def paragraph(self, text):
|
|
|
- """Render paragraph tags, autolinking user handles."""
|
|
|
+DEFAULT_PLUGINS = [plugin_url, plugin_strikethrough, plugin_userify]
|
|
|
+
|
|
|
|
|
|
- text = _re_user.sub(userify, text)
|
|
|
- return super(FlaskBBRenderer, self).paragraph(text)
|
|
|
+class FlaskBBRenderer(mistune.HTMLRenderer):
|
|
|
+ """Mistune renderer that uses pygments to apply code highlighting."""
|
|
|
+
|
|
|
+ def __init__(self, **kwargs):
|
|
|
+ super(FlaskBBRenderer, self).__init__(**kwargs)
|
|
|
|
|
|
- def block_code(self, code, lang):
|
|
|
+ def block_code(self, code, lang=None):
|
|
|
if lang:
|
|
|
try:
|
|
|
lexer = get_lexer_by_name(lang, stripall=True)
|
|
@@ -78,16 +75,34 @@ def flaskbb_load_nonpost_markdown_class():
|
|
|
@impl
|
|
|
def flaskbb_jinja_directives(app):
|
|
|
render_classes = app.pluggy.hook.flaskbb_load_post_markdown_class(app=app)
|
|
|
- app.jinja_env.filters['markup'] = make_renderer(render_classes)
|
|
|
+ plugins = DEFAULT_PLUGINS[:]
|
|
|
+ app.pluggy.hook.flaskbb_load_post_markdown_plugins(
|
|
|
+ plugins=plugins,
|
|
|
+ app=app
|
|
|
+ )
|
|
|
+ app.jinja_env.filters['markup'] = make_renderer(render_classes, plugins)
|
|
|
|
|
|
render_classes = app.pluggy.hook.flaskbb_load_nonpost_markdown_class(
|
|
|
app=app
|
|
|
)
|
|
|
- app.jinja_env.filters['nonpost_markup'] = make_renderer(render_classes)
|
|
|
+ plugins = DEFAULT_PLUGINS[:]
|
|
|
+ plugins = app.pluggy.hook.flaskbb_load_nonpost_markdown_plugins(
|
|
|
+ plugins=plugins,
|
|
|
+ app=app
|
|
|
+ )
|
|
|
+ app.jinja_env.filters['nonpost_markup'] = make_renderer(
|
|
|
+ render_classes,
|
|
|
+ plugins
|
|
|
+ )
|
|
|
|
|
|
|
|
|
-def make_renderer(classes):
|
|
|
+def make_renderer(classes, plugins):
|
|
|
RenderCls = type('FlaskBBRenderer', tuple(classes), {})
|
|
|
|
|
|
- markup = mistune.Markdown(renderer=RenderCls(escape=True, hard_wrap=True))
|
|
|
- return lambda text: Markup(markup.render(text))
|
|
|
+ markup = mistune.create_markdown(
|
|
|
+ renderer=RenderCls(),
|
|
|
+ plugins=plugins,
|
|
|
+ escape=True,
|
|
|
+ hard_wrap=True
|
|
|
+ )
|
|
|
+ return lambda text: Markup(markup(text))
|