# 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) # Omit LaTeX tokens self.packages = {} mistletoe.base_renderer.BaseRenderer.__init__(self, *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_link(self, token): template = '\\href{{{target}}}{{{inner}}}' inner = self.render_inner(token) return template.format(target=token.target, inner=inner) def render_auto_link(self, token): return '\\url{{{}}}'.format(token.target) 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.1cm}\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.1cm' 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\leftskip=\bfseries \phantomsection\addcontentsline{toc}{subsubsection}{}\nopagebreak\par}', content=self.render_inner(token) ) if token.level == 4: heading_last, self.heading_last = self.heading_last, False return format(r'{\par\leftskip=\itshape \nopagebreak\par}', content=self.render_inner(token) ) def render_numbered_heading(self, token): if token.full_label(): sha = hashlib.sha256() sha.update(token.full_label().encode('utf-8')) hyperlink = format(r'\makebox[0pt]{\hypertarget{}{}}', linkname=sha.hexdigest() ) else: hyperlink = '{}' 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.1cm}\bfseries\fontsize{13pt}{15pt}\selectfont\centering\uppercase{Part