def reformat_spaced_repetition_text(key, value, format, meta): if key == 'Para': # the spaced repetition text will always start with 'Q:' first_word = value[0]['c'] if first_word == 'Q:': # the content of a paragraph is a list of inline elements # e.g. links, line breaks, in-line code snippets, text started_parsing_answer: bool = False para_question = [] para_answer = [] for inline in value: # there's always a soft line break before the 'A:' # once we've seen the soft break, we want to start populating # the list containing the inlines that make up the answer if inline['t'] == 'SoftBreak': started_parsing_answer = True if started_parsing_answer: para_answer.append(inline) else: para_question.append(inline) # see constructor doc: https://github.com/jgm/pandocfilters/blob/master/pandocfilters.py return [ Div(attributes({'class': 'question'}), [Plain(para_question)]), Div(attributes({'class': 'answer'}), [Plain(para_answer)]) ]
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)
def pygments(key, value, format, _): # if key not in ["Space", "Str", "RawInline", "Para", "Quoted", "Plain"]: # stderr.write(f"- {key}: {value[:100]}\n") # if (key == "Str") and "fig:" in value: # stderr.write(f"{key}\t{value}\t{format}\n") 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, _ = 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] _, src, _, alt, _ = html.split("\"") return Plain( [Str(f"[[{fig_id}]]\n.{alt}\nimage::{src}[{alt}]")]) elif format == "html4": # Insert "Figure" or "Example" in front of internal references if (key == "Str") and value.startswith("@ref"): _, ref_type, ref_id, _ = split("\(|:|\)", value) return Str(f"{REF_TYPE[ref_type]} {value}") # Highlight code using pygments elif key == "CodeBlock": [[ident, classes, keyvals], code] = value language = classes[0] # stderr.write(f"\n\nformat: {format}\n\n```" + language + "\n" + code + "\n```\n\n\n") result = highlight(code, get_lexer_by_name(language), HtmlFormatter()) return RawBlock("html", result)
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 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 replace_attrtables(key, value, fmt, meta): """Replaces attributed tables while storing reference labels.""" if is_attrtable(key, value): # Parse the table content, caption, label = parse_attrtable(value) # Bail out if the label does not conform if not label or not LABEL_PATTERN.match(label): return None # Save the reference references[label] = len(references) + 1 # Adjust caption depending on the output format if fmt == 'latex': caption = list(caption) + [RawInline('tex', r'\label{%s}' % label)] else: caption = ast('Table %d. ' % references[label]) + list(caption) # Return the replacement # pylint: disable=star-args args = [ caption, ] + content if fmt in ('html', 'html5'): anchor = RawInline('html', '<a name="%s"></a>' % label) return [Plain([anchor]), Table(*args)] else: return Table(*args)
def listing(key, value, format, meta): #eprint("Key: " + key) if key == 'CodeBlock': (caption, _) = get_value(value[0][2], 'caption') if caption is None: return block = CodeBlock(value[0], value[1]) # we only need to add the caption, label is handled by Pandoc return \ [ Plain([latex(r'\begin{listing}' + '\n' + \ r'\caption{' + caption + '}')]) \ , block \ , Plain([latex(r'\end{listing}')]) \ ]
def makePlainFromParaValues(values): newv = [] t = values[0]['t'] if t == 'Image': for v in values: newv.append(v) p = Plain(newv) return p rb1 = RawInline('html', '<text:p text:style-name="Normal">') newv.append(rb1) for v in values: myvals = handleParagraphValue(v) for myv in myvals: newv.append(myv) rb2 = RawInline('html', '</text:p>') newv.append(rb2) p = Plain(newv) return p
def preprocess(key, value, fmt, meta): """Preprocesses to correct for problems.""" if key in ('Para', 'Plain'): while True: newvalue = repair_broken_refs(value) if newvalue: value = newvalue else: break if key == 'Para': return Para(value) else: return Plain(value)
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 preffyify_fractions(key, value, format, meta): if key == 'Plain': modified_value = value[:] for tidx, token in enumerate(modified_value): if token['t'] != 'Str': continue content = token['c'] split = re.split(r'(\d+/\d+)', content) if len(split) > 1: for idx, part in enumerate(split): if idx % 2: split[idx] = fractionalize(part) token['c'] = ''.join(split) return Plain(modified_value)
def pandocfilter(key, value, xformat, meta): ''' {"t":"RawInline","c":["latex","\\index[general]{Command!bconsole}"]}]} ''' logger = logging.getLogger() if key == "RawInline" or key == 'RawBlock': logger.debug('value {}'.format(value)) logger.debug('format {}'.format(xformat)) logger.debug('meta {}'.format(meta)) result = parseAndTranslate(value[1]) logger.debug('result: {}'.format(result)) if key == "RawInline": return Str(result) #return Code(None, result) #return Code(('', [], []), result) elif key == 'RawBlock': return Plain([Str(result)]) return None
def __call__( self, key: str, value: Any, output_format: str, meta: str) -> Any: """Process JSON elements. For each key, this method calls a method "process_key" (with a lower case key). Therefore it dispatches the action calls to appropriate methods. If there is no such method, nothing is changed. """ # print(key, output_format, repr(value), file=sys.stderr) action = getattr(self, 'process_' + key.lower(), None) if action is None: # print(key, output_format, repr(value), file=sys.stderr) return None try: return action(value, output_format, meta) except Exception as exc: # pylint: disable=broad-except print(traceback.format_exc(), file=sys.stderr) return Plain([Strong([Str("Filter error: " + str(exc))])])
def replace_refs(key, value, fmt, meta): """Replaces references to labelled images.""" # Remove braces around references if key in ('Para', 'Plain'): if remove_braces(value): if key == 'Para': return Para(value) else: return Plain(value) # Replace references if is_ref(key, value): prefix, label, suffix = parse_ref(value) # The replacement depends on the output format if fmt == 'latex': return prefix + [RawInline('tex', r'\ref{%s}' % label)] + suffix elif fmt in ('html', 'html5'): link = '<a href="#%s">%s</a>' % (label, references[label]) return prefix + [RawInline('html', link)] + suffix else: return prefix + [Str('%d' % references[label])] + suffix
def replace_attrimages(key, value, fmt, meta): """Replaces attributed images while storing reference labels.""" if is_attrimage(key, value): # Parse the image attrs, caption, target, label = parse_attrimage(value) # Bail out if the label does not conform if not label or not LABEL_PATTERN.match(label): return None # Save the reference references[label] = len(references) + 1 # Adjust caption depending on the output format if fmt == 'latex': caption = list(caption) + [RawInline('tex', r'\label{%s}' % label)] else: caption = ast('Figure %d. ' % references[label]) + list(caption) # Required for pandoc to process the image target[1] = "fig:" # Return the replacement if len(value[0]['c']) == 2: # Old pandoc < 1.16 img = Image(caption, target) else: # New pandoc >= 1.16 assert len(value[0]['c']) == 3 img = AttrImage(attrs, caption, target) if fmt in ('html', 'html5'): anchor = RawInline('html', '<a name="%s"></a>' % label) return [Plain([anchor]), Para([img])] else: return Para([img])
def listof(key, value, format, meta): global headers2 # Is it a header? if key == 'Header': [level, [id, classes, attributes], content] = value if 'unnumbered' not in classes: headers2[level - 1] = headers2[level - 1] + 1 for index in range(level, 6): headers2[index] = 0 # Is it a paragraph with only one string? if key == 'Para' and len(value) == 1 and value[0]['t'] == 'Str': # Is it {tag}? result = re.match('^{(?P<name>(?P<prefix>[a-zA-Z][\w.-]*)(?P<section>\:((?P<sharp>#(\.#)*)|(\d+(\.\d+)*)))?)}$', value[0]['c']) if result: prefix = result.group('prefix') # Get the collection name if result.group('sharp') == None: name = result.group('name') else: level = (len(result.group('sharp')) - 1) // 2 + 1 name = prefix + ':' + '.'.join(map(str, headers2[:level])) # Is it an existing collection if name in collections: if format == 'latex': # Special case for LaTeX output if 'toccolor' in meta: linkcolor = '\\hypersetup{linkcolor=' + stringify(meta['toccolor']['c'], format) + '}' else: linkcolor = '\\hypersetup{linkcolor=black}' if result.group('sharp') == None: suffix = '' else: suffix = '_' return Para([RawInline('tex', linkcolor + '\\makeatletter\\@starttoc{' + name + suffix + '}\\makeatother')]) else: # Prepare the list elements = [] # Loop on the collection for value in collections[name]: # Add an item to the list if pandocVersion() < '1.16': # pandoc 1.15 link = Link([Str(value['text'])], ['#' + prefix + ':' + value['identifier'], '']) else: # pandoc 1.16 link = Link(['', [], []], [Str(value['text'])], ['#' + prefix + ':' + value['identifier'], '']) elements.append([Plain([link])]) # Return a bullet list return BulletList(elements) # Special case where the paragraph start with '{{...' elif re.match('^{{[a-zA-Z][\w.-]*}$', value[0]['c']): value[0]['c'] = value[0]['c'][1:]
def handle_comments(key, value, docFormat, meta): global INLINE_TAG_STACK, BLOCK_COMMENT, INLINE_COMMENT, INLINE_MARGIN,\ INLINE_HIGHLIGHT, INLINE_FONT_COLOR_STACK # If translating to markdown, leave everything alone. if docFormat == 'markdown': return # Get draft status from metadata field (or assume not draft if there's # no such field) try: draft = meta['draft']['c'] except KeyError: draft = False # Check to see if we're starting or closing a Block element if key == 'RawBlock': elementFormat, tag = value if elementFormat != 'html': return tag = tag.lower() if not draft: if BLOCK_COMMENT: # Need to suppress output if tag == '</!comment>': BLOCK_COMMENT = False return [] # Not currently suppressing output ... if tag in ['<!comment>', '<!box>', '<center>', '<!speaker>']: if tag == '<!comment>': BLOCK_COMMENT = True if not draft: return [] INLINE_FONT_COLOR_STACK.append(COLORS[tag]) if docFormat == 'latex': return Para([latex(LATEX_TEXT[tag])]) # FIXME: What about beamer? elif docFormat in ['html', 'html5']: return Plain([html(HTML_TEXT[tag])]) elif docFormat == 'revealjs': return Plain([html(REVEALJS_TEXT[tag])]) else: return elif tag in ['</!comment>', '</!box>', '</center>', '</!speaker>']: if INLINE_TAG_STACK: debug( 'Need to close all inline elements before closing block elements!\n\n{}\n\nbefore\n\n{}\n\n' .format(str(INLINE_TAG_STACK), tag)) exit(1) if tag == '</!comment>': BLOCK_COMMENT = False if not draft: return [] INLINE_FONT_COLOR_STACK.pop() if docFormat == 'latex': return Para([latex(LATEX_TEXT[tag])]) # FIXME: What about beamer? elif docFormat in ['html', 'html5']: return Plain([html(HTML_TEXT[tag])]) elif docFormat == 'revealjs': return Plain([html(REVEALJS_TEXT[tag])]) else: return else: return # TODO Is this the right thing to do? if not draft and BLOCK_COMMENT: return [] # Need to suppress output # Then check to see if we're changing INLINE_TAG_STACK... elif key == 'RawInline': elementFormat, tag = value if elementFormat != 'html': return # Check to see if need to suppress output. We do this only for # `<comment>` and `<margin>` tags; with `<fixme>` and `<highlight>` # tags, we merely suppress the tag. if not draft: if tag == '<comment>': INLINE_COMMENT = True return [] elif tag == '<margin>': INLINE_MARGIN = True return [] elif INLINE_COMMENT: # Need to suppress output if tag == '</comment>': INLINE_COMMENT = False return [] elif INLINE_MARGIN: # Need to suppress output if tag == '</margin>': INLINE_MARGIN = False return [] elif tag in ['<fixme>', '<highlight>', '</fixme>', '</highlight>']: return [] # Suppress the tag (but not the subsequent text) # Not currently suppressing output.... if tag in [ '<comment>', '<fixme>', '<margin>', '<highlight>', '</comment>', '</fixme>', '</margin>', '</highlight>' ]: # LaTeX gets treated differently than HTML if docFormat in ['latex', 'beamer']: preText = '' postText = '' # Cannot change COLORS within highlighting in LaTeX (but # don't do anything when closing the highlight tag!) if INLINE_HIGHLIGHT and tag != '</highlight>': preText = LATEX_TEXT['</highlight>'] postText = LATEX_TEXT['<highlight>'] if tag in ['<comment>', '<fixme>', '<margin>', '<highlight>']: # If any opening tag if tag == '<comment>': INLINE_COMMENT = True INLINE_FONT_COLOR_STACK.append(COLORS[tag]) elif tag == '<fixme>': INLINE_FONT_COLOR_STACK.append(COLORS[tag]) elif tag == '<margin>': INLINE_MARGIN = True INLINE_FONT_COLOR_STACK.append(COLORS[tag]) elif tag == '<highlight>': INLINE_HIGHLIGHT = True INLINE_FONT_COLOR_STACK.append( INLINE_FONT_COLOR_STACK[-1]) INLINE_TAG_STACK.append(tag) return latex(preText + LATEX_TEXT[tag] + postText) elif tag in [ '</comment>', '</fixme>', '</margin>', '</highlight>' ]: if tag == '</comment>': INLINE_COMMENT = False elif tag == '</fixme>': pass elif tag == '</margin>': INLINE_MARGIN = False elif tag == '</highlight>': INLINE_HIGHLIGHT = False INLINE_FONT_COLOR_STACK.pop() previousColor = INLINE_FONT_COLOR_STACK[-1] currentInlineStatus = INLINE_TAG_STACK.pop() if currentInlineStatus[1:] == tag[2:]: # matching opening tag return latex('{}{}\\color{{{}}}{{}}{}'.format( preText, LATEX_TEXT[tag], previousColor, postText)) else: debug( 'Closing tag ({}) does not match opening tag ({}).\n\n' .format(tag, currentInlineStatus)) exit(1) else: # Some docFormat other than LaTeX/beamer if tag in ['<comment>', '<fixme>', '<margin>', '<highlight>']: if tag == '<highlight>': INLINE_HIGHLIGHT = True INLINE_TAG_STACK.append(tag) else: if tag == '</highlight>': INLINE_HIGHLIGHT = False INLINE_TAG_STACK.pop() if docFormat in ['html', 'html5']: return html(HTML_TEXT[tag]) elif docFormat == 'revealjs': return html(REVEALJS_TEXT[tag]) else: return [] elif tag.startswith('<i ') and tag.endswith('>'): # Index if docFormat == 'latex': return latex('\\index{{{}}}'.format(tag[3:-1])) else: return [] elif tag.startswith('<l ') and tag.endswith('>'): # My definition of a label if docFormat == 'latex': return latex('\\label{{{}}}'.format(tag[3:-1])) elif docFormat in ['html', 'html5']: return html('<a name="{}"></a>'.format(tag[3:-1])) elif tag.startswith('<r ') and tag.endswith('>'): # My definition of a reference if docFormat == 'latex': return latex('\\cref{{{}}}'.format(tag[3:-1])) elif docFormat in ['html', 'html5']: return html('<a href="#{}">here</a>'.format(tag[3:-1])) elif tag.startswith('<rp ') and tag.endswith('>'): # My definition of a page reference if docFormat == 'latex': return latex('\\cpageref{{{}}}'.format(tag[4:-1])) elif docFormat in ['html', 'html5']: return html('<a href="#{}">here</a>'.format(tag[4:-1])) elif not draft and (INLINE_COMMENT or INLINE_MARGIN): # Suppress all output return [] # Check some cases at beginnings of paragraphs elif key == 'Para': try: # If translating to LaTeX, beginning a paragraph with '< ' # will cause '\noindent{}' to be output first. if value[0]['t'] == 'Str' and value[0]['c'] == '<' \ and value[1]['t'] == 'Space': if docFormat == 'latex': return Para([latex('\\noindent{}')] + value[2:]) elif docFormat in ['html', 'html5']: return Para([html('<div class="noindent">')] + value[2:] + [html('</div>')]) else: return Para(value[2:]) else: return # Normal paragraph, not affected by this filter except: return # May happen if the paragraph is empty. # Check for tikz CodeBlock. If it exists, try typesetting figure elif key == 'CodeBlock': (id, classes, attributes), code = value if 'tikz' in classes or '\\begin{tikzpicture}' in code: if 'fontfamily' in meta: font = meta['fontfamily']['c'][0]['c'] else: font = DEFAULT_FONT outfile = path.join(IMAGE_PATH, my_sha1(code + font)) filetype = '.pdf' if docFormat == 'latex' else '.png' sourceFile = outfile + filetype caption = '' library = '' for a, b in attributes: if a == 'caption': caption = b elif a == 'tikzlibrary': library = b if not path.isfile(sourceFile): try: mkdir(IMAGE_PATH) debug('Created directory {}\n\n'.format(IMAGE_PATH)) except OSError: pass codeHeader = '\\documentclass{{standalone}}\n\\usepackage{{{}}}\n\\usepackage{{tikz}}\n'.format( font) if library: codeHeader += '\\usetikzlibrary{{{}}}\n'.format(library) codeHeader += '\\begin{document}\n' codeFooter = '\n\\end{document}\n' tikz2image(codeHeader + code + codeFooter, filetype, outfile) debug('Created image {}\n\n'.format(sourceFile)) if caption: # Need to run this through pandoc to get JSON # representation so that captions can be docFormatted text. jsonString = toFormat(caption, 'markdown', 'json') if "blocks" in jsonString: formattedCaption = eval(jsonString)["blocks"][0]['c'] else: # old API formattedCaption = eval(jsonString)[1][0]['c'] else: formattedCaption = [Str('')] return Para([ Image((id, classes, attributes), formattedCaption, [sourceFile, caption]) ]) else: # CodeBlock, but not tikZ return else: # Not text this filter modifies.... return
def _add_markup(fmt, thm, value): """Adds markup to the output.""" attrs = thm['attrs'] ret = None if fmt in ['latex', 'beamer']: # remark: tagged theorems are not (yet) supported # Present theorem as a definition list env = attrs.id.split(':')[0] tmp = value[0][0]['c'][1] title = '' if len(tmp) >= 1: title = '[%s]' % stringify(tmp) start = RawBlock('tex', r'\begin{%s}%s%s' % \ (env, title, '' if thm['is_unreferenceable'] else r'\label{%s} '%attrs.id)) endtags = RawBlock('tex', r'\end{%s}' % env) content = value[1][0] ret = [start] + content + [endtags] elif fmt in ('html', 'html5', 'epub', 'epub2', 'epub3'): if isinstance(targets[attrs.id].num, int): # Numbered reference num = Str(' %d' % targets[attrs.id].num) else: # Tagged reference assert isinstance(targets[attrs.id].num, STRTYPES) text = ' ' + targets[attrs.id].num if text.startswith('$') and text.endswith('$'): math = text.replace(' ', r'\ ')[1:-1] num = Math({"t": "InlineMath", "c": []}, math) else: # Text num = Str(text) # Present theorem as a definition list outer = RawBlock('html', '<dl%sclass="theoremnos">' % \ (' ' if thm['is_unreferenceable'] else ' id="%s" '%attrs.id)) name = names[attrs.id.split(':')[0]] head = RawBlock('html', '<dt>') endhead = RawBlock('html', '</dt><dd>') title = value[0][0]['c'][1] if len(title) >= 1: title.insert(0, Str(' (')) title.insert(0, num) title.append(Str(')')) else: title.append(num) title.insert(0, Str('%s' % name)) title.append(Str(':')) content = value[1][0] endtags = RawBlock('html', '</dd></dl>') ret = [outer, head, Plain(title), endhead] + content + [endtags] # To do: define default behaviour return ret
def pygments(key, value, format, _): global FIG_COUNTER global CHAPTER_NUM # Used for figure log if format == "muse": if key == "Header": level = value[0] if level == 1: try: CHAPTER_NUM = int(value[1][0].split("-")[1]) FIG_COUNTER = 0 except: pass if key == "Div": [[ident, classes, keyvals], code] = value div_type = classes[0] if div_type == "figure": FIG_COUNTER += 1 fig_id = code[2]["c"][0]["c"].split(")")[0][2:] html = code[0]["c"][0]["c"][1] _, src, _, alt, *_ = html.split("\"") src = src.split("/")[-1] redraw = "Redraw" if src.startswith( "diagram_") else "Use as-is" stderr.write( f"{CHAPTER_NUM},{FIG_COUNTER},Yes,\"N/A\",{src},{redraw},\"{alt}\"\n" ) return None if format == "asciidoc": # Fix chapter cross ref # if key == "Link" and value[2][0].startswith("#chapter"): # return RawInline("asciidoc", f"<<{value[2][0][1:]}>>") # if key == "Header": # level = value[0] # chapter_id = "_".join(value[1][0].split("-")[2:]) # if level == 1: # stderr.write(f"HEADER: {value}\n\n") # stderr.write(f"HEADER_ID: {chapter_id}\n\n") # Only keep <!--A...A---> comments if key == "RawBlock": try: if (match := comment_adoc_re.fullmatch(value[1])): return RawBlock("asciidoc", match.group(1)) except: pass # Fix references to figures if (key == "Str") and value.startswith("@ref"): # stderr.write(f"{key}\t{value}\n") #_, ref_type, ref_id, *rest = re.split("\(|:|\)", value) match = ref_re.fullmatch(value) ref_type = match.group(1) ref_id = match.group(2) ref_rest = match.group(3) new_ref = f"<<{ref_type}:{ref_id}>>{ref_rest}" # stderr.write(new_ref + "\n") return Str(new_ref) 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 key == "CodeBlock": [[ident, classes, keyvals], code] = value if classes: language = classes[0] # stderr.write(f"{key}\t{value}\t{format}\n") html_code = conv.convert(code, full=False) html_code = html_code.replace("+", "+") result = "[source,subs=\"+macros\"]\n----\n" for line in html_code.split("\n"): line += "<span></span>" if match := callout_code_re.search(line): line = callout_code_re.sub("", line) line = f"+++{line}+++ <{match.group(1)}>" else: line = f"+++{line}+++" result += line + "\n" result += "----\n\n" # html_code = "+++" + html_code.replace("\n", "<span></span>+++\n+++") + "<span></span>+++" html_code = html_code.replace("<span", "+++<span").replace( "</span>", "</span>+++") #result = "[subs=callouts]\n++++\n<pre data-type=\"programlisting\" style=\"color: #4f4f4f\">" + html_code + "</pre>\n++++\n\n" # result = "[source,subs=\"+macros\"]\n----\n" + html_code + "\n----\n\n" # Turn code callout number into image # result = callout_code_re.sub(lambda x: f"<img src=\"callouts/{int(x.group(1))}.png\" alt=\"{int(x.group(1))}\">", result) # result = callout_code_re.sub(lambda x: f"<a class=\"co\"><img src=\"callouts/{int(x.group(1))}.png\" /></a>", result) # result = callout_code_re.sub(lambda x: f"<!--{int(x.group(1))}-->", result) # result = result.replace("+++<span></span>+++", "") else: result = code return RawBlock("asciidoc", result)