Move callbacks, utils and constants into their own modules.
This commit is contained in:
parent
cbd9834466
commit
aac40ee755
|
@ -36,24 +36,42 @@ class benchmark(object):
|
||||||
print('{0} is not available'.format(name))
|
print('{0} is not available'.format(name))
|
||||||
|
|
||||||
|
|
||||||
@benchmark('mistune')
|
# @benchmark('mistune')
|
||||||
def benchmark_mistune(text):
|
# def benchmark_mistune(text):
|
||||||
import mistune
|
# import mistune
|
||||||
mistune.markdown(text)
|
# mistune.markdown(text)
|
||||||
|
|
||||||
|
|
||||||
@benchmark('misaka')
|
@benchmark('misaka')
|
||||||
def benchmark_misaka(text):
|
def benchmark_misaka(text):
|
||||||
import misaka as m
|
import misaka as m
|
||||||
# mistune has all these features
|
# mistune has all these features
|
||||||
extensions = (
|
# extensions = (
|
||||||
m.EXT_NO_INTRA_EMPHASIS | m.EXT_FENCED_CODE | m.EXT_AUTOLINK |
|
# m.EXT_NO_INTRA_EMPHASIS | m.EXT_FENCED_CODE | m.EXT_AUTOLINK |
|
||||||
m.EXT_TABLES | m.EXT_STRIKETHROUGH
|
# m.EXT_TABLES | m.EXT_STRIKETHROUGH
|
||||||
)
|
# )
|
||||||
# md = m.Markdown(m.HtmlRenderer(), extensions=extensions)
|
# md = m.Markdown(m.HtmlRenderer(), extensions=extensions)
|
||||||
# md.render(text)
|
# md.render(text)
|
||||||
|
|
||||||
m.html(text, extensions)
|
m.html(text, ('no-intra-emphasis', 'fenced=code', 'autolink', 'tables', 'strikethrough'))
|
||||||
|
|
||||||
|
|
||||||
|
@benchmark('misaka_classes')
|
||||||
|
def benchmark_misaka_classes(text):
|
||||||
|
import misaka as m
|
||||||
|
# mistune has all these features
|
||||||
|
# extensions = (
|
||||||
|
# m.EXT_NO_INTRA_EMPHASIS | m.EXT_FENCED_CODE | m.EXT_AUTOLINK |
|
||||||
|
# m.EXT_TABLES | m.EXT_STRIKETHROUGH
|
||||||
|
# )
|
||||||
|
# # md = m.Markdown(m.HtmlRenderer(), extensions=extensions)
|
||||||
|
# # md.render(text)
|
||||||
|
|
||||||
|
# m.html(text, extensions)
|
||||||
|
|
||||||
|
r = m.HtmlRenderer()
|
||||||
|
p = m.Markdown(r, ('no-intra-emphasis', 'fenced=code', 'autolink', 'tables', 'strikethrough'))
|
||||||
|
p(text)
|
||||||
|
|
||||||
|
|
||||||
# @benchmark('markdown2')
|
# @benchmark('markdown2')
|
||||||
|
@ -90,7 +108,7 @@ def benchmark_hoep(text):
|
||||||
m.EXT_TABLES | m.EXT_STRIKETHROUGH | m.EXT_FOOTNOTES
|
m.EXT_TABLES | m.EXT_STRIKETHROUGH | m.EXT_FOOTNOTES
|
||||||
)
|
)
|
||||||
md = m.Hoep(extensions=extensions)
|
md = m.Hoep(extensions=extensions)
|
||||||
md.render(text.decode('utf-8'))
|
md.render(text)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -56,6 +56,7 @@ ffi.set_source(
|
||||||
#include "hoedown/buffer.h"
|
#include "hoedown/buffer.h"
|
||||||
#include "hoedown/document.h"
|
#include "hoedown/document.h"
|
||||||
#include "hoedown/html.h"
|
#include "hoedown/html.h"
|
||||||
|
#include "extra.h"
|
||||||
""",
|
""",
|
||||||
sources=(
|
sources=(
|
||||||
'misaka/hoedown/version.c',
|
'misaka/hoedown/version.c',
|
||||||
|
@ -67,6 +68,7 @@ ffi.set_source(
|
||||||
'misaka/hoedown/document.c',
|
'misaka/hoedown/document.c',
|
||||||
'misaka/hoedown/buffer.c',
|
'misaka/hoedown/buffer.c',
|
||||||
'misaka/hoedown/autolink.c',
|
'misaka/hoedown/autolink.c',
|
||||||
|
'misaka/extra.c',
|
||||||
),
|
),
|
||||||
include_dirs=('misaka',))
|
include_dirs=('misaka',))
|
||||||
|
|
||||||
|
@ -274,6 +276,12 @@ hoedown_renderer *hoedown_html_toc_renderer_new(
|
||||||
);
|
);
|
||||||
void hoedown_html_renderer_free(hoedown_renderer *renderer);
|
void hoedown_html_renderer_free(hoedown_renderer *renderer);
|
||||||
void hoedown_html_smartypants(hoedown_buffer *ob, const uint8_t *data, size_t size);
|
void hoedown_html_smartypants(hoedown_buffer *ob, const uint8_t *data, size_t size);
|
||||||
|
|
||||||
|
// ---------------
|
||||||
|
// --- extra.h ---
|
||||||
|
// ---------------
|
||||||
|
|
||||||
|
void *misaka_get_renderer(const hoedown_renderer_data *data);
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
|
450
misaka/api.py
450
misaka/api.py
|
@ -1,16 +1,10 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import sys
|
|
||||||
import operator as op
|
|
||||||
import warnings
|
|
||||||
from inspect import getmembers, ismethod
|
|
||||||
|
|
||||||
from ._hoedown import lib, ffi
|
from ._hoedown import lib, ffi
|
||||||
|
from .callbacks import python_callbacks, to_string
|
||||||
try:
|
from .constants import *
|
||||||
reduce
|
from .utils import extension_map, html_flag_map, args_to_int, \
|
||||||
except NameError:
|
deprecation, to_string
|
||||||
from functools import reduce
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
@ -21,7 +15,7 @@ __all__ = [
|
||||||
'HtmlRenderer',
|
'HtmlRenderer',
|
||||||
'HtmlTocRenderer',
|
'HtmlTocRenderer',
|
||||||
|
|
||||||
'_args_to_int',
|
'args_to_int',
|
||||||
'extension_map',
|
'extension_map',
|
||||||
'html_flag_map',
|
'html_flag_map',
|
||||||
|
|
||||||
|
@ -59,81 +53,17 @@ __all__ = [
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def _set_constants():
|
|
||||||
is_int = lambda n: isinstance(n, int)
|
|
||||||
|
|
||||||
for name, value in getmembers(lib, is_int):
|
|
||||||
if not name.startswith('HOEDOWN_'):
|
|
||||||
continue
|
|
||||||
setattr(sys.modules[__name__], name[8:], value)
|
|
||||||
|
|
||||||
|
|
||||||
if not hasattr(sys.modules[__name__], 'EXT_TABLES'):
|
|
||||||
_set_constants()
|
|
||||||
|
|
||||||
|
|
||||||
extension_map = {
|
|
||||||
'tables': EXT_TABLES,
|
|
||||||
'fenced-code': EXT_FENCED_CODE,
|
|
||||||
'footnotes': EXT_FOOTNOTES,
|
|
||||||
'autolink': EXT_AUTOLINK,
|
|
||||||
'strikethrough': EXT_STRIKETHROUGH,
|
|
||||||
'underline': EXT_UNDERLINE,
|
|
||||||
'highlight': EXT_HIGHLIGHT,
|
|
||||||
'quote': EXT_QUOTE,
|
|
||||||
'superscript': EXT_SUPERSCRIPT,
|
|
||||||
'math': EXT_MATH,
|
|
||||||
'no-intra-emphasis': EXT_NO_INTRA_EMPHASIS,
|
|
||||||
'space-headers': EXT_SPACE_HEADERS,
|
|
||||||
'math-explicit': EXT_MATH_EXPLICIT,
|
|
||||||
'disable-indented-code': EXT_DISABLE_INDENTED_CODE,
|
|
||||||
}
|
|
||||||
|
|
||||||
html_flag_map = {
|
|
||||||
'skip-html': HTML_SKIP_HTML,
|
|
||||||
'escape': HTML_ESCAPE,
|
|
||||||
'hard-wrap': HTML_HARD_WRAP,
|
|
||||||
'use-xhtml': HTML_USE_XHTML,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
IUNIT = 1024
|
IUNIT = 1024
|
||||||
OUNIT = 64
|
OUNIT = 64
|
||||||
MAX_NESTING = 16
|
MAX_NESTING = 16
|
||||||
|
|
||||||
|
|
||||||
def deprecation(message):
|
|
||||||
warnings.warn(message, DeprecationWarning, stacklevel=3)
|
|
||||||
|
|
||||||
|
|
||||||
def to_string(buffer):
|
|
||||||
if buffer == ffi.NULL or buffer.size == 0:
|
|
||||||
return ''
|
|
||||||
return ffi.string(buffer.data, buffer.size).decode('utf-8')
|
|
||||||
|
|
||||||
|
|
||||||
def _args_to_int(mapping, argument):
|
|
||||||
"""
|
|
||||||
Convert list of strings to an int using a mapping.
|
|
||||||
"""
|
|
||||||
if isinstance(argument, int):
|
|
||||||
if argument == 0:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
deprecation('passing extensions and flags as constants is deprecated')
|
|
||||||
return argument
|
|
||||||
elif isinstance(argument, (tuple, list)):
|
|
||||||
return reduce(op.or_, [mapping[n] for n in argument if n in mapping], 0)
|
|
||||||
|
|
||||||
raise TypeError('argument must be a list of strings or an int')
|
|
||||||
|
|
||||||
|
|
||||||
def html(text, extensions=0, render_flags=0):
|
def html(text, extensions=0, render_flags=0):
|
||||||
"""
|
"""
|
||||||
Convert markdown text to HTML.
|
Convert markdown text to HTML.
|
||||||
"""
|
"""
|
||||||
extensions = _args_to_int(extension_map, extensions)
|
extensions = args_to_int(extension_map, extensions)
|
||||||
render_flags = _args_to_int(html_flag_map, render_flags)
|
render_flags = args_to_int(html_flag_map, render_flags)
|
||||||
|
|
||||||
ib = lib.hoedown_buffer_new(IUNIT)
|
ib = lib.hoedown_buffer_new(IUNIT)
|
||||||
ob = lib.hoedown_buffer_new(OUNIT)
|
ob = lib.hoedown_buffer_new(OUNIT)
|
||||||
|
@ -183,13 +113,13 @@ def smartypants(text):
|
||||||
lib.hoedown_buffer_free(ob);
|
lib.hoedown_buffer_free(ob);
|
||||||
|
|
||||||
|
|
||||||
class Markdown:
|
class Markdown(object):
|
||||||
"""
|
"""
|
||||||
Parses markdown text and renders it using the given renderer.
|
Parses markdown text and renders it using the given renderer.
|
||||||
"""
|
"""
|
||||||
def __init__(self, renderer, extensions=0):
|
def __init__(self, renderer, extensions=0):
|
||||||
self.renderer = renderer
|
self.renderer = renderer
|
||||||
self.extensions = _args_to_int(extension_map, extensions)
|
self.extensions = args_to_int(extension_map, extensions)
|
||||||
|
|
||||||
def __call__(self, text):
|
def __call__(self, text):
|
||||||
"""
|
"""
|
||||||
|
@ -214,340 +144,21 @@ class Markdown:
|
||||||
lib.hoedown_buffer_free(ob);
|
lib.hoedown_buffer_free(ob);
|
||||||
|
|
||||||
|
|
||||||
_callback_signatures = {
|
class BaseRenderer(object):
|
||||||
# block level callbacks - NULL skips the block
|
|
||||||
'blockcode': 'void(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_buffer *lang, const hoedown_renderer_data *data)',
|
|
||||||
'blockquote': 'void(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)',
|
|
||||||
'header': 'void(hoedown_buffer *ob, const hoedown_buffer *content, int level, const hoedown_renderer_data *data)',
|
|
||||||
'hrule': 'void(hoedown_buffer *ob, const hoedown_renderer_data *data)',
|
|
||||||
'list': 'void(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_list_flags flags, const hoedown_renderer_data *data)',
|
|
||||||
'listitem': 'void(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_list_flags flags, const hoedown_renderer_data *data)',
|
|
||||||
'paragraph': 'void(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)',
|
|
||||||
'table': 'void(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)',
|
|
||||||
'table_header': 'void(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)',
|
|
||||||
'table_body': 'void(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)',
|
|
||||||
'table_row': 'void(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)',
|
|
||||||
'table_cell': 'void(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_table_flags flags, const hoedown_renderer_data *data)',
|
|
||||||
'footnotes': 'void(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)',
|
|
||||||
'footnote_def': 'void(hoedown_buffer *ob, const hoedown_buffer *content, unsigned int num, const hoedown_renderer_data *data)',
|
|
||||||
'blockhtml': 'void(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data)',
|
|
||||||
|
|
||||||
# span level callbacks - NULL or return 0 prints the span verbatim
|
|
||||||
'autolink': 'int(hoedown_buffer *ob, const hoedown_buffer *link, hoedown_autolink_type type, const hoedown_renderer_data *data)',
|
|
||||||
'codespan': 'int(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data)',
|
|
||||||
'double_emphasis': 'int(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)',
|
|
||||||
'emphasis': 'int(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)',
|
|
||||||
'underline': 'int(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)',
|
|
||||||
'highlight': 'int(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)',
|
|
||||||
'quote': 'int(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)',
|
|
||||||
'image': 'int(hoedown_buffer *ob, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_buffer *alt, const hoedown_renderer_data *data)',
|
|
||||||
'linebreak': 'int(hoedown_buffer *ob, const hoedown_renderer_data *data)',
|
|
||||||
'link': 'int(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_renderer_data *data)',
|
|
||||||
'triple_emphasis': 'int(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)',
|
|
||||||
'strikethrough': 'int(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)',
|
|
||||||
'superscript': 'int(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)',
|
|
||||||
'footnote_ref': 'int(hoedown_buffer *ob, unsigned int num, const hoedown_renderer_data *data)',
|
|
||||||
'math': 'int(hoedown_buffer *ob, const hoedown_buffer *text, int displaymode, const hoedown_renderer_data *data)',
|
|
||||||
'raw_html': 'int(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data)',
|
|
||||||
|
|
||||||
# low level callbacks - NULL copies input directly into the output
|
|
||||||
'entity': 'void(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data)',
|
|
||||||
'normal_text': 'void(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data)',
|
|
||||||
|
|
||||||
# miscellaneous callbacks
|
|
||||||
'doc_header': 'void(hoedown_buffer *ob, int inline_render, const hoedown_renderer_data *data)',
|
|
||||||
'doc_footer': 'void(hoedown_buffer *ob, int inline_render, const hoedown_renderer_data *data)',
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class BaseRenderer:
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# Use a noop method as a placeholder for render methods that are
|
self.renderer = ffi.new('hoedown_renderer *')
|
||||||
# implemented so there's no need to check if a render method exists
|
|
||||||
# in a callback.
|
|
||||||
for attr in _callback_signatures.keys():
|
|
||||||
if not hasattr(self, attr):
|
|
||||||
setattr(self, attr, self.noop)
|
|
||||||
|
|
||||||
self._callbacks = {k: ffi.callback(v, getattr(self, '_w_' + k))
|
for name in python_callbacks.keys():
|
||||||
for k, v in _callback_signatures.items()}
|
if hasattr(self, name):
|
||||||
self.renderer = ffi.new('hoedown_renderer *', self._callbacks)
|
setattr(self.renderer, name, python_callbacks[name])
|
||||||
|
else:
|
||||||
|
setattr(self.renderer, name, ffi.NULL)
|
||||||
|
|
||||||
def noop(self, *args, **kwargs):
|
# Store the render class' handle in the render data.
|
||||||
return None
|
self._data = ffi.new('hoedown_renderer_data *')
|
||||||
|
self.renderer.opaque = self._data
|
||||||
def _w_blockcode(self, ob, text, lang, data):
|
ffi.cast('hoedown_renderer_data *', self.renderer.opaque).opaque = \
|
||||||
text = to_string(text)
|
ffi.new_handle(self)
|
||||||
lang = to_string(lang)
|
|
||||||
|
|
||||||
result = self.blockcode(text, lang)
|
|
||||||
if result:
|
|
||||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
|
||||||
|
|
||||||
def _w_blockquote(self, ob, content, data):
|
|
||||||
content = to_string(content)
|
|
||||||
result = self.blockquote(content)
|
|
||||||
if result:
|
|
||||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
|
||||||
|
|
||||||
def _w_header(self, ob, content, level, data):
|
|
||||||
content = to_string(content)
|
|
||||||
level = int(level)
|
|
||||||
result = self.header(content, level)
|
|
||||||
if result:
|
|
||||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
|
||||||
|
|
||||||
def _w_hrule(self, ob, data):
|
|
||||||
result = self.hrule()
|
|
||||||
if result:
|
|
||||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
|
||||||
|
|
||||||
# flags: LIST_ORDERED, LI_BLOCK.
|
|
||||||
def _w_list(self, ob, content, flags, data):
|
|
||||||
content = to_string(content)
|
|
||||||
flags = int(flags)
|
|
||||||
is_ordered = flags & LIST_ORDERED != 0
|
|
||||||
is_block = flags & LI_BLOCK != 0
|
|
||||||
result = self.list(content, is_ordered, is_block)
|
|
||||||
if result:
|
|
||||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
|
||||||
|
|
||||||
# flags: LIST_ORDERED, LI_BLOCK.
|
|
||||||
def _w_listitem(self, ob, content, flags, data):
|
|
||||||
content = to_string(content)
|
|
||||||
flags = int(flags)
|
|
||||||
is_ordered = flags & LIST_ORDERED != 0
|
|
||||||
is_block = flags & LI_BLOCK != 0
|
|
||||||
result = self.listitem(content, is_ordered, is_block)
|
|
||||||
if result:
|
|
||||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
|
||||||
|
|
||||||
def _w_paragraph(self, ob, content, data):
|
|
||||||
content = to_string(content)
|
|
||||||
result = self.paragraph(content)
|
|
||||||
if result:
|
|
||||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
|
||||||
|
|
||||||
def _w_table(self, ob, content, data):
|
|
||||||
content = to_string(content)
|
|
||||||
result = self.table(content)
|
|
||||||
if result:
|
|
||||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
|
||||||
|
|
||||||
def _w_table_header(self, ob, content, data):
|
|
||||||
content = to_string(content)
|
|
||||||
result = self.table_header(content)
|
|
||||||
if result:
|
|
||||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
|
||||||
|
|
||||||
def _w_table_body(self, ob, content, data):
|
|
||||||
content = to_string(content)
|
|
||||||
result = self.table_body(content)
|
|
||||||
if result:
|
|
||||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
|
||||||
|
|
||||||
def _w_table_row(self, ob, content, data):
|
|
||||||
content = to_string(content)
|
|
||||||
result = self.table_row(content)
|
|
||||||
if result:
|
|
||||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
|
||||||
|
|
||||||
# flags: TABLE_ALIGNMASK, TABLE_ALIGN_LEFT, TABLE_ALIGN_RIGHT,
|
|
||||||
# TABLE_ALIGN_CENTER, TABLE_HEADER
|
|
||||||
def _w_table_cell(self, ob, content, flags, data):
|
|
||||||
content = to_string(content)
|
|
||||||
flags = int(flags)
|
|
||||||
is_header = flags & TABLE_HEADER != 0
|
|
||||||
align_bit = flags & TABLE_ALIGNMASK
|
|
||||||
|
|
||||||
if align_bit == TABLE_ALIGN_CENTER:
|
|
||||||
align = 'center'
|
|
||||||
elif align_bit == TABLE_ALIGN_LEFT:
|
|
||||||
align = 'left'
|
|
||||||
elif align_bit == TABLE_ALIGN_RIGHT:
|
|
||||||
align = 'right'
|
|
||||||
else:
|
|
||||||
align = ''
|
|
||||||
|
|
||||||
result = self.table_cell(content, align, is_header)
|
|
||||||
if result:
|
|
||||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
|
||||||
|
|
||||||
def _w_footnotes(self, ob, content, data):
|
|
||||||
content = to_string(content)
|
|
||||||
result = self.footnotes(content)
|
|
||||||
if result:
|
|
||||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
|
||||||
|
|
||||||
def _w_footnote_def(self, ob, content, num, data):
|
|
||||||
content = to_string(content)
|
|
||||||
num = int(num)
|
|
||||||
result = self.footnote_def(content, num)
|
|
||||||
if result:
|
|
||||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
|
||||||
|
|
||||||
def _w_blockhtml(self, ob, text, data):
|
|
||||||
text = ffi.string(text.data, text.size).decode('utf-8')
|
|
||||||
result = self.blockhtml(text)
|
|
||||||
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')
|
|
||||||
is_email = int(type) & AUTOLINK_EMAIL != 0
|
|
||||||
result = self.autolink(link, is_email)
|
|
||||||
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 = to_string(content)
|
|
||||||
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 = to_string(content)
|
|
||||||
result = self.emphasis(content)
|
|
||||||
if result:
|
|
||||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
|
||||||
return 1
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def _w_underline(self, ob, content, data):
|
|
||||||
content = to_string(content)
|
|
||||||
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 = to_string(content)
|
|
||||||
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 = to_string(content)
|
|
||||||
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 = to_string(link)
|
|
||||||
title = to_string(title)
|
|
||||||
alt = to_string(alt)
|
|
||||||
result = self.image(link, title, alt)
|
|
||||||
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 = to_string(content)
|
|
||||||
link = to_string(link)
|
|
||||||
title = to_string(title)
|
|
||||||
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 = to_string(content)
|
|
||||||
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 = to_string(content)
|
|
||||||
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 = to_string(content)
|
|
||||||
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 = to_string(text)
|
|
||||||
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 = to_string(text)
|
|
||||||
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 = to_string(text)
|
|
||||||
result = self.entity(text)
|
|
||||||
if result:
|
|
||||||
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
|
||||||
|
|
||||||
def _w_normal_text(self, ob, text, data):
|
|
||||||
text = to_string(text)
|
|
||||||
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):
|
class HtmlRenderer(BaseRenderer):
|
||||||
|
@ -562,21 +173,16 @@ class HtmlRenderer(BaseRenderer):
|
||||||
by the ``Markdown`` instance.
|
by the ``Markdown`` instance.
|
||||||
"""
|
"""
|
||||||
def __init__(self, flags=0, nesting_level=0):
|
def __init__(self, flags=0, nesting_level=0):
|
||||||
flags = _args_to_int(html_flag_map, flags)
|
flags = args_to_int(html_flag_map, flags)
|
||||||
self.renderer = self._new_renderer(flags, nesting_level)
|
self.renderer = self._new_renderer(flags, nesting_level)
|
||||||
callbacks = []
|
|
||||||
|
|
||||||
for name, signature in _callback_signatures.items():
|
# Store the render class' handle in the render state.
|
||||||
if not hasattr(self, name):
|
state = ffi.cast('hoedown_renderer_data *', self.renderer.opaque)
|
||||||
continue
|
state.opaque = ffi.new_handle(self)
|
||||||
|
|
||||||
wrapper = getattr(self, '_w_' + name)
|
for name in python_callbacks.keys():
|
||||||
callback = ffi.callback(signature, wrapper)
|
if hasattr(self, name):
|
||||||
callbacks.append(callback)
|
setattr(self.renderer, name, python_callbacks[name])
|
||||||
setattr(self.renderer, name, callback)
|
|
||||||
|
|
||||||
# Prevent garbage collection of callbacks.
|
|
||||||
self._callbacks = callbacks
|
|
||||||
|
|
||||||
def _new_renderer(self, flags, nesting_level):
|
def _new_renderer(self, flags, nesting_level):
|
||||||
return lib.hoedown_html_renderer_new(flags, nesting_level)
|
return lib.hoedown_html_renderer_new(flags, nesting_level)
|
||||||
|
|
|
@ -0,0 +1,429 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from ._hoedown import lib, ffi
|
||||||
|
from .constants import *
|
||||||
|
from .utils import to_string
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('void(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_buffer *lang, const hoedown_renderer_data *data)')
|
||||||
|
def cb_blockcode(ob, text, lang, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
text = to_string(text)
|
||||||
|
lang = to_string(lang)
|
||||||
|
|
||||||
|
result = renderer.blockcode(text, lang)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('void(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)')
|
||||||
|
def cb_blockquote(ob, content, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
content = to_string(content)
|
||||||
|
result = renderer.blockquote(content)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('void(hoedown_buffer *ob, const hoedown_buffer *content, int level, const hoedown_renderer_data *data)')
|
||||||
|
def cb_header(ob, content, level, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
content = to_string(content)
|
||||||
|
level = int(level)
|
||||||
|
result = renderer.header(content, level)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('void(hoedown_buffer *ob, const hoedown_renderer_data *data)')
|
||||||
|
def cb_hrule(ob, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
result = renderer.hrule()
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
|
# flags: LIST_ORDERED, LI_BLOCK.
|
||||||
|
@ffi.callback('void(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_list_flags flags, const hoedown_renderer_data *data)')
|
||||||
|
def cb_list(ob, content, flags, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
content = to_string(content)
|
||||||
|
flags = int(flags)
|
||||||
|
is_ordered = flags & LIST_ORDERED != 0
|
||||||
|
is_block = flags & LI_BLOCK != 0
|
||||||
|
result = renderer.list(content, is_ordered, is_block)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
|
# flags: LIST_ORDERED, LI_BLOCK.
|
||||||
|
@ffi.callback('void(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_list_flags flags, const hoedown_renderer_data *data)')
|
||||||
|
def cb_listitem(ob, content, flags, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
content = to_string(content)
|
||||||
|
flags = int(flags)
|
||||||
|
is_ordered = flags & LIST_ORDERED != 0
|
||||||
|
is_block = flags & LI_BLOCK != 0
|
||||||
|
result = renderer.listitem(content, is_ordered, is_block)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('void(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)')
|
||||||
|
def cb_paragraph(ob, content, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
content = to_string(content)
|
||||||
|
result = renderer.paragraph(content)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('void(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)')
|
||||||
|
def cb_table(ob, content, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
content = to_string(content)
|
||||||
|
result = renderer.table(content)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('void(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)')
|
||||||
|
def cb_table_header(ob, content, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
content = to_string(content)
|
||||||
|
result = renderer.table_header(content)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('void(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)')
|
||||||
|
def cb_table_body(ob, content, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
content = to_string(content)
|
||||||
|
result = renderer.table_body(content)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('void(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)')
|
||||||
|
def cb_table_row(ob, content, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
content = to_string(content)
|
||||||
|
result = renderer.table_row(content)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
|
# flags: TABLE_ALIGNMASK, TABLE_ALIGN_LEFT, TABLE_ALIGN_RIGHT,
|
||||||
|
# TABLE_ALIGN_CENTER, TABLE_HEADER
|
||||||
|
@ffi.callback('void(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_table_flags flags, const hoedown_renderer_data *data)')
|
||||||
|
def cb_table_cell(ob, content, flags, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
content = to_string(content)
|
||||||
|
flags = int(flags)
|
||||||
|
is_header = flags & TABLE_HEADER != 0
|
||||||
|
align_bit = flags & TABLE_ALIGNMASK
|
||||||
|
|
||||||
|
if align_bit == TABLE_ALIGN_CENTER:
|
||||||
|
align = 'center'
|
||||||
|
elif align_bit == TABLE_ALIGN_LEFT:
|
||||||
|
align = 'left'
|
||||||
|
elif align_bit == TABLE_ALIGN_RIGHT:
|
||||||
|
align = 'right'
|
||||||
|
else:
|
||||||
|
align = ''
|
||||||
|
|
||||||
|
result = renderer.table_cell(content, align, is_header)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('void(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)')
|
||||||
|
def cb_footnotes(ob, content, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
content = to_string(content)
|
||||||
|
result = renderer.footnotes(content)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('void(hoedown_buffer *ob, const hoedown_buffer *content, unsigned int num, const hoedown_renderer_data *data)')
|
||||||
|
def cb_footnote_def(ob, content, num, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
content = to_string(content)
|
||||||
|
num = int(num)
|
||||||
|
result = renderer.footnote_def(content, num)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('void(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data)')
|
||||||
|
def cb_blockhtml(ob, text, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
text = ffi.string(text.data, text.size).decode('utf-8')
|
||||||
|
result = renderer.blockhtml(text)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('int(hoedown_buffer *ob, const hoedown_buffer *link, hoedown_autolink_type type, const hoedown_renderer_data *data)')
|
||||||
|
def cb_autolink(ob, link, type, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
link = ffi.string(link.data, link.size).decode('utf-8')
|
||||||
|
is_email = int(type) & AUTOLINK_EMAIL != 0
|
||||||
|
result = renderer.autolink(link, is_email)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('int(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data)')
|
||||||
|
def cb_codespan(ob, text, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
text = ffi.string(text.data, text.size).decode('utf-8')
|
||||||
|
result = renderer.codespan(text)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('int(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)')
|
||||||
|
def cb_double_emphasis(ob, content, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
content = to_string(content)
|
||||||
|
result = renderer.double_emphasis(content)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('int(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)')
|
||||||
|
def cb_emphasis(ob, content, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
content = to_string(content)
|
||||||
|
result = renderer.emphasis(content)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('int(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)')
|
||||||
|
def cb_underline(ob, content, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
content = to_string(content)
|
||||||
|
result = renderer.underline(content)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('int(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)')
|
||||||
|
def cb_highlight(ob, content, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
content = to_string(content)
|
||||||
|
result = renderer.highlight(content)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('int(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)')
|
||||||
|
def cb_quote(ob, content, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
content = to_string(content)
|
||||||
|
result = renderer.quote(content)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('int(hoedown_buffer *ob, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_buffer *alt, const hoedown_renderer_data *data)')
|
||||||
|
def cb_image(ob, link, title, alt, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
link = to_string(link)
|
||||||
|
title = to_string(title)
|
||||||
|
alt = to_string(alt)
|
||||||
|
result = renderer.image(link, title, alt)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('int(hoedown_buffer *ob, const hoedown_renderer_data *data)')
|
||||||
|
def cb_linebreak(ob, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
result = renderer.linebreak()
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('int(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_renderer_data *data)')
|
||||||
|
def cb_link(ob, content, link, title, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
content = to_string(content)
|
||||||
|
link = to_string(link)
|
||||||
|
title = to_string(title)
|
||||||
|
result = renderer.link(content, link, title)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('int(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)')
|
||||||
|
def cb_triple_emphasis(ob, content, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
content = to_string(content)
|
||||||
|
result = renderer.triple_emphasis(content)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('int(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)')
|
||||||
|
def cb_strikethrough(ob, content, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
content = to_string(content)
|
||||||
|
result = renderer.strikethrough(content)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('int(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)')
|
||||||
|
def cb_superscript(ob, content, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
content = to_string(content)
|
||||||
|
result = renderer.superscript(content)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('int(hoedown_buffer *ob, unsigned int num, const hoedown_renderer_data *data)')
|
||||||
|
def cb_footnote_ref(ob, num, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
num = int(num)
|
||||||
|
result = renderer.footnote_ref(num)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('int(hoedown_buffer *ob, const hoedown_buffer *text, int displaymode, const hoedown_renderer_data *data)')
|
||||||
|
def cb_math(ob, text, displaymode, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
text = to_string(text)
|
||||||
|
displaymode = int(displaymode)
|
||||||
|
result = renderer.math(text, displaymode)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('int(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data)')
|
||||||
|
def cb_raw_html(ob, text, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
text = to_string(text)
|
||||||
|
result = renderer.raw_html(text)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('void(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data)')
|
||||||
|
def cb_entity(ob, text, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
text = to_string(text)
|
||||||
|
result = renderer.entity(text)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('void(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data)')
|
||||||
|
def cb_normal_text(ob, text, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
text = to_string(text)
|
||||||
|
result = renderer.normal_text(text)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('void(hoedown_buffer *ob, int inline_render, const hoedown_renderer_data *data)')
|
||||||
|
def cb_doc_header(ob, inline_render, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
inline_render = int(inline_render)
|
||||||
|
result = renderer.doc_header(inline_render)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('void(hoedown_buffer *ob, int inline_render, const hoedown_renderer_data *data)')
|
||||||
|
def cb_doc_footer(ob, inline_render, data):
|
||||||
|
renderer = ffi.from_handle(lib.misaka_get_renderer(data))
|
||||||
|
inline_render = int(inline_render)
|
||||||
|
result = renderer.doc_footer(inline_render)
|
||||||
|
if result:
|
||||||
|
lib.hoedown_buffer_puts(ob, result.encode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
|
python_callbacks = {
|
||||||
|
# block level callbacks - NULL skips the block
|
||||||
|
'blockcode': cb_blockcode,
|
||||||
|
'blockquote': cb_blockquote,
|
||||||
|
'header': cb_header,
|
||||||
|
'hrule': cb_hrule,
|
||||||
|
'list': cb_list,
|
||||||
|
'listitem': cb_listitem,
|
||||||
|
'paragraph': cb_paragraph,
|
||||||
|
'table': cb_table,
|
||||||
|
'table_header': cb_table_header,
|
||||||
|
'table_body': cb_table_body,
|
||||||
|
'table_row': cb_table_row,
|
||||||
|
'table_cell': cb_table_cell,
|
||||||
|
'footnotes': cb_footnotes,
|
||||||
|
'footnote_def': cb_footnote_def,
|
||||||
|
'blockhtml': cb_blockhtml,
|
||||||
|
|
||||||
|
# span level callbacks - NULL or return 0 prints the span verbatim
|
||||||
|
'autolink': cb_autolink,
|
||||||
|
'codespan': cb_codespan,
|
||||||
|
'double_emphasis': cb_double_emphasis,
|
||||||
|
'emphasis': cb_emphasis,
|
||||||
|
'underline': cb_underline,
|
||||||
|
'highlight': cb_highlight,
|
||||||
|
'quote': cb_quote,
|
||||||
|
'image': cb_image,
|
||||||
|
'linebreak': cb_linebreak,
|
||||||
|
'link': cb_link,
|
||||||
|
'triple_emphasis': cb_triple_emphasis,
|
||||||
|
'strikethrough': cb_strikethrough,
|
||||||
|
'superscript': cb_superscript,
|
||||||
|
'footnote_ref': cb_footnote_ref,
|
||||||
|
'math': cb_math,
|
||||||
|
'raw_html': cb_raw_html,
|
||||||
|
|
||||||
|
# low level callbacks - NULL copies input directly into the output
|
||||||
|
'entity': cb_entity,
|
||||||
|
'normal_text': cb_normal_text,
|
||||||
|
|
||||||
|
# miscellaneous callbacks
|
||||||
|
'doc_header': cb_doc_header,
|
||||||
|
'doc_footer': cb_doc_footer,
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from inspect import getmembers
|
||||||
|
|
||||||
|
from ._hoedown import lib
|
||||||
|
|
||||||
|
|
||||||
|
def _set_constants():
|
||||||
|
is_int = lambda n: isinstance(n, int)
|
||||||
|
|
||||||
|
for name, value in getmembers(lib, is_int):
|
||||||
|
if not name.startswith('HOEDOWN_'):
|
||||||
|
continue
|
||||||
|
setattr(sys.modules[__name__], name[8:], value)
|
||||||
|
|
||||||
|
|
||||||
|
if not hasattr(sys.modules[__name__], 'EXT_TABLES'):
|
||||||
|
_set_constants()
|
|
@ -0,0 +1,9 @@
|
||||||
|
#include "hoedown/document.h"
|
||||||
|
#include "hoedown/html.h"
|
||||||
|
|
||||||
|
void *misaka_get_renderer(const hoedown_renderer_data *data) {
|
||||||
|
// NOTE: Cast to a "hoedown_renderer_data *", because
|
||||||
|
// the structure is assumed to have an "opaque" field.
|
||||||
|
// Otherwise this doesn't work.
|
||||||
|
return ((hoedown_renderer_data *) data->opaque)->opaque;
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
/* extra.h - extra stuff in C */
|
||||||
|
|
||||||
|
void *misaka_get_renderer(const hoedown_renderer_data *data);
|
|
@ -0,0 +1,61 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import operator as op
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
try:
|
||||||
|
reduce
|
||||||
|
except NameError:
|
||||||
|
from functools import reduce
|
||||||
|
|
||||||
|
from ._hoedown import ffi
|
||||||
|
from .constants import *
|
||||||
|
|
||||||
|
|
||||||
|
extension_map = {
|
||||||
|
'tables': EXT_TABLES,
|
||||||
|
'fenced-code': EXT_FENCED_CODE,
|
||||||
|
'footnotes': EXT_FOOTNOTES,
|
||||||
|
'autolink': EXT_AUTOLINK,
|
||||||
|
'strikethrough': EXT_STRIKETHROUGH,
|
||||||
|
'underline': EXT_UNDERLINE,
|
||||||
|
'highlight': EXT_HIGHLIGHT,
|
||||||
|
'quote': EXT_QUOTE,
|
||||||
|
'superscript': EXT_SUPERSCRIPT,
|
||||||
|
'math': EXT_MATH,
|
||||||
|
'no-intra-emphasis': EXT_NO_INTRA_EMPHASIS,
|
||||||
|
'space-headers': EXT_SPACE_HEADERS,
|
||||||
|
'math-explicit': EXT_MATH_EXPLICIT,
|
||||||
|
'disable-indented-code': EXT_DISABLE_INDENTED_CODE,
|
||||||
|
}
|
||||||
|
|
||||||
|
html_flag_map = {
|
||||||
|
'skip-html': HTML_SKIP_HTML,
|
||||||
|
'escape': HTML_ESCAPE,
|
||||||
|
'hard-wrap': HTML_HARD_WRAP,
|
||||||
|
'use-xhtml': HTML_USE_XHTML,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def args_to_int(mapping, argument):
|
||||||
|
"""
|
||||||
|
Convert list of strings to an int using a mapping.
|
||||||
|
"""
|
||||||
|
if isinstance(argument, int):
|
||||||
|
if argument == 0:
|
||||||
|
return 0
|
||||||
|
deprecation('passing extensions and flags as constants is deprecated')
|
||||||
|
return argument
|
||||||
|
elif isinstance(argument, (tuple, list)):
|
||||||
|
return reduce(op.or_, [mapping[n] for n in argument if n in mapping], 0)
|
||||||
|
raise TypeError('argument must be a list of strings or an int')
|
||||||
|
|
||||||
|
|
||||||
|
def deprecation(message):
|
||||||
|
warnings.warn(message, DeprecationWarning, stacklevel=3)
|
||||||
|
|
||||||
|
|
||||||
|
def to_string(buffer):
|
||||||
|
if buffer == ffi.NULL or buffer.size == 0:
|
||||||
|
return ''
|
||||||
|
return ffi.string(buffer.data, buffer.size).decode('utf-8')
|
|
@ -1,14 +1,15 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from chibitest import TestCase, ok
|
from chibitest import TestCase, ok
|
||||||
from misaka import _args_to_int, extension_map, \
|
from misaka import extension_map, \
|
||||||
EXT_TABLES, EXT_FENCED_CODE, EXT_FOOTNOTES
|
EXT_TABLES, EXT_FENCED_CODE, EXT_FOOTNOTES
|
||||||
|
from misaka.utils import args_to_int
|
||||||
|
|
||||||
|
|
||||||
class ArgsToIntTest(TestCase):
|
class ArgsToIntTest(TestCase):
|
||||||
def test_args(self):
|
def test_args(self):
|
||||||
expected = EXT_TABLES | EXT_FENCED_CODE | EXT_FOOTNOTES
|
expected = EXT_TABLES | EXT_FENCED_CODE | EXT_FOOTNOTES
|
||||||
result = _args_to_int(
|
result = args_to_int(
|
||||||
extension_map,
|
extension_map,
|
||||||
('tables', 'fenced-code', 'footnotes'))
|
('tables', 'fenced-code', 'footnotes'))
|
||||||
|
|
||||||
|
@ -16,6 +17,6 @@ class ArgsToIntTest(TestCase):
|
||||||
|
|
||||||
def test_int(self):
|
def test_int(self):
|
||||||
expected = EXT_TABLES | EXT_FENCED_CODE | EXT_FOOTNOTES
|
expected = EXT_TABLES | EXT_FENCED_CODE | EXT_FOOTNOTES
|
||||||
result = _args_to_int(extension_map, expected)
|
result = args_to_int(extension_map, expected)
|
||||||
|
|
||||||
ok(result) == expected
|
ok(result) == expected
|
||||||
|
|
Loading…
Reference in New Issue