Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 21 additions & 15 deletions mikoto/__init__.py
Original file line number Diff line number Diff line change
@@ -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):
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)
11 changes: 6 additions & 5 deletions mikoto/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
80 changes: 39 additions & 41 deletions mikoto/libs/emoji.py → mikoto/emoji.py
Original file line number Diff line number Diff line change
@@ -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:',
Expand All @@ -21,88 +19,88 @@
]


# 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:
:star2: :dizzy: :rocket:
: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', "<br/>")
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'^<p>\s*(' + '|'.join([re.escape(x) for x in self.emojis]) + r')\s*</p>$')
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(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 = '<img src="/static/emoji/%s.png" align="absmiddle"/>'
else:
emoji_img = '<img src="/static/emoji/%s.png" height="20" width="20" align="absmiddle"/>'
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(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(' ', '&nbsp;')
group_text = group_text.replace('\n', "<br/>")
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)
if files:
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'^<p>\s*(' + '|'.join([re.escape(x) for x in all_emojis()]) + r')\s*</p>$')
RE_EMOJI_GROUPS = re.compile('|'.join([re.escape(x) for x in EMOJI_GROUPS.keys()]))
20 changes: 14 additions & 6 deletions mikoto/htmlrenderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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_]+)')
Expand All @@ -15,11 +15,17 @@

class HtmlRenderer(misaka.HtmlRenderer):

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 = parse_emoji(text, is_escape=False)
if self.emoji:
text = render_emoji(self.emoji, text)
return RE_USER_MENTION.sub(USER_LINK_TEXT, text)

def block_code(self, text, lang):
Expand All @@ -44,18 +50,20 @@ def __text_to_unichr(self, text):
text = text.replace("@", "&#64;")
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 '<img src="%s" alt="%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 '<a href="%s" title="%s">%s</a>' % (link, title, content)
7 changes: 3 additions & 4 deletions mikoto/libs/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)?$')
Expand Down Expand Up @@ -61,11 +60,11 @@ def render_markdown_with_team(content, team):
text = render_markdown(content)
text = re.sub(RE_TICKET, r'<a href="' + team.url +
r'issues/\1/" class="issue-link">#\1</a>', 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' <a href="/%s/newpull/\1">#\1</a> ' % project.name,
text)
Expand Down
19 changes: 15 additions & 4 deletions mikoto/markdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,18 @@
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 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
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
Expand All @@ -7,6 +6,7 @@


class PyTest(TestCommand):

def finalize_options(self):
TestCommand.finalize_options(self)
self.test_args = ['tests']
Expand Down
4 changes: 4 additions & 0 deletions tests/test_markdown.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down
2 changes: 1 addition & 1 deletion tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# encoding: utf-8
# -*- coding: utf-8 -*-

from __future__ import absolute_import
from unittest import TestCase
Expand Down