99 lines
3.4 KiB
Python
99 lines
3.4 KiB
Python
"""
|
|
Markdown Extension for Liquid-style Tags
|
|
----------------------------------------
|
|
A markdown extension to allow user-defined tags of the form::
|
|
|
|
{% tag arg1 arg2 ... argn %}
|
|
|
|
Where "tag" is associated with some user-defined extension.
|
|
These result in a preprocess step within markdown that produces
|
|
either markdown or html.
|
|
"""
|
|
import warnings
|
|
import markdown
|
|
import itertools
|
|
import re
|
|
import os
|
|
from functools import wraps
|
|
|
|
# Define some regular expressions
|
|
LIQUID_TAG = re.compile(r'\{%.*?%\}', re.MULTILINE | re.DOTALL)
|
|
EXTRACT_TAG = re.compile(r'(?:\s*)(\S+)(?:\s*)')
|
|
LT_CONFIG = { 'CODE_DIR': 'code',
|
|
'NOTEBOOK_DIR': 'notebooks',
|
|
'FLICKR_API_KEY': 'flickr',
|
|
'GIPHY_API_KEY': 'giphy'
|
|
}
|
|
LT_HELP = { 'CODE_DIR' : 'Code directory for include_code subplugin',
|
|
'NOTEBOOK_DIR' : 'Notebook directory for notebook subplugin',
|
|
'FLICKR_API_KEY': 'Flickr key for accessing the API',
|
|
'GIPHY_API_KEY': 'Giphy key for accessing the API'
|
|
}
|
|
|
|
class _LiquidTagsPreprocessor(markdown.preprocessors.Preprocessor):
|
|
_tags = {}
|
|
def __init__(self, configs):
|
|
self.configs = configs
|
|
|
|
def run(self, lines):
|
|
page = '\n'.join(lines)
|
|
liquid_tags = LIQUID_TAG.findall(page)
|
|
|
|
for i, markup in enumerate(liquid_tags):
|
|
# remove {% %}
|
|
markup = markup[2:-2]
|
|
tag = EXTRACT_TAG.match(markup).groups()[0]
|
|
markup = EXTRACT_TAG.sub('', markup, 1)
|
|
if tag in self._tags:
|
|
liquid_tags[i] = self._tags[tag](self, tag, markup.strip())
|
|
|
|
# add an empty string to liquid_tags so that chaining works
|
|
liquid_tags.append('')
|
|
|
|
# reconstruct string
|
|
page = ''.join(itertools.chain(*zip(LIQUID_TAG.split(page),
|
|
liquid_tags)))
|
|
|
|
# resplit the lines
|
|
return page.split("\n")
|
|
|
|
|
|
class LiquidTags(markdown.Extension):
|
|
"""Wrapper for MDPreprocessor"""
|
|
def __init__(self, config):
|
|
try:
|
|
# Needed for markdown versions >= 2.5
|
|
for key,value in LT_CONFIG.items():
|
|
self.config[key] = [value,LT_HELP[key]]
|
|
super(LiquidTags,self).__init__(**config)
|
|
except AttributeError:
|
|
# Markdown versions < 2.5
|
|
for key,value in LT_CONFIG.items():
|
|
config[key] = [config[key],LT_HELP[key]]
|
|
super(LiquidTags,self).__init__(config)
|
|
|
|
@classmethod
|
|
def register(cls, tag):
|
|
"""Decorator to register a new include tag"""
|
|
def dec(func):
|
|
if tag in _LiquidTagsPreprocessor._tags:
|
|
warnings.warn("Enhanced Markdown: overriding tag '%s'" % tag)
|
|
_LiquidTagsPreprocessor._tags[tag] = func
|
|
return func
|
|
return dec
|
|
|
|
def extendMarkdown(self, md, md_globals):
|
|
self.htmlStash = md.htmlStash
|
|
md.registerExtension(self)
|
|
# for the include_code preprocessor, we need to re-run the
|
|
# fenced code block preprocessor after substituting the code.
|
|
# Because the fenced code processor is run before, {% %} tags
|
|
# within equations will not be parsed as an include.
|
|
md.preprocessors.add('mdincludes',
|
|
_LiquidTagsPreprocessor(self), ">html_block")
|
|
|
|
|
|
def makeExtension(configs=None):
|
|
"""Wrapper for a MarkDown extension"""
|
|
return LiquidTags(configs=configs)
|