def afterframe(s): global lastsection, lastsubsection return [ pf.Header(1, ('', ['unnumbered'], []), [pf.Str(lastsection)]), pf.Header(2, ('', ['unnumbered'], []), [pf.Str(lastsubsection)]), lb(s) ]
def figure_replacement(self, key, value, format, metadata): """Replace figures with appropriate representation. This works with Figure, which is our special type for images with attributes. This allows us to set an id in the attributes. The other way of doing it would be to pull out a '\label{(.*)}' from the caption of an Image and use that to update the references. """ caption, (filename, alt), attr = value if 'unnumbered' in attr[1]: fcaption = caption else: self.fig_replacement_count += 1 if not attr[0]: attr[0] = self.auto_fig_id(self.fig_replacement_count) ref = self.references[attr[0]] if caption: fcaption = [ pf.Str('Figure'), pf.Space(), pf.Str(str(ref['id']) + ':'), pf.Space() ] + caption else: fcaption = [ pf.Str('Figure'), pf.Space(), pf.Str(str(ref['id'])) ] # if 'figure' not in attr[1]: # # FIXME: Currently adding this in html_figure() and html5_figure() # attr[1].append('figure') if format == 'latex' or format == 'beamer': return latex_figure(attr, filename, caption, alt) elif format == 'html': return html_figure(attr, filename, fcaption, alt) elif format == 'html5': return html5_figure(attr, filename, fcaption, alt) elif format == 'markdown': return markdown_figure(attr, filename, fcaption, alt) else: image = pf.Image(attr, fcaption, (filename, alt)) return pf.Para([image])
def suit_symbols(key, value, fmt, meta): if key == 'Str': abbrevs = ['!C', '!D', '!H', '!S', '!N'] orig_value = value if fmt != 'latex': suit_html = ['<font color=green>♣</font>', '<font color=orange>♦</font>', '<font color=red>♥</font>', '<font color=blue>♠</font>', 'N'] suit_other = ['C', 'D', 'H', 'S', 'N'] suit_symbols = suit_html if fmt == 'html' else suit_other for (abbrev, symbol) in zip(abbrevs, suit_symbols): value = value.replace(abbrev, symbol) else: # LaTeX needs special handling (for mbox) value = value.replace('!N', 'N') suit = ['\\clubs{\\1}{\\2}', '\\diamonds{\\1}{\\2}', '\\hearts{\\1}{\\2}', '\\spades{\\1}{\\2}'] for (abbrev, symbol) in zip(abbrevs, suit): value = re.sub('([a-zA-Z0-9]*)%s([a-zA-Z0-9]*)' % abbrev, symbol, value) if (fmt == 'html' or fmt == 'latex') and value != orig_value: return pf.RawInline(fmt, value) return pf.Str(value) else: return None
def process_buffer(buffer, new_value, item=None): if buffer: text = ''.join(buffer) try: translated_text = translate.translate(text) except TypeError: translated_text = text except json.decoder.JSONDecodeError as e: print('Failed to translate', str(e), file=sys.stderr) sys.exit(1) debug(f'Translate: "{text}" -> "{translated_text}"') if text and text[0].isupper() and not translated_text[0].isupper(): translated_text = translated_text[0].upper() + translated_text[1:] if text.startswith(' ') and not translated_text.startswith(' '): translated_text = ' ' + translated_text if text.endswith(' ') and not translated_text.endswith(' '): translated_text = translated_text + ' ' for token in translated_text.split(' '): new_value.append(pandocfilters.Str(token)) new_value.append(pandocfilters.Space()) if item is None and len(new_value): new_value.pop(len(new_value) - 1) else: new_value[-1] = item elif item: new_value.append(item)
def result(self): 'return FCB, Para(url()) and/or CodeBlock(stdout) as ordered' rv = [] enc = sys.getdefaultencoding() # result always unicode for output_elm in self.im_out: if output_elm == 'img': if os.path.isfile(self.outfile): rv.append(pf.Para([self.url()])) else: msg = '?? missing %s' % self.outfile self.msg(1, '>>:', msg) rv.append(pf.Para([pf.Str(msg)])) elif output_elm == 'fcb': rv.append(self.anon_codeblock()) elif output_elm == 'stdout': if self.stdout: attr = ['', self.classes, self.keyvals] rv.append(pf.CodeBlock(attr, to_str(self.stdout, enc))) else: self.msg(1, '>>:', 'stdout requested, but saw nothing') elif output_elm == 'stderr': if self.stderr: attr = ['', self.classes, self.keyvals] rv.append(pf.CodeBlock(attr, to_str(self.stderr, enc))) else: self.msg(1, '>>:', 'stderr requested, but saw nothing') if not rv: return None # no results; None keeps original FCB if len(rv) > 1: return rv # multiple results return rv[0] # just 1 block level element
def create_pandoc_multilink(strings, refs): inlines = [[pf.Str(str(s))] for s in strings] targets = [(r, "") for r in refs] links = [pf.Link(inline, target) for inline, target in zip(inlines, targets)] return join_items(links)
def render(self, watcher, inline): result = [] betweenframes = False for i, f in enumerate(self._filenames): anim = self._anims[i] [options, slide] = self._mangleoptions(self._options[i]) if slide: result.append( li('\\slidefig{%s}{%s}' % ('<' + anim + '>' if len(anim) > 0 else '', f))) betweenframes = True continue if i == 0 and len(self._caption) > 0: result.append(li('\\begin{%s}\n' % self._figtype)) if i == 0 and len(self._caption) == 0 and not inline: result.append(li('{\\centering')) result.append(fig(f, options, anim)) if i + 1 == len(self._filenames) and len(self._caption) > 0: result.extend([li('\\caption{'), li(self._caption), li('}\n')]) result.append(li('\\end{%s}' % self._figtype)) if i + 1 == len(self._filenames) and len( self._caption) == 0 and not inline: result.append(li('\par}')) if inline: if betweenframes: return pf.Str('Unable to return paragraph when in inline mode') return result result = pf.Para(result) return watcher.betweenframes(result) if betweenframes else result
def hand_diagram(hand): void = '--' hold = [x if len(x) > 0 else void for x in hand.split(',')] suit = ['!S', '!H', '!D', '!C'] suits = [pf.Str(s + h) for s, h in zip(suit, hold)] res = sum(([x, pf.LineBreak()] for x in suits), [])[:-1] return pf.Plain(res)
def convert_internal_refs(self, key, value, format, metadata): """Convert all internal links from '#blah' into format specified in self.replacements. """ if key != 'Cite': return None citations, inlines = value if len(citations) > 1: ''' Note: Need to check that *all* of the citations in a multicitation are in the reference list. If not, the citation is bibliographic, and we want LaTeX to handle it, so just return unmodified. ''' for citation in citations: if citation['citationId'] not in self.references: return return self.convert_multiref(key, value, format, metadata) else: citation = citations[0] prefix = pf.stringify(citation['citationPrefix']) suffix = pf.stringify(citation['citationSuffix']) if prefix: prefix += ' ' label = citation['citationId'] if label not in self.references: return rtype = self.references[label]['type'] n = self.references[label]['id'] text = self.replacements[rtype].format(n) if format == 'latex' and self.autoref: link = u'{pre}\\autoref{{{label}}}{post}'.format(pre=prefix, label=label, post=suffix) return pf.RawInline('latex', link) elif format == 'latex' and not self.autoref: link = u'{pre}\\ref{{{label}}}{post}'.format(pre=prefix, label=label, post=suffix) return pf.RawInline('latex', link) else: link_text = '{}{}{}'.format(prefix, text, suffix) link = pf.Link([pf.Str(link_text)], ('#' + label, '')) return link
def include_filter(k, v, f, m): if k == 'Div': [[ident, classes, attrs], content] = v if 'include' in classes: with open(ident, 'r') as f: content = f.read() if 'code' in classes: return pf.CodeBlock( (ident, [get_attr_in_list(attrs, 'language')], []), content) else: return [pf.Para([pf.Str(content)])]
def convert_internal_refs(self, key, value, format, metadata): """Convert all internal links from '#blah' into format specified in self.replacements. """ if key != 'Cite': return None citations, inlines = value if len(citations) > 1: ''' Note: Need to check that *all* of the citations in a multicitation are in the reference list. If not, the citation is bibliographic, and we want LaTeX to handle it, so just return unmodified. ''' for citation in citations: if citation['citationId'] not in self.references: return return self.convert_multiref(key, value, format, metadata) else: citation = citations[0] prefix = citation['citationPrefix'] suffix = citation['citationSuffix'] label = citation['citationId'] if label not in self.references: return if prefix: prefix += [pf.Space()] rtype = self.references[label]['type'] n = self.references[label]['id'] text = self.replacements[rtype].format(n) if format in ['latex', 'beamer'] and self.autoref: link = pf.RawInline('latex', '\\cref{{{label}}}'.format(label=label)) return prefix + [link] + suffix elif format in ['latex', 'beamer'] and not self.autoref: link = pf.RawInline('latex', '\\ref{{{label}}}'.format(label=label)) return prefix + [link] + suffix else: link = pf.Link(["", [], []], [pf.Str(text)], ('#' + label, '')) return prefix + [link] + suffix
def add_eq_number_and_id(fmt, value, num, labelName): num = str(num) outer = pf.RawInline( 'html', f'<span id="{labelName}" style="display: inline-block; position: relative; width: 100%;">' ) inner = pf.RawInline( 'html', '<span style="position: absolute; right: 0em; top: 50%; line-height: 0; ">' ) eqno = pf.Str('(%s)' % num) endtags = pf.RawInline('html', '</span></span>') return [outer, elt('Math', 2)(*value), inner, eqno, endtags]
def inline_hands(key, value, fmt, meta): if key == 'Code': hand = value[1] if hand.count(',') == 3 and len(hand) == 16: hold = hand.split(',') suit = ['!S', '!H', '!D', '!C'] res = ' '.join(s + (h if len(h) > 0 else '--') for s, h in zip(suit, hold)) return pf.Str(res) return None
def convert_multiref(self, key, value, format, metadata): """Convert all internal links from '#blah' into format specified in self.replacements. """ citations, inlines = value labels = [citation['citationId'] for citation in citations] if format in ['latex', 'beamer'] and self.autoref: link = self.latex_multi_autolink.format(pre='', post='', labels=','.join(labels)) return RawInline('latex', link) elif format in ['latex', 'beamer'] and not self.autoref: link = ''.join(create_latex_multilink(labels)) return RawInline('latex', link) else: D = [self.references[label] for label in labels] # uniquely ordered types types = list(OrderedDict.fromkeys(d['type'] for d in D)) links = [] for t in set(types): n = [d['id'] for d in D if d['type'] == t] labels = ['#' + d['label'] for d in D if d['type'] == t] multi_link = create_pandoc_multilink(n, labels) if len(labels) == 1: multi_link.insert(0, pf.Str(self.replacements[t].format(''))) else: multi_link.insert(0, pf.Str(self.multi_replacements[t])) links.append(multi_link) return join_items(links, method='extend')
def process_buffer(buffer, new_value, item=None, is_header=False): if buffer: text = ''.join(buffer) try: translated_text = translate.translate(text) except TypeError: translated_text = text except json.decoder.JSONDecodeError as e: print('Failed to translate', str(e), file=sys.stderr) sys.exit(1) debug(f'Translate: "{text}" -> "{translated_text}"') if text and text[0].isupper() and not translated_text[0].isupper(): translated_text = translated_text[0].upper() + translated_text[1:] if text.startswith(' ') and not translated_text.startswith(' '): translated_text = ' ' + translated_text if text.endswith(' ') and not translated_text.endswith(' '): translated_text = translated_text + ' ' if is_header and translated_text.endswith('.'): translated_text = translated_text.rstrip('.') title_case = is_header and translate.default_target_language == 'en' and text[ 0].isupper() title_case_whitelist = { 'a', 'an', 'the', 'and', 'or', 'that', 'of', 'on', 'for', 'from', 'with', 'to', 'in' } is_first_iteration = True for token in translated_text.split(' '): if title_case and token.isascii() and not token.isupper(): if len(token) > 1 and token.lower( ) not in title_case_whitelist: token = token[0].upper() + token[1:] elif not is_first_iteration: token = token.lower() is_first_iteration = False new_value.append(pandocfilters.Str(token)) new_value.append(pandocfilters.Space()) if item is None and len(new_value): new_value.pop(len(new_value) - 1) else: new_value[-1] = item elif item: new_value.append(item)
def figure_replacement(self, key, value, format, metadata): """Replace figures with appropriate representation. This works with Figure, which is our special type for images with attributes. This allows us to set an id in the attributes. The other way of doing it would be to pull out a '\label{(.*)}' from the caption of an Image and use that to update the references. """ _caption, (filename, target), attrs = value caption = pf.stringify(_caption) attr = PandocAttributes(attrs) if 'unnumbered' in attr.classes: star = '*' fcaption = caption else: self.fig_replacement_count += 1 if not attr.id: attr.id = self.auto_fig_id(self.fig_replacement_count) ref = self.references[attr.id] star = '' if caption: fcaption = u'Figure {n}: {caption}'.format(n=ref['id'], caption=caption) else: fcaption = u'Figure {n}'.format(n=ref['id']) if 'figure' not in attr.classes: attr.classes.insert(0, 'figure') if format in self.formats: figure = self.figure_styles[format].format(attr=attr, filename=filename, alt=fcaption, fcaption=fcaption, caption=caption, star=star).encode('utf-8') return RawBlock(format, figure) else: alt = [pf.Str(fcaption)] target = (filename, '') image = pf.Image(alt, target) figure = pf.Para([image]) return pf.Div(attr.to_pandoc(), [figure])
def tableattrs_replacement(self, key, value, format, metadata): """Replace TableAttrs with appropriate representation. TableAttrs is our special type for tables with attributes, allowing us to set an id in the attributes. """ caption, alignment, size, headers, rows, (id, classes, kvs) = value if 'unnumbered' in classes: fcaption = caption else: self.table_replacement_count += 1 if not id: id = self.auto_table_id(self.table_replacement_count) ref = self.references[id] if caption: fcaption = [ pf.Str('Table'), pf.Space(), pf.Str(str(ref['id']) + ':'), pf.Space() ] + caption else: fcaption = [ pf.Str('Table'), pf.Space(), pf.Str(str(ref['id'])) ] if format == 'latex' or format == 'beamer': return latex_table(caption, alignment, size, headers, rows, id, classes, kvs) else: return pf.Div([id, classes, kvs], [pf.Table(fcaption, alignment, size, headers, rows)])
def process_buffer(buffer, new_value, item=None, is_header=False): if buffer: text = ''.join(buffer) try: translated_text = translate.translate(text) except TypeError: translated_text = text except json.decoder.JSONDecodeError as e: print('Failed to translate', str(e), file=sys.stderr) sys.exit(1) debug(f'Translate: "{text}" -> "{translated_text}"') if text and text[0].isupper() and not translated_text[0].isupper(): translated_text = translated_text.capitalize() if text.startswith(' ') and not translated_text.startswith(' '): translated_text = ' ' + translated_text if text.endswith(' ') and not translated_text.endswith(' '): translated_text = translated_text + ' ' title_case = is_header and translate.default_target_language == 'en' and text[ 0].isupper() title_case_whitelist = {'a', 'an', 'the', 'and', 'or'} for token in translated_text.split(' '): if title_case and not token.isupper(): if token not in title_case_whitelist: token = token.capitalize() new_value.append(pandocfilters.Str(token)) new_value.append(pandocfilters.Space()) if item is None and len(new_value): new_value.pop(len(new_value) - 1) else: new_value[-1] = item elif item: new_value.append(item)
def section_replacement(self, key, value, format, metadata): """Replace sections with appropriate representation. """ level, attr, text = value label, classes, kvs = attr if 'unnumbered' in classes or not self.numbersections: pretext = '' else: ref = self.references[label] pretext = '{}. '.format(ref['id']) pretext = [pf.Str(pretext)] if format in ('html', 'html5', 'markdown'): return pf.Header(level, attr, pretext + text) elif format == 'latex' or format == 'beamer': # have to do this to get rid of hyperref return pf.Header(level, attr, text) else: return pf.Header(level, attr, pretext + text)
def translate_filter(key, value, _format, _): if key not in ['Space', 'Str']: debug(key, value) try: cls = getattr(pandocfilters, key) except AttributeError: return if key == 'Para' and value: marker = value[0].get('c') if isinstance(marker, str) and marker.startswith('!!!') and len(value) > 2: # Admonition case if marker != '!!!': # Lost space after !!! case value.insert(1, pandocfilters.Str(marker[3:])) value.insert(1, pandocfilters.Space()) value[0]['c'] = '!!!' admonition_value = [] remaining_para_value = [] in_admonition = True for item in value: if in_admonition: if item.get('t') == 'SoftBreak': in_admonition = False else: admonition_value.append(item) else: remaining_para_value.append(item) break_value = [ pandocfilters.LineBreak(), pandocfilters.Str(' ' * 4) ] if admonition_value[-1].get('t') == 'Quoted': text = process_sentence(admonition_value[-1]['c'][-1]) text[0]['c'] = '"' + text[0]['c'] text[-1]['c'] = text[-1]['c'] + '"' admonition_value.pop(-1) admonition_value += text else: text = admonition_value[-1].get('c') if text: text = translate(text[0].upper() + text[1:]) admonition_value.append(pandocfilters.Space()) admonition_value.append(pandocfilters.Str(f'"{text}"')) return cls(admonition_value + break_value + process_sentence(remaining_para_value)) else: return cls(process_sentence(value)) elif key == 'Plain' or key == 'Strong' or key == 'Emph': return cls(process_sentence(value)) elif key == 'Link': try: # Plain links case if value[2][0] == value[1][0].get('c'): return pandocfilters.Str(value[2][0]) except IndexError: pass value[1] = process_sentence(value[1]) return cls(*value) elif key == 'Header': # TODO: title case header in en if '_' not in value[1][0]: # Preserve some manually specified anchors value[1][0] = slugify.slugify(value[1][0], separator='-', word_boundary=True, save_order=True) value[2] = process_sentence(value[2]) return cls(*value) elif key == 'SoftBreak': return pandocfilters.LineBreak() return
def translate_filter(key, value, _format, _): if key not in ['Space', 'Str']: debug(key, value) try: cls = getattr(pandocfilters, key) except AttributeError: return if key == 'Para' and value: marker = value[0].get('c') if isinstance(marker, str) and marker.startswith('!!!') and len(value) > 2: # Admonition case if marker != '!!!': # Lost space after !!! case value.insert(1, pandocfilters.Str(marker[3:])) value.insert(1, pandocfilters.Space()) value[0]['c'] = '!!!' admonition_value = [] remaining_para_value = [] in_admonition = True break_value = [pandocfilters.LineBreak(), pandocfilters.Str(' ' * 4)] for item in value: if in_admonition: if item.get('t') == 'SoftBreak': in_admonition = False else: admonition_value.append(item) else: if item.get('t') == 'SoftBreak': remaining_para_value += break_value else: remaining_para_value.append(item) if admonition_value[-1].get('t') == 'Quoted': text = process_sentence(admonition_value[-1]['c'][-1]) text[0]['c'] = '"' + text[0]['c'] text[-1]['c'] = text[-1]['c'] + '"' admonition_value.pop(-1) admonition_value += text else: text = admonition_value[-1].get('c') if text: text = translate.translate(text[0].upper() + text[1:]) admonition_value.append(pandocfilters.Space()) admonition_value.append(pandocfilters.Str(f'"{text}"')) return cls(admonition_value + break_value + process_sentence(remaining_para_value)) else: return cls(process_sentence(value)) elif key == 'Plain' or key == 'Strong' or key == 'Emph': return cls(process_sentence(value)) elif key == 'Link': try: # Plain links case if value[2][0] == value[1][0].get('c'): return pandocfilters.Str(value[2][0]) except IndexError: pass value[1] = process_sentence(value[1]) href = value[2][0] if not (href.startswith('http') or href.startswith('#')): anchor = None attempts = 10 if '#' in href: href, anchor = href.split('#', 1) if href.endswith('.md') and not href.startswith('/'): parts = [part for part in os.environ['INPUT'].split('/') if len(part) == 2] lang = parts[-1] script_path = os.path.dirname(__file__) base_path = os.path.abspath(f'{script_path}/../../{lang}') href = os.path.join( os.path.relpath(base_path, os.path.dirname(os.environ['INPUT'])), os.path.relpath(href, base_path) ) if anchor: href = f'{href}#{anchor}' value[2][0] = href return cls(*value) elif key == 'Header': if value[1][0].islower() and '_' not in value[1][0]: # Preserve some manually specified anchors value[1][0] = slugify.slugify(value[1][0], separator='-', word_boundary=True, save_order=True) # TODO: title case header in en value[2] = process_sentence(value[2], is_header=True) return cls(*value) elif key == 'SoftBreak': return pandocfilters.LineBreak() return
def make_cell(r): return [pf.Plain([pf.Str(r)])]