104 lines
3.3 KiB
Python
104 lines
3.3 KiB
Python
|
# mistletoe-rtf: RTF output for the mistletoe Markdown parser
|
||
|
# Copyright © 2019 Lee Yingtong Li (RunasSudo)
|
||
|
#
|
||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||
|
|
||
|
import mistletoe
|
||
|
|
||
|
class RTFRenderer(mistletoe.base_renderer.BaseRenderer):
|
||
|
def __init__(self, *extras):
|
||
|
super().__init__(*extras)
|
||
|
|
||
|
def render_strong(self, token):
|
||
|
return r'{{\b {}}}'.format(self.render_inner(token))
|
||
|
|
||
|
def render_emphasis(self, token):
|
||
|
return r'{{\i {}}}'.format(self.render_inner(token))
|
||
|
|
||
|
def render_inline_code(self, token):
|
||
|
return r'{{\f1 {}}}'.format(self.render_inner(token))
|
||
|
|
||
|
def render_raw_text(self, token):
|
||
|
return token.content.replace('\\', '\\\\').replace('{', r'\{').replace('}', r'\}')
|
||
|
|
||
|
def render_strikethrough(self, token):
|
||
|
return r'{{\strike {}}}'.format(self.render_inner(token))
|
||
|
|
||
|
def render_image(self, token):
|
||
|
raise Exception('NYI')
|
||
|
|
||
|
def render_link(self, token):
|
||
|
return r'{{\field{{\*\fldinst{{HYPERLINK "{target}"}}}}{{\fldrslt{{\ul\cf1 {inner}}}}}}}'.format(target=token.target, inner=self.render_inner(token))
|
||
|
|
||
|
def render_auto_link(self, token):
|
||
|
raise Exception('NYI')
|
||
|
|
||
|
def render_escape_sequence(self, token):
|
||
|
raise Exception('NYI')
|
||
|
|
||
|
def render_heading(self, token):
|
||
|
template = r'{{\b\fs{fontsize}{inner}\par}}'
|
||
|
fontsize = {1: 32, 2: 28, 3: 24, 4: 24, 5: 24, 6: 24}[token.level]
|
||
|
return template.format(fontsize=fontsize, inner=self.render_inner(token))
|
||
|
|
||
|
def render_quote(self, token):
|
||
|
return r'{{\li400 {}}}'.format(self.render_inner(token))
|
||
|
|
||
|
def render_paragraph(self, token):
|
||
|
template = r'{{{}\par}}'
|
||
|
return template.format(self.render_inner(token))
|
||
|
|
||
|
def render_block_code(self, token):
|
||
|
return r'{{\li400\f1 {}\par}}'.format(self.render_inner(token).rstrip('\n').replace('\n', r'\line '))
|
||
|
|
||
|
def render_list(self, token):
|
||
|
raise Exception('NYI')
|
||
|
|
||
|
def render_list_item(self, token):
|
||
|
raise Exception('NYI')
|
||
|
|
||
|
def render_table(self, token):
|
||
|
template = r'{{\sa0\trowd{cellxs} {inner}}}'
|
||
|
|
||
|
cell_width = (6*1440) / len(token.column_align) # 6 inches
|
||
|
|
||
|
cellxs = [r'\cellx{}'.format(int(cell_width*(i+1))) for i in range(len(token.column_align))]
|
||
|
|
||
|
if hasattr(token, 'header'):
|
||
|
head_rendered = self.render_table_row(token.header)
|
||
|
|
||
|
inner = self.render_inner(token)
|
||
|
|
||
|
return template.format(cellxs=''.join(cellxs), inner=head_rendered+inner)
|
||
|
|
||
|
def render_table_row(self, token):
|
||
|
cells = [self.render(child) for child in token.children]
|
||
|
return ''.join(cells) + r'\row '
|
||
|
|
||
|
def render_table_cell(self, token):
|
||
|
template = r'{{{inner}\intbl\cell}}'
|
||
|
return template.format(inner=self.render_inner(token))
|
||
|
|
||
|
def render_thematic_break(self, token):
|
||
|
raise Exception('NYI')
|
||
|
|
||
|
def render_line_break(self, token):
|
||
|
return r'\line '
|
||
|
|
||
|
def render_document(self, token):
|
||
|
template = r'{{\rtf1\deff0{{\fonttbl{{\f0\froman Times;}}{{\f1\froman Courier;}}}}{{\colortbl;\red0\green0\blue0\;\red0\green0\blue255;}}\sa200\f0 {inner}}}'
|
||
|
|
||
|
result_str = template.format(inner=self.render_inner(token))
|
||
|
|
||
|
# Escape Unicode
|
||
|
result = []
|
||
|
for char in result_str:
|
||
|
if ord(char) <= 0x7f:
|
||
|
result.append(char)
|
||
|
else:
|
||
|
result.append(r'\u{}?'.format(ord(char)))
|
||
|
|
||
|
return ''.join(result)
|