Permalink
Please
sign in to comment.
Showing
with
264 additions
and 0 deletions.
- +61 −0 README.md
- +167 −0 mdx_unimoji.py
- +36 −0 setup.py
| @@ -0,0 +1,61 @@ | |||
| Unicode Emojis for Python-Markdown | |||
| ================================== | |||
|
|
|||
| Converts defined emoticon symbols to Unicode emojis, supported on a | |||
| variety of devices [1]. | |||
|
|
|||
| [1]: http://apps.timwhitlock.info/emoji/tables/unicode#block-1-emoticons | |||
|
|
|||
| Usage: | |||
|
|
|||
| >>> from __future__ import print_function | |||
| >>> from markdown import markdown | |||
| >>> text = 'I <3 you! Just kidding. :P' | |||
| >>> print(markdown(text, ['unimoji'])) # doctest: +NORMALIZE_WHITESPACE | |||
| <p>I <span class="emoji" style="color:red">❤</span> you! \ | |||
| Just kidding. <span class="emoji">😛</span></p> | |||
| **NOTE**: The emojis are only replaced when whitespace-delimited on both sides! | |||
|
|
|||
| The following options are accepted: | |||
|
|
|||
| - `emoji`, the emoticon-to-list-of-aliases mapping, | |||
| - `span_class`, the class name of the encompassing `<span>` element | |||
| (default: 'emoji'). No element is created if `None`. | |||
|
|
|||
| An example with these custom settings: | |||
|
|
|||
| >>> from mdx_unimoji import UnimojiExtension | |||
| >>> img_heart = '<img alt="love" src="heart.png"/>' | |||
| >>> img_tongue = '<img alt=":P" src="tongue.png"/>' | |||
| >>> overrides = UnimojiExtension.EMOJI | |||
| >>> overrides.update({img_heart: ['<3'], | |||
| ... img_tongue: ':p :P :-p :-P'.split()}) | |||
| >>> print(markdown(text, | |||
| ... extensions=[UnimojiExtension(span_class='other', | |||
| ... emoji=overrides)])) | |||
| ... # doctest: +NORMALIZE_WHITESPACE | |||
| <p>I <img alt="love" class="other" src="heart.png" /> you! \ | |||
| Just kidding. <img alt=":P" class="other" src="tongue.png" /></p> | |||
| You can use the `span_class` value in your CSS, e.g.: | |||
|
|
|||
| .emoji { | |||
| font-family: "Apple Color Emoji", "Segoe UI Emoji", | |||
| "Noto Color Emoji", EmojiSymbols, "DejaVu Sans", Symbola; | |||
| } | |||
|
|
|||
| Install | |||
| ------- | |||
|
|
|||
| To install and make available to Markdown, you can issue: | |||
|
|
|||
| pip install mdx_unimoji | |||
|
|
|||
| or | |||
|
|
|||
| pip install --upgrade git+git://github.com/kernc/mdx_unimoji.git | |||
|
|
|||
| Then use the above provided examples to figure your way around. | |||
|
|
|||
| HF! | |||
| @@ -0,0 +1,167 @@ | |||
| # coding: utf-8 | |||
| """ | |||
| Unicode Emojis for Python-Markdown | |||
| ================================== | |||
| Converts defined emoticon symbols to Unicode emojis, supported on a | |||
| variety of devices [1]. | |||
| [1]: http://apps.timwhitlock.info/emoji/tables/unicode#block-1-emoticons | |||
| Usage: | |||
| >>> from __future__ import print_function | |||
| >>> from markdown import markdown | |||
| >>> text = 'I <3 you! Just kidding. :P' | |||
| >>> print(markdown(text, ['unimoji'])) # doctest: +NORMALIZE_WHITESPACE | |||
| <p>I <span class="emoji" style="color:red">❤</span> you! \ | |||
| Just kidding. <span class="emoji">😛</span></p> | |||
| **NOTE**: The emojis are only replaced when whitespace-delimited on both sides! | |||
| The following options are accepted: | |||
| - `emoji`, the emoticon-to-list-of-aliases mapping, | |||
| - `span_class`, the class name of the encompassing `<span>` element | |||
| (default: 'emoji'). No element is created if `None`. | |||
| An example with these custom settings: | |||
| >>> from mdx_unimoji import UnimojiExtension | |||
| >>> img_heart = '<img alt="love" src="heart.png"/>' | |||
| >>> img_tongue = '<img alt=":P" src="tongue.png"/>' | |||
| >>> overrides = UnimojiExtension.EMOJI | |||
| >>> overrides.update({img_heart: ['<3'], | |||
| ... img_tongue: ':p :P :-p :-P'.split()}) | |||
| >>> print(markdown(text, | |||
| ... extensions=[UnimojiExtension(span_class='other', | |||
| ... emoji=overrides)])) | |||
| ... # doctest: +NORMALIZE_WHITESPACE | |||
| <p>I <img alt="love" class="other" src="heart.png" /> you! \ | |||
| Just kidding. <img alt=":P" class="other" src="tongue.png" /></p> | |||
| You can use the `span_class` value in your CSS, e.g.: | |||
| .emoji { | |||
| font-family: "Apple Color Emoji", "Segoe UI Emoji", | |||
| "Noto Color Emoji", EmojiSymbols, "DejaVu Sans", Symbola; | |||
| } | |||
| HF! | |||
| """ | |||
| from __future__ import unicode_literals | |||
| from markdown import Extension | |||
| from markdown.util import etree | |||
| from markdown.inlinepatterns import Pattern | |||
|
|
|||
| class UnimojiExtension(Extension): | |||
| EMOJI = { | |||
| '😊': ':) :-) :] :-] =) =] ^^ ^_^ ☺'.split(), | |||
| '😉': ';) ;-) ;] ;-]'.split(), | |||
| '😄': ':D :-D =D'.split(), | |||
| '😂': ":,D :'D =,D ='D".split(), | |||
| '😆': 'xD XD'.split(), | |||
| '😛': ':p :-p :P :-P =p =P'.split(), | |||
| '😜': ';p ;-p ;P ;-P'.split(), | |||
| '😏': ':> :->'.split(), | |||
| '😞': ':( :-( ;( ;-( =( =[ ☹'.split(), | |||
| '😣': 'x( X('.split(), | |||
| '😢': ":,( :'( =,( ='(".split(), | |||
| '😠': '>:( >=('.split(), | |||
| '😲': ':O :-O 8-O =O'.split(), | |||
| '😵': 'x-O X-O'.split(), | |||
| '😳': ':$ :-$ :">'.split(), | |||
| '😴': ':zzz:'.split(), | |||
| '😓': ':-X :X :-# :# :-& :&'.split(), | |||
| '😇': 'O:) O:-)'.split(), | |||
| '😈': '3:) 3:-) >:) >:-) >;) >;-)'.split(), | |||
| '😎': '8)'.split(), | |||
| '😖': ':s :-s :S :-S'.split(), | |||
| '😒': ':/ :-/ :\\ :-\\ =/ =\\ :L'.split(), | |||
| '😚': ':* :-*'.split(), | |||
| '😘': ';* ;-*'.split(), | |||
| '❤': '<3'.split(), | |||
| '💔': '</3'.split(), | |||
| '👍': ':y: :Y: :+1:'.split(), | |||
| '👎': ':n: :N: :-1:'.split(), | |||
| '🙌': '\\o/'.split(), | |||
| '🍰': ':cake:'.split(), | |||
| '😸': ':^) :} :-} :3 :-3'.split(), | |||
| '😺': ':^D =^D'.split(), | |||
| '😿': ':^( :{'.split(), | |||
| } | |||
| STYLES = { | |||
| '❤': 'color:red', | |||
| '💔': 'color:red', | |||
| '🍰': 'color:maroon', | |||
| } | |||
| config = { | |||
| 'emoji': [ | |||
| EMOJI, | |||
| 'A mapping from emoticon symbols to a list of aliases.' | |||
| ], | |||
| 'styles': [ | |||
| STYLES, | |||
| 'A mapping from emoticon symbol to a CSS style string. ' | |||
| 'Only works if span_class is enabled.' | |||
| ], | |||
| 'span_class': [ | |||
| 'emoji', | |||
| 'A CSS class (default: "emoji") for the emoticons-encompassing' | |||
| '<span>. Disabled if None.' | |||
| ], | |||
| } | |||
|
|
|||
| def __init__ (self, *args, **kwargs): | |||
| super(UnimojiExtension, self).__init__(*args, **kwargs) | |||
| # Set keys as aliases so they get processed the same | |||
| for k, v in self.getConfig('emoji').items(): v.append(k) | |||
| # Inverse the emoji mapping | |||
| aliases = {} | |||
| for emoticon, alias in self.getConfig('emoji').items(): | |||
| for a in alias: | |||
| aliases[a] = emoticon | |||
| self.config['aliases'] = [aliases, ''] | |||
|
|
|||
| def extendMarkdown(self, md, md_globals): | |||
| import re | |||
| RE = r'((?<=\s)|(?<=^))(?P<emoticon>%s)(?=\s|$)' % '|'.join(map(re.escape, self.getConfig('aliases'))) | |||
| md.inlinePatterns['emoji'] = UnimojiPattern(RE, md, self) | |||
|
|
|||
|
|
|||
| class UnimojiPattern(Pattern): | |||
| def __init__ (self, pattern, md, extension): | |||
| super(UnimojiPattern, self).__init__(pattern, md) | |||
| self.ext = extension | |||
|
|
|||
| def handleMatch(self, m): | |||
| # Get the preferred Unicode emoticon, or override | |||
| emoticon = self.ext.getConfig('aliases')[m.group('emoticon')] | |||
| # Try to parse it as HTML in case it's overriden | |||
| try: element = etree.fromstring(emoticon.encode('utf-8')) | |||
| except etree.ParseError: | |||
| pass | |||
| # Apply class name if needed | |||
| span_class = self.ext.getConfig('span_class') | |||
| if span_class: | |||
| try: element | |||
| except NameError: | |||
| element = etree.Element('span') | |||
| element.text = emoticon | |||
| element.set('class', span_class) | |||
| # Apply style formatting | |||
| style = self.ext.getConfig('styles').get(emoticon) | |||
| if style: element.set('style', style) | |||
| try: | |||
| return element | |||
| except NameError: | |||
| return emoticon | |||
|
|
|||
|
|
|||
| def makeExtension(*args, **kwargs): | |||
| return UnimojiExtension(*args, **kwargs) | |||
|
|
|||
|
|
|||
| if __name__ == '__main__': | |||
| import doctest; doctest.testmod() | |||
| @@ -0,0 +1,36 @@ | |||
| #!/usr/bin/env python | |||
|
|
|||
| from setuptools import setup | |||
| import doctest | |||
|
|
|||
| MODULE = 'mdx_unimoji' | |||
|
|
|||
| tests = lambda: doctest.DocTestSuite(MODULE) | |||
|
|
|||
| setup( | |||
| name=MODULE, | |||
| version='1.0', | |||
| author='Jack Nicholson', | |||
| author_email='kern.ce.ce++@gmail.com', | |||
| description='Python-Markdown extension that replaces common smileys with their Unicode emoji emoticons. ;)', | |||
| long_description_markdown_filename='README.md', | |||
| url='https://github.com/kernc/' + MODULE, | |||
| py_modules=[MODULE], | |||
| test_suite='setup.tests', | |||
| install_requires=['Markdown'], | |||
| setup_requires=['setuptools-markdown'], | |||
| license='GPLv3+', | |||
| keywords='markdown unicode emoji emoticon', | |||
| classifiers=[ | |||
| 'Development Status :: 5 - Production/Stable', | |||
| 'Operating System :: OS Independent', | |||
| 'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)', | |||
| 'Environment :: Web Environment', | |||
| 'Programming Language :: Python :: 2.7', | |||
| 'Programming Language :: Python :: 3', | |||
| 'Topic :: Internet :: WWW/HTTP :: Dynamic Content :: Message Boards', | |||
| 'Topic :: Internet :: WWW/HTTP :: Dynamic Content :: News/Diary', | |||
| 'Topic :: Text Processing :: Filters', | |||
| 'Topic :: Text Processing :: Markup :: HTML' | |||
| ] | |||
| ) | |||
0 comments on commit
5225b1d