def _extract_attrs(x, n): """Extracts attributes for an image. n is the index where the attributes begin. Extracted elements are deleted from the element list x. Attrs are returned in pandoc format. """ try: return extract_attrs(x, n) except (ValueError, IndexError): if PANDOCVERSION < '1.16': # Look for attributes attached to the image path, as occurs with # image references for pandoc < 1.16 (pandoc-fignos Issue #14). # See http://pandoc.org/MANUAL.html#images for the syntax. # Note: This code does not handle the "optional title" for # image references (search for link_attributes in pandoc's docs). assert x[n - 1]['t'] == 'Image' image = x[n - 1] s = image['c'][-1][0] if '%20%7B' in s: path = s[:s.index('%20%7B')] attrs = unquote(s[s.index('%7B'):]) image['c'][-1][0] = path # Remove attr string from the path return PandocAttributes(attrs.strip(), 'markdown').to_pandoc() raise
def action(key, value, fmt, meta): # pylint: disable=unused-argument """Processes elements.""" global has_lettrine # pylint: disable=global-statement if key == 'Span': attrs = PandocAttributes(value[0], 'pandoc') if 'lettrine' in attrs.classes: has_lettrine = True firstword = value[1][0]['c'] content = value[1][1:] # Replace span in para with the elements ret = [PRE, Str(firstword[0]), MID] if len(firstword) > 1: ret.append(Str(firstword[1:])) ret.append(POST) ret += content return ret return None
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 action(key, value, fmt, meta): # pylint: disable=unused-argument """Processes elements.""" if key == 'Div': attrs = PandocAttributes(value[0], 'pandoc') if 'marginnote' in attrs.classes: offset = attrs['offset'] if 'offset' in attrs else '0pt' if 'documentclass' in meta and \ get_meta(meta, 'documentclass') in \ ['tufte-book', 'tufte-handout']: pre = RawInline('tex', r'\marginnote[%s]{'%offset) post = RawInline('tex', r'}') assert value[1][0]['t'] == 'Para' assert value[1][-1]['t'] == 'Para' value[1][0]['c'].insert(0, pre) value[1][-1]['c'].append(post) elif warninglevel: STDERR.write(WARNING)
def _process_equation(value, fmt): """Processes the equation. Returns a dict containing eq properties.""" # pylint: disable=global-statement global Nreferences # Global references counter global cursec # Current section global has_unnumbered_equations # Flags that unnumbered eqs were found # Initialize the return value eq = { 'is_unnumbered': False, 'is_unreferenceable': False, 'is_tagged': False } # Parse the equation attrs = eq['attrs'] = PandocAttributes(value[0], 'pandoc') # Bail out if the label does not conform to expectations if not LABEL_PATTERN.match(attrs.id): eq.update({'is_unnumbered': True, 'is_unreferenceable': True}) return eq # Identify unreferenceable equations if attrs.id == 'eq:': # Make up a unique description attrs.id += str(uuid.uuid4()) eq['is_unreferenceable'] = True # Update the current section number if attrs['secno'] != cursec: # The section number changed cursec = attrs['secno'] # Update the global section tracker Nreferences = 1 # Resets the global reference counter # Pandoc's --number-sections supports section numbering latex/pdf, html, # epub, and docx if numbersections: # Latex/pdf supports equation numbers by section natively. For the # other formats we must hard-code in equation numbers by section as # tags. if fmt in ['html', 'html5', 'epub', 'epub2', 'epub3', 'docx'] and \ 'tag' not in attrs: attrs['tag'] = str(cursec + secoffset) + '.' + str(Nreferences) Nreferences += 1 # Save reference information eq['is_tagged'] = 'tag' in attrs if eq['is_tagged']: # ... then save the tag # Remove any surrounding quotes if attrs['tag'][0] == '"' and attrs['tag'][-1] == '"': attrs['tag'] = attrs['tag'].strip('"') elif attrs['tag'][0] == "'" and attrs['tag'][-1] == "'": attrs['tag'] = attrs['tag'].strip("'") references[attrs.id] = pandocxnos.Target(attrs['tag'], cursec, attrs.id in references) else: references[attrs.id] = pandocxnos.Target(Nreferences, cursec, attrs.id in references) Nreferences += 1 # Increment the global reference counter return eq
def _process_theorem(value, fmt): """Processes the theorem. Returns a dict containing theorem properties.""" # pylint: disable=global-statement global Ntargets # Global targets counter global cursec # Current section # Initialize the return value thm = {'is_unreferenceable': False, 'is_tagged': False} # Parse the theorem attributes attrs = thm['attrs'] = PandocAttributes(value[0], 'pandoc') # Bail out if the label does not conform to expectations assert LABEL_PATTERN and LABEL_PATTERN.match(attrs.id) # Identify unreferenceable theorems if attrs.id[-1] == ':': # Make up a unique description attrs.id += str(uuid.uuid4()) thm['is_unreferenceable'] = True counter = attrs.id.split(':')[0] if sharedcounter: counter = 'shared' # Update the current section number if attrs['secno'] != cursec: # The section number changed cursec = attrs['secno'] # Update the global section tracker for key, nref in Ntargets.items(): # pylint: disable=unused-variable Ntargets[key] = 1 # Resets the global target counter # Pandoc's --number-sections supports section numbering latex/pdf, html, # epub, and docx if numbersections: # Latex/pdf supports theorems numbers by section natively. For the # other formats we must hard-code in theorem numbers by section as # tags. if fmt in ['html', 'html5', 'epub', 'epub2', 'epub3', 'docx'] and \ 'tag' not in attrs: attrs['tag'] = str(cursec+secoffset) + '.' + \ str(Ntargets[counter]) Ntargets[counter] += 1 # Save reference information thm['is_tagged'] = 'tag' in attrs if thm['is_tagged']: # ... then save the tag # Remove any surrounding quotes if attrs['tag'][0] == '"' and attrs['tag'][-1] == '"': attrs['tag'] = attrs['tag'].strip('"') elif attrs['tag'][0] == "'" and attrs['tag'][-1] == "'": attrs['tag'] = attrs['tag'].strip("'") targets[attrs.id] = pandocxnos.Target(attrs['tag'], cursec, attrs.id in targets) else: targets[attrs.id] = pandocxnos.Target(Ntargets[counter], cursec, attrs.id in targets) Ntargets[counter] += 1 # Increment the global reference counter return thm
def test_kvs(self): """Tests PandocAttributes.kvs.""" attrs = PandocAttributes(['', [], [['tag', 'B.1']]], 'pandoc') kvs = attrs.kvs # Ensure that changing the kvs changes attrs too kvs['tag'] = 'B.3' self.assertEqual(attrs['tag'], 'B.3')
def action(key, value, fmt, meta): # pylint: disable=unused-argument """Processes elements.""" if key == 'Div': attrs = PandocAttributes(value[0], 'pandoc') if 'noindent' in attrs.classes: return [PRE, Div(*value), POST] return None
def action(key, value, fmt, meta): # pylint: disable=unused-argument """Processes elements.""" if key == 'Span': attrs = PandocAttributes(value[0], 'pandoc') if 'newthought' in attrs.classes: if 'documentclass' in meta and \ get_meta(meta, 'documentclass') in \ ['tufte-book', 'tufte-handout']: pre = RawInline('tex', r'\newthought{') post = RawInline('tex', r'}') value[1].insert(0, pre) value[1].append(post) elif warninglevel: STDERR.write(WARNING)
def processor(meta, blocks): """Document processor.""" has_epigraph = False # Flags that an epigraph was found noindent = False # Flags that next para should not be indented # Process the blocks for block in blocks: if block['t'] == 'Div': attrs = PandocAttributes(block['c'][0]) # Process epigraph divs if 'epigraph' in attrs.classes: # Insert tex into div content content = block['c'][1] content[0]['c'].insert(0, PRE) content[-2]['c'].append(MID) for el in content[-1]['c']: content[-2]['c'].append(el) content[-2]['c'].append(POST) del content[-1] # Set flags and continue has_epigraph = True noindent = True continue # Don't indent the first non-empty paragraph after an epigraph if block['t'] == 'Para' and noindent: content = stringify(quotify(copy.deepcopy(block['c']))) if content.strip(): block['c'].insert(0, RawInline('tex', r'\noindent ')) noindent = False if has_epigraph: pandocxnos.add_to_header_includes( meta, 'tex', textwrap.dedent(r''' \usepackage{epigraph} '''), warninglevel)
def _process_equation(value, fmt): """Processes the equation. Returns a dict containing eq properties.""" # pylint: disable=global-statement global Nreferences # Global references counter global cursec # Current section # Parse the equation attrs = value[0] # Initialize the return value eq = {'is_unnumbered': False, 'is_unreferenceable': False, 'is_tagged': False, 'attrs': attrs} # Bail out if the label does not conform if not LABEL_PATTERN.match(attrs[0]): eq['is_unnumbered'] = True eq['is_unreferenceable'] = True return eq # Process unreferenceable equations if attrs[0] == 'eq:': # Make up a unique description attrs[0] = attrs[0] + str(uuid.uuid4()) eq['is_unreferenceable'] = True unreferenceable.append(attrs[0]) # For html, hard-code in the section numbers as tags kvs = PandocAttributes(attrs, 'pandoc').kvs if numbersections and fmt in ['html', 'html5'] and 'tag' not in kvs: if kvs['secno'] != cursec: cursec = kvs['secno'] Nreferences = 1 kvs['tag'] = cursec + '.' + str(Nreferences) Nreferences += 1 # Save to the global references tracker eq['is_tagged'] = 'tag' in kvs if eq['is_tagged']: # Remove any surrounding quotes if kvs['tag'][0] == '"' and kvs['tag'][-1] == '"': kvs['tag'] = kvs['tag'].strip('"') elif kvs['tag'][0] == "'" and kvs['tag'][-1] == "'": kvs['tag'] = kvs['tag'].strip("'") references[attrs[0]] = kvs['tag'] else: Nreferences += 1 references[attrs[0]] = Nreferences # Adjust equation depending on the output format if fmt in ['latex', 'beamer']: if not eq['is_unreferenceable']: # Code in the tags value[-1] += r'\tag{%s}\label{%s}' % \ (references[attrs[0]].replace(' ', r'\ '), attrs[0]) \ if eq['is_tagged'] else r'\label{%s}'%attrs[0] elif fmt in ('html', 'html5'): pass # Insert html in process_equations() instead else: # Hard-code in the number/tag if isinstance(references[attrs[0]], int): # Numbered reference value[-1] += r'\qquad (%d)' % references[attrs[0]] else: # Tagged reference assert isinstance(references[attrs[0]], STRTYPES) text = references[attrs[0]].replace(' ', r'\ ') if text.startswith('$') and text.endswith('$'): # Math tag = text[1:-1] else: # Text tag = r'\text{%s}' % text value[-1] += r'\qquad (%s)' % tag return eq
def _process_figure(value, fmt): """Processes the figure. Returns a dict containing figure properties.""" # pylint: disable=global-statement global Nreferences # Global references counter global has_unnumbered_figures # Flags unnumbered figures were found global cursec # Current section # Parse the image attrs, caption = value[0]['c'][:2] # Initialize the return value fig = { 'is_unnumbered': False, 'is_unreferenceable': False, 'is_tagged': False, 'attrs': attrs } # Bail out if the label does not conform if not LABEL_PATTERN.match(attrs[0]): has_unnumbered_figures = True fig['is_unnumbered'] = True fig['is_unreferenceable'] = True return fig # Process unreferenceable figures if attrs[0] == 'fig:': # Make up a unique description attrs[0] = attrs[0] + str(uuid.uuid4()) fig['is_unreferenceable'] = True unreferenceable.append(attrs[0]) # For html, hard-code in the section numbers as tags kvs = PandocAttributes(attrs, 'pandoc').kvs if numbersections and fmt in ['html', 'html5'] and not 'tag' in kvs: if kvs['secno'] != cursec: cursec = kvs['secno'] Nreferences = 1 kvs['tag'] = cursec + '.' + str(Nreferences) Nreferences += 1 # Save to the global references tracker fig['is_tagged'] = 'tag' in kvs if fig['is_tagged']: # Remove any surrounding quotes if kvs['tag'][0] == '"' and kvs['tag'][-1] == '"': kvs['tag'] = kvs['tag'].strip('"') elif kvs['tag'][0] == "'" and kvs['tag'][-1] == "'": kvs['tag'] = kvs['tag'].strip("'") references[attrs[0]] = kvs['tag'] else: Nreferences += 1 references[attrs[0]] = Nreferences # Adjust caption depending on the output format if fmt in ['latex', 'beamer']: # Append a \label if this is referenceable if not fig['is_unreferenceable']: value[0]['c'][1] += [RawInline('tex', r'\label{%s}' % attrs[0])] else: # Hard-code in the caption name and number/tag if type(references[attrs[0]]) is int: # Numbered reference value[0]['c'][1] = [Str(captionname), Space(), Str('%d:'%references[attrs[0]]), Space()] + \ list(caption) else: # Tagged reference assert type(references[attrs[0]]) in STRTYPES text = references[attrs[0]] if text.startswith('$') and text.endswith('$'): # Math math = text.replace(' ', r'\ ')[1:-1] els = [Math({"t": "InlineMath", "c": []}, math), Str(':')] else: # Text els = [Str(text + ':')] value[0]['c'][1] = [Str(captionname), Space()]+ els + [Space()] + \ list(caption) return fig
def _process_figure(key, value, fmt): """Processes a figure. Returns a dict containing figure properties. Parameters: key - 'Para' (for a normal figure) or 'Div' value - the content of the figure fmt - the output format ('tex', 'html', ...) """ # pylint: disable=global-statement global cursec # Current section being processed global Ntargets # Number of targets in current section (or document) global has_unnumbered_figures # Flags that unnumbered figures were found # Initialize the return value fig = { 'is_unnumbered': False, 'is_unreferenceable': False, 'is_tagged': False } # Bail out if there are no attributes if key == 'Para' and len(value[0]['c']) == 2: has_unnumbered_figures = True fig.update({'is_unnumbered': True, 'is_unreferenceable': True}) return fig # Parse the figure attrs = fig['attrs'] = \ PandocAttributes(value[0]['c'][0] if key == 'Para' else value[0], 'pandoc') fig['caption'] = value[0]['c'][1] if key == 'Para' else None # Bail out if the label does not conform to expectations if not LABEL_PATTERN.match(attrs.id): has_unnumbered_figures = True fig.update({'is_unnumbered': True, 'is_unreferenceable': True}) return fig # Identify unreferenceable figures if attrs.id == 'fig:': attrs.id += str(uuid.uuid4()) fig['is_unreferenceable'] = True # Update the current section number if attrs['secno'] != cursec: # The section number changed cursec = attrs['secno'] # Update the global section tracker Ntargets = 1 # Resets the global target counter # Pandoc's --number-sections supports section numbering latex/pdf, html, # epub, and docx if numbersections: # Latex/pdf supports equation numbers by section natively. For the # other formats we must hard-code in figure numbers by section as # tags. if fmt in ['html', 'html5', 'epub', 'epub2', 'epub3', 'docx'] and \ 'tag' not in attrs: attrs['tag'] = str(cursec + secoffset) + '.' + str(Ntargets) Ntargets += 1 # Update the global targets tracker fig['is_tagged'] = 'tag' in attrs if fig['is_tagged']: # ... then save the tag # Remove any surrounding quotes if attrs['tag'][0] == '"' and attrs['tag'][-1] == '"': attrs['tag'] = attrs['tag'].strip('"') elif attrs['tag'][0] == "'" and attrs['tag'][-1] == "'": attrs['tag'] = attrs['tag'].strip("'") targets[attrs.id] = pandocxnos.Target(attrs['tag'], cursec, attrs.id in targets) else: # ... then save the figure number targets[attrs.id] = pandocxnos.Target(Ntargets, cursec, attrs.id in targets) Ntargets += 1 # Increment the global targets counter return fig
def _process_equation(value, fmt): """Processes the equation. Returns a dict containing eq properties.""" # pylint: disable=global-statement global Ntargets # Global targets counter global cursec # Current section global has_unnumbered_equations # Flags that unnumbered eqs were found # Initialize the return value eq = { 'is_unnumbered': False, 'is_unreferenceable': False, 'is_tagged': False } # Parse the equation attrs = eq['attrs'] = PandocAttributes(value[0], 'pandoc') import sys # Bail out if the label does not conform to expectations if not LABEL_PATTERN.match(attrs.id): eq.update({'is_unnumbered': True, 'is_unreferenceable': True}) return eq # Identify unreferenceable equations if attrs.id == 'eq:': # Make up a unique description attrs.id += str(uuid.uuid4()) eq['is_unreferenceable'] = True sublabels = _get_sublabels(attrs) # Update the current section number if attrs['secno'] != cursec: # The section number changed cursec = attrs['secno'] # Update the global section tracker if numbersections: Ntargets = 0 # Resets the global targets counter # Pandoc's --number-sections supports section numbering latex/pdf, html, # epub, and docx section_prefix = "" if numbersections: # Latex/pdf supports equation numbers by section natively. For the # other formats we must hard-code in equation numbers by section as # tags. if fmt in ['html', 'html4', 'html5', 'epub', 'epub2', 'epub3', 'docx']: section_prefix = str(cursec + secoffset) + '.' eq['is_tagged'] = 'tag' in attrs # Save reference information if eq['is_tagged']: # ... then save the tag # Remove any surrounding quotes if attrs['tag'][0] == '"' and attrs['tag'][-1] == '"': attrs['tag'] = attrs['tag'].strip('"') elif attrs['tag'][0] == "'" and attrs['tag'][-1] == "'": attrs['tag'] = attrs['tag'].strip("'") targets[attrs.id] = pandocxnos.Target(attrs['tag'], cursec, attrs.id in targets) for sublabel in sublabels: # Sublabel number Ntargets will not be shown, fill in a dummy value targets[sublabel] = pandocxnos.Target(Ntargets, cursec, sublabel in targets) else: # Not tagged = numbered if not sublabels: Ntargets += 1 targets[attrs.id] = pandocxnos.Target( section_prefix + str(Ntargets), cursec, attrs.id in targets) else: if eq['is_unreferenceable']: # Main label does not increase number # If there are sublabels, treat each sublabel as an equation with a new number. targets[attrs.id] = pandocxnos.Target( section_prefix + str(Ntargets), cursec, attrs.id in targets) for sublabel in sublabels: Ntargets += 1 targets[sublabel] = pandocxnos.Target( section_prefix + str(Ntargets), cursec, sublabel in targets) else: # Main equation has one number, increased by one Ntargets += 1 targets[attrs.id] = pandocxnos.Target( section_prefix + str(Ntargets), cursec, attrs.id in targets) for i, sublabel in enumerate(sublabels): Nsubtargets = chr(ord('a') + i) targets[sublabel] = pandocxnos.Target( section_prefix + str(Ntargets) + Nsubtargets, cursec, sublabel in targets) return eq
def _process_table(value, fmt): """Processes the table. Returns a dict containing table properties.""" # pylint: disable=global-statement global cursec # Current section being processed global Nreferences # Number of refs in current section (or document) global has_unnumbered_tables # Flags unnumbered tables were found # Initialize the return value table = { 'is_unnumbered': False, 'is_unreferenceable': False, 'is_tagged': False } # Bail out if there are no attributes if len(value) == 5: has_unnumbered_tables = True table.update({'is_unnumbered': True, 'is_unreferenceable': True}) return table # Parse the table attrs = table['attrs'] = PandocAttributes(value[0], 'pandoc') table['caption'] = value[1] # Bail out if the label does not conform to expectations if not LABEL_PATTERN.match(attrs.id): has_unnumbered_tables = True table.update({'is_unnumbered': True, 'is_unreferenceable': True}) return table # Identify unreferenceable tables if attrs.id == 'tbl:': # Make up a unique description attrs.id = 'tbl:' + str(uuid.uuid4()) table['is_unreferenceable'] = True # Update the current section number if attrs['secno'] != cursec: # The section number changed cursec = attrs['secno'] # Update the global section tracker Nreferences = 1 # Resets the global reference counter # Pandoc's --number-sections supports section numbering latex/pdf, html, # epub, and docx if numbersections: if fmt in ['html', 'html5', 'epub', 'epub2', 'epub3', 'docx'] and \ 'tag' not in attrs: attrs['tag'] = str(cursec + secoffset) + '.' + str(Nreferences) Nreferences += 1 # Save reference information table['is_tagged'] = 'tag' in attrs if table['is_tagged']: # Remove any surrounding quotes if attrs['tag'][0] == '"' and attrs['tag'][-1] == '"': attrs['tag'] = attrs['tag'].strip('"') elif attrs['tag'][0] == "'" and attrs['tag'][-1] == "'": attrs['tag'] = attrs['tag'].strip("'") references[attrs.id] = pandocxnos.Target(attrs['tag'], cursec, attrs.id in references) else: # ... then save the table number references[attrs.id] = pandocxnos.Target(Nreferences, cursec, attrs.id in references) Nreferences += 1 # Increment the global reference counter return table
def _is_theorem(item): """Returns True if item is a theorem; false otherwise.""" if item[0][0]['t'] != 'Span': return False attrs = PandocAttributes(item[0][0]['c'][0], 'pandoc') return bool(LABEL_PATTERN.match(attrs.id)) if LABEL_PATTERN else False