def handle_mnref(self, cmd_args, elem): r"""Handle ``\MNRef`` command. This command inserts a section link. """ target = cmd_args[0] return block_wrap( pf.Link(url=target, attributes={"data-mnref": "true"}), elem)
def handle_mref(self, cmd_args, elem): r"""Handle ``\MRef`` command. This command translates to ``\vref``. """ url = "#%s" % cmd_args[0] return block_wrap(pf.Link(url=url, attributes={"data-mref": "true"}), elem)
def table_links(elem, doc): if isinstance(elem, pf.Str): text = pf.stringify(elem) if str_is_table_link.search(text): label = str_is_table_link.search(text).group(1) return pf.Link(pf.Str(label), url=label, classes=["table_note"])
def header(elem, doc): if not isinstance(elem, pf.Header): return None if elem.identifier == 'bibliography': elem.classes.remove('unnumbered') elem.content.append( pf.Link(url='#{}'.format(elem.identifier), classes=['self-link']))
def handle_mextlink(self, cmd_args, elem): r"""Handle ``\MExtLink`` command. This command inserts an external link. """ url = cmd_args[0] text = destringify(cmd_args[1]) link = pf.Link(*text, url=url) return block_wrap(link, elem)
def finalize(doc): try: filepath = doc.get_metadata('filepath') label = 'Link' except: filepath = '' label = 'No link' doc.content.insert(0, pf.Para(pf.Link(pf.Str(label), url=filepath))) return doc
def handle_msref(self, cmd_args, elem): r"""Handle ``\MSRef`` command. This command inserts a fragment-style link. """ url = "#%s" % cmd_args[0] description = destringify(cmd_args[1]) return block_wrap( pf.Link(*description, url=url, attributes={"data-msref": "true"}), elem, )
def parse_abbreviations(elem, doc): if hasattr(elem, "text") and is_abbreviation.search(elem.text): # text = pf.stringify(elem) text = elem.text content = [] logger.debug(f"Original element: {elem}") for s, c in utils.re_split(is_abbreviation, text): logger.debug(f"re_plit of {text} gave {s} > {c}") content.append(s) if c: pl = "1" if elem.text.startswith("++") else "" c = c.split("@") if len(c) > 1: specifier = c.pop(0) else: specifier = "" identifier = c.pop(0) uppercase = "1" if identifier[ 0] in string.ascii_uppercase else "" # Now we know whether it's uppercase identifier = identifier.lower() if (identifier not in doc.abbr["aliases"] and identifier[-1] == "s" and not pl and identifier[:-1] in doc.abbr["aliases"]): identifier = identifier[:-1] pl = "1" identifier = doc.abbr["aliases"].get(identifier, identifier) doc.abbr["used"].append(identifier) attributes = { "identifier": identifier, "plural": pl, "uppercase": uppercase, "specifier": specifier, } content.append( pf.Link(pf.Str(identifier), classes=["abbr"], attributes=attributes)) return pf.Span(*content)
def handle_myoutubevideo(self, cmd_args, elem): r"""Handle ``\MYoutubeVideo``. Just return a Link Element. """ title, _, _, url = cmd_args link = pf.Link( *destringify(title), url=url, title=title, classes=ELEMENT_CLASSES["MYOUTUBE_VIDEO"], ) return block_wrap(link, elem)
def getgitlink(elem_in, elem_out, linkstr=''): for i in elem_in.content: istr = pf.stringify(i) if linkstr or istr[:2] == '[[': linkstr += istr # is the link complete? if linkstr[-2:] == ']]': link = linkstr[2:-2].split('|') elem_out.content.append( pf.Link(pf.Str(link[0]), url=link[-1] + '.html')) linkstr = '' else: elem_out.content.append(i) return linkstr
def handle_mvideo(self, cmd_args, elem): r"""Handle ``\MVideo``. Just return a Link Element. """ filename = "{}.mp4".format(cmd_args[0]) title = cmd_args[1] link = pf.Link( *destringify(title), url=filename, title=title, classes=ELEMENT_CLASSES["MVIDEO"], ) remember(elem.doc, "label", link) return block_wrap(link, elem)
def action ( elem,doc ) : """ action of filter, get all equations with class and ref them """ if isinstance(elem,pf.Header): doc.heq.incHeader(elem.level) if isinstance(elem,pf.Para) and has_eq(elem) and len(elem.content) > 1 : doc.heq.n += 1 doc.heq.elemToId(elem) doc.backmatter.append( doc.heq.itself() ) eq = elem.content[0] anchor = pf.Link(identifier=doc.heq.label(),url=doc.heq.url(),classes=["eq"]) return pf.Para(eq,anchor)
def _table_links(elem, doc): table_note_prefix = doc.table_note_prefix if isinstance(elem, pf.Str): text = pf.stringify(elem) match = TABLE_LINK.search(text) if match: label = match.group("label") label = _num_label_to_symbol(label) label = _format_label(label) if doc.format == "latex": return pf.RawInline(f"\\tnotex{{{table_note_prefix}:{label}}}", format="latex") else: return pf.Link(pf.Str(label), url=label, classes=["table_note"])
def action(elem, doc): global section nameref = "\\nameref{" if isinstance(elem, pf.RawInline ) and elem.format == 'tex' and elem.text.startswith(nameref): # get the ref out of the text (turns "\nameref{header}" into "header"): section_id = elem.text[len(nameref):-1] # find *any* element that has an ID that matches the one we just extracted def matches_id(elem, doc): global section if hasattr(elem, 'identifier') and elem.identifier == section_id: section = elem doc.walk(matches_id) # Make a link to that section link = pf.Link(pf.Str(pf.stringify(section)), url=f"#{section_id}") section = None return link
def formatCell(text): if len(text) < 10 or text.isdigit(): return pf.Plain(pf.Str(text)) try: text = float(text) if text > 0 and text < .001: return pf.Plain(pf.Str('%.3E' % text)) return pf.Plain(pf.Str('%.3f' % text)) except (ValueError, TypeError): # transform links elems = [] lastend = None for m in re.finditer(r'\[(.+?)\]\((.+?)\)', text): if lastend is None: elems.append(pf.Str(text[:m.start()])) else: elems.append(pf.Str(text[lastend:m.start()])) elems.append(pf.Link(pf.Str(m.group(1)), url = m.group(2))) lastend = m.end() if elems: elems.append(pf.Str(text[lastend:])) return pf.Plain(*elems) return pf.Plain(pf.Str(text))
def fenced_action(options, data, element, doc): # We'll only run this for CodeBlock elements of class 'table' caption = options.get('caption', 'Untitled Table') #caption = [pf.Str(caption)] filepath = options.get('file') has_header = options.get('header', True) width = options.get('width', 1) total_width = float(options.get('total_width', .8)) align = options.get('align', 'default') nrows = options.get('rows', 0) ncols = options.get('cols', 0) csvargs = options.get('csvargs', {}) dtargs = options.get('dtargs', {}) mediadir = doc.get_metadata('mediadir') csvargs['dialect'] = csvargs.get('dialect', "unix") csvargs['delimiter'] = csvargs.get('delimiter', "\t").encode().decode('unicode_escape') f = io.StringIO(data) if data else open(filepath) try: reader = csv.reader(f, **csvargs) body = [] for i, row in enumerate(reader): if nrows and i > nrows: continue cells = [ pf.TableCell(formatCell(x)) for k, x in enumerate(row) if not ncols or k < ncols] body.append(pf.TableRow(*cells)) finally: f.close() ncols = min(ncols, len(row)) if ncols else len(row) if has_header: header = body.pop(0) if body and len(body[0].content) == len(header.content) + 1: header.content.insert(0, pf.TableCell(pf.Plain(pf.Str('')))) elif nrows: header = None body = body[:nrows] if not isinstance(width, list): width = [width] if len(width) == 1 and ncols: width = width * ncols sumwidth = float(sum(width)) total_width = min(total_width, 1) width = [float(wid)*float(total_width)/sumwidth for wid in width] if not isinstance(align, list): align = [align] if len(align) == 1 and ncols: align = align * ncols align = ['Align' + al.capitalize() for al in align] if mediadir and filepath: # copy file to mediadir and check if file exists filepath = Path(filepath) mediadir = Path(mediadir) mediadir.mkdir(exist_ok = True, parents = True) destfile = mediadir / filepath.name destfile = _copyfile(filepath, destfile) caption = [pf.Link( pf.Str(caption), url = str(destfile.relative_to(destfile.parent.parent)), title = 'Right clink and "Save link as" to download whole table.', attributes = {'target': '_blank'})] else: caption = [pf.Str(caption)] table = pf.Table(*body, header=header, caption=caption, width=width, alignment = align) if dtargs is False: return pf.Div(table, classes = ['tablewrapper']) else: return pf.Div(table, classes = ['tablewrapper', 'datatablewrapper'], attributes = { 'data-datatable': json.dumps(dtargs) })
def render_abbreviations(elem, doc): if isinstance(elem, pf.Link) and "abbr" in elem.classes: identifier = elem.attributes["identifier"] uppercase = elem.attributes["uppercase"] plural = elem.attributes["plural"] specifier = elem.attributes["specifier"] if identifier not in doc.abbr["definitions"]: return pf.Str(identifier) else: abbr = doc.abbr["definitions"][identifier] short = abbr[0] long_ = abbr[1] description = long_.title() # needed later for definition liat options = abbr[2] if doc.format == "latex": if identifier not in doc.abbr["rendered"]: doc.abbr["rendered"].append(identifier) pl = "pl" if plural else "" gls = "Gls" if uppercase else "gls" specifier = f"xtr{specifier}" if specifier else specifier raw = pf.RawInline(f"\\{gls}{specifier}{pl}{{{identifier}}}", format="latex") return raw else: category = options.get("category") if uppercase: short = short.upper() long_ = long_.title() if plural: short = pluralize.plural(short) long_ = pluralize.plural(long_) if identifier not in doc.abbr["rendered"]: text = f"{long_} ({short})" if category == "alwaysshort": text = short elif category == "nevershort": text = long_ definition_item = pf.Span(pf.Str(short), identifier=f"abbr:{identifier}") definition_description = pf.Para(pf.Str(description)) if not options.get("type") == "ignored": doc.abbr["appendix"].append(( identifier, pf.DefinitionItem( [definition_item], [pf.Definition(definition_description)], ), )) doc.abbr["rendered"].append(identifier) else: text = short if category == "nevershort": text = long_ return pf.Link(pf.Str(text), url=f"#abbr:{identifier}", title=long_)
def convert(self): doc = panflute.Doc( api_version=(1, 17, 5), metadata={ 'pagetitle': self.title, }, ) doc.content.append(panflute.Header(panflute.Str(self.title))) lists = {} tables = {} table_rows = {} table_cells = {} for chunk in self._attr_chunks(): self.logger.debug(chunk) container = panflute.Para() cdiv = panflute.Div(container) # Handle lists if 'list_class' in chunk[0]['attrs']: lc = chunk[0]['attrs']['list_class'] check_state = None if lc in ['checked', 'unchecked']: check_state = lc lc = 'checklist' ld = chunk[0]['attrs']['list_depth'] # prune any lists that are lower than us, they're finished for i in list(lists.keys()): if i > ld: lists.pop(i) # non-homogenous list types can be immediately adjacent without # ending up merged if ld in lists and lists[ld]['class'] != lc: lists.pop(ld) # checklists are a special case, they can't contain other lists if lc != 'checklist' and lists and lists[1][ 'class'] == 'checklist': lists = {} # make sure any intermediate lists were created, including # the top level because boxnotes for i in range(1, ld + 1): if i not in lists: lists[i] = self._list(lc, i) if i != ld: lists[i]['pf'].content.append(panflute.ListItem()) lp = lists[i]['pf'] if lc == 'checklist': lp = panflute.Div(lp, classes=['checklist']) if i == 1: doc.content.append(lp) else: lists[i - 1]['pf'].content[-1].content.append(lp) # set the container for the other subchunks container = panflute.Plain() cdiv.content = [container] cdiv.classes.append(lc) if check_state: cdiv.classes.append(check_state) lists[ld]['pf'].content.append(panflute.ListItem(cdiv)) if check_state == 'checked': container.content.append(panflute.Str(CHECKED)) elif check_state == 'unchecked': container.content.append(panflute.Str(UNCHECKED)) elif 'table_id' in chunk[-1]['attrs']: table_id = chunk[-1]['attrs']['table_id'] row_id = chunk[-1]['attrs']['table_row'] cell_id = row_id + chunk[-1]['attrs']['table_col'] if table_id not in tables: # There's some magic in the constructor for panflute tables # that isn't exposed in any other way, so we can't create # the table until we've finished populating the rows. # Instead, use a placeholder div to locate it within the # document. tables[table_id] = { 'div': panflute.Div(), 'rows': [], } doc.content.append(tables[table_id]['div']) if row_id not in table_rows: table_rows[row_id] = panflute.TableRow() tables[table_id]['rows'].append(table_rows[row_id]) if cell_id not in table_cells: cdiv = panflute.Div(panflute.Plain()) table_cells[cell_id] = panflute.TableCell(cdiv) table_rows[row_id].content.append(table_cells[cell_id]) container = table_cells[cell_id].content[0].content[0] else: lists = {} doc.content.append(cdiv) if 'align' in chunk[0]['attrs']: cdiv.attributes['style'] = 'text-align: ' + chunk[0]['attrs'][ 'align'] + ';' for subchunk in chunk: if subchunk['newlines'] > 1: # we've had an extra linebreak, no more adding on to lists lists = {} # don't do anything with markers if subchunk['text'] == '*' and 'lmkr' in subchunk['attrs']: continue scont = container if 'href' in subchunk['attrs']: scont = panflute.Link(url=subchunk['attrs']['href']) container.content.append(scont) if 'image' in subchunk['attrs']: scont.content.append( panflute.Image( url=self._image(subchunk['attrs']['author'], subchunk['attrs']['image']))) continue span = panflute.Span() lines = subchunk['text'].splitlines() while lines: subtext = lines.pop(0) span.content.append(panflute.Str(subtext)) if lines: span.content.append(panflute.LineBreak()) if 'font' in subchunk['attrs']: color = subchunk['attrs']['font'].get('color', '000000') size = subchunk['attrs']['font'].get('size', 'medium') span.classes.append('font-size-' + size) span.classes.append('font-color-' + color) # I don't actually know what the possible colors are and I # don't feel like finding out, so just inject it as an # inline style. if color != '000000': span.attributes['style'] = 'color: #' + color + ';' if subchunk['attrs'].get('underline'): span.classes.append('underline') if subchunk['attrs'].get('bold'): span = panflute.Strong(span) if subchunk['attrs'].get('italic'): span = panflute.Emph(span) if subchunk['attrs'].get('strikethrough'): span = panflute.Strikeout(span) scont.content.append(span) # Actually create the tables for x in tables: tables[x]['div'].content.append(panflute.Table(*tables[x]['rows'])) with io.StringIO() as f: panflute.dump(doc, f) return f.getvalue()
def toLink(self): return pf.Link(pf.Str(self.label()),url=self.url(),classes=["aeq"])
def header(elem, doc): if not isinstance(elem, pf.Header): return None elem.content.append( pf.Link(url='#{}'.format(elem.identifier), classes=['self-link']))
def divspan(elem, doc): """ Non-code diffs: `add` and `rm` are classes that can be added to a `Div` or a `Span`. `add` colors the text with `addcolor` and `rm` colors the text `rmcolor`. For `Span`s, `add` underlines and `rm` strikes out the text. # Example ## `Div` Unchanged portion ::: add New paragraph > Quotes More new paragraphs ::: ## `Span` > The return type is `decltype(`_e_(`m`)`)` [for the first form]{.add}. """ def _wrap(opening, closing): if isinstance(elem, pf.Div): if elem.content and isinstance(elem.content[0], pf.Para): elem.content[0].content.insert(0, opening) else: elem.content.insert(0, pf.Plain(opening)) if elem.content and isinstance(elem.content[-1], pf.Para): elem.content[-1].content.append(closing) else: elem.content.append(pf.Plain(closing)) elif isinstance(elem, pf.Span): elem.content.insert(0, opening) elem.content.append(closing) def _color(html_color): _wrap(pf.RawInline('{{\\color[HTML]{{{}}}'.format(html_color), 'latex'), pf.RawInline('}', 'latex')) elem.attributes['style'] = 'color: #{}'.format(html_color) def _nonnormative(name): _wrap(pf.Span(pf.Str('[ '), pf.Emph(pf.Str('{}:'.format(name.title()))), pf.Space), pf.Span(pf.Str(' — '), pf.Emph(pf.Str('end {}'.format(name.lower()))), pf.Str(' ]'))) 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 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 example(): _nonnormative('example') def note(): _nonnormative('note') def ednote(): _wrap(pf.Str("[ Editor's note: "), pf.Str(' ]')) _color('0000ff') def add(): _diff('addcolor', 'uline', 'ins') def rm(): _diff('rmcolor', 'sout', 'del') if not any(isinstance(elem, cls) for cls in [pf.Div, pf.Span]): return None if 'pnum' in elem.classes and isinstance(elem, pf.Span): return pnum() if 'sref' in elem.classes and isinstance(elem, pf.Span): target = pf.stringify(elem) number = stable_names.get(target) link = pf.Link( pf.Str('[{}]'.format(target)), url='https://wg21.link/{}'.format(target)) if number is not None: return pf.Span(pf.Str(number), pf.Space(), link) else: pf.debug('mpark/wg21: stable name', target, 'not found') return link note_cls = next(iter(cls for cls in elem.classes if cls in {'example', 'note', 'ednote'}), None) if note_cls == 'example': example() elif note_cls == 'note': note() elif note_cls == 'ednote': ednote(); return diff_cls = next(iter(cls for cls in elem.classes if cls in {'add', 'rm'}), None) if diff_cls == 'add': add() elif diff_cls == 'rm': rm()
def Image_to_Link(elem, doc): if type(elem) == pf.Image: text = elem.content url = elem.url return pf.Link(*text, url=url)