Exemple #1
0
def replace_unit(key, value, format, meta):
    """
    Try to perform the replacements in `value` according to `pattern`.

    If nothing is replaced the this function does not return any value. If
    a replacement is performed then a `RawInline` object is returned to
    pandoc.

    Parameters
    ----------

    key : (string) The pandoc element type. Here we check if it is 'Str'.

    value : (string) The original text.
    format : (string) The output format of pandoc.
    meta : Not used here.
    """
    if key == 'Str':
        if format == 'html' or format == 'html5':
            replacement = ("<span class=\"phy-quantity\">"
                           # First regex group is the number
                           "<span class=\"phy-number\">\\1</span>"
                           # First regex group is the unit
                           "<span class=\"phy-unit\">\\2</span>"
                           "</span>")
            newValue = pattern.sub(replacement, value)
            if newValue != value:
                return RawInline("html", newValue)

        elif format == 'latex':
            replacement = "\\SI{\\1}{\\2}"
            newValue = pattern.sub(replacement, value)
            if newValue != value:
                return RawInline("latex", newValue)

        else:
            # For other formats we just add a space between the number and
            # the unit
            replacement = "\\1 \\2"
            newValue = pattern.sub(replacement, value)
            if newValue != value:
                return Str(newValue)

    elif key == 'Math':
        if format == 'latex':
            mathText = value[1]
            replacement = "\\\\SI{\\1}{\\2}"
            newMathText = pattern.sub(replacement, mathText)
            if newMathText != mathText:
                value[1] = newMathText
                return Math(value[0], value[1])
        else:
            mathText = value[1]
            replacement = "\\1\\;\\\\text{\\2}"
            newMathText = pattern.sub(replacement, mathText)
            if newMathText != mathText:
                value[1] = newMathText
                return Math(value[0], value[1])
Exemple #2
0
def gitlab_markdown(key, value, format, meta):
    if key == "CodeBlock":
        [[identification, classes, keyvals], code] = value
        if classes[0] == "math":
            fmt = {'t': 'DisplayMath', 'c': []}
            return Para([Math(fmt, code)])

    elif key == "Math":
        [fmt, code] = value
        if isinstance(fmt, dict) and fmt['t'] == "InlineMath":
            # if fmt['t'] == "InlineMath":
            return Math(fmt, code.strip('`'))
Exemple #3
0
def gitlab_markdown(key, value, format, meta):
    if key == "CodeBlock":
        [[identification, classes, keyvals], code] = value
        if len(classes) > 0 and classes[0] == "math":
            fmt = {'t': 'DisplayMath',
                   'c': []}
            return Para([Math(fmt, code)])

    elif key == "Link":
        if len(value) <= 2:
            return None
        # sys.stderr.write("Raw ")
        # sys.stderr.write(str(len(value)))
        # sys.stderr.write(str(value))
        # sys.stderr.write("\n")
        link = value[2]
        if str(link[0]).endswith(".md"):
            link = '#'
            needSep = 0
            for item in value[1]:
                if 't' in item:
                    if item['t'] == 'Str':
                        if needSep != 0:
                            link += '-'
                        link += item['c'].lower()
                        needSep = 1
            # sys.stderr.write(str(link))
            value[2] = [link, '']
def wordpressify(key, value, format_, meta):
    '''
    Convert math formulas so they work with WordPress.
    When writing to HTML, use -m in pandoc so the $s are preserved
    '''
    if key == 'Math':
        return Math(value[0], "LaTeX " + value[1])
Exemple #5
0
def _add_markup(fmt, eq, value):
    """Adds markup to the output."""

    attrs = eq['attrs']

    # Context-dependent output
    if eq['is_unnumbered']:  # Unnumbered is also unreferenceable
        ret = None
    elif fmt in ['latex', 'beamer']:
        ret = RawInline('tex', r'\begin{equation}%s\end{equation}' % value[-1])
    elif fmt in ('html', 'html5', 'epub', 'epub2', 'epub3') and \
      LABEL_PATTERN.match(attrs.id):
        # Present equation and its number in a span
        num = str(references[attrs.id].num)
        outer = RawInline('html',
                          '<span%sclass="eqnos">' % \
                            (' ' if eq['is_unreferenceable'] else
                             ' id="%s" '%attrs.id))
        inner = RawInline('html', '<span class="eqnos-number">')
        eqno = Math({"t":"InlineMath"}, '(%s)' % num[1:-1]) \
          if num.startswith('$') and num.endswith('$') \
          else Str('(%s)' % num)
        endtags = RawInline('html', '</span></span>')
        ret = [outer, AttrMath(*value), inner, eqno, endtags]
    elif fmt == 'docx':
        # As per http://officeopenxml.com/WPhyperlink.php
        bookmarkstart = \
          RawInline('openxml',
                    '<w:bookmarkStart w:id="0" w:name="%s"/><w:r><w:t>'
                    %attrs.id)
        bookmarkend = \
          RawInline('openxml',
                    '</w:t></w:r><w:bookmarkEnd w:id="0"/>')
        ret = [bookmarkstart, AttrMath(*value), bookmarkend]
    return ret
Exemple #6
0
def cleanup(k, v, fmt, meta):
    if k in ['Math']:
        if fmt in ['latex', 'beamer', 'json', 'html5']:
            math_type = v[0].get('t', None)
            if math_type in [u'InlineMath'] and len(v) > 1:
                solution_match = STRIP_BACKTICKS_RE.search(v[1])
                if solution_match:
                    return Math(v[0], solution_match.group('contents'))
def process_equations(key, value, fmt, meta):
    """Processes the attributed equations."""

    if key == 'Math' and len(value) == 3:

        # Process the equation
        eq = _process_equation(value, fmt)

        # Get the attributes and label
        attrs = eq['attrs']
        label = attrs[0]
        if eq['is_unreferenceable']:
            attrs[0] = ''  # The label isn't needed outside this function

        # Context-dependent output
        if eq['is_unnumbered']:  # Unnumbered is also unreferenceable
            return None
        if fmt in ['latex', 'beamer']:
            return RawInline('tex',
                             r'\begin{equation}%s\end{equation}' % value[-1])
        if fmt in ('html', 'html5') and LABEL_PATTERN.match(label):
            # Present equation and its number in a span
            text = str(references[label])
            outerspan = RawInline('html',
                                  '<span %s style="display: inline-block; '
                                  'position: relative; width: 100%%">'%(''\
                                  if eq['is_unreferenceable'] \
                                  else 'id="%s"'%label))
            innerspan = RawInline(
                'html', '<span style="position: absolute; '
                'right: 0em; top: %s; line-height:0; '
                'text-align: right">' % ('0' if text.startswith('$')
                                         and text.endswith('$') else '50%', ))
            num = Math({"t":"InlineMath"}, '(%s)' % text[1:-1]) \
              if text.startswith('$') and text.endswith('$') \
              else Str('(%s)' % text)
            endspans = RawInline('html', '</span></span>')
            return [outerspan, AttrMath(*value), innerspan, num, endspans]
        if fmt in ('epub', 'epub2', 'epub3') and LABEL_PATTERN.match(label):
            outerspan = RawInline('html',
                                  '<span %s style="display: inline-block; '
                                  'position: relative; width: 100%%">'%(''\
                                  if eq['is_unreferenceable'] \
                                  else 'id="%s"'%label))
            endspan = RawInline('html', '</span>')
            return [outerspan, AttrMath(*value), endspan]
        if fmt == 'docx':
            # As per http://officeopenxml.com/WPhyperlink.php
            bookmarkstart = \
              RawInline('openxml',
                        '<w:bookmarkStart w:id="0" w:name="%s"/><w:r><w:t>'
                        %label)
            bookmarkend = \
              RawInline('openxml',
                        '</w:t></w:r><w:bookmarkEnd w:id="0"/>')
            return [bookmarkstart, AttrMath(*value), bookmarkend]

    return None
Exemple #8
0
def processMathTag(key, value, _format, _meta):
  if key == "Math":
    [fmt, code] = value
    searchRe = re.search(r'\s*\\tag\s*{(.+)}|\s*\\tag\s*(\d)', code)
    if searchRe != None:
      if searchRe.group(1):
        tagContent = searchRe.group(1).replace('$', '')
      else:
        tagContent = searchRe.group(2).replace('$', '')
      code = code.replace(searchRe.group(), '\\#(' + tagContent + ')')
      return Math(fmt, code)
Exemple #9
0
def cleveref_ast_sub(source):
    res = []
    sub_res = cleveref_re.sub(cleveref_sub, source)
    try:
        prefix_str, ref_str = sub_res.split('~')
        res += [Str(prefix_str + u'\xa0')]
    except:
        ref_str = sub_res

    res += [Math({'t': 'InlineMath', 'c': []}, ref_str)]
    return res
def tikz(key, value, format, meta):
    global N_FIGS, N_TABS
    if key == 'Div':
        if "figure*" in str(value):
            N_FIGS += 1
            [[ident, classes, kvs], _contents] = value
            newcontents = [html(fig.format(path=f"float{N_FIGS:03}.png"))]
            ident = f"fig:{N_FIGS}"
            return Div([ident, classes, kvs], newcontents)
    if key == 'Table':
        N_TABS += 1
        newcontents = [html(fig.format(path=f"float{N_TABS:03}.png"))]
        ident = f"tab:{N_TABS}"
        return Div([ident, [], []], newcontents)
    if key == 'Link':
        label = value[-1][0].replace("#", "")
        if len(label.split(",")) > 1:
            links = []
            for label in label.split(","):
                pref = label.split(":")[0]
                # ppprint(pref, "pref")
                links.append(
                    link(href=f"#{pref}:{label_to_fignum[label]}",
                         label=f"{label_to_fignum[label]}"), )
                links.append(Str(","))

            del links[-1]
            return links
        if label in label_to_fignum:
            pref = label.split(":")[0]
            value[-2][0]['c'] = f"{label_to_fignum[label]}"
            value[-1][0] = f"#{pref}:{label_to_fignum[label]}"
        if "eq:" in label:
            return Math({'t': 'InlineMath'}, f"\eqref{{{label}}}")
        if "sec:" in label:
            value[-2][0]['c'] = value[-2][0]['c'][1:-1].split(":")[1]

    if key == 'Span' and "label" in str(value):
        value[-1][0]['c'] = ""
    if key == 'Para':
        ret = []
        rets = []
        for v in value:
            if v['t'] == 'Math' and v['c'][0]['t'] == 'DisplayMath':
                rets.append(Para(ret))
                rets.append(Para([v]))
                ret = []
            else:
                ret.append(v)
        if len(ret):
            ret = Para(ret)
            rets.append(ret)
        if len(rets):
            return rets
Exemple #11
0
def replace_smallcaps(key, val, fmt=None, meta=None):
    """
    Replaces \textsc with a hack that has the same effect.

    https://stackoverflow.com/questions/11576237/mathjax-textsc
    """
    if key != 'Math':
        return

    latex = val[1]
    latex = TEXTSC_REGEX.sub(_textsc_replace, latex)
    return Math(val[0], latex)
Exemple #12
0
def _adjust_caption(fmt, fig, value):
    """Adjusts the caption."""
    attrs, caption = fig['attrs'], fig['caption']
    if fmt in ['latex', 'beamer']:  # Append a \label if this is referenceable
        if PANDOCVERSION < '1.17' and not fig['is_unreferenceable']:
            # pandoc >= 1.17 installs \label for us
            value[0]['c'][1] += \
              [RawInline('tex', r'\protect\label{%s}'%attrs.id)]
    else:  # Hard-code in the caption name and number/tag
        if fig['is_unnumbered']:
            return
        sep = {
            'none': '',
            'colon': ':',
            'period': '.',
            'space': ' ',
            'quad': u'\u2000',
            'newline': '\n'
        }[separator]

        num = targets[attrs.id].num
        if isinstance(num, int):  # Numbered target
            if fmt in ['html', 'html5', 'epub', 'epub2', 'epub3']:
                value[0]['c'][1] = [
                    RawInline('html', r'<span>'),
                    Str(captionname),
                    Space(),
                    Str('%d%s' % (num, sep)),
                    RawInline('html', r'</span>')
                ]
            else:
                value[0]['c'][1] = [
                    Str(captionname),
                    Space(),
                    Str('%d%s' % (num, sep))
                ]
            value[0]['c'][1] += [Space()] + list(caption)
        else:  # Tagged target
            if num.startswith('$') and num.endswith('$'):  # Math
                math = num.replace(' ', r'\ ')[1:-1]
                els = [Math({"t": "InlineMath", "c": []}, math), Str(sep)]
            else:  # Text
                els = [Str(num + sep)]
            if fmt in ['html', 'html5', 'epub', 'epub2', 'epub3']:
                value[0]['c'][1] = \
                  [RawInline('html', r'<span>'),
                   Str(captionname),
                   Space()] + els + [RawInline('html', r'</span>')]
            else:
                value[0]['c'][1] = [Str(captionname), Space()] + els
            value[0]['c'][1] += [Space()] + list(caption)
def _add_markup(fmt, eq, value):
    """Adds markup to the output."""

    attrs = eq['attrs']

    # Context-dependent output
    if eq['is_unnumbered']:  # Unnumbered is also unreferenceable
        ret = None
    elif fmt in ['latex', 'beamer']:
        if re.search(r'&', value[-1]) is not None:
            # check if it's an aligned multiline equation
            equation = r'\begin{split}%s\end{split}'%value[-1]
            environment = "equation"
        elif re.search(r'\\\\', value[-1]) is not None:
            # check if it's an unaligned multiline equation
            equation = value[-1]
            environment = "multiline"
        else:
            # regular equation
            equation = value[-1]
            environment = "equation"

        ret = RawInline('tex',
                        "\\begin{{{env}}}{eq}\\end{{{env}}}".format(env=environment,
                                                                    eq=equation))
    elif fmt in ('html', 'html5', 'epub', 'epub2', 'epub3') and \
      LABEL_PATTERN.match(attrs.id):
        # Present equation and its number in a span
        num = str(references[attrs.id].num)
        outer = RawInline('html',
                          '<span%sclass="eqnos">' % \
                            (' ' if eq['is_unreferenceable'] else
                             ' id="%s" '%attrs.id))
        inner = RawInline('html', '<span class="eqnos-number">')
        eqno = Math({"t":"InlineMath"}, '(%s)' % num[1:-1]) \
          if num.startswith('$') and num.endswith('$') \
          else Str('(%s)' % num)
        endtags = RawInline('html', '</span></span>')
        ret = [outer, AttrMath(*value), inner, eqno, endtags]
    elif fmt == 'docx':
        # As per http://officeopenxml.com/WPhyperlink.php
        bookmarkstart = \
          RawInline('openxml',
                    '<w:bookmarkStart w:id="0" w:name="%s"/><w:r><w:t>'
                    %attrs.id)
        bookmarkend = \
          RawInline('openxml',
                    '</w:t></w:r><w:bookmarkEnd w:id="0"/>')
        ret = [bookmarkstart, AttrMath(*value), bookmarkend]
    return ret
Exemple #14
0
    def _cite_replacement(key, value, fmt, meta):
        """Returns context-dependent content to replace a Cite element."""

        assert key == 'Cite'

        attrs, label = value[0], _get_label(key, value)
        attrs = PandocAttributes(attrs, 'pandoc')

        assert label in references

        # Get the replacement value
        text = str(references[label])

        # Choose between \Cref, \cref and \ref
        use_cleveref = attrs['modifier'] in ['*', '+'] \
          if 'modifier' in attrs.kvs else use_cleveref_default
        plus = attrs['modifier'] == '+' if 'modifier' in attrs.kvs \
          else use_cleveref_default
        name = plusname[0] if plus else starname[0]  # Name used by cref

        # The replacement depends on the output format
        if fmt == 'latex':
            if use_cleveref:
                # Renew commands needed for cleveref fakery
                if not 'xnos-cleveref-fake' in meta or \
                  get_meta(meta, 'xnos-cleveref-fake'):
                    faketex = (r'\xrefname' if plus else r'\Xrefname') + \
                      '{%s}' % name
                else:
                    faketex = ''
                macro = r'\cref' if plus else r'\Cref'
                ret = RawInline('tex', r'%s%s{%s}'%(faketex, macro, label))
            elif use_eqref:
                ret = RawInline('tex', r'\eqref{%s}'%label)
            else:
                ret = RawInline('tex', r'\ref{%s}'%label)
        else:
            if use_eqref:
                text = '(' + text + ')'

            linktext = [Math({"t":"InlineMath", "c":[]}, text[1:-1]) \
               if text.startswith('$') and text.endswith('$') \
               else Str(text)]

            link = elt('Link', 2)(linktext, ['#%s' % label, '']) \
              if _PANDOCVERSION < '1.16' else \
              Link(['', [], []], linktext, ['#%s' % label, ''])
            ret = ([Str(name), Space()] if use_cleveref else []) + [link]

        return ret
Exemple #15
0
def insert_equation_labels(val):
    '''
    Insert equation numbers as strings after equations. Returns the ID
    of the equation and its new children.
    '''
    latex = val[1]
    match = LABEL_REGEX.search(latex)
    if match:
        label = match.group(1)
        index = incr_latest_index('equation')
        ref_index = 'equation-%d' % index

        # Replace label with actual number in the equation
        latex = latex.replace(match.group(0), '')
        latex = latex + '\\tag{%s}' % index

        label_map[label] = Label(
            ref_string='Equation %d' % index,
            ref_index=ref_index,
            prev_strings=['equation', 'eqn.', 'eqn', 'eq.', 'eq'],
        )

        return ref_index, [Math(val[0], latex)]
    return '', [Math(*val)]
def _adjust_caption(fmt, table, value):
    """Adjusts the caption."""
    attrs, caption = table['attrs'], table['caption']
    num = references[attrs.id].num
    if fmt in ['latex', 'beamer']:  # Append a \label if this is referenceable
        if not table['is_unreferenceable']:
            value[1] += [RawInline('tex', r'\label{%s}' % attrs.id)]
    else:  # Hard-code in the caption name and number/tag
        sep = {
            'none': '',
            'colon': ':',
            'period': '.',
            'space': ' ',
            'quad': u'\u2000',
            'newline': '\n'
        }[separator]

        if isinstance(num, int):  # Numbered reference
            if fmt in ['html', 'html5', 'epub', 'epub2', 'epub3']:
                value[1] = [
                    RawInline('html', r'<span>'),
                    Str(captionname),
                    Space(),
                    Str('%d%s' % (num, sep)),
                    RawInline('html', r'</span>')
                ]
            else:
                value[1] = [
                    Str(captionname),
                    Space(),
                    Str('%d%s' % (num, sep))
                ]
            value[1] += [Space()] + list(caption)
        else:  # Tagged reference
            assert isinstance(num, STRTYPES)
            if num.startswith('$') and num.endswith('$'):
                math = num.replace(' ', r'\ ')[1:-1]
                els = [Math({"t": "InlineMath", "c": []}, math), Str(sep)]
            else:  # Text
                els = [Str(num + sep)]
            if fmt in ['html', 'html5', 'epub', 'epub2', 'epub3']:
                value[1] = \
                  [RawInline('html', r'<span>'),
                   Str(captionname),
                   Space()] + els + [RawInline('html', r'</span>')]
            else:
                value[1] = [Str(captionname), Space()] + els
            value[1] += [Space()] + list(caption)
Exemple #17
0
def cross_refs(key, value, fmt, meta):
    """Lookup reference and return number or create reference/number."""

    global crossrefs

    if key == 'Str':
        crossref, string = parse(crossrefs, value)
        if crossref:
            return Str(string)

    if key == 'Math':
        t, s = value
        crossref, string = parse(crossrefs, s)
        if crossref:
            s = s.replace('@{' + crossref + '}', string)
            return Math(t, s)
Exemple #18
0
def processMathDoubleBackslash(key, value, _format, _meta):
  if key == 'Para':
    if len(value) == 1 and value[0]['t'] == 'Math':
      [fmt, code] = value[0]['c']
      if '\\\\' in code:
        if fmt['t'] == 'DisplayMath':
          res = code.split('\\\\')
          for item in res:
            if item.count('\\begin') != item.count('\\end'):
              return
          return list(map(lambda item : Para([Math(fmt, item)]), res))
  elif key == 'Math':
    [fmt, code] = value
    if '\\\\' in code:
      if fmt['t'] == 'InlineMath':
        res = list(filter(None, re.split(r'( *\\\\ *)', code)))
        mathlist = list(map(lambda item : LineBreak() if re.match(r'( *\\\\ *)', item) else Math(fmt, item), res))
        return mathlist
Exemple #19
0
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
Exemple #20
0
def processMathOverToFrac(key, value, _format, _meta):
  if key == "Math":
    [fmt, code] = value
    while '\\over' in code:
      code = convertOverToFrac(code)
    return Math(fmt, code)
Exemple #21
0
def filter_main(key, value, format, meta):
    # f.write(repr(key) + '\n')
    # f.write(repr(value) + '\n')
    # f.write('------\n')
    if key == 'CodeBlock':
        text = value[1]
        m = re.match(r'%%%%lyxblog-raw\n(.*)', text, flags=re.DOTALL | re.I)
        if m:
            return RawBlock('html', m[1])
    elif key == 'Math' and value[0]['t'] == 'DisplayMath':  # i.e. not inline
        # MathJax supports labels and eq. numbering only for AMS envs, so we
        # convert non-AMS envs into AMS envs.
        latex = value[1]
        if not latex.startswith(r'\begin{'):  # not AMS env
            # We assume there are no comments inside math blocks (if the file
            # is produced by LyX, there shouldn't be any).
            pos = latex.find(r'\label{')
            if pos == -1:  # no labels => no numbering
                fixed = r'\begin{align*}' + value[1] + r'\end{align*}'
            else:
                fixed = r'\begin{align}' + value[1] + r'\end{align}'
            return Math(value[0], fixed)
    elif key == 'Span':
        # This supports general labels (i.e. labels not in equations, captions
        # or section headers).
        id, classes, key_values = value[0]
        if len(key_values) == 1 and key_values[0][0] == 'label':
            # we remove the text from the label.
            return Span(value[0], [])
    elif key == 'Header':
        content = value[2]
        if content[-1]['t'] == 'Span':
            [id, classes, key_values], text = content[-1]['c']
            if len(key_values) == 1 and key_values[0][0] == 'label':
                # we label the header itself (id) and delete the label-span
                label_name = key_values[0][1]
                value[1][0] = label_name
                return Header(value[0], value[1], content[:-1])
    elif key == 'Math' and value[0]['t'] == 'InlineMath':
        if value[1].startswith('\\ref{') and value[1][-1] == '}':
            name = value[1][len('\\ref{'):-1]

            # We try to extract the text from the label itself.
            # (=00007B and =00007D represent '{' and '}' and are in the TeX
            # file produced by LyX.)
            m = re.match(r'.*=00007B([^}]+)=00007D$', name)
            if m:
                return RawInline('html',
                                 '<a href="#{}">{}</a>'.format(name, m[1]))

            # We only handle references to sections and images here.
            # (Mathjax already handles the equations.)
            num = sec_name_to_num.get(name, img_name_to_num.get(name, None))
            if num:
                return RawInline('html',
                                 '<a href="#{}">{}</a>'.format(name, num))

    elif key == 'Para' and value[0]['t'] == 'Image':
        # NOTE:
        #   In pandoc 2, a Para[Image] where Image.title is 'fig:' becomes
        #   a <figure> with a <figcaption>.

        [id, classes, style], alt, [src, title] = value[0]['c']
        style = {k: v for k, v in style}
        width = float(style.get('width', '100.0%')[:-1])
        margin = (100 - width) / 2

        global image_idx
        src = image_info[image_idx]
        image_idx += 1

        label = ''
        if alt[-1]['t'] == 'Span':
            id, classes, key_values = alt[-1]['c'][0]  # attr
            key_values = dict(key_values)
            if 'label' in key_values:
                # remove the label from the caption (it'll be put right before
                # the image).
                alt = alt[:-1]  # remove the label from the caption
                label = key_values['label']

        fake_class = '{}:{:.5}%'.format(UID2, margin)
        img_attrs = make_attrs(label, [fake_class], {'width': '100%'})
        caption = [Emph([Str('Figure {}.'.format(image_idx))])]
        if title == 'fig:':
            caption += [Space()] + alt

        para_content = [Image(img_attrs, caption, (src, 'fig:'))]

        return Para(para_content)
Exemple #22
0
def latex_prefilter(key, value, oformat, meta, *args, **kwargs):
    r""" A prefilter that adds more latex capabilities to Pandoc's tex to
    markdown features.

    Currently implemented:
        * Keeps unmatched `\eqref` (drops the rest)
        * Wraps equation blocks with `equation[*]` environment depending on
          whether or not their body contains a `\label`
        * Converts custom environments to div objects

    Set the variables `preserved_tex` and `env_conversions` to
    allow more raw latex commands and to convert latex environment names
    to CSS class names, respectively.

    # TODO: Describe more.

    # XXX: This filter does some questionable recursive calling at the
    # shell level.

    Parameters
    ==========
    TODO: Document parameters.

    """
    pandoc_logger.debug((u"Filter key:{}, value:{}, meta:{},"
                   "args:{}, kwargs:{}\n").format(
                       key, value, meta, args, kwargs))

    global custom_inline_math, preserved_tex,\
        env_conversions, figure_dirs, fig_fname_ext

    custom_inline_math = custom_inline_math.copy()
    custom_inline_math.update(meta.get(
        'custom_inline_math', {}).get('c', {}))

    env_conversions = env_conversions.copy()
    env_conversions.update(meta.get(
        'env_conversions', {}).get('c', {}))

    preserved_tex += meta.get('preserved_tex', {}).get('c', [])

    figure_dir_meta = meta.get('figure_dir', {}).get('c', None)
    if figure_dir_meta is not None:
        figure_dirs.add(figure_dir_meta)

    fig_fname_ext = meta.get('figure_ext', {}).get('c', None)

    if key == 'RawInline' and value[0] == 'latex':
        if any(c_ in value[1] for c_ in preserved_tex):
            # Check for `\includegraphics` commands and their
            # corresponding files.
            new_value = copy(value[1])
            figure_files = graphics_pattern.findall(new_value)

            def repstep(x, y):
                new_y = rename_find_fig(y, figure_dirs, fig_fname_ext)
                return x.replace(y, new_y)

            new_value = reduce(repstep, figure_files, new_value)

            pandoc_logger.debug("figure_files: {}\tnew_value: {}\n".format(
                figure_files, new_value))

            for from_, to_ in custom_inline_math.items():
                if callable(to_):
                    new_value = to_(new_value)
                else:
                    new_value = new_value.replace(from_, to_)
                    new_value = [Math({'t': 'InlineMath', 'c': []},
                                      new_value)]

            return new_value
        else:
            # Check for `\graphicspaths` commands to parse for
            # new paths.
            gpaths_matches = gpath_pattern_1.search(value[1])
            if gpaths_matches is not None:
                for gpaths in gpaths_matches.groups():
                    gpaths = gpath_pattern_2.findall(gpaths)
                    figure_dirs.update(gpaths)

            # Do not include `\graphicspath` in output.
            return []

    elif key == "Image":

        return process_image(key, value, oformat, meta)

    elif key == "Math" and value[0]['t'] == "DisplayMath":

        star = '*'
        if '\\label' in value[1]:
            star = ''
        wrapped_value = ("\\begin{{equation{}}}\n"
                         "{}\n"
                         "\\end{{equation{}}}").format(
                             star, value[1], star)
        return Math(value[0], wrapped_value)

    if key == 'RawBlock' and value[0] == 'latex':

        return process_latex_envs(key, value, oformat, meta)

    elif "Raw" in key:
        return []
Exemple #23
0
    def _cite_replacement(key, value, fmt, meta):
        """Returns context-dependent content to replace a Cite element."""

        assert key == 'Cite'

        # Extract the attributes
        attrs = PandocAttributes(value[0], 'pandoc')

        # Check if the nolink attribute is set
        nolink = attrs['nolink'].capitalize() == 'True' if 'nolink' in attrs \
          else False

        # Extract the label
        label = value[-2][0]['citationId']
        if allow_implicit_refs and not label in references and ':' in label:
            testlabel = label.split(':')[-1]
            if testlabel in references:
                label = testlabel

        # Get the target metadata; typecast it as a Target for easier access
        target = references[label] if label in references else None
        if target and not isinstance(target, Target):
            target = Target(*target)

        # Issue a warning for duplicate targets
        if _WARNINGLEVEL and target and target.has_duplicate:
            msg = textwrap.dedent("""
                %s: Referenced label has duplicate: %s
            """ % (_FILTERNAME, label))
            STDERR.write(msg)
            STDERR.flush()

        # Get the replacement value
        text = str(target.num) if target else '??'

        # Choose between \Cref, \cref and \ref
        use_cleveref = attrs['modifier'] in ['*', '+'] \
          if 'modifier' in attrs else use_cleveref_default
        is_plus_ref = attrs['modifier'] == '+' if 'modifier' in attrs \
          else use_cleveref_default
        refname = plusname[0] if is_plus_ref else starname[0]  # Reference name

        # The replacement content depends on the output format
        if fmt == 'latex':
            if use_cleveref:
                macro = r'\cref' if is_plus_ref else r'\Cref'
                ret = RawInline('tex', r'%s{%s}' % (macro, label))
            elif use_eqref:
                ret = RawInline('tex', r'\eqref{%s}' % label)
            else:
                ret = RawInline('tex', r'\ref{%s}' % label)
            if nolink:  # https://tex.stackexchange.com/a/323919
                ret['c'][1] = \
                  r'{\protect\NoHyper' + ret['c'][1] + r'\protect\endNoHyper}'
        else:
            if use_eqref:
                text = '(' + text + ')'

            elem = Math({"t":"InlineMath", "c":[]}, text[1:-1]) \
              if text.startswith('$') and text.endswith('$') \
              else Str(text)

            if not nolink and target:
                prefix = 'ch%03d.xhtml' % target.secno \
                  if fmt in ['epub', 'epub2', 'epub3'] and \
                  target.secno else ''

                elem = elt('Link', 2)([elem],
                                      ['%s#%s' % (prefix, label), '']) \
                  if version(_PANDOCVERSION) < version('1.16') else \
                  Link(['', [], []], [elem], ['%s#%s' % (prefix, label), ''])

            ret = ([Str(refname + NBSP)] if use_cleveref else []) + [elem]

        # If the Cite was square-bracketed then wrap everything in a span
        s = stringify(value[-1])

        # pandoc strips off intervening space between the prefix and the Cite;
        # we may have to add it back in
        prefix = value[-2][0]['citationPrefix']
        spacer = [Space()] \
          if prefix and not stringify(prefix).endswith(('{', '+', '*', '!')) \
          else []
        if s.startswith('[') and s.endswith(']'):
            els = value[-2][0]['citationPrefix'] + \
              spacer + ([ret] if fmt == 'latex' else ret) + \
              value[-2][0]['citationSuffix']
            # We don't yet know if there will be attributes, so leave them
            # as None.  This is fixed later when attributes are processed.
            ret = Span(None, els)

        return ret
Exemple #24
0
def reformat_math(key, value, format, meta):
    if key != 'Str':
        return
    if not any(c in value for c in math_characters):
        return
    return Math([], value)
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
Exemple #26
0
 def test_replace_smallcaps(self):
     result = replace_smallcaps('Math', [
         {'t': 'DisplayMath'}, '\\text{\\textsc{3CosAdd} }'])
     self.assertEqual(result, Math(
         {'t': 'DisplayMath'},
         '\\rm{3C{\small OS}A{\small DD}}'))