def table_matrix_to_pf(matrix, doc): options = matrix[0] t_kwargs = options caption = matrix[1] table = matrix[2] footnotes = [i for i in list_to_elems([matrix[3]])] row_cnt = len(table) rows = [] new_col_cnt = 0 old_col_cnt = None for r, row in enumerate(table): cells = [] r_kwargs = row[1] for c, cell in enumerate(row[0]): if isinstance(cell, tuple): c_args = cell[0] c_kwargs = cell[1] col_span = utils.check_type(c_kwargs.get("col_span", 1), int) repeat = 1 if "repeat" in c_kwargs: repeat = utils.check_type(c_kwargs.get("repeat", 1), int) del c_kwargs["repeat"] for _ in range(repeat): new_col_cnt += 1 cells.append(TableCell(*list_to_elems(c_args), **c_kwargs)) for i in range(1, col_span): new_col_cnt += 1 cells.append(TableCell(pf.Null(), covered=True)) else: new_col_cnt += 1 cells.append(TableCell(*list_to_elems([cell]))) if old_col_cnt is None: old_col_cnt = new_col_cnt if new_col_cnt != old_col_cnt: raise IndexError(f"Expected {old_col_cnt} columns " f"but got {new_col_cnt} in {row}") new_col_cnt = 0 rows.append(TableRow(*cells, **r_kwargs)) if caption: t_kwargs["caption"] = [pf.Span(pf.Str(caption))] return pf.Div( Table(*rows, col_cnt=old_col_cnt, row_cnt=row_cnt, **t_kwargs), *footnotes, classes=["custom_table"], )
def finalize(doc): if doc.backmatter: doc.replacement_ok = False backmatter = pf.Div(*doc.backmatter, identifier='backmatter') pf.replace_keyword(doc, '$backmatter', backmatter) assert doc.replacement_ok, "Couldn't replace '$backmatter'" else: pf.replace_keyword(doc, '$backmatter', pf.Null())
def action(table, doc): if not isinstance(table, pf.Div) or 'tonytable' not in table.classes: return None rows = [] kwargs = {} headers = [] widths = [] examples = [] header = pf.Null() width = 0 table.content.append(pf.HorizontalRule()) for elem in table.content: if isinstance(elem, pf.Header): header, width = build_header(elem) elif isinstance(elem, pf.CodeBlock): headers.append(header) widths.append(width) header = pf.Null() width = 0 examples.append(build_code(elem, doc.format)) elif isinstance(elem, pf.HorizontalRule) and examples: if not all(isinstance(header, pf.Null) for header in headers): rows.append(build_row(headers)) if 'width' not in kwargs: kwargs['width'] = widths rows.append(build_row(examples)) headers = [] widths = [] examples = [] else: pf.debug("[Warning] The following is ignored by a Tony Table:", pf.stringify(elem)) return pf.Table(*rows, **kwargs)
def cmptable(table, doc): """ Comparison Tables: Code blocks are the first-class entities that get added to the table. Each code block is pushed onto the current row. A horizontal rule (`---`) is used to move to the next row. In the first row, the last header (if any) leading upto the i'th code block is the header for the i'th column of the table. The last block quote (if any) is used as the caption. # Example ::: cmptable > compare inspect of unconstrained and constrained types ### Before ```cpp std::visit([&](auto&& x) { strm << "got auto: " << x; }, v); ``` ### After ```cpp inspect (v) { <auto> x: strm << "got auto: " << x; } ``` --- ```cpp std::visit([&](auto&& x) { using X = std::remove_cvref_t<decltype(x)>; if constexpr (C1<X>()) { strm << "got C1: " << x; } else if constexpr (C2<X>()) { strm << "got C2: " << x; } }, v); ``` ```cpp inspect (v) { <C1> c1: strm << "got C1: " << c1; <C2> c2: strm << "got C2: " << c2; } ``` ::: # Generates Table: compare inspect of unconstrained and constrained types +------------------------------------------------+---------------------------------------------+ | __Before__ | __After__ | +================================================+=============================================+ | ```cpp | ```cpp | | std::visit([&](auto&& x) { | inspect (v) { | | strm << "got auto: " << x; | <auto> x: strm << "got auto: " << x; | | }, v); | } | | | ``` | +------------------------------------------------+---------------------------------------------+ | std::visit([&](auto&& x) { | ```cpp | | using X = std::remove_cvref_t<decltype(x)>; | inspect (v) { | | if constexpr (C1<X>()) { | <C1> c1: strm << "got C1: " << c1; | | strm << "got C1: " << x; | <C2> c2: strm << "got C2: " << c2; | | } else if constexpr (C2<X>()) { | } | | strm << "got C2: " << x; | ``` | | } | | | }, v); | | +------------------------------------------------+---------------------------------------------+ """ if not isinstance(table, pf.Div): return None if not any(cls in table.classes for cls in ['cmptable', 'tonytable']): return None rows = [] kwargs = {} headers = [] widths = [] examples = [] header = pf.Null() caption = None width = 0 first_row = True table.content.append(pf.HorizontalRule()) def warn(elem): pf.debug('mpark/wg21:', type(elem), pf.stringify(elem, newlines=False), 'in a comparison table is ignored') for elem in table.content: if isinstance(elem, pf.Header): if not isinstance(header, pf.Null): warn(header) if first_row: header = pf.Plain(*elem.content) width = float(elem.attributes['width']) if 'width' in elem.attributes else 0 else: warn(elem) elif isinstance(elem, pf.BlockQuote): if caption is not None: warn(caption) caption = elem elif isinstance(elem, pf.CodeBlock): if first_row: headers.append(header) widths.append(width) header = pf.Null() width = 0 examples.append(elem) elif isinstance(elem, pf.HorizontalRule) and examples: first_row = False rows.append(pf.TableRow(*[pf.TableCell(example) for example in examples])) examples = [] else: warn(elem) if not all(isinstance(header, pf.Null) for header in headers): kwargs['header'] = pf.TableRow(*[pf.TableCell(header) for header in headers]) if caption is not None: kwargs['caption'] = caption.content[0].content kwargs['width'] = widths return pf.Table(*rows, **kwargs)
def tonytable(table, doc): """ Tony Tables: CodeBlocks are the first-class entities that get added to the table. The last (if any) header leading upto a CodeBlock is the header that gets attached to the table cell with the CodeBlock. Each CodeBlock entry is pushed onto the current row. Horizontal rule is used to move to the next row. # Example ::: tonytable ### Before ```cpp std::visit([&](auto&& x) { strm << "got auto: " << x; }, v); ``` ### After ```cpp inspect (v) { <auto> x: strm << "got auto: " << x; } ``` --- ```cpp std::visit([&](auto&& x) { using X = std::remove_cvref_t<decltype(x)>; if constexpr (C1<X>()) { strm << "got C1: " << x; } else if constexpr (C2<X>()) { strm << "got C2: " << x; } }, v); ``` ```cpp inspect (v) { <C1> c1: strm << "got C1: " << c1; <C2> c2: strm << "got C2: " << c2; } ``` ::: # Generates +------------------------------------------------+-------------------------------------------------+ | __Before__ | __After__ | +------------------------------------------------+-------------------------------------------------+ | ```cpp | ```cpp | | std::visit([&](auto&& x) { | inspect (v) { | | strm << "got auto: " << x; | <auto> x: strm << "got auto: " << x; | | }, v); | } | | | ``` | +------------------------------------------------+-------------------------------------------------+ | std::visit([&](auto&& x) { | ```cpp | | using X = std::remove_cvref_t<decltype(x)>; | inspect (v) { | | if constexpr (C1<X>()) { | <C1> c1: strm << "got C1: " << c1; | | strm << "got C1: " << x; | <C2> c2: strm << "got C2: " << c2; | | } else if constexpr (C2<X>()) { | } | | strm << "got C2: " << x; | ``` | | } | | | }, v); | | +------------------------------------------------+-------------------------------------------------+ """ 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 build_code(elem, format): if (format != 'gfm'): return elem lang = ' lang="{}"'.format(elem.classes[0]) if elem.classes else '' code = html.escape(elem.text) return pf.RawBlock('\n\n<pre{lang}>\n{code}\n</pre>'.format(lang=lang, code=code)) def build_row(elems): return pf.TableRow(*[pf.TableCell(elem) for elem in elems]) if not isinstance(table, pf.Div) or 'tonytable' not in table.classes: return None rows = [] kwargs = {} headers = [] widths = [] examples = [] header = pf.Null() width = 0 table.content.append(pf.HorizontalRule()) for elem in table.content: if isinstance(elem, pf.Header): header, width = build_header(elem) elif isinstance(elem, pf.CodeBlock): headers.append(header) widths.append(width) header = pf.Null() width = 0 examples.append(build_code(elem, doc.format)) elif isinstance(elem, pf.HorizontalRule) and examples: if not all(isinstance(header, pf.Null) for header in headers): rows.append(build_row(headers)) if 'width' not in kwargs: kwargs['width'] = widths rows.append(build_row(examples)) headers = [] widths = [] examples = [] else: pf.debug("[Warning] The following is ignored by a Tony Table:", pf.stringify(elem)) return pf.Table(*rows, **kwargs)