def _finalize(doc): logging.debug("Finalize doc!") hdr_inc = "header-includes" # Add header-includes if necessary if "header-includes" not in doc.metadata: if doc.get_metadata("output.beamer_presentation.includes") is None: logging.debug("No 'header-includes' nor `includes` ? Created 'header-includes'!") doc.metadata[hdr_inc] = pf.MetaList() else: logging.ERROR("Found 'includes'! SAD THINK") exit(1) # Convert header-includes to MetaList if necessary logging.debug("Append background packages to `header-includes`") if not isinstance(doc.metadata[hdr_inc], pf.MetaList): logging.debug("The '" + hdr_inc + "' is not a list? Converted!") doc.metadata[hdr_inc] = pf.MetaList(doc.metadata[hdr_inc]) frmt = doc.format if doc.format in ("latex", "beamer"): frmt = "latex" if doc.format in ("tex", "latex", "beamer"): doc.metadata[hdr_inc].append( pf.MetaInlines(pf.RawInline("\\usepackage{xspace}", frmt)) ) doc.metadata[hdr_inc].append( pf.MetaInlines(pf.RawInline("\\usepackage{trimclip}", frmt)) )
def action(e, doc): if isinstance(e, pf.Image) and (doc.format == 'latex') and ('parbox' in e.classes): subs = {'image':e.url} before = pf.RawInline(TEX_BEFORE, format='latex') after = pf.RawInline(TEX_AFTER.safe_substitute(subs), format='latex') span = pf.Span(before, *e.content, after, classes=e.classes, identifier=e.identifier, attributes=e.attributes) return(span)
def format_span_cites(span, doc): # type: (Cite, Doc) -> Element if not isinstance(span, pf.Span): return None if CONVERTED_CITE_CLASS not in span.classes: return None if doc.format in ("latex", "tex"): cite_tag = "cite" if span.attributes["format"] == "latex": cite_tag = span.attributes["tag"] # TODO use cref for rst ref/numref return pf.RawInline("\\{0}{{{1}}}".format(cite_tag, span.identifier, format="tex")) if doc.format == "rst": cite_role = "cite" if span.attributes["format"] == "rst": cite_role = span.attributes["role"] # TODO use ref for latex ref/cref/Cref return [ pf.RawInline(":{0}:`{1}`".format(cite_role, span.identifier), format='rst') ] if doc.format in ("html", "html5"): # <cite data-cite="cite_key">text</cite> return ([ pf.RawInline('<cite data-cite="{}">'.format(span.identifier), format="html") ] + list(span.content) + [pf.RawInline('</cite>', format="html")])
def parse(elem, doc): if isinstance(elem, pf.Span) and 'gloss' in elem.classes: content = [ c for c in elem.content if not isinstance(c, common.SPACE_TYPES) ] if len(content) != 3: raise Exception('invalid gloss syntax') elem.content = [] if doc.format == 'html': elem.content.append(content[0]) elem.content.append(pf.RawInline('<br/>', format=doc.format)) elem.content.append(content[1]) elem.content.append(pf.RawInline('<br/>', format=doc.format)) elem.content.append(content[2]) elif doc.format == 'latex': elem.content.append( pf.RawInline('\\begin{exe}\n', format=doc.format)) elem.content.append(pf.RawInline('\\ex\n', format=doc.format)) elem.content.append(pf.RawInline('\\gll', format=doc.format)) elem.content.append(pf.Space()) elem.content.append(content[0]) elem.content.append(pf.RawInline('\\\\\n', format=doc.format)) elem.content.append(content[1]) elem.content.append(pf.RawInline('\\\\\n', format=doc.format)) elem.content.append(pf.RawInline('\\trans', format=doc.format)) elem.content.append(pf.Space()) elem.content.append(content[2]) elem.content.append(pf.RawInline('\n', format=doc.format)) elem.content.append(pf.RawInline('\\end{exe}', format=doc.format))
def handleHeaderBlockLevel(e, doc): """ :param e: :param doc: :return: """ global blocktag tag = blocktag blocktag = None before = None if tag: before = pf.RawBlock("\\end{" + tag + "}\n", "latex") if "endblock" in e.classes: return before for blocktype in BLOCKCLASSES: if blocktype in e.classes: logging.debug("BLOCKTYPE:" + blocktype) if not isinstance(e.content, pf.ListContainer): logging.debug("CONTENT:" + pf.stringify(e.content)) tag = TEX_BLOCKCLASSES_TAG[blocktype] elem = pf.Div() elem.content = [ pf.Plain(pf.RawInline("\n\\begin{" + tag + "}[", "latex"), e.content, pf.RawInline("]\n", "latex")) ] blocktag = tag if before: return [before, elem] return elem else: logging.debug("CONTENT: Listcontainer")
def finalize(doc): """Adds the pgfplots and caption packages to the header-includes if needed. """ if doc.plot_found: pgfplots_inline = pf.MetaInlines(pf.RawInline( r'''% \makeatletter \@ifpackageloaded{pgfplots}{}{\usepackage{pgfplots}} \makeatother \usepgfplotslibrary{groupplots} ''', format='tex')) try: doc.metadata['header-includes'].append(pgfplots_inline) except KeyError: doc.metadata['header-includes'] = pf.MetaList(pgfplots_inline) if doc.caption_found: caption_inline = pf.MetaInlines(pf.RawInline( r'''% \makeatletter \@ifpackageloaded{caption}{}{\usepackage{caption}} \@ifpackageloaded{cleveref}{}{\usepackage{cleveref}} \@ifundefined{codelisting}{% \DeclareCaptionType{codelisting}[Code Listing][List of Code Listings] \crefname{codelisting}{code listing}{code listings} \Crefname{codelisting}{Code Listing}{Code Listings} \captionsetup[codelisting]{position=bottom} }{} \makeatother ''', format='tex')) try: doc.metadata['header-includes'].append(caption_inline) except KeyError: doc.metadata['header-includes'] = pf.MetaList(caption_inline)
def wrapfig(elem, doc): attrs = elem.attributes caption = ''.join(pf.stringify(e) for e in elem.content) # caption = elem.content # pf.debug(caption) target = elem.url fmt = "latex" # Strip tag size = attrs.get("width") if "lineheight" in attrs: lineheight = attrs.lineheight latex_begin = r"\begin{wrapfigure}[" + lineheight + "]{l}{" + size + "}" else: latex_begin = r"\begin{wrapfigure}{l}{" + size + "}" if len(caption) > 0: latex_fig = r"\centering\includegraphics{" + target + "}\caption{" latex_end = r"}\end{wrapfigure}" return pf.RawInline(latex_begin + latex_fig + caption + latex_end, fmt) # return list(pf.RawInline(latex_begin + latex_fig), caption, pf.RawInline(latex_end)) else: latex_fig = r"\centering\includegraphics{" + target[0] + "}" latex_end = r"\end{wrapfigure}" return pf.RawInline(latex_begin + latex_fig + latex_end, fmt)
def _diff(color, latex_tag, html_tag): if isinstance(elem, pf.Span): _wrap(pf.RawInline('\\{}{{'.format(latex_tag), 'latex'), pf.RawInline('}', 'latex')) _wrap(pf.RawInline('<{}>'.format(html_tag), 'html'), pf.RawInline('</{}>'.format(html_tag), 'html')) _color(color)
def h_latex_cite(e, doc): """Handle cite. Just feed it to a cite command and hope for the best. This is pretty hacky and should be changed.""" if not isinstance(e, pf.Cite): return None logstring(f"I am {e} and my parent is {e.parent}", doc) if isinstance(e.parent, pf.Citation): return [] s = pf.stringify(e).replace("[", "").replace("]", "").replace("@", "").strip() if s[-1] == ",": s = s[:-1] if doc.format == "latex": tex = f"\\cite{{{s}}}" return pf.RawInline(tex, format="latex") if doc.format == "html": html = "" for a in s.split(','): a = a.strip() if a in doc.bibentries: D = doc.bibentries[a] authors, title, year = D["author"], D["title"], D["year"] authors = bibtexparser.customization.getnames([ i.strip() for i in authors.replace('\n', ' ').split(" and ") ]) author = ", ".join([a.split(',')[0] for a in authors]) T_encode = latex_accents.LaTexAccents_to_UTF8() author = T_encode.decode_Tex_Accents(author) title = T_encode.decode_Tex_Accents(title) q = f'{author} {title}'.replace(' ', '+') html += rf' (<a href="https://scholar.google.com/scholar?hl=en&q={q}" target="_blank">{author}, {year}</a>) ' if not html: html = s return pf.RawInline(html, format="html")
def render_links(elem, doc): if isinstance(elem, pf.Link) and doc.format == "latex": url = elem.url ref = _get_ref(url, doc) head = "\\myref{{{ref}}}" tail = "" if ref: if elem.content: head = "\\myref{{{ref}}}[" tail = "]" return [ pf.RawInline(head.format(ref=ref), format="latex"), *elem.content, pf.RawInline(tail, format="latex"), ] alt_url = pf.stringify(elem).strip() ref = _get_ref(alt_url, doc) if ref: return [ pf.RawInline(head.format(ref=ref), format="latex"), pf.RawInline(tail, format="latex"), ] logger.debug(url)
def build_header(elem): # We use a `pf.RawInline` here because setting the `align` # attribute on `pf.Div` does not work for some reason. header = pf.Plain(pf.RawInline('<div align="center">', 'html'), pf.Strong(*elem.content), pf.RawInline('</div>', 'html')) width = float( elem.attributes['width']) if 'width' in elem.attributes else 0 return header, width
def filter_hatena_blockquote(elem, doc): if isinstance(elem, pf.BlockQuote): quotecomponents = [pf.RawInline('>>'), pf.RawInline('\n')] + list(elem.content[0].content) + [pf.RawInline('\n'), pf.RawInline('<<')] return pf.Plain(*quotecomponents) elif isinstance(elem, pf.Div) and 'epigraph' in elem.classes: epigraph_phrase = elem.content[0] epigraph_source = elem.content[1] return pf.Plain(*[pf.RawInline(f'>')] + list(epigraph_source.content) + [pf.RawInline('>'), pf.RawInline('\n')] + list(epigraph_phrase.content) + [pf.RawInline('\n'), pf.RawInline('<<')])
def code_filter(elem, doc): if isinstance(elem, pf.Code): return [ pf.RawInline("\colorbox{colorbox-background}{\\texttt{", format='tex'), pf.Str(elem.text), pf.RawInline("}}", format='tex') ]
def figure_extensions(elem, doc): if isinstance(elem, pf.Image): url = elem.url ## Skip regular URLS if '://' in url: return None basename, file_extension = os.path.splitext(url) override_extension = False ## Support for tikz if file_extension == ".tex": if latex_format(doc.format): if "standalone" in elem.classes: if "standalone_opts" in elem.attributes: tag = "includestandalone[%s]" % elem.attributes[ "standalone_opts"] else: tag = "includestandalone" else: tag = "input" ## tikz inline centered if len(elem.parent.content) == 3: return [ pf.RawInline('\\' + tag + '{' + basename + '}', format='latex') ] ## Replace includegraphics with input (tikzpicture) raw_item = pf.convert_text(elem.parent, input_format='panflute', output_format='latex') #pf.debug(raw_item) replacement = r'\\' + tag + '{' + basename + '}' raw_item = re.sub(r'\\includegraphics\[*.*\]*\{.*\}', replacement, raw_item) #pf.debug(raw_item) return [pf.RawInline(raw_item, format='latex')] else: override_extension = True if (file_extension == ".pdf" or file_extension == ".eps") and html_format(doc.format): override_extension = True if file_extension == "": override_extension = True if override_extension: if "alt-ext" in elem.attributes: ext = get_suitable_extension(elem.attributes["alt-ext"], doc.format) if ext: elem.url = basename + ext del elem.attributes["alt-ext"] else: elem.url = basename
def filter_hatena_mathjax(elem, doc): if isinstance(elem, pf.Math): math_expr = elem.text math_expr = re.sub('^\\\\begin{aligned}', r'\\begin{align}', math_expr) math_expr = re.sub('\\\\end{aligned}', r'\\end{align}', math_expr) math_code = pf.RawInline('[tex: {}]'.format(math_expr)) if elem.format == 'DisplayMath': return [pf.RawInline('\n'), pf.Span(math_code, classes=['Math', 'DisplayMath']), pf.RawInline('\n')] elif elem.format == 'InlineMath': return math_code
def _diff(color, latex_tag, html_tag): if isinstance(elem, pf.Span): def protect_code(elem, doc): if isinstance(elem, pf.Code): return pf.Span(pf.RawInline('\\mbox{', 'latex'), elem, pf.RawInline('}', 'latex')) elem.walk(protect_code) _wrap(pf.RawInline('\\{}{{'.format(latex_tag), 'latex'), pf.RawInline('}', 'latex')) _wrap(pf.RawInline('<{}>'.format(html_tag), 'html'), pf.RawInline('</{}>'.format(html_tag), 'html')) _color(doc.get_metadata(color))
def sage(elem, doc): elemtype = type(elem) if elemtype in [pf.Math, pf.RawInline]: contents = replace_sagecommand(elem.text) if elemtype == pf.Math: return pf.Math(contents, format=elem.format) else: return pf.RawInline(contents, format=elem.format) if elemtype == pf.CodeBlock: isSageSilent = 'sagesilent' in elem.classes isSageBlock = 'sageblock' in elem.classes isSagePlot = 'sageplot' in elem.classes code = elem.text if isSageBlock or isSagePlot or isSageSilent: img_file = get_image_output_filename(code) sage_file = get_sage_filename(code) if isSagePlot: code = code.strip("\n") codelist = code.split("\n") plot_cmd = codelist.pop() code = "\n".join(codelist) m = re.search(r"sageplot\[(?P<first_name>.*)\]\((.*)\)", plot_cmd) if m == None: para, cmd = "", plot_cmd else: para, cmd = m.group(1), m.group(2) if len(para) > 0: para = ',' + para code += "\n(%s).save(\"%s\"%s)" % (cmd, img_file, para) out, err = run_sage(code) if isSageSilent: return pf.Plain(pf.RawInline("", "tex")) elif isSageBlock: sys.stderr.write('\n convert markdown \n') return pf.convert_text(out) else: return pf.Para( pf.Image(url=img_file, attributes=elem.attributes)) if 'latex' in elem.classes: out, err, img_file = run_tex(code) return pf.Para(pf.Image(url=img_file, attributes=elem.attributes))
def format_math(math, doc): # type: (Math, Doc) -> Element """ originally adapted from: `pandoc-eqnos <https://github.com/tomduck/pandoc-eqnos/>`_ """ if not isinstance(math, pf.Math): return None if math.format != "DisplayMath": return None span = None number = "" env = "equation" label_tag = "" if (isinstance(math.parent, pf.Span) and LABELLED_MATH_CLASS in math.parent.classes): span = math.parent number = '*' if "unnumbered" in span.classes else '' env = span.attributes.get("env", "equation") if doc.format in ("tex", "latex"): label_tag = "\\label{{{0}}}".format(span.identifier) else: label_tag = "" # construct latex environment tex = '\\begin{{{0}{1}}}{2}{3}\\end{{{0}{1}}}'.format( env, number, math.text, label_tag) if doc.format in ("tex", "latex"): return pf.RawInline(tex, format="tex") elif doc.format in ("rst"): if not span: rst = '\n\n.. math::\n :nowrap:\n\n {0}\n\n'.format(tex) else: rst = ('\n\n.. math::\n :nowrap:\n :label: {0}' '\n\n {1}\n\n'.format(span.identifier, tex)) return pf.RawInline(rst, format="rst") elif doc.format in ('html', 'html5'): # new_span = pf.Span(anchor_start, math, anchor_end) # TODO add formatting # TODO name by count if span: math.text = tex return _wrap_in_anchor(math, span.identifier) else: return None
def finalize(doc): # Add header-includes if necessary if 'header-includes' not in doc.metadata: doc.metadata['header-includes'] = pf.MetaList() # Convert header-includes to MetaList if necessary elif not isinstance(doc.metadata['header-includes'], pf.MetaList): doc.metadata['header-includes'] = pf.MetaList( doc.metadata['header-includes']) # Add usefull LaTexPackage doc.metadata['header-includes'].append( pf.MetaInlines(pf.RawInline('\\usepackage{pstricks}', 'tex'))) doc.metadata['header-includes'].append( pf.MetaInlines(pf.RawInline('\\usepackage{pst-barcode}', 'tex')))
def pnum(): num = pf.stringify(elem) if '.' in num: num = '({})'.format(num) if doc.format == 'latex': return pf.RawInline('\\pnum{{{}}}'.format(num), 'latex') elif doc.format == 'html': return pf.Span( pf.RawInline('<a class="marginalized">{}</a>'.format(num), 'html'), classes=['marginalizedparent']) return pf.Superscript(pf.Str(num))
def filter_hatena_link(elem, doc): """ ハイパーリンクをはてな記法に置き換え """ if isinstance(elem, pf.Link): if elem.url[0] != '#': url_title = pf.stringify(elem).strip() if url_title == ':title:': return pf.RawInline('[{}:title]'.format(elem.url)) if url_title == ':embed:': return pf.RawInline('[{}:embed:title]'.format(elem.url)) elif url_title == '': return pf.RawInline('[{}]'.format(elem.url)) else: return pf.RawInline('[{0}:title={1}]'.format(elem.url, url_title))
def filter_hatena_toc(elem, doc): """ 目次を挿入する場合ははてな記法で自動生成するように置き換え """ if isinstance(elem, pf.RawBlock): if elem.format == 'latex' and elem.text == r'\tableofcontents{}': return pf.Plain(pf.RawInline('[:contents]'))
def filter_eqref(elem, doc): """ [eq:...] の参照タグを MathJax 参照に置き換える """ if isinstance(elem, pf.Link) and elem.url[:4] == '#eq:': ref_id_eq = elem.url[1:] return pf.Span(pf.RawInline('(\\ref{' + ref_id_eq + '})'), attributes={'data-reference-type': 'ref', 'data-reference': f'{ref_id_eq}'})
def h_math(e, doc): r"""Make multiletter identifiers mathit{..} For now just handle uppercase identifiers. Also format better the empty string. For HTML we also change \label{blah} to (1.1) """ if not isinstance(e, pf.Math): return None text = e.text reg = r'\\label\{([a-zA-Z\:\_\-0-9]+)\}' eqlabel = "" def _tmp(m): nonlocal eqlabel l = m.groups()[0] eqlabel = l if l in doc.labels: return fr"\;\;({doc.labels[l]['number']})" return "" if doc.format == 'html': text = re.sub(reg, _tmp, text) reg = r"(?<=[^\\A-Z\{\:a-z])([A-Z][A-Z]+)" text = re.sub(reg, r"\\ensuremath{\\mathit{\1}}", text) reg2 = r"\A([A-Z][A-Z]+)" text = re.sub(reg2, r"\\ensuremath{\\mathit{\1}}", text) e.text = text.replace('""', r'\ensuremath{\text{\texttt{""}}}') if not eqlabel or doc.format != "html": return e p = e.parent t = pf.RawInline(rf"<a id='{eqlabel}'></a>", format='html') i = p.content.index(e) p.content.insert(i + 1, t) return e
def to_inline(elem, classes=[], attributes={}): """Convert any given pandoc element to inline element(s). Some information may be lost.""" if not classes: classes = getattr(elem, "classes", []) if not attributes: attributes = getattr(elem, "attributes", {}) if isinstance(elem, pf.Inline): return elem if isinstance(elem, pf.CodeBlock): return pf.Code(elem.text, classes=classes, attributes=attributes) if isinstance(elem, pf.RawBlock): return pf.RawInline(elem.text, format=elem.format) elems = [] if isinstance(elem, pf.Block): elems = elem.content elif isinstance(elem, list): elems = elem # dont nest too many spans if len(elems) == 1: return to_inline(elems[0], classes=classes, attributes=attributes) ret = [to_inline(x, classes=classes, attributes=attributes) for x in elems] return pf.Span(*ret, classes=classes, attributes=attributes)
def latex(key: keys.Key) -> panflute.RawInline: """Generate the LaTeX output from a key This method inspects the given :class:`keys.Key` and determine the properly formatted version of the LaTeX acronym. Parameters ---------- key: :class:`keys.Key` The :class:`keys.Key` to interpret. Returns ------- :class:`panflute.RawInline` The LaTeX formatted acronym. """ macro = "\\" + ("A" if key.capitalize else "a") + "c" \ + {"full": "f", "short": "s", "long": "l" }.get(key.type, "") \ + ("p" if key.plural else "") \ + ("*" if not key.count else "") \ + f"{{{key.value}}}" \ + key.post return panflute.RawInline(macro, format="latex")
def action(e, doc): if not doc.format == 'latex': return None if isinstance(e, pf.Span) and 'textquote' in e.classes: cite = e.attributes.get('cite') if cite: cite = pf.convert_text(cite, extra_args=['--biblatex'], input_format='markdown', output_format='latex') text = pf.convert_text(pf.Plain(e), extra_args=['--biblatex'], input_format='panflute', output_format='latex') values = { 'lang': e.attributes.get('lang'), 'cite': cite, 'punct': e.attributes.get('punct'), 'text': text } tex = QUOTE.render(values) return pf.RawInline(tex, format='latex') else: return None
def htmlBlockThree( first, second, third, ): return pf.RawInline(first + thinSpaceHTML + second + thinSpaceHTML + third, format="html")
def _span(elem, doc): text = elem.text if doc.format == "latex": return pf.RawInline(f"{{{text}}}", format="latex") else: return pf.Span(*elem.content)
def finalize(doc): content = doc.content colour_boxes = [] count = 0 for t in tag_sequence: colour = outcome_colours[t] if doc.format in ('html', 'html5'): div = pf.Span( attributes={ 'style': f"width:4px;height:40px;background-color:{colour[1]};float:left" }) elif doc.format == 'latex': div = pf.RawInline( f"\\tcbox[tcbox width=forced center,boxrule=0mm,before=,after=,left=0mm,right=0mm,width=1mm,height=4em,arc=0mm,colframe={colour[1]},colback={colour[1]}]{{}}", format='latex') colour_boxes.append(div) colour_block = pf.Div(pf.Plain(*colour_boxes), attributes={'style': 'height:45px'}) barcodes.append((collect_tags, colour_block)) # Now insert them in reverse order (biggest insertion point first) so that # when we insert things into the document, stuff below doesn't get shifted # down. barcodes.reverse() for (spot, block) in barcodes: content.insert(spot, block)