Add remaining render callbacks.
This commit is contained in:
parent
6117424b29
commit
3304d94255
12
THANKS
12
THANKS
|
@ -1,8 +1,8 @@
|
|||
People who contributed code and fixed bugs:
|
||||
|
||||
- tanoku
|
||||
- heintz
|
||||
- honza
|
||||
- francescomari
|
||||
- andrew-d
|
||||
- tkf
|
||||
- vmg
|
||||
- heintz
|
||||
- honza
|
||||
- francescomari
|
||||
- andrew-d
|
||||
- tkf
|
||||
|
|
205
misaka/api.py
205
misaka/api.py
|
@ -11,9 +11,14 @@ __all__ = [
|
|||
]
|
||||
|
||||
|
||||
IUNIT = 1024
|
||||
OUNIT = 64
|
||||
MAX_NESTING = 16
|
||||
|
||||
|
||||
def html(text, extensions=0, render_flags=0):
|
||||
ib = lib.hoedown_buffer_new(1024)
|
||||
ob = lib.hoedown_buffer_new(64)
|
||||
ib = lib.hoedown_buffer_new(IUNIT)
|
||||
ob = lib.hoedown_buffer_new(OUNIT)
|
||||
renderer = lib.hoedown_html_renderer_new(0, 0)
|
||||
document = lib.hoedown_document_new(renderer, 0, 16);
|
||||
|
||||
|
@ -30,16 +35,17 @@ def html(text, extensions=0, render_flags=0):
|
|||
|
||||
|
||||
class Markdown:
|
||||
def __init__(self, renderer):
|
||||
def __init__(self, renderer, extensions=0):
|
||||
# NOTE: Prevent the renderer from being garbage collected
|
||||
self.renderer = renderer
|
||||
self.extensions = extensions
|
||||
|
||||
def render(self, text):
|
||||
ib = lib.hoedown_buffer_new(1024)
|
||||
ib = lib.hoedown_buffer_new(IUNIT)
|
||||
lib.hoedown_buffer_puts(ib, text.encode('utf-8'))
|
||||
|
||||
ob = lib.hoedown_buffer_new(64)
|
||||
document = lib.hoedown_document_new(self.renderer.renderer, 0, 16);
|
||||
ob = lib.hoedown_buffer_new(OUNIT)
|
||||
document = lib.hoedown_document_new(self.renderer.renderer, self.extensions, MAX_NESTING);
|
||||
lib.hoedown_document_render(document, ob, ib.data, ib.size);
|
||||
|
||||
lib.hoedown_buffer_free(ib);
|
||||
|
@ -51,7 +57,7 @@ class Markdown:
|
|||
lib.hoedown_buffer_free(ob);
|
||||
|
||||
|
||||
callback_signatures = {
|
||||
_callback_signatures = {
|
||||
# block level callbacks - NULL skips the block
|
||||
'blockcode': 'void (*blockcode)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_buffer *lang, const hoedown_renderer_data *data)',
|
||||
'blockquote': 'void (*blockquote)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)',
|
||||
|
@ -97,33 +103,19 @@ callback_signatures = {
|
|||
}
|
||||
|
||||
|
||||
# TODO: Do this in Python:
|
||||
# static hoedown_renderer *
|
||||
# null_renderer_new()
|
||||
# {
|
||||
# hoedown_renderer *renderer;
|
||||
# renderer = hoedown_malloc(sizeof(hoedown_renderer));
|
||||
# memset(renderer, 0x0, sizeof(hoedown_renderer));
|
||||
|
||||
# return renderer;
|
||||
# }
|
||||
|
||||
# static void
|
||||
# null_renderer_free(hoedown_renderer *renderer)
|
||||
# {
|
||||
# free(renderer);
|
||||
# }
|
||||
class BaseRenderer:
|
||||
def __init__(self):
|
||||
# TODO: Make a null renderer.
|
||||
self.renderer = None
|
||||
self.renderer = lib.null_renderer_new()
|
||||
self.set_callbacks()
|
||||
|
||||
def __del__(self):
|
||||
lib.null_renderer_free(self.renderer)
|
||||
|
||||
def set_callbacks(self):
|
||||
callbacks = []
|
||||
|
||||
for name, func in getmembers(self, predicate=ismethod):
|
||||
signature = callback_signatures.get(name)
|
||||
signature = _callback_signatures.get(name)
|
||||
if signature is None:
|
||||
continue
|
||||
|
||||
|
@ -232,6 +224,31 @@ class BaseRenderer:
|
|||
if result:
|
||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||
|
||||
def _w_autolink(self, ob, link, type, data):
|
||||
link = ffi.string(link.data, link.size).decode('utf-8')
|
||||
type = int(type)
|
||||
result = self.autolink(link, type)
|
||||
if result:
|
||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def _w_codespan(self, ob, text, data):
|
||||
text = ffi.string(text.data, text.size).decode('utf-8')
|
||||
result = self.codespan(text)
|
||||
if result:
|
||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def _w_double_emphasis(self, ob, content, data):
|
||||
content = ffi.string(content.data, content.size).decode('utf-8')
|
||||
result = self.double_emphasis(content)
|
||||
if result:
|
||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def _w_emphasis(self, ob, content, data):
|
||||
content = ffi.string(content.data, content.size).decode('utf-8')
|
||||
result = self.emphasis(content)
|
||||
|
@ -240,10 +257,142 @@ class BaseRenderer:
|
|||
return 1
|
||||
return 0
|
||||
|
||||
def _w_underline(self, ob, content, data):
|
||||
content = ffi.string(content.data, content.size).decode('utf-8')
|
||||
result = self.underline(content)
|
||||
if result:
|
||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def _w_highlight(self, ob, content, data):
|
||||
content = ffi.string(content.data, content.size).decode('utf-8')
|
||||
result = self.highlight(content)
|
||||
if result:
|
||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def _w_quote(self, ob, content, data):
|
||||
content = ffi.string(content.data, content.size).decode('utf-8')
|
||||
result = self.quote(content)
|
||||
if result:
|
||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def _w_image(self, ob, link, title, alt, data):
|
||||
link = ffi.string(link.data, link.size).decode('utf-8')
|
||||
title = ffi.string(title.data, title.size).decode('utf-8')
|
||||
alt = ffi.string(alt.data, alt.size).decode('utf-8')
|
||||
result = self.image(link, title, alt)
|
||||
if result:
|
||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def _w_quote(self, ob, content, data):
|
||||
content = ffi.string(content.data, content.size).decode('utf-8')
|
||||
result = self.quote(content)
|
||||
if result:
|
||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def _w_linebreak(self, ob, data):
|
||||
result = self.linebreak()
|
||||
if result:
|
||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def _w_link(self, ob, content, link, title, data):
|
||||
content = ffi.string(content.data, content.size).decode('utf-8')
|
||||
link = ffi.string(link.data, link.size).decode('utf-8')
|
||||
title = ffi.string(title.data, title.size).decode('utf-8')
|
||||
result = self.link(content, link, title)
|
||||
if result:
|
||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def _w_triple_emphasis(self, ob, content, data):
|
||||
content = ffi.string(content.data, content.size).decode('utf-8')
|
||||
result = self.triple_emphasis(content)
|
||||
if result:
|
||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def _w_strikethrough(self, ob, content, data):
|
||||
content = ffi.string(content.data, content.size).decode('utf-8')
|
||||
result = self.strikethrough(content)
|
||||
if result:
|
||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def _w_superscript(self, ob, content, data):
|
||||
content = ffi.string(content.data, content.size).decode('utf-8')
|
||||
result = self.superscript(content)
|
||||
if result:
|
||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def _w_footnote_ref(self, ob, num, data):
|
||||
num = int(num)
|
||||
result = self.footnote_ref(num)
|
||||
if result:
|
||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def _w_math(self, ob, text, displaymode, data):
|
||||
text = ffi.string(text.data, text.size).decode('utf-8')
|
||||
displaymode = int(displaymode)
|
||||
result = self.math(text, displaymode)
|
||||
if result:
|
||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def _w_raw_html(self, ob, text, data):
|
||||
text = ffi.string(text.data, text.size).decode('utf-8')
|
||||
result = self.raw_html(text)
|
||||
if result:
|
||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def _w_entity(self, ob, text, data):
|
||||
text = ffi.string(text.data, text.size).decode('utf-8')
|
||||
result = self.entity(text)
|
||||
if result:
|
||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||
|
||||
def _w_normal_text(self, ob, text, data):
|
||||
text = ffi.string(text.data, text.size).decode('utf-8')
|
||||
result = self.normal_text(text)
|
||||
if result:
|
||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||
|
||||
def _w_doc_header(self, ob, inline_render, data):
|
||||
inline_render = int(inline_render)
|
||||
result = self.doc_header(inline_render)
|
||||
if result:
|
||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||
|
||||
def _w_doc_footer(self, ob, inline_render, data):
|
||||
inline_render = int(inline_render)
|
||||
result = self.doc_footer(inline_render)
|
||||
if result:
|
||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||
|
||||
|
||||
class HtmlRenderer(BaseRenderer):
|
||||
def __init__(self):
|
||||
self.renderer = lib.hoedown_html_renderer_new(0, 0)
|
||||
def __init__(self, flags=0):
|
||||
self.renderer = lib.hoedown_html_renderer_new(flags, 0)
|
||||
self.set_callbacks()
|
||||
|
||||
def __del__(self):
|
||||
|
|
|
@ -10,14 +10,13 @@ from subprocess import Popen, PIPE, STDOUT
|
|||
|
||||
import misaka
|
||||
|
||||
from misaka import Markdown, BaseRenderer, HtmlRenderer, SmartyPants, \
|
||||
from misaka import Markdown, BaseRenderer, HtmlRenderer, \
|
||||
EXT_NO_INTRA_EMPHASIS, EXT_TABLES, EXT_FENCED_CODE, EXT_AUTOLINK, \
|
||||
EXT_STRIKETHROUGH, EXT_LAX_SPACING, EXT_SPACE_HEADERS, \
|
||||
EXT_STRIKETHROUGH, EXT_SPACE_HEADERS, \
|
||||
EXT_SUPERSCRIPT, \
|
||||
HTML_SKIP_HTML, HTML_SKIP_STYLE, HTML_SKIP_IMAGES, HTML_SKIP_LINKS, \
|
||||
HTML_EXPAND_TABS, HTML_SAFELINK, HTML_TOC, HTML_HARD_WRAP, \
|
||||
HTML_USE_XHTML, HTML_ESCAPE, \
|
||||
HTML_SMARTYPANTS
|
||||
HTML_SKIP_HTML, \
|
||||
HTML_HARD_WRAP, \
|
||||
HTML_USE_XHTML, HTML_ESCAPE
|
||||
|
||||
from minitest import TestCase, ok, runner
|
||||
|
||||
|
@ -31,48 +30,48 @@ def clean_html(dirty_html):
|
|||
return stdout.decode('utf-8')
|
||||
|
||||
|
||||
class SmartyPantsTest(TestCase):
|
||||
name = 'SmartyPants'
|
||||
# class SmartyPantsTest(TestCase):
|
||||
# name = 'SmartyPants'
|
||||
|
||||
def setup(self):
|
||||
self.r = lambda html: misaka.html(html, render_flags=HTML_SMARTYPANTS)
|
||||
# def setup(self):
|
||||
# self.r = lambda html: misaka.html(html, render_flags=HTML_SMARTYPANTS)
|
||||
|
||||
def test_single_quotes_re(self):
|
||||
html = self.r('<p>They\'re not for sale.</p>\n')
|
||||
ok(html).diff('<p>They’re not for sale.</p>\n')
|
||||
# def test_single_quotes_re(self):
|
||||
# html = self.r('<p>They\'re not for sale.</p>\n')
|
||||
# ok(html).diff('<p>They’re not for sale.</p>\n')
|
||||
|
||||
def test_single_quotes_ll(self):
|
||||
html = self.r('<p>Well that\'ll be the day</p>\n')
|
||||
ok(html).diff('<p>Well that’ll be the day</p>\n')
|
||||
# def test_single_quotes_ll(self):
|
||||
# html = self.r('<p>Well that\'ll be the day</p>\n')
|
||||
# ok(html).diff('<p>Well that’ll be the day</p>\n')
|
||||
|
||||
def test_double_quotes_to_curly_quotes(self):
|
||||
html = self.r('<p>"Quoted text"</p>\n')
|
||||
ok(html).diff('<p>“Quoted text”</p>\n')
|
||||
# def test_double_quotes_to_curly_quotes(self):
|
||||
# html = self.r('<p>"Quoted text"</p>\n')
|
||||
# ok(html).diff('<p>“Quoted text”</p>\n')
|
||||
|
||||
def test_single_quotes_ve(self):
|
||||
html = self.r('<p>I\'ve been meaning to tell you ..</p>\n')
|
||||
ok(html).diff('<p>I’ve been meaning to tell you ..</p>\n')
|
||||
# def test_single_quotes_ve(self):
|
||||
# html = self.r('<p>I\'ve been meaning to tell you ..</p>\n')
|
||||
# ok(html).diff('<p>I’ve been meaning to tell you ..</p>\n')
|
||||
|
||||
def test_single_quotes_m(self):
|
||||
html = self.r('<p>I\'m not kidding</p>\n')
|
||||
ok(html).diff('<p>I’m not kidding</p>\n')
|
||||
# def test_single_quotes_m(self):
|
||||
# html = self.r('<p>I\'m not kidding</p>\n')
|
||||
# ok(html).diff('<p>I’m not kidding</p>\n')
|
||||
|
||||
def test_single_quotes_d(self):
|
||||
html = self.r('<p>what\'d you say?</p>\n')
|
||||
ok(html).diff('<p>what’d you say?</p>\n')
|
||||
# def test_single_quotes_d(self):
|
||||
# html = self.r('<p>what\'d you say?</p>\n')
|
||||
# ok(html).diff('<p>what’d you say?</p>\n')
|
||||
|
||||
|
||||
class HtmlRenderTest(TestCase):
|
||||
name = 'Html Renderer'
|
||||
|
||||
def setup(self):
|
||||
pants = SmartyPants()
|
||||
# pants = SmartyPants()
|
||||
|
||||
self.r = {
|
||||
HTML_SKIP_HTML: HtmlRenderer(HTML_SKIP_HTML),
|
||||
HTML_SKIP_IMAGES: HtmlRenderer(HTML_SKIP_IMAGES),
|
||||
HTML_SKIP_LINKS: HtmlRenderer(HTML_SKIP_LINKS),
|
||||
HTML_SAFELINK: HtmlRenderer(HTML_SAFELINK),
|
||||
# HTML_SKIP_IMAGES: HtmlRenderer(HTML_SKIP_IMAGES),
|
||||
# HTML_SKIP_LINKS: HtmlRenderer(HTML_SKIP_LINKS),
|
||||
# HTML_SAFELINK: HtmlRenderer(HTML_SAFELINK),
|
||||
HTML_ESCAPE: HtmlRenderer(HTML_ESCAPE),
|
||||
HTML_HARD_WRAP: HtmlRenderer(HTML_HARD_WRAP)
|
||||
}
|
||||
|
@ -109,17 +108,17 @@ Through <em>NO</em> <script>DOUBLE NO</script>
|
|||
markdown = self.render_with(HTML_SKIP_HTML, 'Lorem, \nipsum\n')
|
||||
ok(markdown).diff('<p>Lorem,<br>\nipsum</p>\n')
|
||||
|
||||
def test_skip_image(self):
|
||||
markdown = self.render_with(HTML_SKIP_IMAGES, '![dust mite](http://dust.mite/image.png) <img src="image.png" />')
|
||||
ok(markdown).not_contains('<img')
|
||||
# def test_skip_image(self):
|
||||
# markdown = self.render_with(HTML_SKIP_IMAGES, '![dust mite](http://dust.mite/image.png) <img src="image.png" />')
|
||||
# ok(markdown).not_contains('<img')
|
||||
|
||||
def test_skip_links(self):
|
||||
markdown = self.render_with(HTML_SKIP_LINKS, '[This link](http://example.net/) <a href="links.html">links</a>')
|
||||
ok(markdown).not_contains('<a ')
|
||||
# def test_skip_links(self):
|
||||
# markdown = self.render_with(HTML_SKIP_LINKS, '[This link](http://example.net/) <a href="links.html">links</a>')
|
||||
# ok(markdown).not_contains('<a ')
|
||||
|
||||
def test_safelink(self):
|
||||
markdown = self.render_with(HTML_SAFELINK, '[IRC](irc://chat.freenode.org/#freenode)')
|
||||
ok(markdown).diff('<p>[IRC](irc://chat.freenode.org/#freenode)</p>\n')
|
||||
# def test_safelink(self):
|
||||
# markdown = self.render_with(HTML_SAFELINK, '[IRC](irc://chat.freenode.org/#freenode)')
|
||||
# ok(markdown).diff('<p>[IRC](irc://chat.freenode.org/#freenode)</p>\n')
|
||||
|
||||
def test_hard_wrap(self):
|
||||
markdown = self.render_with(HTML_HARD_WRAP, '''
|
||||
|
@ -177,14 +176,14 @@ class MarkdownParserTest(TestCase):
|
|||
'<p>A wise man once said:</p>\n\n' \
|
||||
'<blockquote>\n<p>Isn't it wonderful just to be alive.</p>\n</blockquote>\n')
|
||||
|
||||
def test_html_block_not_wrapped_in_p(self):
|
||||
markdown = self.render_with(
|
||||
'Things to watch out for\n\n' \
|
||||
'<ul>\n<li>Blah</li>\n</ul>\n',
|
||||
extensions=EXT_LAX_SPACING)
|
||||
ok(markdown).diff(
|
||||
'<p>Things to watch out for</p>\n\n' \
|
||||
'<ul>\n<li>Blah</li>\n</ul>\n')
|
||||
# def test_html_block_not_wrapped_in_p(self):
|
||||
# markdown = self.render_with(
|
||||
# 'Things to watch out for\n\n' \
|
||||
# '<ul>\n<li>Blah</li>\n</ul>\n',
|
||||
# extensions=EXT_LAX_SPACING)
|
||||
# ok(markdown).diff(
|
||||
# '<p>Things to watch out for</p>\n\n' \
|
||||
# '<ul>\n<li>Blah</li>\n</ul>\n')
|
||||
|
||||
# http://github.com/rtomayko/rdiscount/issues/#issue/13
|
||||
def test_headings_with_trailing_space(self):
|
||||
|
@ -252,11 +251,11 @@ This is some awesome code
|
|||
ok(self.render_with(text)).not_contains('<code')
|
||||
ok(self.render_with(text, extensions=EXT_FENCED_CODE)).contains('<code')
|
||||
|
||||
def test_fenced_code_blocks_without_space(self):
|
||||
text = 'foo\nbar\n```\nsome\ncode\n```\nbaz'
|
||||
# def test_fenced_code_blocks_without_space(self):
|
||||
# text = 'foo\nbar\n```\nsome\ncode\n```\nbaz'
|
||||
|
||||
ok(self.render_with(text)).not_contains('<pre><code>')
|
||||
ok(self.render_with(text, extensions=EXT_FENCED_CODE | EXT_LAX_SPACING)).contains('<pre><code>')
|
||||
# ok(self.render_with(text)).not_contains('<pre><code>')
|
||||
# ok(self.render_with(text, extensions=EXT_FENCED_CODE | EXT_LAX_SPACING)).contains('<pre><code>')
|
||||
|
||||
def test_linkable_headers(self):
|
||||
markdown = self.r('### Hello [GitHub](http://github.com)')
|
||||
|
@ -333,7 +332,7 @@ class UnicodeTest(TestCase):
|
|||
|
||||
def run_tests():
|
||||
runner([
|
||||
SmartyPantsTest,
|
||||
# SmartyPantsTest,
|
||||
HtmlRenderTest,
|
||||
MarkdownParserTest,
|
||||
MarkdownConformanceTest_10,
|
||||
|
|
Loading…
Reference in New Issue