From 31ef07b1ef7c4c6d98dc630319868514ee9d6c74 Mon Sep 17 00:00:00 2001 From: XTao Date: Mon, 22 Sep 2014 01:34:19 +0800 Subject: [PATCH 1/2] Refactor emoji. --- mikoto/__init__.py | 2 +- mikoto/{libs => }/emoji.py | 80 +++++++++++++++++++------------------- mikoto/htmlrenderer.py | 8 +++- mikoto/libs/text.py | 7 ++-- mikoto/markdown.py | 21 ++++++++-- 5 files changed, 66 insertions(+), 52 deletions(-) rename mikoto/{libs => }/emoji.py (66%) diff --git a/mikoto/__init__.py b/mikoto/__init__.py index 4391033..6b55399 100644 --- a/mikoto/__init__.py +++ b/mikoto/__init__.py @@ -9,7 +9,7 @@ class Mikoto(object): - def __init__(self, text): + def __init__(self, text, emoji=None): self.text = text self.unicode = translate_to_unicode(text) diff --git a/mikoto/libs/emoji.py b/mikoto/emoji.py similarity index 66% rename from mikoto/libs/emoji.py rename to mikoto/emoji.py index 8189657..e63a4df 100644 --- a/mikoto/libs/emoji.py +++ b/mikoto/emoji.py @@ -1,9 +1,7 @@ -#!/usr/bin/env python -# encoding: utf-8 +# -*- coding: utf-8 -*- -import re import os -from cgi import escape +import re EMOJIS = [ ':airplane:', ':alien:', ':art:', ':bear:', ':beer:', ':bike:', ':bomb:', @@ -21,33 +19,28 @@ ] -# EMOJIS dir: /hub/static/emoji/ -EMOJI_GROUPS = { +GROUPED_EMOJIS = { ":mergetime:": """ :zap::zap::zap::zap::zap::zap::zap::zap::zap::zap: :zap::metal: M E R G E T I M E :metal::zap: :zap::zap::zap::zap::zap::zap::zap::zap::zap::zap: """, - ":sparklock:": """ :black_circle::point_down::black_circle: :point_right::sparkler::point_left: :black_circle::point_up_2::black_circle: """, - ":myballoon:": """ :cloud::partly_sunny::cloud::cloud::cloud::cloud::cloud: - + :balloon: - + :runner::dash: """, - ":getit:": """ :balloon: :raised_hand: """, - ":apollo:": """ :octocat: :star2: :us: :sparkles: :sparkles: :full_moon: @@ -55,41 +48,55 @@ :sparkles: :collision: :partly_sunny: :collision: :sparkles: :zap: :collision: -:earth_asia: :sparkles: :dizzy: +:earth_asia: :sparkles: :dizzy: """, } -def parse_emoji_groups(text): - groups = set(RE_EMOJI_GROUPS.findall(text)) - for group in groups: - group_text = EMOJI_GROUPS[group] - group_text = group_text.replace(' ', ' ') - group_text = group_text.replace('\n', "
") - text = text.replace(group, group_text) - return text +class Emoji(object): + + def __init__(self, emojis=None, grouped_emojis=None): + self.emojis = emojis or [] + self.grouped_emojis = grouped_emojis or {} + + def init(self): + self.emoji_pattern = re.compile(r'(' + '|'.join([re.escape(x) for x in self.emojis]) + r')') + self.emoji_only_pattern = re.compile(r'^

\s*(' + '|'.join([re.escape(x) for x in self.emojis]) + r')\s*

$') + self.grouped_emoji_pattern = re.compile('|'.join([re.escape(x) for x in self.grouped_emojis.keys()])) -def parse_emoji(text, is_escape=True): +emoji = Emoji(emojis=EMOJIS, grouped_emojis=GROUPED_EMOJIS) +emoji.init() + + +def render_emoji(text): if not text: return '' - if is_escape: - text = escape(text) - text = parse_emoji_groups(text) - if RE_EMOJI_ONLY.match(text.strip()): + text = render_grouped_emoji(emoji, text) + if emoji.emoji_only_pattern.match(text.strip()): emoji_img = '' else: emoji_img = '' - result = RE_EMOJI.sub(lambda x: emoji_img % x.group().strip(':'), text) - return result + text = emoji.emoji_pattern.sub(lambda x: emoji_img % x.group().strip(':'), text) + return text + + +def render_grouped_emoji(text): + groups = set(emoji.grouped_emoji_pattern.findall(text)) + for group in groups: + group_text = emoji.grouped_emojis[group] + group_text = group_text.replace(' ', ' ') + group_text = group_text.replace('\n', "
") + text = text.replace(group, group_text) + return text -def all_emojis(): +def discover_emoji(): sub_emoji = 'hub/static/emoji' - emoji_dir = os.path.join(os.path.curdir, sub_emoji) + emoji_file_path = os.path.join(os.path.curdir, sub_emoji) realpath = os.path.dirname(os.path.realpath(__file__)) - curdir = os.path.join(realpath, os.path.pardir, sub_emoji) - for dir in [emoji_dir, curdir]: + cur_path = os.path.join(realpath, os.path.pardir, sub_emoji) + for dir in [emoji_file_path, cur_path]: abs_emoji_dir = os.path.abspath(dir) if os.path.isdir(abs_emoji_dir): files = os.listdir(abs_emoji_dir) @@ -97,12 +104,3 @@ def all_emojis(): return [':{}:'.format(fn[:-4]) for fn in files if fn.endswith('.png')] return EMOJIS - - -def url_for_emoji(emoji): - return '/static/emoji/%s.png' % emoji[1:-1] - - -RE_EMOJI = re.compile(r'(' + '|'.join([re.escape(x) for x in all_emojis()]) + r')') -RE_EMOJI_ONLY = re.compile(r'^

\s*(' + '|'.join([re.escape(x) for x in all_emojis()]) + r')\s*

$') -RE_EMOJI_GROUPS = re.compile('|'.join([re.escape(x) for x in EMOJI_GROUPS.keys()])) diff --git a/mikoto/htmlrenderer.py b/mikoto/htmlrenderer.py index 49ee1b2..f5933e0 100644 --- a/mikoto/htmlrenderer.py +++ b/mikoto/htmlrenderer.py @@ -6,7 +6,7 @@ from pygments import highlight from pygments.lexers import get_lexer_by_name from pygments.formatters import HtmlFormatter -from mikoto.libs.emoji import parse_emoji +from mikoto.emoji import render_emoji from mikoto.checklist import render_checklist RE_USER_MENTION = re.compile(r'(^|\W)@([a-zA-Z0-9_]+)') @@ -15,11 +15,15 @@ class HtmlRenderer(misaka.HtmlRenderer): + #def __init__(self, *k, **kw): + # self.emoji = kw.pop('emoji', None) + # super(HtmlRenderer, self).__init__(*k, **kw) + def postprocess(self, text): if not text: return text text = render_checklist(text) - text = parse_emoji(text, is_escape=False) + text = render_emoji(text) return RE_USER_MENTION.sub(USER_LINK_TEXT, text) def block_code(self, text, lang): diff --git a/mikoto/libs/text.py b/mikoto/libs/text.py index 42579dd..36611c9 100644 --- a/mikoto/libs/text.py +++ b/mikoto/libs/text.py @@ -5,10 +5,9 @@ from mikoto.htmlrenderer import RE_USER_MENTION from mikoto.markdown import render_markdown -from mikoto.checklist import get_checkbox_count +from mikoto.emoji import render_emoji from mikoto.libs.consts import (SOURCE_FILE, NOT_GENERATED, IGNORE_FILE_EXTS, IS_GENERATED) -from mikoto.libs.emoji import parse_emoji RST_RE = re.compile(r'.*\.re?st(\.txt)?$') @@ -61,11 +60,11 @@ def render_markdown_with_team(content, team): text = render_markdown(content) text = re.sub(RE_TICKET, r'#\1', text) - return parse_emoji(text, is_escape=False) + return render_emoji(text) def render_commit_message(message, project): - text = parse_emoji(message) + text = render_emoji(message) text = re.sub(RE_PR_IN_MESSAGE, r' #\1 ' % project.name, text) diff --git a/mikoto/markdown.py b/mikoto/markdown.py index f9cb273..db3cba8 100644 --- a/mikoto/markdown.py +++ b/mikoto/markdown.py @@ -21,7 +21,20 @@ misaka.EXT_STRIKETHROUGH) -def render_markdown(content): - if not content: - content = '' - return _markdown_renderer.render(content) +def render_markdown(text): + if not text: + text = '' + renderer = _markdown_renderer + return renderer.render(text) + + +def generate_renderer(emoji): + # TODO + generic_renderer = HtmlRenderer(_render_flags, emoji=emoji) + markdown_renderer = misaka.Markdown(generic_renderer, + extensions=misaka.EXT_FENCED_CODE | + misaka.EXT_NO_INTRA_EMPHASIS | + misaka.EXT_AUTOLINK | + misaka.EXT_TABLES | + misaka.EXT_STRIKETHROUGH) + return markdown_renderer From 1978a9cb6c0e03c230ac33251407aef1dbf8718f Mon Sep 17 00:00:00 2001 From: XTao Date: Tue, 23 Sep 2014 01:38:15 +0800 Subject: [PATCH 2/2] Fix --- mikoto/__init__.py | 36 +++++++++++++++++++++--------------- mikoto/code.py | 11 ++++++----- mikoto/emoji.py | 4 ++-- mikoto/htmlrenderer.py | 20 ++++++++++++-------- mikoto/markdown.py | 20 +++++++++----------- setup.py | 2 +- tests/test_markdown.py | 4 ++++ tests/test_utils.py | 2 +- 8 files changed, 56 insertions(+), 43 deletions(-) diff --git a/mikoto/__init__.py b/mikoto/__init__.py index 6b55399..53bfce7 100644 --- a/mikoto/__init__.py +++ b/mikoto/__init__.py @@ -1,29 +1,35 @@ # -*- coding: utf-8 -*- -from mikoto.markdown import render_markdown +from mikoto.markdown import render_markdown, init_markdown from mikoto.rst import render_rst from mikoto.code import render_code, render_highlight_code from mikoto.text import translate_to_unicode __all__ = ['Mikoto'] + class Mikoto(object): - def __init__(self, text, emoji=None): - self.text = text - self.unicode = translate_to_unicode(text) + def __init__(self): + self.markdown = None + + def init_markdown(self, **kw): + self.markdown = init_markdown(**kw) - @property - def markdown(self): - return render_markdown(self.unicode) + def render_markdown(self, text, path): + text = translate_to_unicode(text) + if self.markdown: + return render_markdown(text) + return self.markdown.render(text) - @property - def restructuredtext(self): - return render_rst(self.unicode) + def render_restructuredtext(self, text, path): + text = translate_to_unicode(text) + return render_rst(text) - @property - def code(self): - return render_code(self.unicode) + def render_code(self, text, path): + text = translate_to_unicode(text) + return render_code(text) - def highlight_code(self, path): - return render_highlight_code(self.unicode, path) + def render_highlight_code(self, text, path): + text = translate_to_unicode(text) + return render_highlight_code(text, path) diff --git a/mikoto/code.py b/mikoto/code.py index dfb94ef..d9a04dd 100644 --- a/mikoto/code.py +++ b/mikoto/code.py @@ -59,11 +59,12 @@ def render_highlight_code(text, path, **kwargs): formatter = CodeHtmlFormatter - return highlight(text, lexer, formatter(linenos='inline', - lineanchors='L', - anchorlinenos=True, - encoding='utf-8', - **kwargs)) + output = highlight(text, lexer, formatter(linenos='inline', + lineanchors='L', + anchorlinenos=True, + encoding='utf-8', + **kwargs)) + return output.decode('utf-8') class CodeHtmlFormatter(HtmlFormatter): diff --git a/mikoto/emoji.py b/mikoto/emoji.py index e63a4df..1962b6a 100644 --- a/mikoto/emoji.py +++ b/mikoto/emoji.py @@ -69,7 +69,7 @@ def init(self): emoji.init() -def render_emoji(text): +def render_emoji(emoji, text): if not text: return '' text = render_grouped_emoji(emoji, text) @@ -81,7 +81,7 @@ def render_emoji(text): return text -def render_grouped_emoji(text): +def render_grouped_emoji(emoji, text): groups = set(emoji.grouped_emoji_pattern.findall(text)) for group in groups: group_text = emoji.grouped_emojis[group] diff --git a/mikoto/htmlrenderer.py b/mikoto/htmlrenderer.py index f5933e0..25700cb 100644 --- a/mikoto/htmlrenderer.py +++ b/mikoto/htmlrenderer.py @@ -15,15 +15,17 @@ class HtmlRenderer(misaka.HtmlRenderer): - #def __init__(self, *k, **kw): - # self.emoji = kw.pop('emoji', None) - # super(HtmlRenderer, self).__init__(*k, **kw) + def __init__(self, *k, **kw): + self.emoji = kw.pop('emoji', None) + self.link_prefix = kw.pop('link_prefix', None) + super(HtmlRenderer, self).__init__(*k, **kw) def postprocess(self, text): if not text: return text text = render_checklist(text) - text = render_emoji(text) + if self.emoji: + text = render_emoji(self.emoji, text) return RE_USER_MENTION.sub(USER_LINK_TEXT, text) def block_code(self, text, lang): @@ -48,18 +50,20 @@ def __text_to_unichr(self, text): text = text.replace("@", "@") return text - def __link_to_local_project(self, link): + def __link_to_local(self, link): if not (link.startswith("http://") or link.startswith("https://")): - link = "[PROJECT]%s" % link + link = "[MIKOTO_PREFIX]%s" % link return link def image(self, link, title, alt_text): alt_text = alt_text or "" - link = self.__link_to_local_project(link) + if self.link_prefix: + link = self.__link_to_local(link) return '%s' % (link, alt_text) def link(self, link, title, content): title = title or "" - link = self.__link_to_local_project(link) + if self.link_prefix: + link = self.__link_to_local(link) return '%s' % (link, title, content) diff --git a/mikoto/markdown.py b/mikoto/markdown.py index db3cba8..45602dd 100644 --- a/mikoto/markdown.py +++ b/mikoto/markdown.py @@ -27,14 +27,12 @@ def render_markdown(text): renderer = _markdown_renderer return renderer.render(text) - -def generate_renderer(emoji): - # TODO - generic_renderer = HtmlRenderer(_render_flags, emoji=emoji) - markdown_renderer = misaka.Markdown(generic_renderer, - extensions=misaka.EXT_FENCED_CODE | - misaka.EXT_NO_INTRA_EMPHASIS | - misaka.EXT_AUTOLINK | - misaka.EXT_TABLES | - misaka.EXT_STRIKETHROUGH) - return markdown_renderer +def init_markdown(emoji=None, link_prefix=None): + html = HtmlRenderer(_render_flags, emoji=emoji, link_prefix=link_prefix) + markdown = misaka.Markdown(html, + extensions=misaka.EXT_FENCED_CODE | + misaka.EXT_NO_INTRA_EMPHASIS | + misaka.EXT_AUTOLINK | + misaka.EXT_TABLES | + misaka.EXT_STRIKETHROUGH) + return markdown diff --git a/setup.py b/setup.py index 73fc965..58797ff 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # -*- coding: utf-8 -*- import sys @@ -7,6 +6,7 @@ class PyTest(TestCommand): + def finalize_options(self): TestCommand.finalize_options(self) self.test_args = ['tests'] diff --git a/tests/test_markdown.py b/tests/test_markdown.py index ddfb434..6be6197 100644 --- a/tests/test_markdown.py +++ b/tests/test_markdown.py @@ -1,8 +1,12 @@ +# -*- coding: utf-8 -*- + from unittest import TestCase from mikoto.libs.text import render +#from mikoto.markdown import render_markdown as render class TestMarkdown(TestCase): + def test_tasklist(self): md = ''' - [x] this is a complete item diff --git a/tests/test_utils.py b/tests/test_utils.py index 5a07d7f..b0d084f 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,4 +1,4 @@ -# encoding: utf-8 +# -*- coding: utf-8 -*- from __future__ import absolute_import from unittest import TestCase