Permalink
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
168 lines (122 sloc) 4.29 KB

title: Using Emojis with Pelican and Python Markdown date: 2018-06-10 19:20 tags: markdown, python, pelican category: python slug: markdown_emoji_extension author: Philipp Wagner summary: This article shows how to write a custom Markdown Extension.

I didn't have much time this weekend, but I wanted to write a little code for keeping my brain active. So I looked at my website and noticed: I can't use emojis! ::face_with_open_mouth::

Supporting emojis sounds like a nice little task, so let's take a look at how to do it.

You can find the final extensions on the GitHub repository at:

Pelican

This website is generated by Pelican, which is a static site generator written in Python:

I am using Markdown for writing the posts, so the plan is: Write a custom Python Markdown extension to replace Emoji Names with their Unicode representation.

Writing Python Markdown Extensions is quite simple and there is a good tutorial here:

Emojis

Then I got a list of Emojis from the EmojiCodeSheet project:

There are several JSON files, with the emojis as Unicode characters:

[
  "peoples": {
    "people": [
      {
        "key": "grinning_face",
        "value": "😀"
      },
      {
        "key": "grimacing_face",
        "value": "😬"
      },
      
      ...
]

I turned it into a list of Key / Value Pairs, so it looks like this:

[
  {
    "key": "grinning_face",
    "value": "😀"
  },
  {
    "key": "grimacing_face",
    "value": "😬"
  },
  
  ...
]

Implementing the Markdown Extension

import io
import json
from markdown.extensions import Extension
from markdown.inlinepatterns import Pattern

EMOJI_RE = r'(::)(.*?)::'

class EmojiExtension(Extension):

    def __init__(self, **kwargs):
        self.config = {
            'emojis': [[], 'List of Emojis.']
        }
        super(EmojiExtension, self).__init__(**kwargs)
        
    def extendMarkdown(self, md, md_globals):
        emojis = self._as_dictionary(self.getConfig('emojis'))
        pattern = EmojiInlinePattern(EMOJI_RE, emojis)
        md.inlinePatterns.add('emoji', pattern,'<not_strong')
        
    def _as_dictionary(self, emojis):
        return dict((emoji['key'], emoji['value']) for emoji in emojis)
    
    @staticmethod
    def create_from_json(filename):
        with io.open(filename, encoding='utf-8') as filehandle:
            data = json.load(filehandle)
            return EmojiExtension(emojis=data)
        
class EmojiInlinePattern(Pattern):
    
    def __init__(self, pattern, emojis):
        super(EmojiInlinePattern, self).__init__(pattern)
        self.emojis = emojis
        
    def handleMatch(self, m):
        emoji_key = m.group(3)
        
        return self.emojis.get(emoji_key, '')

Finally I wrote a setup.py file to install the Extension:

from setuptools import setup

setup(
    name='emojiextension',
    description='Extension for displaying Emojis',
    version='1.1',
    py_modules=['emojiextension'],
    install_requires = ['markdown>=2.5']
)

The extension can now be installed by running:

python setup.py install

Integrating it into Pelican

What's left is to integrate the Markdown extension into Pelican. So in the Pelican Settings file I am first importing the EmojiExtension:

from emojiextension import EmojiExtension

And then register it in the MARKDOWN variable:

# Markdown Configuration:
MARKDOWN = {
    'extensions' : [EmojiExtension.create_from_json('./resources/emojis.json')],
    'extension_configs': {
        'markdown.extensions.codehilite': {'css_class': 'highlight'},
        'markdown.extensions.toc' : {},
        'markdown.extensions.extra': {},
        'markdown.extensions.meta': {},
    },
    'output_format': 'html5',
}

And that's it!

Does it work?

I think so! ::thumbs_up::