I write my blog posts in markdown and pelican does the magic with it. So I don't really like to have html code in my markdown files. Unfortunatly, like many people know, Markdown has no download or abbreviation tags. That's why I wrote my own markdown extensions for pelican to handle that for me.

General

I store all my extensions in a directory markdown. To import the extension classes I will append the directory to the python path. In my configuration file I firstly import the extension class we will create for each extension.

sys.path.append("markdown")
from markdown_extension import Extension

In the pelican configuration file we will add a dictionary with a list with all the extensions in it.

MARKDOWN = {
    "extensions": [Extension()]
}

Abbreviation

markdown/markdown_abbreviation.py

import re
from markdown.extensions import Extension
from markdown.postprocessors import Postprocessor

def makeExtension(configs=None):
    if configs is None:
        return AbbreviationExtension()
    else:
        return AbbreviationExtension(configs=configs)

class AbbreviationExtension(Extension):
    def __init__(self, **kwargs):
        self.config = {}
        super(AbbreviationExtension, self).__init__(**kwargs)
    def extendMarkdown(self, md, md_globals):
        postprocessors = AbbreviationPostprocessor(md)
        md.postprocessors.add("abbreviation", postprocessors, ">raw_html")

class AbbreviationPostprocessor(Postprocessor):
    abbreviation_pattern = re.compile(r"\?\[([^\[]*)\]\[([^\[]*)\]")
    def __init__(self, *args, **kwargs):
        super(AbbreviationPostprocessor, self).__init__(*args, **kwargs)
    def run(self, html):
        return re.sub(self.abbreviation_pattern, self._code, html)
    def _code(self, match):
        title, name = match.groups()
        return "<abbr title=\"" + title + "\">" + name + "</abbr>"

Download

markdown/markdown_download.py

import re

from markdown.extensions import Extension
from markdown.preprocessors import Preprocessor
from markdown.postprocessors import Postprocessor

def makeExtension(configs=None):
    if configs is None:
        return DownloadExtension()
    else:
        return DownloadExtension(configs=configs)

class DownloadExtension(Extension):
    def __init__(self, **kwargs):
        self.config = {}
        super(DownloadExtension, self).__init__(**kwargs)

    def extendMarkdown(self, md, md_globals):
        postprocessors = DownloadPostprocessor(md)
        md.postprocessors.add("download", postprocessors, ">raw_html")

class DownloadPostprocessor(Postprocessor):
    download_pattern = re.compile(r"\%\[([^\[]*)\]\[([^\[]*)\]")

    def __init__(self, *args, **kwargs):
        super(DownloadPostprocessor, self).__init__(*args, **kwargs)

    def run(self, html):
        return re.sub(self.download_pattern, self._code, html)

    def _code(self, match):
        url, name = match.groups()
        return "<a href=\"{static}/files/" + url + "\" download>" + name + "</a>"