def make_codelisting(inner_elements, caption, label, *, shortcaption=None, above=True): r"""Creates a source code listing: \begin{codelisting}[hbtp] inner_elements \caption[caption]{\label{label}caption} \end{codelisting} and returns the list containing the pandoc elements. Args: inner_elements: A list of inner pandoc elements, usually a code block and potentially outputs etc. caption: The caption to be used. Will be used below code and in list of code listings. label: The label to use. shortcaption: A short caption to be used in the list of code listings. If None, the normal caption will be used. above: The caption is placed above (True) or below (False) the code listing. Returns: A list of elements for this codelisting. """ begin = pf.RawBlock(r'\begin{codelisting}[hbtp]', format='tex') end = pf.RawBlock(r'\end{codelisting}', format='tex') if not shortcaption: shortcaption = caption cap_begin = f'\\caption[{shortcaption}]{{\\label{{{label}}}' caption_elem = pf.RawBlock(cap_begin + caption + '}', format='tex') if above: return [begin, caption_elem] + inner_elements + [end] return [begin] + inner_elements + [caption_elem, end]
def codeblock(elem, doc): if not isinstance(elem, pf.CodeBlock) or escape_char not in elem.text: return None is_raw = not elem.classes if is_raw: elem.classes.append('default') elem.attributes['style'] = 'color: inherit' datadir = doc.get_metadata('datadir') syntaxdir = os.path.join(datadir, 'syntax') text = pf.convert_text(elem, input_format='panflute', output_format=doc.format, extra_args=[ '--syntax-definition', os.path.join(syntaxdir, 'isocpp.xml') ]) def repl(match_obj): match = match_obj.group(1) if not match: # @@ return match_obj.group(0) if match.isspace(): # @ @ return match return pf.convert_text(pf.Plain(*pf.convert_text(match)[0].content), input_format='panflute', output_format=doc.format) result = pf.RawBlock(escape_span.sub(repl, text), doc.format) return pf.Div(pf.RawBlock('{\\renewcommand{\\NormalTok}[1]{#1}', 'latex'), result, pf.RawBlock('}', 'latex')) if is_raw else result
def finalize(doc): """Function called at the end of the filter""" doc.metadata["compiletime"] = pf.MetaString( time.strftime("%m/%d/%Y %H:%M:%S")) if doc.format == "html": dumpyaml(doc.toc, "toc.yaml") writetoc(doc, tochtml(doc.toc, doc.get_metadata("booktitle", ""))) if doc.get_metadata("indexpage", False): indexhtml(doc) file = doc.get_metadata("filename", "") title = doc.get_metadata("title", "") searchindex = doc.get_metadata("searchindex", "") logstring("Search index " + file + "," + title + "," + searchindex, doc) if file and title and searchindex: t = re.sub(r"\\\w+", " ", doc.searchtext.lower()) text = re.sub("[^a-zA-Z -]", "", t) updateindex(searchindex, file + ".html", title, text, doc) if doc.format == "html" and doc.footnotecontents: logstring("inserting " + str(doc.footnotecontents), doc) L = ([pf.RawBlock("<ol>", format="html")] + doc.footnotecontents + [pf.RawBlock("</ol>", format="html")]) footnotes = pf.Div(*L, identifier="footnotediv", classes=["footnotes"]) doc.content.append(footnotes) doc.logfile.close()
def prepare(doc): date = doc.get_metadata('date') if date == 'today': doc.metadata['date'] = datetime.date.today().isoformat() doc.metadata['pagetitle'] = pf.convert_text( pf.Plain(*doc.metadata['title'].content), input_format='panflute', output_format='markdown') datadir = doc.get_metadata('datadir') with open(os.path.join(datadir, 'annex-f'), 'r') as f: stable_names.update(line.split() for line in f) def highlighting(output_format): return pf.convert_text( '`_`{.default}', output_format=output_format, extra_args=[ '--highlight-style', os.path.join(datadir, 'syntax', 'wg21.theme'), '--template', os.path.join(datadir, 'template', 'highlighting') ]) doc.metadata['highlighting-macros'] = pf.MetaBlocks( pf.RawBlock(highlighting('latex'), 'latex')) doc.metadata['highlighting-css'] = pf.MetaBlocks( pf.RawBlock(highlighting('html'), 'html'))
def table_separators(elem, doc): if isinstance(elem, pf.Table) and doc.enable_traditional_tables: if latex_format(doc.format): doc.metadata['tables'] = True raw_item = pf.convert_text(elem, input_format='panflute', output_format='latex') print("raw_item", file=sys.stderr) #pf.debug(hack_table(raw_item)) return [pf.RawBlock(hack_table(raw_item), 'latex')] elif html_format(doc.format): raw_item = pf.convert_text(elem, input_format='panflute', output_format='html') raw_item = raw_item.replace( '<table>', '<table style=\'border-collapse: collapse; border: 1px solid black\'>' ) raw_item = raw_item.replace( '<th ', '<th style=\'border: 1px solid black\' ') raw_item = raw_item.replace( '<td ', '<td style=\'border: 1px solid black; height: 20px;\' ') return [pf.RawBlock(raw_item, 'html')] return None
def prepare(doc): datadir = doc.get_metadata('datadir') kate = pf.run_pandoc(args=['--print-highlight-style', 'kate']) json_styles = json.loads(kate) json_styles['background-color'] = '#' + doc.get_metadata('shadecolor') text_styles = json_styles['text-styles'] text_styles['BuiltIn'] = text_styles['Normal'] text_styles['Comment']['italic'] = True text_styles['ControlFlow'] = text_styles['DataType'] text_styles['Keyword'] = text_styles['DataType'] text_styles['Variable']['text-color'] = '#' + doc.get_metadata('addcolor') text_styles['String']['text-color'] = '#' + doc.get_metadata('rmcolor') with tempfile.NamedTemporaryFile('w', suffix='.theme') as f: json.dump(json_styles, f) f.flush() def highlighting(output_format): return pf.convert_text('`_`{.cpp}', output_format=output_format, extra_args=[ '--highlight-style', f.name, '--template', os.path.join(datadir, 'template', 'highlighting') ]) doc.metadata['highlighting-macros'] = pf.MetaBlocks( pf.RawBlock(highlighting('latex'), 'latex')) doc.metadata['highlighting-css'] = pf.MetaBlocks( pf.RawBlock(highlighting('html'), 'html'))
def h_latex_div(e, doc): r"""make every div with class=foo to begin{foo} ... end{foo} if there is title then it is begin{foo}[title] instead if there is an identifier then we add \label[foo]{id}""" if not isinstance(e, pf.Div): return None if not len(e.classes): return None c = e.classes[0] title = e.attributes.get("title", "") label = labelref(e, doc) if label in doc.labels: name = getlabel(label, doc)[0] else: name = c.capitalize() if title: name += f" ({title}) " e.attributes["name"] = name if e.identifier: doc.label_descriptions[e.identifier] = c.capitalize() if doc.format == 'html' and c == 'quote': return pf.BlockQuote(e) if doc.format != 'latex': return None dref = e.attributes.get("data-ref", None) if not title and c == "proof" and dref and dref != doc.lastlabel: title = fr"Proof of \cref{{{dref}}}" label = labelref(e, doc) doc.lastlabel = label before = rf"\begin{{{c}}}[{title}]" if title else rf"\begin{{{c}}}" if label: before += rf" \label[{c}]{{{label}}}" if c == "algorithm": before += r"~ \\ \noindent" + "\n" after = rf"\end{{{c}}}" _before = pf.RawBlock(before, format='latex') _after = pf.RawBlock(after, format='latex') e.content = [_before] + list(e.content) + [_after] return e
def h_pseudocode(e, doc): if not isinstance(e, pf.CodeBlock) or not "algorithm" in e.classes: return None content = e.text if e.identifier: doc.label_descriptions[e.identifier] = "Algorithm" label = labelref(e, doc) _, number_, _ = get_full_label(label, doc) if number_ and number_ != "??": i = number_.rfind(".") number = int(number_[i + 1:]) if i > -1 else int(number_) else: number = 0 title = e.attributes.get("title", "") if doc.format == "latex": textitle = f"[{title}]" if title else "" result = (dedent(rf""" \begin{{algorithm}}{textitle} \label[algorithm]{{{label}}} ~ \\ \noindent \begin{{algorithmic}}[1] """) + "\n" + format_pseudocode(content) + dedent(fr""" \end{{algorithmic}} \end{{algorithm}} """)) return pf.RawBlock(result, format="latex") if doc.format == "html": textitle = f"\caption{{{title}}}" if title else "" uid = str(uuid.uuid4()) content = (format_pseudocode(content).replace( "\\INPUT", "\\REQUIRE").replace("\\OUTPUT", "\\ENSURE")) result = (dedent(rf""" <pre id="{uid}" class="pseudocodetext" style="display:none;"> \begin{{algorithm}} {textitle} \begin{{algorithmic}} """) + "\n" + content + dedent(fr""" \end{{algorithmic}} \end{{algorithm}} </pre> <div id="{uid}result" class="pseudocodeoutput" ></div> <script> document.addEventListener('readystatechange', event => {{ if (event.target.readyState === "complete") {{ var code = document.getElementById('{uid}').textContent; var resultEl = document.getElementById('{uid}result'); resultEl.innerHTML = ''; var options = {{ captionCount: {number-1}, lineNumber: true }}; pseudocode.render(code, resultEl, options); }} }}); </script> """)) return pf.RawBlock(result, format="html") return None
def avm(elem, doc): """ The actual panflute style pandoc filter """ if isinstance(elem, pf.CodeBlock): if "<cx" in elem.text: if doc.format == 'latex': return pf.RawBlock(CreateAvm(elem.text, "tex"), "latex") elif doc.format == 'html': return pf.RawBlock(CreateAvm(elem.text, "html"), "html")
def collapse(elem, doc): if isinstance(elem, pf.CodeBlock) and "html" in doc.format: content = [ pf.RawBlock("<details>", format="html"), pf.RawBlock(""" <summary onclick="this.innerHTML == ' Show code ' ? this.innerHTML = ' Hide code ': this.innerHTML = ' Show code '"> Show code </summary> """), elem, pf.RawBlock("</details>", format="html"), ] div = pf.Div(*content, classes=["collapsible_code"]) return div
def h_html_footnote(e, doc): """Handle footnotes with bigfoot""" if not isinstance(e, pf.Note) or doc.format != "html": return None htmlref = rf'<sup id="fnref:{doc.footnotecounter}"><a href="#fn:{doc.footnotecounter}" rel="footnote">{doc.footnotecounter}</a></sup>' htmlcontent_before = rf'<li class="footnote" id="fn:{doc.footnotecounter}"><p>' htmlcontent_after = rf'<a href="#fnref:{doc.footnotecounter}" title="return to article"> ↩</a><p></li>' doc.footnotecounter += 1 conts = pf.Div(*e.content) doc.footnotecontents += [ pf.RawBlock(htmlcontent_before, format="html") ] + [conts] + [pf.RawBlock(htmlcontent_after, format="html")] return pf.RawInline(htmlref, format="html")
def codeblock(elem, doc): if not isinstance(elem, pf.CodeBlock): return None if not elem.classes: elem.classes.append('default') result = elem if any(cls in elem.classes for cls in ['cpp', 'default', 'diff']) and escape_char in elem.text: datadir = doc.get_metadata('datadir') syntaxdir = os.path.join(datadir, 'syntax') text = pf.convert_text(elem, input_format='panflute', output_format=doc.format, extra_args=[ '--syntax-definition', os.path.join(syntaxdir, 'isocpp.xml') ]) def repl(match_obj): match = match_obj.group(1) if not match: # @@ return match_obj.group(0) if match.isspace(): # @ @ return match if doc.format == 'latex': # Undo `escapeLaTeX` from https://github.com/jgm/skylighting match = match.replace('\\textbackslash{}', '\\') \ .replace('\\{', '{') \ .replace('\\}', '}') plain = pf.Plain(*pf.convert_text(match)[0].content) return pf.convert_text(plain.walk(divspan, doc), input_format='panflute', output_format=doc.format) result = pf.RawBlock(escape_span.sub(repl, text), doc.format) if 'diff' not in elem.classes: return result # For HTML, this is handled via CSS in `data/template/wg21.html`. command = '\\renewcommand{{\\{}}}[1]{{\\textcolor[HTML]{{{}}}{{#1}}}}' return pf.Div( pf.RawBlock( command.format('VariableTok', doc.get_metadata('addcolor')), 'latex'), pf.RawBlock(command.format('StringTok', doc.get_metadata('rmcolor')), 'latex'), result)
def alteration(elem, doc): text = pf.stringify(elem).strip() is_relevant = isinstance(elem, pf.Para) and text.startswith("::alteration-") if not is_relevant: return if text.endswith("-begin"): return pf.RawBlock("{\\color{alterationcolor}", format="latex") if text.endswith("-end"): return pf.RawBlock("}", format="latex")
class DocxPagebreak(object): pagebreak = pf.RawBlock("<w:p><w:r><w:br w:type=\"page\" /></w:r></w:p>", format="openxml") sectionbreak = pf.RawBlock( "<w:p><w:pPr><w:sectPr><w:type w:val=\"nextPage\" /></w:sectPr></w:pPr></w:p>", format="openxml") toc = pf.RawBlock(r""" <w:sdt> <w:sdtContent xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"> <w:p> <w:r> <w:fldChar w:fldCharType="begin" w:dirty="true" /> <w:instrText xml:space="preserve">TOC \o "1-3" \h \z \u</w:instrText> <w:fldChar w:fldCharType="separate" /> <w:fldChar w:fldCharType="end" /> </w:r> </w:p> </w:sdtContent> </w:sdt> """, format="openxml") def action(self, elem, doc): if isinstance(elem, (pf.Para, pf.Plain)): for child in elem.content: if isinstance(child, pf.Str) and child.text == r"\newpage": if (doc.format == "docx"): pf.debug("Page Break") elem = self.pagebreak if isinstance(elem, pf.RawBlock): if elem.text == r"\newpage": if (doc.format == "docx"): pf.debug("Page Break") elem = self.pagebreak # elif elem.text == r"\newsection": # if (doc.format == "docx"): # pf.debug("Section Break") # elem = self.sectionbreak # else: # elem = [] elif elem.text == r"\toc": if (doc.format == "docx"): pf.debug("Table of Contents") para = [ pf.Para(pf.Str("Table"), pf.Space(), pf.Str("of"), pf.Space(), pf.Str("Contents")) ] div = pf.Div(*para, attributes={"custom-style": "TOC Heading"}) elem = [div, self.toc] else: elem = [] return elem
def process_code_latex(code, doc): # type: (pf.CodeBlock, Doc) -> Element if doc.format not in ("tex", "latex"): return None if not isinstance(code, pf.CodeBlock): return None # TODO line wrapping return [ pf.RawBlock("\\begin{mdframed}", format=doc.format), code, pf.RawBlock("\\end{mdframed}", format=doc.format), ]
class DocxPagebreak(object): pagebreak = pf.RawBlock("<w:p><w:r><w:br w:type=\"page\" /></w:r></w:p>", format="openxml") sectionbreak = pf.RawBlock("<w:p><w:pPr><w:sectPr><w:type w:val=\"nextPage\" /></w:sectPr></w:pPr></w:p>", format="openxml") toc = r""" <w:sdt> <w:sdtPr> <w:docPartObj> <w:docPartGallery w:val="{}" /> </w:docPartObj> </w:sdtPr> <w:sdtContent xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"> <w:p> <w:pPr> <w:pStyle w:val="TOCHeading" /> </w:pPr> <w:r> <w:t xml:space="preserve">{}</w:t> </w:r> </w:p> <w:p> <w:r> <w:fldChar w:fldCharType="begin" w:dirty="true" /> <w:instrText xml:space="preserve">TOC \o "1-3" \h \z \u</w:instrText> <w:fldChar w:fldCharType="separate" /> <w:fldChar w:fldCharType="end" /> </w:r> </w:p> </w:sdtContent> </w:sdt> """ def action(self, elem, doc): toctitle = doc.get_metadata('toc-title', "Table of Contents") if isinstance(elem, pf.RawBlock): if elem.text == r"\newpage": if (doc.format == "docx"): pf.debug("Page Break") elem = self.pagebreak # elif elem.text == r"\newsection": # if (doc.format == "docx"): # pf.debug("Section Break") # elem = self.sectionbreak # else: # elem = [] elif elem.text == r"\toc": if (doc.format == "docx"): pf.debug("Table of Contents") elem = pf.RawBlock(self.toc.format(toctitle,toctitle),format="openxml") else: elem = [] return elem
def handle_code_block(elem): try: language = elem.classes[0] except IndexError: language = 'python' begin_raw = '\\begin{{{}code}}'.format(language) end_raw = '\\end{{{}code}}'.format(language) begin_block = pf.RawBlock(begin_raw, format='tex') content = pf.RawBlock(elem.text, format='tex') end_block = pf.RawBlock(end_raw, format='tex') return [begin_block, content, end_block]
def handleHeader(e, doc): """ :param e: :param doc: :return: """ global blocktag tag = blocktag blocktag = None if "endblock" in e.classes: return pf.RawBlock("\\end{" + tag + "}\n") if tag: return [pf.RawBlock("\\end{" + tag + "}\n", "latex"), e]
def h_html_code_block(e, doc): """HTML code block""" if not isinstance(e, pf.CodeBlock) or doc.format != "html": return None if "algorithm" in e.classes: return None if not "full" in e.classes: return None label = labelref(e, doc) name, number, file = get_full_label(label, doc) title = e.attributes.get("title", "") before = rf"<p><i>Figure {number}: {title}</i></p>" + "\n" after = r"<p></p>" return pf.Div(pf.RawBlock(before, format='html'), e, pf.RawBlock(after, format='html'))
def action(elem, doc): if isinstance(elem, panflute.Header): if elem.level == 1: text = panflute.stringify(elem) rainbow_header = '<h1 id="' + text + '">' + rainbowify( text) + '</h1>' return (panflute.RawBlock(rainbow_header))
def fenced_latex(options, data, element, doc): raw_caption = options.get('caption') caption = pf.convert_text(options.get('caption'), extra_args=['--biblatex'], input_format='markdown', output_format='latex') if raw_caption else None raw_shortcaption = options.get('shortcaption') shortcaption = pf.convert_text( options.get('shortcaption'), extra_args=['--biblatex'], input_format='markdown', output_format='latex') if raw_shortcaption else None latex = CODEBLOCK.render({ 'floating': options.get('caption'), 'placement': options.get('placement'), 'options': options.get('mintedopts'), 'language': options.get('language'), 'content': data, 'caption': caption, 'shortcaption': shortcaption, 'identifier': options.get('identifier', '') }) return pf.RawBlock(latex, format='latex')
def csv_to_table_markdown(options, data, use_grid_tables): """Construct pipe/grid table directly. """ # prepare table in list from data/include table_list = read_csv( options.get('include', None), data, encoding=options.get('include-encoding', None), csv_kwargs=options.get('csv-kwargs', dict()), ) # regularize table: all rows should have same length n_col = regularize_table_list(table_list) # parse alignment alignment = parse_alignment(options.get('alignment', None), n_col) del n_col # get caption caption = options.get('caption', None) text = csv_to_grid_tables( table_list, caption, alignment, (len(table_list) > 1 and options.get( 'header', True))) if use_grid_tables else csv_to_pipe_tables( table_list, caption, alignment) raw_markdown = options.get('raw_markdown', False) if raw_markdown: return panflute.RawBlock(text, format='markdown') else: return panflute.convert_text(text)
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 indexhtml(doc): """Generate HTML index for title page""" keys = sorted(doc.toc.keys(), key=placekey) def depth(key): return key.count(".") HTML = fr"""<ul>""" for k in keys: e = doc.toc[k] title = e["title"] file = os.path.splitext(e["filename"])[0] base = doc.get_metadata("binarybaseurl", "") if depth(k) > 0: continue entry = dedent(fr""" <li><a href="{file+'.html'}"><b>Chapter {k}:</b> {title}</a> <small>(<a href="{base+'/'+file+'.pdf'}"><i class="fas fa-file-pdf"></i>PDF: best formatting</a> , <a href="{base+'/'+file+'.docx'}"><i class="fas fa-file-word"></i>Word: buggy</a>)</small> </li> """) HTML += entry HTML += r"""</ul>""" doc.metadata["indexcontents"] = pf.MetaBlocks( pf.RawBlock(HTML, format="html"))
def gb4e(lst): """ Convert an example list into a series of gb4e-formatted interlinear glosses. Because example list references are replaced at parsing by Pandoc, the normal syntax of (@foo) cannot be used for labels; instead, a label syntax similar to that used for headers (and tables and figures with pandoc-crossref) is used, namely a {#ex:foo} inserted after the translation, which will be stripped and replaced with a LaTeX label on the relevant example. """ latex = "\\begin{exe}\n" for li in lst.content: lines = break_plain(li.content[0]) if len(lines) != 3: continue orig, gloss, trans = map(partial(pf.stringify, newlines=False), lines) gloss = smallcapify(gloss) label_match = label_re.search(trans) if label_match: label = label_match.group(1) trans = trans[:label_match.start() - 1] latex += gb4e_fmt_labelled.format(orig, gloss, trans, label=label) else: latex += gb4e_fmt.format(orig, gloss, trans) latex += "\\end{exe}" return pf.RawBlock(latex, format='latex')
def fenced_blockquote(options, data, element, doc, language): values = { 'language': language, 'mintedopts': '', 'caption': '', 'identifier': '', 'text': data } caption = options.get('caption') if caption: converted_caption = pf.convert_text(caption, extra_args=['--biblatex'], input_format='markdown', output_format='latex') values['caption'] = r'\caption{{{}}}'.format(converted_caption) identifier = options.get('identifier') if identifier: values['identifier'] = r'\label{{{}}}'.format(identifier) mintedopts = options.get('mintedopts', '') if mintedopts: values['mintedopts'] = r'[{}]'.format(mintedopts) tex = TEMPLATE_CODEBLOCK.safe_substitute(values) return pf.RawBlock(tex, format='latex')
def _test_content_box(self, handler, element_classes, env_args=None): # some latex content in the environment elem_content = r""" \begin{itemize} \item{item1} \item{item2} \end{itemize} """ # should return a div with the given classes self.doc.content.extend([pf.RawBlock(elem_content, format="latex")]) elem = self.doc.content[0] # this sets up elem.parent div = handler(elem_content, env_args, elem) self.assertIsInstance(div, pf.Div) self.assertEqual(div.classes, element_classes) for cls in element_classes: with self.subTest(cls=cls): self.assertIn(cls, div.classes) # and the content of the environment should be parsed correctly bullet_list = div.content[0] self.assertIsInstance(bullet_list, pf.BulletList) self.assertEqual( bullet_list.content[0].content[0].content[0].content[0].text, "item1", ) return div
def test_handle_html(self): """html""" doc = pf.Doc(metadata={"lang": "en"}) html = r"""<p> <h3 class="start">Suitable browsers</h3> The following browsers can be used for the course: Firefox, Internet Explorer, Chrome, Safari, Opera.<br /> Some other browsers have difficulties rendering our unit pages correctly. <br /> We recommend using only the fully updated latest versions of these browsers. In particular, the course cannot be completed with obsolete browsers such as Internet Explorer 8 or earlier. </p>""" elem_content = r"\\begin{{html}}\n{}\n\\end{{html}}" "".format(html) doc.content.extend([pf.RawBlock(elem_content, format="latex")]) elem = doc.content[0] # this sets up elem.parent ret = self.environments.handle_html(html, [], elem) header = ret[0] self.assertIsInstance(header, pf.Header) self.assertEqual(header.content[0].text, "Suitable") self.assertEqual(header.content[2].text, "browsers") para = ret[1] self.assertIsInstance(para, pf.Para) self.assertEqual(len(para.content), 107) self.assertEqual(para.content[106].text, "earlier.")
def test_handle_mxinfo_math_title(self): """MXInfo with Math in title""" doc = pf.Doc(metadata={"lang": "en"}) elem_content = r""" \begin{MXInfo}{Ableitung $x^n$} Foo bar \end{MXInfo} """ doc.content.extend([pf.RawBlock(elem_content, format="latex")]) elem = doc.content[0] # this sets up elem.parent ret = self.environments.handle_mxinfo("Foo bar", ["Ableitung $x^n$"], elem) self.assertIsInstance(ret, pf.Div) header = ret.content[0] self.assertIsInstance(header, pf.Header) self.assertIsInstance(header.content[0], pf.Str) self.assertEqual(header.content[0].text, "Ableitung") self.assertIsInstance(header.content[1], pf.Space) self.assertIsInstance(header.content[2], pf.Math) self.assertEqual(header.content[2].text, "x^n") self.assertEqual(header.content[2].format, "InlineMath") para = ret.content[1] self.assertIsInstance(para.content[0], pf.Str) self.assertEqual(para.content[0].text, "Foo") self.assertIsInstance(para.content[1], pf.Space) self.assertIsInstance(para.content[2], pf.Str) self.assertEqual(para.content[2].text, "bar")
def test_handle_mtest_section_title(self): """MTest""" doc = pf.Doc(metadata={"lang": "en"}) elem_content = r""" \begin{MTest}{Abschlusstest Kapitel \arabic{section}} Foo bar \end{MXContent}""" doc.content.extend([pf.RawBlock(elem_content, format="latex")]) elem = doc.content[0] # this sets up elem.parent ret = self.environments.handle_mtest( "Foo bar", [r"Abschlusstest Kapitel \arabic{section}"], elem) self.assertEqual(len(ret), 2) header = ret[0] self.assertIsInstance(header, pf.Header) self.assertEqual(pf.stringify(header), "Abschlusstest") para = ret[1] self.assertIsInstance(para.content[0], pf.Str) self.assertEqual(para.content[0].text, "Foo") self.assertIsInstance(para.content[1], pf.Space) self.assertIsInstance(para.content[2], pf.Str) self.assertEqual(para.content[2].text, "bar")