# legalmd: Markdown-based legal markup
# Copyright © 2019 Lee Yingtong Li (RunasSudo)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
import hashlib
import mistletoe
import mistletoe.latex_renderer
LMARG = '1cm'
def format(fstr, *args, **kwargs):
fstr2 = fstr
fstr2 = fstr2.replace('\\N', '\n')
fstr2 = fstr2.replace('{', '{{')
fstr2 = fstr2.replace('}', '}}')
fstr2 = fstr2.replace('<', '{')
fstr2 = fstr2.replace('>', '}')
kwargs['lmarg'] = LMARG
return fstr2.format(*args, **kwargs)
class LaTeXRenderer(mistletoe.latex_renderer.LaTeXRenderer):
def __init__(self, *extras):
super().__init__(*extras)
self.render_map['CrossReference'] = self.render_cross_reference
self.render_map['NumberedHeading'] = self.render_numbered_heading
self.render_map['Subrules'] = self.render_subrules
self.render_map['SubrulesItem'] = self.render_subrules_item
self.render_map['Note'] = self.render_note
self.render_map['Definition'] = self.render_definition
self.heading_last = False
def render_raw_text(self, token):
result = super().render_raw_text(token)
result = result.replace('★★★', r'\texorpdfstring{\freeserif ★★★}{★★★}')
return result
def render_cross_reference(self, token):
reference = token.get_reference()
if not reference:
raise Exception('Unable to resolve reference "{}"'.format(token.reference_num))
sha = hashlib.sha256()
sha.update(reference.full_label().encode('utf-8'))
return format(r'\hyperlink{}{}',
linkname=sha.hexdigest(),
reference_type=(token.reference_type + '~') if token.reference_type else '',
reference_num=token.reference_num
)
def render_heading(self, token):
if token.level == 1:
heading_last, self.heading_last = self.heading_last, True
return format(r'{\par\vspace{1cm plus 0.3cm minus 0.3cm}\bfseries\fontsize{13pt}{15pt}\selectfont\centering\uppercase{}\phantomsection\addcontentsline{toc}{section}{}\nopagebreak\par}',
content=self.render_inner(token)
)
if token.level == 2:
heading_last, self.heading_last = self.heading_last, True
return format(r'{\par\vspace{}\bfseries\fontsize{13pt}{15pt}\selectfont\centering \phantomsection\addcontentsline{toc}{subsection}{}\nopagebreak\par}',
space_above='1cm plus 0.3cm minus 0.3cm' if not heading_last else '0cm',
content=self.render_inner(token)
)
if token.level == 3:
heading_last, self.heading_last = self.heading_last, False
return format(r'{\par\bfseries\makebox[][l]{~}\phantomsection\addcontentsline{toc}{subsubsection}{}\nopagebreak\par}',
content=self.render_inner(token)
)
def render_numbered_heading(self, token):
sha = hashlib.sha256()
sha.update(token.full_label().encode('utf-8'))
hyperlink = format(r'\hypertarget{}{}',
linkname=sha.hexdigest()
)
if token.level == 1:
# Part
heading_last, self.heading_last = self.heading_last, True
return format(r'{\par\vspace{1cm plus 0.3cm minus 0.3cm}\bfseries\fontsize{13pt}{15pt}\selectfont\centering\uppercase{Part