def replaceCodelistingForLstlisting(token): begin_token = RawBlock('latex', '\\begin{codelisting}') end_token = RawBlock('latex', '\\end{codelisting}') if (begin_token, end_token) != (token[1][0], token[1][3]): return token ret = [token[0], [Plain([])]] # a content of `Div` token # set begin command line = '\\begin{lstlisting}[' params = extractParameters(token[1][2]) params_strings = [ "{}={}".format(key, item) for key, item in params.items() ] ret[1][0]['c'].append( RawInline('latex', line + ",".join(params_strings) + "]\n")) # set the source code for line in token[1][2]['c'][1].split('\n'): ret[1][0]['c'].append(RawInline('latex', line + "\n")) # set end command ret[1][0]['c'].append(RawInline('latex', '\\end{lstlisting}')) return Div(*ret)
def handleCodeBlock(value): t = "code" if value[0][0]: t = value[0][0] r = [] ## debut hack if t == "header": # title, author, date return getTitleAuthorDate(value[1]) elif t == "keywords": return getKeywords(value[1]) ## fin hack linenbr = 0 for s in value[1].split('\n'): linenbr = linenbr + 1 rb1 = RawBlock('html', '<text:p text:style-name="' + t + '">') r.append(rb1) # add line number for code blocks only if t == "code": linenbrstr = "{:02d}".format(linenbr) i = 0 #while i < len(linenbrstr) and linenbrstr[i] == " ": ##lnlspaces = len(linenbrstr) - len(linenbrstr.lstrip(' ')) ##if lnlspaces > 0: # r.append(RawBlock('html', '<text:s/>')) # i += 1 r.append(RawBlock('html', linenbrstr)) # count number of space characters at the beginning of the line lspaces = len(s) - len(s.lstrip(' ')) if lspaces > 0: r.append( RawBlock('html', '<text:s text:c="' + str(lspaces) + '"/>')) r.append(Plain([Str(s)])) rb2 = RawBlock('html', '</text:p>') r.append(rb2) return r
def getKeywords(value): r = [] keywords = value.split(",") rb1 = RawBlock( 'html', '<text:p text:style-name="pragma">/// <text:span text:style-name="T1">Mots-clés ///</text:span></text:p>' ) r.append(rb1) r.append(RawBlock('html', '<text:p text:style-name="Normal">')) i = 0 for kw in keywords: separator = "" if i < len(keywords) - 1: separator = " / " rb = RawBlock( 'html', '<text:span text:style-name="Normal">' + kw + separator + '</text:span>') r.append(rb) i += 1 r.append(RawBlock('html', '</text:p>')) rb2 = RawBlock( 'html', '<text:p text:style-name="pragma">/// <text:span text:style-name="T1">Fin Mots-clés ///</text:span></text:p>' ) r.append(rb2) return r
def prism(key, value, format, meta): """ Use minted for code in LaTeX. Args: key: type of pandoc object value: contents of pandoc object format: target output format meta: document metadata """ if format == "html": if key == 'CodeBlock': body, language, params, source_file = unpack(value, meta) if language is None: return if source_file is None: html = '<pre><code class="language-%s">%s</code></pre>' % ( language, body) return [RawBlock(format, html)] else: content = r'\inputminted[' + params + ']{' + language + '}{' + source_file + '}' return [RawBlock(format, content)] elif key == 'Code': body, language, params, source_file = unpack(value, meta) if language is None: return html = '<code class="language-%s">%s</code>' % (language, body) return [RawInline(format, html)]
def action(key, value, fmt, meta): # pylint: disable=unused-argument """Processes elements.""" global replaced_figure_env # pylint: disable=global-statement if is_figure(key, value): attrs = PandocAttributes(value[0]['c'][0], 'pandoc') # Convert figures with `marginfigure` class to marginfigures if 'marginfigure' in attrs.classes: if 'documentclass' in meta and \ get_meta(meta, 'documentclass') in \ ['tufte-book', 'tufte-handout']: replaced_figure_env = True # Get the marginfigure options offset = attrs['offset'] if 'offset' in attrs else '0pt' # LaTeX used to apply the environment pre = RawBlock('tex', r'\begin{marginfigure_}[%s]' % offset) post = RawBlock('tex', r'\end{marginfigure_}') return [pre, Para(value), post] if warninglevel: STDERR.write(WARNING) return None
def environment(key, value, format, meta): # Is it a div and the right format? if key == 'Div' and format in ['latex', 'beamer']: # Get the attributes [[id, classes, properties], content] = value currentClasses = set(classes) for environment, definedClasses in getDefined(meta).items(): # Is the classes correct? if currentClasses >= definedClasses: if id != '': label = ' \\label{' + id + '}' else: label = '' currentProperties = dict(properties) if 'title' in currentProperties: title = '[' + currentProperties['title'] + ']' else: title = '' value[1] = [ RawBlock('tex', '\\begin{' + environment + '}' + title + label) ] + content + [RawBlock('tex', '\\end{' + environment + '}')] break
def handleOrderedList(value): number = value[0][0] r = [] r1 = RawBlock('html', '<text:list text:style-name="L3">') r.append(r1) for v in value[1]: r.append(RawBlock('html', '<text:list-item>')) for item in v: t = item['t'] p = None if t.endswith('BulletList'): p = handleBulletList(item['c']) for e in p: r.append(e) elif t.endswith('OrderedList'): p = handleOrderedList(item['c']) for e in p: r.append(e) else: p = Para(item['c']) p = makePlainFromPara(p) r.append(p) r.append(RawBlock('html', '</text:list-item>')) r2 = RawBlock('html', '</text:list>') r.append(r2) return r
def process(key, value, format, meta): if key == 'RawBlock': type, content = value if type == 'tikz': header = r'\begin{tikzpicture}[thick,scale=0.8,transform shape]' footer = r'\end{tikzpicture}' return RawBlock('latex', header + content + footer) if type == 'algorithm': header = r'{\scriptsize\begin{algorithmic}[1]' footer = r'\end{algorithmic}}' return RawBlock('latex', header + content + footer) if key == 'BlockQuote': header = [RawInline('latex', r'\begin{block}{')] def extract_title(key, value, format, meta): if key == 'Header': header.extend(value[2]) return [] return process(key, value, format, meta) content = walk(value, extract_title, format, meta) header.append(RawInline('latex', '}')) header = [Para(header)] footer = [RawBlock('latex', r'\end{block}')] return header + content + footer if key == 'Header' and value[0] == 1: global lastheader lastheader = Header(*value) if key == 'HorizontalRule': return walk(lastheader, process, format, meta)
def prism(key, value, format, meta): """ Use minted for code in LaTeX. Args: key: type of pandoc object value: contents of pandoc object format: target output format meta: document metadata """ if format == "html": if key == 'Image': import base64 path = value[2][0] if not os.path.exists(path): print("No such image: " + path) encoded = "data:image/png;base64," + base64.b64encode(open(path, "rb").read()).decode() html = '<img alt="" src="%s">' % (encoded) return [RawInline(format, html)] if key == 'CodeBlock': body, language, params, source_file = unpack(value, meta) if language is None: return if source_file is None: html = '<pre><code class="language-%s">%s</code></pre>' % (language, body) return [RawBlock(format, html)] else: with open(source_file, 'r') as file: code = file.readlines() lastline = len(code) firstline = 0 if 'lastline' in params: lastline = min(lastline, int(params['lastline'])) if 'firstline' in params: firstline = max(firstline, min(lastline, int(params['firstline'])-1)) body = "".join(code[firstline: lastline]) # determine language by ending dot_index = source_file.rindex(".") ending = source_file[dot_index + 1:] if ending not in ENDINGS: raise AttributeError("Unknown ending: " + ending) language = ENDINGS[ending] html = '<pre><code class="language-%s">%s</code><pre>' % (language, body) return [RawBlock(format, html)] elif key == 'Code': body, language, params, source_file = unpack(value, meta) if language is None: return html = '<code class="language-%s">%s</code>' % (language, body) return [RawInline(format, html)]
def mkCodeBlock(classes, code): code = code.replace('<', '<').replace('>', '>') if (len(classes) == 0): return RawBlock('html', "<pre><code>" + code + "</code></pre>") else: c = (classes[0].split(':'))[0] return RawBlock( 'html', "<pre><code class=\"" + c + "\">" + code + "</code></pre>")
def header2box(key, value, format, meta): if format not in ["latex", "pdf", "native"]: return if key == 'Header' and value[0] == 1: return RawBlock('latex', template1 % stringify(value)) if key == 'Header' and value[0] == 2: return RawBlock('latex', template2 % stringify(value))
def process_tables(key, value, fmt, meta): """Processes the attributed tables.""" global has_unnumbered_tables # pylint: disable=global-statement # Process block-level Table elements if key == 'Table': # Inspect the table if len(value) == 5: # Unattributed, bail out has_unnumbered_tables = True if fmt in ['latex']: return [ RawBlock('tex', r'\begin{no-prefix-table-caption}'), Table(*value), RawBlock('tex', r'\end{no-prefix-table-caption}') ] return None # Process the table table = _process_table(value, fmt) # Context-dependent output attrs = table['attrs'] if table['is_unnumbered']: if fmt in ['latex']: return [ RawBlock('tex', r'\begin{no-prefix-table-caption}'), AttrTable(*value), RawBlock('tex', r'\end{no-prefix-table-caption}') ] elif fmt in ['latex']: if table['is_tagged']: # Code in the tags tex = '\n'.join([r'\let\oldthetable=\thetable', r'\renewcommand\thetable{%s}'%\ references[attrs[0]]]) pre = RawBlock('tex', tex) tex = '\n'.join([ r'\let\thetable=\oldthetable', r'\addtocounter{table}{-1}' ]) post = RawBlock('tex', tex) return [pre, AttrTable(*value), post] elif table['is_unreferenceable']: attrs[0] = '' # The label isn't needed any further elif fmt in ('html', 'html5') and LABEL_PATTERN.match(attrs[0]): # Insert anchor anchor = RawBlock('html', '<a name="%s"></a>' % attrs[0]) return [anchor, AttrTable(*value)] elif fmt == 'docx': # As per http://officeopenxml.com/WPhyperlink.php bookmarkstart = \ RawBlock('openxml', '<w:bookmarkStart w:id="0" w:name="%s"/>' %attrs[0]) bookmarkend = \ RawBlock('openxml', '<w:bookmarkEnd w:id="0"/>') return [bookmarkstart, AttrTable(*value), bookmarkend] return None
def filter(key, value, fmt, meta): if key == 'CodeBlock': value[1] = value[1].replace(b'\xef\xbf\xbd', '?') [[ident, classes, kvs], code] = value c = classes[0].split(',')[0] if c == 'rust': return mkListingsEnvironment(code) elif key == 'Link': [_, text, [href, _]] = value if text == [Str("include")]: return mkInputListings(href) elif (not href.startswith("http")) and href.endswith(".md"): src = re.search(r'(?:./)?(.+\.md)', href).group(1) return mkRef(src) elif key == 'Image': [_, _, [src, _]] = value if src.startswith("http"): fileName = src.split("/")[-1] os.system("cd img && curl -O " + src) return mkIncludegraphics(fileName) elif key == 'Str': return (Str(value.replace(b'\xef\xbf\xbd', '?').replace(u"〜", u"~"))) elif key == 'Code': value[1] = value[1].replace(b'\xef\xbf\xbd', '?') elif key == 'Header': [level, _, _] = value if level == 1: file_name = os.getenv('FILENAME', "FILE_DOES_NOT_EXIST") value[1][0] = file_name elif key == 'RawInline': [t, s] = value if t == 'html' and '<img' in s: src = re.search(r'src="img/(.+?)"', s).group(1) return mkIncludegraphics(src) elif t == 'html' and s == '<sup>': return mkBeginSup() elif t == 'html' and s == '</sup>': return mkEndSup() elif key == 'Para': if value[0]['t'] == 'RawInline': fmt, content = value[0]['c'] if fmt == 'html' and '<img' in content: src = re.search(r'src="(img/.+?)"', content).group(1) cls = re.search(r'class="(.+?)"', content) if cls: cls = cls.group(1) width = re.search(r'style="width: *(\d+)%;?', content) if width: width = float(width.group(1)) / 100 return mkFigure(src, align=cls, scale=width) elif fmt == 'html' and 'class="caption"' in content: return [Para(value), RawBlock('latex', r'\vspace{1em}')] elif fmt == 'html' and 'class="filename"' in content: return [RawBlock('latex', r'\vspace{1em}'), Para(value)]
def _insert_cleveref_fakery(key, value, meta): r"""Inserts TeX to support clever referencing in LaTeX documents if the key isn't a RawBlock. If the key is a RawBlock, then check the value to see if the TeX was already inserted. The \providecommand macro is used to fake the cleveref package's behaviour if it is not provided in the template via \usepackage{cleveref}. TeX is inserted into the value. Replacement elements are returned. """ global _cleveref_tex_flag # pylint: disable=global-statement comment1 = '% pandoc-xnos: cleveref formatting' tex1 = [ comment1, r'\crefformat{%s}{%s~#2#1#3}' % (target, plusname[0]), r'\Crefformat{%s}{%s~#2#1#3}' % (target, starname[0]) ] if key == 'RawBlock': # Check for existing cleveref TeX if value[1].startswith(comment1): # Append the new portion value[1] = value[1] + '\n' + '\n'.join(tex1[1:]) _cleveref_tex_flag = False # Cleveref fakery already installed elif key != 'RawBlock': # Write the cleveref TeX _cleveref_tex_flag = False # Cancels further attempts ret = [] # Check first to see if fakery is turned off if not 'xnos-cleveref-fake' in meta or \ check_bool(get_meta(meta, 'xnos-cleveref-fake')): # Cleveref fakery tex2 = [ r'% pandoc-xnos: cleveref fakery', r'\newcommand{\plusnamesingular}{}', r'\newcommand{\starnamesingular}{}', r'\newcommand{\xrefname}[1]{'\ r'\protect\renewcommand{\plusnamesingular}{#1}}', r'\newcommand{\Xrefname}[1]{'\ r'\protect\renewcommand{\starnamesingular}{#1}}', r'\providecommand{\cref}{\plusnamesingular~\ref}', r'\providecommand{\Cref}{\starnamesingular~\ref}', r'\providecommand{\crefformat}[2]{}', r'\providecommand{\Crefformat}[2]{}'] ret.append(RawBlock('tex', '\n'.join(tex2))) ret.append(RawBlock('tex', '\n'.join(tex1))) return ret return None
def main(): """Filters the document AST.""" # Get the output format, document and metadata fmt = args.fmt doc = json.loads(STDIN.read()) meta = doc[0]['unMeta'] # Process the metadata variables process(meta) # First pass altered = functools.reduce(lambda x, action: walk(x, action, fmt, meta), [attach_attrs_image, process_figures, detach_attrs_image], doc) # Second pass process_refs = process_refs_factory(references.keys()) replace_refs = replace_refs_factory(references, cleveref_default, plusname, starname, 'figure') altered = functools.reduce(lambda x, action: walk(x, action, fmt, meta), [repair_refs, process_refs, replace_refs], altered) # Insert supporting TeX if fmt == 'latex': rawblocks = [] if has_unnumbered_figures: rawblocks += [RawBlock('tex', TEX0), RawBlock('tex', TEX1), RawBlock('tex', TEX2)] if captionname != 'Figure': rawblocks += [RawBlock('tex', TEX3 % captionname)] insert_rawblocks = insert_rawblocks_factory(rawblocks) altered = functools.reduce(lambda x, action: walk(x, action, fmt, meta), [insert_rawblocks], altered) # Dump the results json.dump(altered, STDOUT) # Flush stdout STDOUT.flush()
def handleHeaders(value): depth = value[0] text = value[1][0] if depth >= 1 and depth <= 3: r = [] r.append( RawBlock( 'html', '<text:h text:style-name="Heading_20_1" text:outline-level="' + str(depth) + '">' + getHeaderNumber(depth))) r.append(Plain(value[2])) r.append(RawBlock('html', '</text:h>')) return r else: raise Exception("unknown header depth: ", depth)
def getTitleAuthorDate(value): s = value.split("\n") title = s[0] authors = s[1] date = s[2] r = [] rb1 = RawBlock( 'html', '<text:p text:style-name="Title"><text:soft-page-break/>' + title + '</text:p>') rb2 = RawBlock( 'html', '<text:p text:style-name="Signature">' + authors + '</text:p>') r.append(rb1) r.append(rb2) return r
def pygmentize(key, value, format, meta): if key == 'CodeBlock': #LOG("key : {}\n value : {}\n format : {}\n meta : {}\n\n\n".format(key, value, format, meta)) [[ident, classes, keyvals], code] = value lexer = None for klass in classes: try: lexer = get_lexer_by_name(klass) break except: pass if lexer is None: try: lexer = guess_lexer(code) except: lexer = TextLexer() options = {} if ('numberLines' in value[0][1]): options['linenos'] = 'table' return [ RawBlock( format, highlight(code, lexer, get_formatter_by_name(format, **options))) ]
def media(key, value, format, meta): if key == 'Para' and value[0] == PERCENT and value[1]['t'] == 'Link': # get filename and caption title, src = value[1]['c'][1], value[1]['c'][2][0] title = ' '.join(d['c'] for d in title if d['t'] == u'Str') width = WIDTH opt = value[1]['c'][0] if len(opt) > 2: for key, val in opt[2]: if key == 'width' and val.endswith('%'): width *= int(val[:-1]) / 100 # get video height ffmpeg = run(['ffmpeg', '-i', src], stderr=PIPE).stderr.decode().split('\n') for line in ffmpeg: if 'Stream' in line: for word in line.split(): if 'x' in word and not word.startswith('0x'): resolution = word break else: raise ValueError('resolution not found in %s' % line) break else: raise ValueError('stream not found in %s' % ffmpeg) x, y = resolution.split('x') height = int(y) * width / int(x) for fmt_name, fmt_values in FORMATS.items(): if format in fmt_values: if PDFPC: movie = TEMPLATES['pdfpc'] % (src, width, height, src) else: movie = TEMPLATES['movie'] % (width, height, width, src, src) return [RawBlock(fmt_name, TEMPLATES[fmt_name] % (movie, title))]
def __call__(self, key, value, format, meta): # When we hit the block opening element that has a embedmath-tex attr, keep deleting until the next block if self._delete_everything: if key == 'RawBlock': self._delete_everything = False return [] # Our HTML rendered math is one of these nodes that's also HTML if key not in ('RawInline', 'RawBlock'): return kind, content = value if kind != 'html': return # Parse it soup = BeautifulSoup(content, 'html.parser') node = list(soup.childGenerator())[0] if node.get('embedmath-tex', None) is not None: tex = json.loads('"{}"'.format(node['embedmath-tex'])) node.replace_with(tex) if key == 'RawBlock': self._delete_everything = True if key == 'RawInline': return RawInline('markdown', str(soup)) elif key == 'RawBlock': return RawBlock('markdown', str(soup)) else: raise TypeError('Unhandled key {}'.format(repr(key)))
def environment(key, value, format, meta): # Is it a div and the right format? if key == 'Div' and format == 'latex': # Get the attributes [[id, classes, properties], content] = value currentClasses = set(classes) for environment, definedClasses in getDefined(meta).items(): # Is the classes correct? if currentClasses >= definedClasses: value[1] = [ RawBlock('tex', '\\begin{' + environment + '}') ] + content + [RawBlock('tex', '\\end{' + environment + '}')] break
def setBrushForCodeBlocks(key, value, fmt, meta): if key == "CodeBlock" and fmt == "html": [[ident, classes, keyvals], code] = value keyvals = dict(keyvals) # Convert from the default class to the KV list we'll parse. if classes and classes[0] in supportedBrushes: keyvals["brush"] = classes[0] classes.pop(0) elif "brush" not in keyvals: keyvals["brush"] = "lua" # SH uses some wacky classes. Because they would be a pain to define via # markdown as classes, we remap them here. for k in keyvals: if k in shSpecialKeys: classes.insert(0, k + ":") classes.insert(1, keyvals[k] + ";") # Rewrite the block as raw, otherwise Pandoc will include <code> tags that SH # won't like. preId = " id=\"" + ident + "\"" if ident else "" preClasses = " class=\"" + " ".join(classes) + "\"" if classes else "" return RawBlock( "html", "<pre" + preId + preClasses + ">" + code.replace("<", "<") + "</pre>")
def minted(key, value, format, meta): ''' Use minted for code in LaTeX. Args: key type of pandoc object value contents of pandoc object format target output format meta document metadata ''' if format == 'latex': if key == 'CodeBlock': body, language = unpack(value, meta) if language is None: return begin = r'\begin{minted}{' + language + '}\n' end = '\n' + r'\end{minted}' return [RawBlock(format, begin + body + end)] elif key == 'Code': body, language = unpack(value, meta) if language is None: return begin = r'\mintinline{' + language + '}{' end = '}' return [RawInline(format, begin + body + end)]
def pygmentize(key, value, format, meta): if key == 'CodeBlock': [[ident, classes, keyvals], code] = value lexer = None for klass in classes: if klass == "commonlisp": klass = "lisp" try: lexer = get_lexer_by_name(klass) break except: pass if lexer is None: try: lexer = guess_lexer(code) except: lexer = TextLexer() if format == "html5": format = "html" if format == "html": formatter = get_formatter_by_name(format) \ .__class__(cssclass="highlight " + klass) else: formatter = get_formatter_by_name(format) return RawBlock(format, highlight(code, lexer, formatter))
def media(key, value, format, meta): if key == 'Para' and value[0] == PERCENT and value[1]['t'] == 'Link': title, src = value[1]['c'][1], value[1]['c'][2][0] title = ' '.join(d['c'] for d in title if d['t'] == u'Str') for fmt_name, fmt_values in FORMATS.items(): if format in fmt_values: return [RawBlock(fmt_name, TEMPLATES[fmt_name] % (src, title))]
def textbook(key, value, format, meta): if key == "Header": [level, [ident, classes, keyvals], inlines] = value if (level == 5 or level == 1) and not "unnumbered" in classes: return Header(level, [ident, classes + ["unnumbered"], keyvals], inlines) if key == "CodeBlock": [[ident, classes, keyvals], code] = value if format == "html": return RawBlock("html", "<pre>" + process_html(code) + "</pre>") if key == "Code": [[ident, classes, keyvals], code] = value if format == "html": return RawInline("html", "<code>" + process_html(code) + "</code>") if key == "Image": [attr, inlines, [src, tit]] = value if format != "icml": return Image(attr, inlines, [src.replace(".pdf", ".png"), tit]) if key == "Div": [[ident, classes, keyvals], blocks] = value if format == "docx": if "numbers" in classes: return Null() if any(cls in classes for cls in [ "keyterm", "keyterms", "didyouknow", "syntax", "quickcheck", "program" ]): return Div([ident, classes, keyvals], [HorizontalRule()] + walk(blocks, textbook, format, meta) + [HorizontalRule()])
def environment(key, value, format, meta): # Is it a div and the right format? if key == 'Div' and format == 'latex': # Get the attributes [[id, classes, properties], content] = value currentClasses = set(classes) for environment, definedClasses in getDefined(meta).items(): # Is the classes correct? if currentClasses >= definedClasses: if id != '': label = ' \\label{' + id + '}' else: label = '' option = '' arguments = '' for key, value in properties: if key == 'option': if option == '': option = '[' + value + ']' else: sys.stderr.write("Warning: ignoring option '{}'". format(value)) elif key == 'argument': arguments += '{' + value + '}' return [RawBlock('tex', '\\begin{' + environment + '}' + option + arguments + label)] + content + [RawBlock('tex', '\\end{' + environment + '}')]
def insert_rawblocks(key, value, fmt, meta): """Inserts non-duplicate RawBlock elements.""" if not rawblocks: return None # Put the RawBlock elements in front of the first block element that # isn't also a RawBlock. if not key in [ 'Plain', 'Para', 'CodeBlock', 'RawBlock', 'BlockQuote', 'OrderedList', 'BulletList', 'DefinitionList', 'Header', 'HorizontalRule', 'Table', 'Div', 'Null' ]: return None if key == 'RawBlock': # Remove duplicates rawblock = RawBlock(*value) if rawblock in rawblocks: rawblocks.remove(rawblock) return None if rawblocks: # Insert blocks el = _getel(key, value) return [rawblocks.pop(0) for i in range(len(rawblocks))] + [el] return None
def create_rule(rule_list): raw = shrink_list(rule_list)[3:].split(':') rule_name = '<div class="rule-name">{0}</div>'.format(raw[0]) rule_definition = '<div class="rule-definition">{0}</div>'.format( raw[1].strip()) html = '<div class="rule">' + rule_name + rule_definition + '</div>' return RawBlock('html', html)
def pygments(key, value, format, _): if format == "asciidoc": # Fix references to figures if (key == "Str") and value.startswith("@ref"): # stderr.write(f"{key}\t{value}\n") _, ref_type, ref_id, _ = re.split("\(|:|\)", value) return Str(f"<<{ref_type}:{ref_id}>>") elif key == "Div": [[ident, classes, keyvals], code] = value div_type = classes[0] # Fix admonition if div_type.startswith("rmd"): adm_type = div_type[3:] return Plain([Str(f"[{ADM_TYPE[adm_type]}]\n====\n")] + code[0]["c"] + [Str("\n====\n\n")]) # Fix figures elif div_type == "figure": fig_id = code[2]["c"][0]["c"].split(")")[0][2:] html = code[0]["c"][0]["c"][1] stderr.write(f"{html}\n") _, src, _, alt, *_ = html.split("\"") return Plain( [Str(f"[[{fig_id}]]\n.{alt}\nimage::{src}[{alt}]")]) elif format == "html4": # Turn text callout number into unicode char if (key == "Str") and (match := callout_text_re.fullmatch(value)): num = int(match.group(1)) br = "<br>" if num > 1 else "" return RawInline( "html", f"{br}<span class=\"callout\">&#{num + 10121};</span>") # Insert "Figure" or "Example" in front of internal references if (key == "Str") and value.startswith("@ref"): _, ref_type, ref_id, _ = re.split("\(|:|\)", value) return Str(f"{REF_TYPE[ref_type]} {value}") elif key == "CodeBlock": [[ident, classes, keyvals], code] = value if classes: language = classes[0] # stderr.write(f"{key}\t{value}\t{format}\n") result = "<pre>" + conv.convert(code, full=False) + "</pre>" # Turn code callout number into unicode char result = callout_code_re.sub( lambda x: f"<span class=\"callout\">&#{int(x.group(1))+10121};</span>", result) else: result = code return RawBlock("html", result)