Пример #1
0
def sphinx_code_orig(filestr, format):
    # NOTE: THIS FUNCTION IS NOT USED!!!!!!

    # In rst syntax, code blocks are typeset with :: (verbatim)
    # followed by intended blocks. This function indents everything
    # inside code (or TeX) blocks.

    # grab #sphinx code-blocks: cod=python cpp=c++ etc line
    # (do this before code is inserted in case verbatim blocks contain
    # such specifications for illustration)
    m = re.search(r'#\s*[Ss]phinx\s+code-blocks?:(.+?)\n', filestr)
    if m:
        defs_line = m.group(1)
        # turn defs into a dictionary definition:
        defs = {}
        for definition in defs_line.split():
            key, value = definition.split('=')
            defs[key] = value
    else:
        # default mappings:
        defs = dict(
            cod='python',
            pro='python',
            pycod='python',
            cycod='cython',
            pypro='python',
            cypro='cython',
            fcod='fortran',
            fpro='fortran',
            ccod='c',
            cppcod='c++',
            cpro='c',
            cpppro='c++',
            mcod='matlab',
            mpro='matlab',
            plcod='perl',
            plpro='perl',
            shcod='bash',
            shpro='bash',
            rbcod='ruby',
            rbpro='ruby',
            sys='console',
            dat='python',
            ipy='python',
            xmlcod='xml',
            xmlpro='xml',
            xml='xml',
            htmlcod='html',
            htmlpro='html',
            html='html',
            texcod='latex',
            texpro='latex',
            tex='latex',
        )
        # (the "python" typesetting is neutral if the text
        # does not parse as python)

    # first indent all code/tex blocks by 1) extracting all blocks,
    # 2) intending each block, and 3) inserting the blocks:
    filestr, code_blocks, tex_blocks = remove_code_and_tex(filestr)
    for i in range(len(code_blocks)):
        code_blocks[i] = indent_lines(code_blocks[i], format)
    for i in range(len(tex_blocks)):
        tex_blocks[i] = indent_lines(tex_blocks[i], format)
        # remove all \label{}s inside tex blocks:
        tex_blocks[i] = re.sub(
            fix_latex(r'\label\{.+?\}', application='match'), '',
            tex_blocks[i])
        # remove those without \ if there are any:
        tex_blocks[i] = re.sub(r'label\{.+?\}', '', tex_blocks[i])

        # fix latex constructions that do not work with sphinx math
        commands = [
            r'\begin{equation}',
            r'\end{equation}',
            r'\begin{equation*}',
            r'\end{equation*}',
            r'\begin{eqnarray}',
            r'\end{eqnarray}',
            r'\begin{eqnarray*}',
            r'\end{eqnarray*}',
            r'\begin{align}',
            r'\end{align}',
            r'\begin{align*}',
            r'\end{align*}',
            r'\begin{multline}',
            r'\end{multline}',
            r'\begin{multline*}',
            r'\end{multline*}',
            r'\begin{split}',
            r'\end{split}',
            r'\begin{gather}',
            r'\end{gather}',
            r'\begin{gather*}',
            r'\end{gather*}',
            r'\[',
            r'\]',
            # some common abbreviations (newcommands):
            r'\beqan',
            r'\eeqan',
            r'\beqa',
            r'\eeqa',
            r'\balnn',
            r'\ealnn',
            r'\baln',
            r'\ealn',
            r'\beq',
            r'\eeq',  # the simplest, contained in others, must come last!
        ]
        for command in commands:
            tex_blocks[i] = tex_blocks[i].replace(command, '')
        tex_blocks[i] = re.sub('&\s*=\s*&', ' &= ', tex_blocks[i])
        # provide warnings for problematic environments
        if '{alignat' in tex_blocks[i]:
            print '\nWarning: the "alignat" environment will give errors in Sphinx:\n\n', tex_blocks[
                i], '\n'

    filestr = insert_code_and_tex(filestr, code_blocks, tex_blocks, 'rst')

    for key in defs:
        language = defs[key]
        if not language in legal_pygments_languages:
            raise TypeError('%s is not a legal Pygments language '\
                            '(lexer) in line with:\n  %s' % \
                                (language, defs_line))
        #filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
        #                 '\n.. code-block:: %s\n\n' % defs[key], filestr,
        #                 flags=re.MULTILINE)
        cpattern = re.compile(r'^!bc\s+%s\s*\n' % key, flags=re.MULTILINE)
        filestr, n = cpattern.subn('\n.. code-block:: %s\n\n' % defs[key],
                                   filestr)
        print key, n
        if n > 0:
            print 'sphinx: %d subst %s by %s' % (n, key, defs[key])

    # any !bc with/without argument becomes a py (python) block:
    #filestr = re.sub(r'^!bc.+\n', '\n.. code-block:: py\n\n', filestr,
    #                 flags=re.MULTILINE)
    cpattern = re.compile(r'^!bc.+$', flags=re.MULTILINE)
    filestr = cpattern.sub('\n.. code-block:: py\n\n', filestr)

    filestr = re.sub(r'^!ec *\n', '\n', filestr, flags=re.MULTILINE)
    #filestr = re.sub(r'^!ec\n', '\n', filestr, flags=re.MULTILINE)
    #filestr = re.sub(r'^!ec\n', '', filestr, flags=re.MULTILINE)
    filestr = re.sub(r'^!bt *\n',
                     '\n.. math::\n\n',
                     filestr,
                     flags=re.MULTILINE)
    filestr = re.sub(r'^!et *\n', '\n\n', filestr, flags=re.MULTILINE)

    return filestr
Пример #2
0
def sphinx_code_newmathlabels(filestr, format):
    # NOTE: THIS FUNCTION IS NOT USED!!!!!!

    # In rst syntax, code blocks are typeset with :: (verbatim)
    # followed by intended blocks. This function indents everything
    # inside code (or TeX) blocks.

    # grab #sphinx code-blocks: cod=python cpp=c++ etc line
    # (do this before code is inserted in case verbatim blocks contain
    # such specifications for illustration)
    m = re.search(r'#\s*[Ss]phinx\s+code-blocks?:(.+?)\n', filestr)
    if m:
        defs_line = m.group(1)
        # turn defs into a dictionary definition:
        defs = {}
        for definition in defs_line.split():
            key, value = definition.split('=')
            defs[key] = value
    else:
        # default mappings:
        defs = dict(cod='python',
                    pycod='python',
                    cppcod='c++',
                    fcod='fortran',
                    ccod='c',
                    pro='python',
                    pypro='python',
                    cpppro='c++',
                    fpro='fortran',
                    cpro='c',
                    sys='console',
                    dat='python')
        # (the "python" typesetting is neutral if the text
        # does not parse as python)

    # First indent all code/tex blocks by 1) extracting all blocks,
    # 2) intending each block, and 3) inserting the blocks.
    # In between, handle the math blocks.

    filestr, code_blocks, tex_blocks = remove_code_and_tex(filestr)
    for i in range(len(code_blocks)):
        code_blocks[i] = indent_lines(code_blocks[i], format)

    math_labels = []
    for i in range(len(tex_blocks)):
        tex_blocks[i] = indent_lines(tex_blocks[i], format)
        # extract all \label{}s inside tex blocks and typeset them
        # with :label: tags
        label_regex1 = fix_latex(r'\label\{(.+?)\}', application='match')
        label_regex2 = fix_latex(r'label\{(.+?)\}', application='match')
        math_labels.extend(re.findall(label_regex1, tex_blocks[i]))
        tex_blocks[i] = re.sub(label_regex1, r' :label: \g<1> ', tex_blocks[i])
        # handle also those without \ if there are any:
        math_labels.extend(re.findall(label_regex2, tex_blocks[i]))
        tex_blocks[i] = re.sub(label_regex2, r' :label: \g<1> ', tex_blocks[i])

    # replace all references to equations:
    for label in math_labels:
        filestr = filestr.replace(':ref:`%s`' % label, ':eq:`%s`' % label)

    filestr = insert_code_and_tex(filestr, code_blocks, tex_blocks, 'rst')

    for key in defs:
        language = defs[key]
        if not language in legal_pygments_languages:
            raise TypeError('%s is not a legal Pygments language '\
                            '(lexer) in line with:\n  %s' % \
                                (language, defs_line))
        #filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
        #                 '\n.. code-block:: %s\n\n' % defs[key], filestr,
        #                 flags=re.MULTILINE)
        cpattern = re.compile(r'^!bc\s+%s\s*\n' % key, flags=re.MULTILINE)
        filestr = cpattern.sub('\n.. code-block:: %s\n\n' % defs[key], filestr)

    # any !bc with/without argument becomes a py (python) block:
    #filestr = re.sub(r'^!bc.+\n', '\n.. code-block:: py\n\n', filestr,
    #                 flags=re.MULTILINE)
    cpattern = re.compile(r'^!bc.+$', flags=re.MULTILINE)
    filestr = cpattern.sub('\n.. code-block:: py\n\n', filestr)

    filestr = re.sub(r'!ec *\n', '\n', filestr)
    #filestr = re.sub(r'!ec\n', '\n', filestr)
    #filestr = re.sub(r'!ec\n', '', filestr)
    filestr = re.sub(r'!bt *\n', '\n.. math::\n   :nowrap:\n\n', filestr)
    filestr = re.sub(r'!et *\n', '\n\n', filestr)

    return filestr
Пример #3
0
def sphinx_code_newmathlabels(filestr, format):
    # NOTE: THIS FUNCTION IS NOT USED!!!!!!

    # In rst syntax, code blocks are typeset with :: (verbatim)
    # followed by intended blocks. This function indents everything
    # inside code (or TeX) blocks.

    # grab #sphinx code-blocks: cod=python cpp=c++ etc line
    # (do this before code is inserted in case verbatim blocks contain
    # such specifications for illustration)
    m = re.search(r'#\s*[Ss]phinx\s+code-blocks?:(.+?)\n', filestr)
    if m:
        defs_line = m.group(1)
        # turn defs into a dictionary definition:
        defs = {}
        for definition in defs_line.split():
            key, value = definition.split('=')
            defs[key] = value
    else:
        # default mappings:
        defs = dict(cod='python', pycod='python', cppcod='c++',
                    fcod='fortran', ccod='c',
                    pro='python', pypro='python', cpppro='c++',
                    fpro='fortran', cpro='c',
                    sys='console', dat='python')
        # (the "python" typesetting is neutral if the text
        # does not parse as python)

    # First indent all code/tex blocks by 1) extracting all blocks,
    # 2) intending each block, and 3) inserting the blocks.
    # In between, handle the math blocks.

    filestr, code_blocks, tex_blocks = remove_code_and_tex(filestr)
    for i in range(len(code_blocks)):
        code_blocks[i] = indent_lines(code_blocks[i], format)

    math_labels = []
    for i in range(len(tex_blocks)):
        tex_blocks[i] = indent_lines(tex_blocks[i], format)
        # extract all \label{}s inside tex blocks and typeset them
        # with :label: tags
        label_regex1 = fix_latex(r'\label\{(.+?)\}', application='match')
        label_regex2 = fix_latex( r'label\{(.+?)\}', application='match')
        math_labels.extend(re.findall(label_regex1, tex_blocks[i]))
        tex_blocks[i] = re.sub(label_regex1,
                              r' :label: \g<1> ', tex_blocks[i])
        # handle also those without \ if there are any:
        math_labels.extend(re.findall(label_regex2, tex_blocks[i]))
        tex_blocks[i] = re.sub(label_regex2, r' :label: \g<1> ', tex_blocks[i])

    # replace all references to equations:
    for label in math_labels:
        filestr = filestr.replace(':ref:`%s`' % label, ':eq:`%s`' % label)

    filestr = insert_code_and_tex(filestr, code_blocks, tex_blocks, 'rst')

    for key in defs:
        language = defs[key]
        if not language in legal_pygments_languages:
            raise TypeError('%s is not a legal Pygments language '\
                            '(lexer) in line with:\n  %s' % \
                                (language, defs_line))
        #filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
        #                 '\n.. code-block:: %s\n\n' % defs[key], filestr,
        #                 flags=re.MULTILINE)
        cpattern = re.compile(r'^!bc\s+%s\s*\n' % key, flags=re.MULTILINE)
        filestr = cpattern.sub('\n.. code-block:: %s\n\n' % defs[key], filestr)

    # any !bc with/without argument becomes a py (python) block:
    #filestr = re.sub(r'^!bc.+\n', '\n.. code-block:: py\n\n', filestr,
    #                 flags=re.MULTILINE)
    cpattern = re.compile(r'^!bc.+$', flags=re.MULTILINE)
    filestr = cpattern.sub('\n.. code-block:: py\n\n', filestr)

    filestr = re.sub(r'!ec *\n', '\n', filestr)
    #filestr = re.sub(r'!ec\n', '\n', filestr)
    #filestr = re.sub(r'!ec\n', '', filestr)
    filestr = re.sub(r'!bt *\n', '\n.. math::\n   :nowrap:\n\n', filestr)
    filestr = re.sub(r'!et *\n', '\n\n', filestr)

    return filestr
Пример #4
0
def sphinx_code(filestr, code_blocks, code_block_types, tex_blocks, format):
    # In rst syntax, code blocks are typeset with :: (verbatim)
    # followed by intended blocks. This function indents everything
    # inside code (or TeX) blocks.

    # default mappings of !bc environments and pygments languages:
    envir2lang = dict(cod='python',
                      pro='python',
                      pycod='python',
                      cycod='cython',
                      pypro='python',
                      cypro='cython',
                      fcod='fortran',
                      fpro='fortran',
                      ccod='c',
                      cppcod='c++',
                      cpro='c',
                      cpppro='c++',
                      mcod='matlab',
                      mpro='matlab',
                      plcod='perl',
                      plpro='perl',
                      shcod='bash',
                      shpro='bash',
                      rbcod='ruby',
                      rbpro='ruby',
                      sys='console',
                      rst='rst',
                      dat='python',
                      ipy='python',
                      xmlcod='xml',
                      xmlpro='xml',
                      xml='xml',
                      htmlcod='html',
                      htmlpro='html',
                      html='html',
                      texcod='latex',
                      texpro='latex',
                      tex='latex',
                      pyoptpro='python')

    # grab line with: # Sphinx code-blocks: cod=python cpp=c++ etc
    # (do this before code is inserted in case verbatim blocks contain
    # such specifications for illustration)
    m = re.search(r'.. *[Ss]phinx +code-blocks?:(.+)', filestr)
    if m:
        defs_line = m.group(1)
        # turn specifications into a dictionary:
        for definition in defs_line.split():
            key, value = definition.split('=')
            envir2lang[key] = value

    # First indent all code blocks

    for i in range(len(code_blocks)):
        if code_block_types[i].startswith('pyoptpro'):
            code_blocks[i] = python_online_tutor(code_blocks[i],
                                                 return_tp='iframe')
        code_blocks[i] = indent_lines(code_blocks[i], format)

    # Treat math labels. Drop labels in environments with multiple
    # equations since these do not work in Sphinx. Method: keep
    # label if there is one and only one. Otherwise use old
    # method of removing labels. Do not use :nowrap: since this will
    # generate other labels that we cannot refer to.
    #
    # After transforming align environments to separate equations
    # the problem with multiple math labels has disappeared.
    # (doconce.py applies align2equations, which takes all align
    # envirs and translates them to separate equations, but align*
    # environments are allowed.
    # Any output of labels in align means an error in the
    # align -> equation transformation...)
    math_labels = []
    multiple_math_labels = []  # sphinx has problems with multiple math labels
    for i in range(len(tex_blocks)):
        tex_blocks[i] = indent_lines(tex_blocks[i], format)
        # extract all \label{}s inside tex blocks and typeset them
        # with :label: tags
        label_regex = fix_latex(r'label\{(.+?)\}', application='match')
        labels = re.findall(label_regex, tex_blocks[i])
        if len(labels) == 1:
            tex_blocks[i] = '   :label: %s\n' % labels[0] + tex_blocks[i]
        elif len(labels) > 1:
            multiple_math_labels.append(labels)
        if len(labels) > 0:
            math_labels.extend(labels)
        tex_blocks[i] = re.sub(label_regex, '', tex_blocks[i])

        # fix latex constructions that do not work with sphinx math
        commands = [
            r'\begin{equation}',
            r'\end{equation}',
            r'\begin{equation*}',
            r'\end{equation*}',
            r'\begin{eqnarray}',
            r'\end{eqnarray}',
            r'\begin{eqnarray*}',
            r'\end{eqnarray*}',
            r'\begin{align}',
            r'\end{align}',
            r'\begin{align*}',
            r'\end{align*}',
            r'\begin{multline}',
            r'\end{multline}',
            r'\begin{multline*}',
            r'\end{multline*}',
            r'\begin{split}',
            r'\end{split}',
            r'\begin{gather}',
            r'\end{gather}',
            r'\begin{gather*}',
            r'\end{gather*}',
            r'\[',
            r'\]',
            # some common abbreviations (newcommands):
            r'\beqan',
            r'\eeqan',
            r'\beqa',
            r'\eeqa',
            r'\balnn',
            r'\ealnn',
            r'\baln',
            r'\ealn',
            r'\beq',
            r'\eeq',  # the simplest, contained in others, must come last!
        ]
        for command in commands:
            tex_blocks[i] = tex_blocks[i].replace(command, '')
        tex_blocks[i] = re.sub('&\s*=\s*&', ' &= ', tex_blocks[i])
        # provide warnings for problematic environments
        if '{alignat' in tex_blocks[i]:
            print '\nWarning: the "alignat" environment will give errors in Sphinx:\n\n', tex_blocks[
                i], '\n'

    # Replace all references to equations that have labels in math environments:
    for label in math_labels:
        filestr = filestr.replace('(:ref:`%s`)' % label, ':eq:`%s`' % label)

    multiple_math_labels_with_refs = []  # collect the labels with references
    for labels in multiple_math_labels:
        for label in labels:
            ref = ':eq:`%s`' % label  # ref{} is translated to eq:``
            if ref in filestr:
                multiple_math_labels_with_refs.append(label)

    if multiple_math_labels_with_refs:
        print """
Detected non-align equation systems with multiple labels
(that Sphinx will not handle - labels will be removed
and references to them will be empty):"""
        for label in multiple_math_labels_with_refs:
            print 'label{%s}' % label
        print

    filestr = insert_code_and_tex(filestr, code_blocks, tex_blocks, 'rst')

    # Remove all !bc ipy since interactive sessions are automatically
    # handled by sphinx without indentation (just a blank line before
    # and after)
    cpattern = re.compile(r'^!bc +ipy *\n(.*?)^!ec *\n',
                          re.DOTALL | re.MULTILINE)
    filestr = cpattern.sub('\n\g<1>\n', filestr)

    # Make correct code-block:: language constructions
    for key in envir2lang:
        language = envir2lang[key]
        if not language in legal_pygments_languages:
            raise TypeError('%s is not a legal Pygments language '\
                            '(lexer) in line with:\n  %s' % \
                                (language, defs_line))
        #filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
        #                 '\n.. code-block:: %s\n\n' % envir2lang[key], filestr,
        #                 flags=re.MULTILINE)
        if key == 'pyoptpro':
            filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
                             '\n.. raw:: html\n\n',
                             filestr,
                             flags=re.MULTILINE)
        else:
            filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
                             '\n.. code-block:: %s\n\n' % \
                             envir2lang[key], filestr, flags=re.MULTILINE)

    # any !bc with/without argument becomes a text block:
    #filestr = re.sub(r'^!bc.+\n', '\n.. code-block:: text\n\n', filestr,
    #                 flags=re.MULTILINE)
    filestr = re.sub(r'^!bc.*$',
                     '\n.. code-block:: text\n\n',
                     filestr,
                     flags=re.MULTILINE)

    filestr = re.sub(r'^!ec *\n', '\n', filestr, flags=re.MULTILINE)
    #filestr = re.sub(r'^!ec\n', '\n', filestr, flags=re.MULTILINE)
    #filestr = re.sub(r'^!ec\n', '', filestr, flags=re.MULTILINE)
    filestr = re.sub(r'^!bt *\n', '\n.. math::\n', filestr, flags=re.MULTILINE)
    filestr = re.sub(r'^!et *\n', '\n', filestr, flags=re.MULTILINE)

    # Final fixes

    filestr = fix_underlines_in_headings(filestr)
    # Ensure blank line before comments
    filestr = re.sub(r'([.:;?!])\n^\.\. ',
                     r'\g<1>\n\n.. ',
                     filestr,
                     flags=re.MULTILINE)

    return filestr
Пример #5
0
def sphinx_code(filestr, code_blocks, code_block_types,
                tex_blocks, format):
    # In rst syntax, code blocks are typeset with :: (verbatim)
    # followed by intended blocks. This function indents everything
    # inside code (or TeX) blocks.

    # default mappings of !bc environments and pygments languages:
    envir2lang = dict(
        cod='python', pro='python',
        pycod='python', cycod='cython',
        pypro='python', cypro='cython',
        fcod='fortran', fpro='fortran',
        ccod='c', cppcod='c++',
        cpro='c', cpppro='c++',
        mcod='matlab', mpro='matlab',
        plcod='perl', plpro='perl',
        shcod='bash', shpro='bash',
        rbcod='ruby', rbpro='ruby',
        sys='console',
        rst='rst',
        dat='python',
        ipy='python',
        xmlcod='xml', xmlpro='xml', xml='xml',
        htmlcod='html', htmlpro='html', html='html',
        texcod='latex', texpro='latex', tex='latex',
        pyoptpro='python'
        )

    # grab line with: # Sphinx code-blocks: cod=python cpp=c++ etc
    # (do this before code is inserted in case verbatim blocks contain
    # such specifications for illustration)
    m = re.search(r'.. *[Ss]phinx +code-blocks?:(.+)', filestr)
    if m:
        defs_line = m.group(1)
        # turn specifications into a dictionary:
        for definition in defs_line.split():
            key, value = definition.split('=')
            envir2lang[key] = value

    # First indent all code blocks

    for i in range(len(code_blocks)):
        if code_block_types[i].startswith('pyoptpro'):
            code_blocks[i] = python_online_tutor(code_blocks[i],
                                                 return_tp='iframe')
        code_blocks[i] = indent_lines(code_blocks[i], format)

    # Treat math labels. Drop labels in environments with multiple
    # equations since these do not work in Sphinx. Method: keep
    # label if there is one and only one. Otherwise use old
    # method of removing labels. Do not use :nowrap: since this will
    # generate other labels that we cannot refer to.
    #
    # After transforming align environments to separate equations
    # the problem with multiple math labels has disappeared.
    # (doconce.py applies align2equations, which takes all align
    # envirs and translates them to separate equations, but align*
    # environments are allowed.
    # Any output of labels in align means an error in the
    # align -> equation transformation...)
    math_labels = []
    multiple_math_labels = []  # sphinx has problems with multiple math labels
    for i in range(len(tex_blocks)):
        tex_blocks[i] = indent_lines(tex_blocks[i], format)
        # extract all \label{}s inside tex blocks and typeset them
        # with :label: tags
        label_regex = fix_latex( r'label\{(.+?)\}', application='match')
        labels = re.findall(label_regex, tex_blocks[i])
        if len(labels) == 1:
            tex_blocks[i] = '   :label: %s\n' % labels[0] + tex_blocks[i]
        elif len(labels) > 1:
            multiple_math_labels.append(labels)
        if len(labels) > 0:
            math_labels.extend(labels)
        tex_blocks[i] = re.sub(label_regex, '', tex_blocks[i])

        # fix latex constructions that do not work with sphinx math
        commands = [r'\begin{equation}',
                    r'\end{equation}',
                    r'\begin{equation*}',
                    r'\end{equation*}',
                    r'\begin{eqnarray}',
                    r'\end{eqnarray}',
                    r'\begin{eqnarray*}',
                    r'\end{eqnarray*}',
                    r'\begin{align}',
                    r'\end{align}',
                    r'\begin{align*}',
                    r'\end{align*}',
                    r'\begin{multline}',
                    r'\end{multline}',
                    r'\begin{multline*}',
                    r'\end{multline*}',
                    r'\begin{split}',
                    r'\end{split}',
                    r'\begin{gather}',
                    r'\end{gather}',
                    r'\begin{gather*}',
                    r'\end{gather*}',
                    r'\[',
                    r'\]',
                    # some common abbreviations (newcommands):
                    r'\beqan',
                    r'\eeqan',
                    r'\beqa',
                    r'\eeqa',
                    r'\balnn',
                    r'\ealnn',
                    r'\baln',
                    r'\ealn',
                    r'\beq',
                    r'\eeq',  # the simplest, contained in others, must come last!
                    ]
        for command in commands:
            tex_blocks[i] = tex_blocks[i].replace(command, '')
        tex_blocks[i] = re.sub('&\s*=\s*&', ' &= ', tex_blocks[i])
        # provide warnings for problematic environments
        if '{alignat' in tex_blocks[i]:
            print '\nWarning: the "alignat" environment will give errors in Sphinx:\n\n', tex_blocks[i], '\n'

    # Replace all references to equations that have labels in math environments:
    for label in math_labels:
        filestr = filestr.replace('(:ref:`%s`)' % label, ':eq:`%s`' % label)

    multiple_math_labels_with_refs = [] # collect the labels with references
    for labels in multiple_math_labels:
        for label in labels:
            ref = ':eq:`%s`' % label  # ref{} is translated to eq:``
            if ref in filestr:
                multiple_math_labels_with_refs.append(label)

    if multiple_math_labels_with_refs:
        print """
Detected non-align equation systems with multiple labels
(that Sphinx will not handle - labels will be removed
and references to them will be empty):"""
        for label in multiple_math_labels_with_refs:
            print 'label{%s}' % label
        print

    filestr = insert_code_and_tex(filestr, code_blocks, tex_blocks, 'rst')

    # Remove all !bc ipy since interactive sessions are automatically
    # handled by sphinx without indentation (just a blank line before
    # and after)
    cpattern = re.compile(r'^!bc +ipy *\n(.*?)^!ec *\n',
                          re.DOTALL|re.MULTILINE)
    filestr = cpattern.sub('\n\g<1>\n', filestr)

    # Make correct code-block:: language constructions
    for key in envir2lang:
        language = envir2lang[key]
        if not language in legal_pygments_languages:
            raise TypeError('%s is not a legal Pygments language '\
                            '(lexer) in line with:\n  %s' % \
                                (language, defs_line))
        #filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
        #                 '\n.. code-block:: %s\n\n' % envir2lang[key], filestr,
        #                 flags=re.MULTILINE)
        if key == 'pyoptpro':
            filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
                             '\n.. raw:: html\n\n',
                             filestr, flags=re.MULTILINE)
        else:
            filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
                             '\n.. code-block:: %s\n\n' % \
                             envir2lang[key], filestr, flags=re.MULTILINE)

    # any !bc with/without argument becomes a text block:
    #filestr = re.sub(r'^!bc.+\n', '\n.. code-block:: text\n\n', filestr,
    #                 flags=re.MULTILINE)
    filestr = re.sub(r'^!bc.*$', '\n.. code-block:: text\n\n', filestr,
                     flags=re.MULTILINE)

    filestr = re.sub(r'^!ec *\n', '\n', filestr, flags=re.MULTILINE)
    #filestr = re.sub(r'^!ec\n', '\n', filestr, flags=re.MULTILINE)
    #filestr = re.sub(r'^!ec\n', '', filestr, flags=re.MULTILINE)
    filestr = re.sub(r'^!bt *\n', '\n.. math::\n', filestr, flags=re.MULTILINE)
    filestr = re.sub(r'^!et *\n', '\n', filestr, flags=re.MULTILINE)

    # Final fixes

    filestr = fix_underlines_in_headings(filestr)
    # Ensure blank line before comments
    filestr = re.sub(r'([.:;?!])\n^\.\. ', r'\g<1>\n\n.. ',
                     filestr, flags=re.MULTILINE)

    return filestr
Пример #6
0
def sphinx_code_orig(filestr, format):
    # NOTE: THIS FUNCTION IS NOT USED!!!!!!

    # In rst syntax, code blocks are typeset with :: (verbatim)
    # followed by intended blocks. This function indents everything
    # inside code (or TeX) blocks.

    # grab #sphinx code-blocks: cod=python cpp=c++ etc line
    # (do this before code is inserted in case verbatim blocks contain
    # such specifications for illustration)
    m = re.search(r'#\s*[Ss]phinx\s+code-blocks?:(.+?)\n', filestr)
    if m:
        defs_line = m.group(1)
        # turn defs into a dictionary definition:
        defs = {}
        for definition in defs_line.split():
            key, value = definition.split('=')
            defs[key] = value
    else:
        # default mappings:
        defs = dict(cod='python',
                    pro='python',
                    pycod='python', cycod='cython',
                    pypro='python', cypro='cython',
                    fcod='fortran', fpro='fortran',
                    ccod='c', cppcod='c++',
                    cpro='c', cpppro='c++',
                    mcod='matlab', mpro='matlab',
                    plcod='perl', plpro='perl',
                    shcod='bash', shpro='bash',
                    rbcod='ruby', rbpro='ruby',
                    sys='console',
                    dat='python',
                    ipy='python',
                    xmlcod='xml', xmlpro='xml', xml='xml',
                    htmlcod='html', htmlpro='html', html='html',
                    texcod='latex', texpro='latex', tex='latex',
                    )
        # (the "python" typesetting is neutral if the text
        # does not parse as python)

    # first indent all code/tex blocks by 1) extracting all blocks,
    # 2) intending each block, and 3) inserting the blocks:
    filestr, code_blocks, tex_blocks = remove_code_and_tex(filestr)
    for i in range(len(code_blocks)):
        code_blocks[i] = indent_lines(code_blocks[i], format)
    for i in range(len(tex_blocks)):
        tex_blocks[i] = indent_lines(tex_blocks[i], format)
        # remove all \label{}s inside tex blocks:
        tex_blocks[i] = re.sub(fix_latex(r'\label\{.+?\}', application='match'),
                              '', tex_blocks[i])
        # remove those without \ if there are any:
        tex_blocks[i] = re.sub(r'label\{.+?\}', '', tex_blocks[i])

        # fix latex constructions that do not work with sphinx math
        commands = [r'\begin{equation}',
                    r'\end{equation}',
                    r'\begin{equation*}',
                    r'\end{equation*}',
                    r'\begin{eqnarray}',
                    r'\end{eqnarray}',
                    r'\begin{eqnarray*}',
                    r'\end{eqnarray*}',
                    r'\begin{align}',
                    r'\end{align}',
                    r'\begin{align*}',
                    r'\end{align*}',
                    r'\begin{multline}',
                    r'\end{multline}',
                    r'\begin{multline*}',
                    r'\end{multline*}',
                    r'\begin{split}',
                    r'\end{split}',
                    r'\begin{gather}',
                    r'\end{gather}',
                    r'\begin{gather*}',
                    r'\end{gather*}',
                    r'\[',
                    r'\]',
                    # some common abbreviations (newcommands):
                    r'\beqan',
                    r'\eeqan',
                    r'\beqa',
                    r'\eeqa',
                    r'\balnn',
                    r'\ealnn',
                    r'\baln',
                    r'\ealn',
                    r'\beq',
                    r'\eeq',  # the simplest, contained in others, must come last!
                    ]
        for command in commands:
            tex_blocks[i] = tex_blocks[i].replace(command, '')
        tex_blocks[i] = re.sub('&\s*=\s*&', ' &= ', tex_blocks[i])
        # provide warnings for problematic environments
        if '{alignat' in tex_blocks[i]:
            print '\nWarning: the "alignat" environment will give errors in Sphinx:\n\n', tex_blocks[i], '\n'


    filestr = insert_code_and_tex(filestr, code_blocks, tex_blocks, 'rst')

    for key in defs:
        language = defs[key]
        if not language in legal_pygments_languages:
            raise TypeError('%s is not a legal Pygments language '\
                            '(lexer) in line with:\n  %s' % \
                                (language, defs_line))
        #filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
        #                 '\n.. code-block:: %s\n\n' % defs[key], filestr,
        #                 flags=re.MULTILINE)
        cpattern = re.compile(r'^!bc\s+%s\s*\n' % key, flags=re.MULTILINE)
        filestr, n = cpattern.subn('\n.. code-block:: %s\n\n' % defs[key], filestr)
        print key, n
        if n > 0:
            print 'sphinx: %d subst %s by %s' % (n, key, defs[key])

    # any !bc with/without argument becomes a py (python) block:
    #filestr = re.sub(r'^!bc.+\n', '\n.. code-block:: py\n\n', filestr,
    #                 flags=re.MULTILINE)
    cpattern = re.compile(r'^!bc.+$', flags=re.MULTILINE)
    filestr = cpattern.sub('\n.. code-block:: py\n\n', filestr)

    filestr = re.sub(r'^!ec *\n', '\n', filestr, flags=re.MULTILINE)
    #filestr = re.sub(r'^!ec\n', '\n', filestr, flags=re.MULTILINE)
    #filestr = re.sub(r'^!ec\n', '', filestr, flags=re.MULTILINE)
    filestr = re.sub(r'^!bt *\n', '\n.. math::\n\n', filestr,
                     flags=re.MULTILINE)
    filestr = re.sub(r'^!et *\n', '\n\n', filestr,
                     flags=re.MULTILINE)

    return filestr
Пример #7
0
def sphinx_code(filestr, code_blocks, code_block_types, tex_blocks, format):
    # In rst syntax, code blocks are typeset with :: (verbatim)
    # followed by intended blocks. This function indents everything
    # inside code (or TeX) blocks.

    # default mappings of !bc environments and pygments languages:
    envir2pygments = dict(
        cod='python',
        pro='python',
        pycod='python',
        cycod='cython',
        pypro='python',
        cypro='cython',
        fcod='fortran',
        fpro='fortran',
        ccod='c',
        cppcod='c++',
        cpro='c',
        cpppro='c++',
        mcod='matlab',
        mpro='matlab',
        plcod='perl',
        plpro='perl',
        shcod='bash',
        shpro='bash',
        rbcod='ruby',
        rbpro='ruby',
        #sys='console',
        sys='text',
        rst='rst',
        css='css',
        csspro='css',
        csscod='css',
        dat='text',
        csv='text',
        txt='text',
        cc='text',
        ccq='text',  # not possible with extra indent for ccq
        ipy='ipy',
        xmlcod='xml',
        xmlpro='xml',
        xml='xml',
        htmlcod='html',
        htmlpro='html',
        html='html',
        texcod='latex',
        texpro='latex',
        tex='latex',
        latexcod='latex',
        latexpro='latex',
        latex='latex',
        do='doconce',
        pyshell='python',
        pyoptpro='python',
        pyscpro='python',
    )

    # grab line with: # sphinx code-blocks: cod=python cpp=c++ etc
    # (do this before code is inserted in case verbatim blocks contain
    # such specifications for illustration)
    m = re.search(r'.. *[Ss]phinx +code-blocks?:(.+)', filestr)
    if m:
        defs_line = m.group(1)
        # turn specifications into a dictionary:
        for definition in defs_line.split():
            key, value = definition.split('=')
            envir2pygments[key] = value

    # First indent all code blocks

    for i in range(len(code_blocks)):
        if code_block_types[i].startswith(
                'pyoptpro') and not option('runestone'):
            code_blocks[i] = online_python_tutor(code_blocks[i],
                                                 return_tp='iframe')
        if code_block_types[i].endswith('-h'):
            indentation = ' ' * 8
        else:
            indentation = ' ' * 4
        code_blocks[i] = indent_lines(code_blocks[i], format, indentation)

    # After transforming align environments to separate equations
    # the problem with math labels in multiple eqs has disappeared.
    # (doconce.py applies align2equations, which takes all align
    # envirs and translates them to separate equations, but align*
    # environments are allowed.
    # Any output of labels in align means an error in the
    # align -> equation transformation...)
    math_labels = []
    multiple_math_labels = []  # sphinx has problems with multiple math labels
    for i in range(len(tex_blocks)):
        tex_blocks[i] = indent_lines(tex_blocks[i], format)
        # extract all \label{}s inside tex blocks and typeset them
        # with :label: tags
        label_regex = fix_latex(r'label\{(.+?)\}', application='match')
        labels = re.findall(label_regex, tex_blocks[i])
        if len(labels) == 1:
            tex_blocks[i] = '   :label: %s\n' % labels[0] + tex_blocks[i]
        elif len(labels) > 1:
            multiple_math_labels.append(labels)
        if len(labels) > 0:
            math_labels.extend(labels)
        tex_blocks[i] = re.sub(label_regex, '', tex_blocks[i])

        # fix latex constructions that do not work with sphinx math
        # (just remove them)
        commands = [
            r'\begin{equation}',
            r'\end{equation}',
            r'\begin{equation*}',
            r'\end{equation*}',
            #r'\begin{eqnarray}',
            #r'\end{eqnarray}',
            #r'\begin{eqnarray*}',
            #r'\end{eqnarray*}',
            #r'\begin{align}',
            #r'\end{align}',
            #r'\begin{align*}',
            #r'\end{align*}',
            r'\begin{multline}',
            r'\end{multline}',
            r'\begin{multline*}',
            r'\end{multline*}',
            #r'\begin{split}',
            #r'\end{split}',
            #r'\begin{gather}',
            #r'\end{gather}',
            #r'\begin{gather*}',
            #r'\end{gather*}',
            r'\[',
            r'\]',
            # some common abbreviations (newcommands):
            r'\beqan',
            r'\eeqan',
            r'\beqa',
            r'\eeqa',
            r'\balnn',
            r'\ealnn',
            r'\baln',
            r'\ealn',
            r'\beq',
            r'\eeq',  # the simplest name, contained in others, must come last!
        ]
        for command in commands:
            tex_blocks[i] = tex_blocks[i].replace(command, '')
        # &=& -> &=
        tex_blocks[i] = re.sub('&\s*=\s*&', ' &= ', tex_blocks[i])
        # provide warnings for problematic environments

    # Replace all references to equations that have labels in math environments:
    for label in math_labels:
        filestr = filestr.replace('(:ref:`%s`)' % label, ':eq:`%s`' % label)

    multiple_math_labels_with_refs = []  # collect the labels with references
    for labels in multiple_math_labels:
        for label in labels:
            ref = ':eq:`%s`' % label  # ref{} is translated to eq:``
            if ref in filestr:
                multiple_math_labels_with_refs.append(label)

    if multiple_math_labels_with_refs:
        errwarn("""
*** warning: detected non-align math environment with multiple labels
    (Sphinx cannot handle this equation system - labels will be removed
    and references to them will be empty):""")
        for label in multiple_math_labels_with_refs:
            errwarn('    label{%s}' % label)
        print

    filestr = insert_code_and_tex(filestr, code_blocks, tex_blocks, 'sphinx')

    # Remove all !bc ipy and !bc pyshell since interactive sessions
    # are automatically handled by sphinx without indentation
    # (just a blank line before and after)
    filestr = re.sub(r'^!bc +d?ipy *\n(.*?)^!ec *\n', '\n\g<1>\n', filestr,
                     re.DOTALL | re.MULTILINE)
    filestr = re.sub(r'^!bc +d?pyshell *\n(.*?)^!ec *\n', '\n\g<1>\n', filestr,
                     re.DOTALL | re.MULTILINE)

    # Check if we have custom pygments lexers
    if 'ipy' in code_block_types:
        if not has_custom_pygments_lexer('ipy'):
            envir2pygments['ipy'] = 'python'
    if 'do' in code_block_types:
        if not has_custom_pygments_lexer('doconce'):
            envir2pygments['do'] = 'text'

    # Make correct code-block:: language constructions
    legal_pygments_languages = get_legal_pygments_lexers()
    for key in set(code_block_types):
        if key in envir2pygments:
            if not envir2pygments[key] in legal_pygments_languages:
                errwarn(
                    """*** warning: %s is not a legal Pygments language (lexer)
found in line:
  %s

    The 'text' lexer will be used instead.
""" % (envir2pygments[key], defs_line))
                envir2pygments[key] = 'text'

        #filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
        #                 '\n.. code-block:: %s\n\n' % envir2pygments[key], filestr,
        #                 flags=re.MULTILINE)

        # Check that we have code installed to handle pyscpro
        if 'pyscpro' in filestr and key == 'pyscpro':
            try:
                import icsecontrib.sagecellserver
            except ImportError:
                errwarn("""
*** warning: pyscpro for computer code (sage cells) is requested, but'
    icsecontrib.sagecellserver from https://github.com/kriskda/sphinx-sagecell
    is not installed. Using plain Python typesetting instead.""")
                key = 'pypro'

        if key == 'pyoptpro':
            if option('runestone'):
                filestr = re.sub(
                    r'^!bc\s+%s\s*\n' % key,
                    '\n.. codelens:: codelens_\n   :showoutput:\n\n',
                    filestr,
                    flags=re.MULTILINE)
            else:
                filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
                                 '\n.. raw:: html\n\n',
                                 filestr,
                                 flags=re.MULTILINE)
        elif key == 'pyscpro':
            if option('runestone'):
                filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
                                 """
.. activecode:: activecode_
   :language: python

""",
                                 filestr,
                                 flags=re.MULTILINE)
            else:
                filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
                                 '\n.. sagecellserver::\n\n',
                                 filestr,
                                 flags=re.MULTILINE)
        elif key == 'pysccod':
            if option('runestone'):
                # Include (i.e., run) all previous code segments...
                # NOTE: this is most likely not what we want
                include = ', '.join([i for i in range(1, activecode_counter)])
                filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
                                 """
.. activecode:: activecode_
   :language: python
   "include: %s
""" % include,
                                 filestr,
                                 flags=re.MULTILINE)
            else:
                errwarn(
                    '*** error: pysccod for sphinx is not supported without the --runestone flag\n    (but pyscpro is via Sage Cell Server)'
                )
                _abort()

        elif key == '':
            # any !bc with/without argument becomes a text block:
            filestr = re.sub(r'^!bc$',
                             '\n.. code-block:: text\n\n',
                             filestr,
                             flags=re.MULTILINE)
        elif key.endswith('hid'):
            if key in ('pyhid', 'jshid', 'htmlhid') and option('runestone'):
                # Allow runestone books to run hidden code blocks
                # (replace pyhid by pycod, then remove all !bc *hid)
                for i in range(len(code_block_types)):
                    if code_block_types[i] == key:
                        code_block_types[i] = key.replace('hid', 'cod')

                key2language = dict(py='python', js='javascript', html='html')
                language = key2language[key.replace('hid', '')]
                include = ', '.join([i for i in range(1, activecode_counter)])
                filestr = re.sub(r'^!bc +%s\s*\n' % key,
                                 """
.. activecode:: activecode_
   :language: %s
   :include: %s
   :hidecode:

""" % (language, include),
                                 filestr,
                                 flags=re.MULTILINE)
            else:
                # Remove hidden code block
                pattern = r'^!bc +%s\n.+?^!ec' % key
                filestr = re.sub(pattern,
                                 '',
                                 filestr,
                                 flags=re.MULTILINE | re.DOTALL)
        else:
            show_hide = False
            if key.endswith('-h'):
                key_orig = key
                key = key[:-2]
                show_hide = True
            # Use the standard sphinx code-block directive
            if key in envir2pygments:
                pygments_language = envir2pygments[key]
            elif key in legal_pygments_languages:
                pygments_language = key
            else:
                errwarn('*** error: detected code environment "%s"' % key)
                errwarn(
                    '    which is not registered in sphinx.py (sphinx_code)')
                errwarn('    or not a language registered in pygments')
                _abort()
            if show_hide:
                filestr = re.sub(r'^!bc +%s\s*\n' % key_orig,
                                 '\n.. container:: toggle\n\n    .. container:: header\n\n        **Show/Hide Code**\n\n    .. code-block:: %s\n\n' % \
                                 pygments_language, filestr, flags=re.MULTILINE)
                # Must add 4 indent in corresponding code_blocks[i], done above
            else:
                filestr = re.sub(r'^!bc +%s\s*\n' % key,
                                 '\n.. code-block:: %s\n\n' % \
                                 pygments_language, filestr, flags=re.MULTILINE)

    # any !bc with/without argument becomes a text block:
    filestr = re.sub(r'^!bc.*$',
                     '\n.. code-block:: text\n\n',
                     filestr,
                     flags=re.MULTILINE)
    filestr = re.sub(r'^!ec *\n', '\n', filestr, flags=re.MULTILINE)
    #filestr = re.sub(r'^!ec\n', '\n', filestr, flags=re.MULTILINE)
    #filestr = re.sub(r'^!ec\n', '', filestr, flags=re.MULTILINE)

    filestr = re.sub(r'^!bt *\n', '\n.. math::\n', filestr, flags=re.MULTILINE)
    filestr = re.sub(r'^!et *\n', '\n', filestr, flags=re.MULTILINE)
    # Fix lacking blank line after :label:
    filestr = re.sub(r'^(   :label: .+?)(\n *[^ ]+)',
                     r'\g<1>\n\n\g<2>',
                     filestr,
                     flags=re.MULTILINE)

    # Insert counters for runestone blocks
    if option('runestone'):
        codelens_counter = 0
        activecode_counter = 0
        lines = filestr.splitlines()
        for i in range(len(lines)):
            if '.. codelens:: codelens_' in lines[i]:
                codelens_counter += 1
                lines[i] = lines[i].replace('codelens_',
                                            'codelens_%d' % codelens_counter)
            if '.. activecode:: activecode_' in lines[i]:
                activecode_counter += 1
                lines[i] = lines[i].replace(
                    'activecode_', 'activecode_%d' % activecode_counter)
        filestr = '\n'.join(lines)

    # Final fixes

    filestr = fix_underlines_in_headings(filestr)
    # Ensure blank line before and after comments
    filestr = re.sub(r'([.:;?!])\n^\.\. ',
                     r'\g<1>\n\n.. ',
                     filestr,
                     flags=re.MULTILINE)
    filestr = re.sub(r'(^\.\. .+)\n([^ \n]+)',
                     r'\g<1>\n\n\g<2>',
                     filestr,
                     flags=re.MULTILINE)

    # Line breaks interfer with tables and needs a final blank line too
    lines = filestr.splitlines()
    inside_block = False
    for i in range(len(lines)):
        if lines[i].startswith('<linebreakpipe>') and not inside_block:
            inside_block = True
            lines[i] = lines[i].replace('<linebreakpipe> ', '') + '\n'
            continue
        if lines[i].startswith('<linebreakpipe>') and inside_block:
            lines[i] = '|' + lines[i].replace('<linebreakpipe>', '')
            continue
        if inside_block and not lines[i].startswith('<linebreakpipe>'):
            inside_block = False
            lines[i] = '| ' + lines[i] + '\n'
    filestr = '\n'.join(lines)

    # Remove double !split (TOC with a prefix !split gives two !splits)
    pattern = '^.. !split\s+.. !split'
    filestr = re.sub(pattern, '.. !split', filestr, flags=re.MULTILINE)

    if option('html_links_in_new_window'):
        # Insert a comment to be recognized by automake_sphinx.py such that it
        # can replace the default links by proper modified target= option.
        #filestr = '\n\n.. NOTE: Open external links in new windows.\n\n' + filestr
        # Use JavaScript instead
        filestr = """.. raw:: html

        <script type="text/javascript">
        $(document).ready(function() {
            $("a[href^='http']").attr('target','_blank');
        });
        </script>

""" + filestr

    # Remove too much vertical space
    filestr = re.sub(r'\n{3,}', '\n\n', filestr)

    return filestr
Пример #8
0
def sphinx_code(filestr, code_blocks, code_block_types,
                tex_blocks, format):
    # In rst syntax, code blocks are typeset with :: (verbatim)
    # followed by intended blocks. This function indents everything
    # inside code (or TeX) blocks.

    # default mappings of !bc environments and pygments languages:
    envir2pygments = dict(
        cod='python', pro='python',
        pycod='python', cycod='cython',
        pypro='python', cypro='cython',
        fcod='fortran', fpro='fortran',
        ccod='c', cppcod='c++',
        cpro='c', cpppro='c++',
        mcod='matlab', mpro='matlab',
        plcod='perl', plpro='perl',
        shcod='bash', shpro='bash',
        rbcod='ruby', rbpro='ruby',
        #sys='console',
        sys='text',
        rst='rst',
        css='css', csspro='css', csscod='css',
        dat='text', csv='text', txt='text',
        cc='text', ccq='text',  # not possible with extra indent for ccq
        ipy='ipy',
        xmlcod='xml', xmlpro='xml', xml='xml',
        htmlcod='html', htmlpro='html', html='html',
        texcod='latex', texpro='latex', tex='latex',
        latexcod='latex', latexpro='latex', latex='latex',
        do='doconce',
        pyshell='python',
        pyoptpro='python', pyscpro='python',
        )

    # grab line with: # Sphinx code-blocks: cod=python cpp=c++ etc
    # (do this before code is inserted in case verbatim blocks contain
    # such specifications for illustration)
    m = re.search(r'.. *[Ss]phinx +code-blocks?:(.+)', filestr)
    if m:
        defs_line = m.group(1)
        # turn specifications into a dictionary:
        for definition in defs_line.split():
            key, value = definition.split('=')
            envir2pygments[key] = value

    # First indent all code blocks

    for i in range(len(code_blocks)):
        if code_block_types[i].startswith('pyoptpro') and not option('runestone'):
            code_blocks[i] = online_python_tutor(code_blocks[i],
                                                 return_tp='iframe')
        code_blocks[i] = indent_lines(code_blocks[i], format)

    # After transforming align environments to separate equations
    # the problem with math labels in multiple eqs has disappeared.
    # (doconce.py applies align2equations, which takes all align
    # envirs and translates them to separate equations, but align*
    # environments are allowed.
    # Any output of labels in align means an error in the
    # align -> equation transformation...)
    math_labels = []
    multiple_math_labels = []  # sphinx has problems with multiple math labels
    for i in range(len(tex_blocks)):
        tex_blocks[i] = indent_lines(tex_blocks[i], format)
        # extract all \label{}s inside tex blocks and typeset them
        # with :label: tags
        label_regex = fix_latex( r'label\{(.+?)\}', application='match')
        labels = re.findall(label_regex, tex_blocks[i])
        if len(labels) == 1:
            tex_blocks[i] = '   :label: %s\n' % labels[0] + tex_blocks[i]
        elif len(labels) > 1:
            multiple_math_labels.append(labels)
        if len(labels) > 0:
            math_labels.extend(labels)
        tex_blocks[i] = re.sub(label_regex, '', tex_blocks[i])

        # fix latex constructions that do not work with sphinx math
        commands = [r'\begin{equation}',
                    r'\end{equation}',
                    r'\begin{equation*}',
                    r'\end{equation*}',
                    r'\begin{eqnarray}',
                    r'\end{eqnarray}',
                    r'\begin{eqnarray*}',
                    r'\end{eqnarray*}',
                    r'\begin{align}',
                    r'\end{align}',
                    r'\begin{align*}',
                    r'\end{align*}',
                    r'\begin{multline}',
                    r'\end{multline}',
                    r'\begin{multline*}',
                    r'\end{multline*}',
                    r'\begin{split}',
                    r'\end{split}',
                    r'\begin{gather}',
                    r'\end{gather}',
                    r'\begin{gather*}',
                    r'\end{gather*}',
                    r'\[',
                    r'\]',
                    # some common abbreviations (newcommands):
                    r'\beqan',
                    r'\eeqan',
                    r'\beqa',
                    r'\eeqa',
                    r'\balnn',
                    r'\ealnn',
                    r'\baln',
                    r'\ealn',
                    r'\beq',
                    r'\eeq',  # the simplest, contained in others, must come last!
                    ]
        for command in commands:
            tex_blocks[i] = tex_blocks[i].replace(command, '')
        tex_blocks[i] = re.sub('&\s*=\s*&', ' &= ', tex_blocks[i])
        # provide warnings for problematic environments
        if '{alignat' in tex_blocks[i]:
            print '*** warning: the "alignat" environment will give errors in Sphinx:\n\n', tex_blocks[i], '\n'

    # Replace all references to equations that have labels in math environments:
    for label in math_labels:
        filestr = filestr.replace('(:ref:`%s`)' % label, ':eq:`%s`' % label)

    multiple_math_labels_with_refs = [] # collect the labels with references
    for labels in multiple_math_labels:
        for label in labels:
            ref = ':eq:`%s`' % label  # ref{} is translated to eq:``
            if ref in filestr:
                multiple_math_labels_with_refs.append(label)

    if multiple_math_labels_with_refs:
        print """
*** warning: detected non-align math environment with multiple labels
    (Sphinx cannot handle this equation system - labels will be removed
    and references to them will be empty):"""
        for label in multiple_math_labels_with_refs:
            print '    label{%s}' % label
        print

    filestr = insert_code_and_tex(filestr, code_blocks, tex_blocks, 'sphinx')

    # Remove all !bc ipy and !bc pyshell since interactive sessions
    # are automatically handled by sphinx without indentation
    # (just a blank line before and after)
    filestr = re.sub(r'^!bc +d?ipy *\n(.*?)^!ec *\n',
                     '\n\g<1>\n', filestr, re.DOTALL|re.MULTILINE)
    filestr = re.sub(r'^!bc +d?pyshell *\n(.*?)^!ec *\n',
                     '\n\g<1>\n', filestr, re.DOTALL|re.MULTILINE)

    # Check if we have custom pygments lexers
    if 'ipy' in code_block_types:
        if not has_custom_pygments_lexer('ipy'):
            envir2pygments['ipy'] = 'python'
    if 'do' in code_block_types:
        if not has_custom_pygments_lexer('doconce'):
            envir2pygments['do'] = 'text'

    # Make correct code-block:: language constructions
    legal_pygments_languages = get_legal_pygments_lexers()
    for key in set(code_block_types):
        if key in envir2pygments:
            if not envir2pygments[key] in legal_pygments_languages:
                print """*** warning: %s is not a legal Pygments language (lexer)
found in line:
  %s

    The 'text' lexer will be used instead.
""" % (envir2pygments[key], defs_line)
                envir2pygments[key] = 'text'

        #filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
        #                 '\n.. code-block:: %s\n\n' % envir2pygments[key], filestr,
        #                 flags=re.MULTILINE)

        # Check that we have code installed to handle pyscpro
        if 'pyscpro' in filestr and key == 'pyscpro':
            try:
                import icsecontrib.sagecellserver
            except ImportError:
                print """
*** warning: pyscpro for computer code (sage cells) is requested, but'
    icsecontrib.sagecellserver from https://github.com/kriskda/sphinx-sagecell
    is not installed. Using plain Python typesetting instead."""
                key = 'pypro'

        if key == 'pyoptpro':
            if option('runestone'):
                filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
                    '\n.. codelens:: codelens_\n   :showoutput:\n\n',
                    filestr, flags=re.MULTILINE)
            else:
                filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
                                 '\n.. raw:: html\n\n',
                                 filestr, flags=re.MULTILINE)
        elif key == 'pyscpro':
            if option('runestone'):
                filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
                                 """
.. activecode:: activecode_
   :language: python

""", filestr, flags=re.MULTILINE)
            else:
                filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
                                 '\n.. sagecellserver::\n\n',
                                 filestr, flags=re.MULTILINE)
        elif key == 'pysccod':
            if option('runestone'):
                # Include (i.e., run) all previous code segments...
                # NOTE: this is most likely not what we want
                include = ', '.join([i for i in range(1, activecode_counter)])
                filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
                                 """
.. activecode:: activecode_
   :language: python
   "include: %s
""" % include, filestr, flags=re.MULTILINE)
            else:
                print '*** error: pysccod for sphinx is not supported without the --runestone flag\n    (but pyscpro is via Sage Cell Server)'
                _abort()

        elif key == '':
            # any !bc with/without argument becomes a text block:
            filestr = re.sub(r'^!bc$', '\n.. code-block:: text\n\n', filestr,
                             flags=re.MULTILINE)
        elif key.endswith('hid'):
            if key in ('pyhid', 'jshid', 'htmlhid') and option('runestone'):
                # Allow runestone books to run hidden code blocks
                # (replace pyhid by pycod, then remove all !bc *hid)
                for i in range(len(code_block_types)):
                    if code_block_types[i] == key:
                        code_block_types[i] = key.replace('hid', 'cod')

                key2language = dict(py='python', js='javascript', html='html')
                language = key2language[key.replace('hid', '')]
                include = ', '.join([i for i in range(1, activecode_counter)])
                filestr = re.sub(r'^!bc +%s\s*\n' % key,
                                 """
.. activecode:: activecode_
   :language: %s
   :include: %s
   :hidecode:

""" % (language, include), filestr, flags=re.MULTILINE)
            else:
                # Remove hidden code block
                pattern = r'^!bc +%s\n.+?^!ec' % key
                filestr = re.sub(pattern, '', filestr,
                                 flags=re.MULTILINE|re.DOTALL)
        else:
            # Use the standard sphinx code-block directive
            if key in envir2pygments:
                pygments_language = envir2pygments[key]
            elif key in legal_pygments_languages:
                pygments_language = key
            else:
                print '*** error: detected code environment "%s"' % key
                print '    which is not registered in sphinx.py (sphinx_code)'
                print '    or not a language registered in pygments'
                _abort()
            filestr = re.sub(r'^!bc +%s\s*\n' % key,
                             '\n.. code-block:: %s\n\n' % \
                             pygments_language, filestr, flags=re.MULTILINE)

    # any !bc with/without argument becomes a text block:
    filestr = re.sub(r'^!bc.*$', '\n.. code-block:: text\n\n', filestr,
                     flags=re.MULTILINE)
    filestr = re.sub(r'^!ec *\n', '\n', filestr, flags=re.MULTILINE)
    #filestr = re.sub(r'^!ec\n', '\n', filestr, flags=re.MULTILINE)
    #filestr = re.sub(r'^!ec\n', '', filestr, flags=re.MULTILINE)
    filestr = re.sub(r'^!bt *\n', '\n.. math::\n', filestr, flags=re.MULTILINE)
    filestr = re.sub(r'^!et *\n', '\n', filestr, flags=re.MULTILINE)

    # Insert counters for runestone blocks
    if option('runestone'):
        codelens_counter = 0
        activecode_counter = 0
        lines = filestr.splitlines()
        for i in range(len(lines)):
            if '.. codelens:: codelens_' in lines[i]:
                codelens_counter += 1
                lines[i] = lines[i].replace('codelens_', 'codelens_%d' %
                                            codelens_counter)
            if '.. activecode:: activecode_' in lines[i]:
                activecode_counter += 1
                lines[i] = lines[i].replace('activecode_', 'activecode_%d' %
                                            activecode_counter)
        filestr = '\n'.join(lines)


    # Final fixes

    filestr = fix_underlines_in_headings(filestr)
    # Ensure blank line before and after comments
    filestr = re.sub(r'([.:;?!])\n^\.\. ', r'\g<1>\n\n.. ',
                     filestr, flags=re.MULTILINE)
    filestr = re.sub(r'(^\.\. .+)\n([^ \n]+)', r'\g<1>\n\n\g<2>',
                     filestr, flags=re.MULTILINE)
    # Line breaks interfer with tables and needs a final blank line too
    lines = filestr.splitlines()
    inside_block = False
    for i in range(len(lines)):
        if lines[i].startswith('<linebreakpipe>') and not inside_block:
            inside_block = True
            lines[i] = lines[i].replace('<linebreakpipe> ', '') + '\n'
            continue
        if lines[i].startswith('<linebreakpipe>') and inside_block:
            lines[i] = '|' + lines[i].replace('<linebreakpipe>', '')
            continue
        if inside_block and not lines[i].startswith('<linebreakpipe>'):
            inside_block = False
            lines[i] = '| ' + lines[i] + '\n'
    filestr = '\n'.join(lines)

    # Remove double !split (TOC with a prefix !split gives two !splits)
    pattern = '^.. !split\s+.. !split'
    filestr = re.sub(pattern, '.. !split', filestr, flags=re.MULTILINE)

    if option('html_links_in_new_window'):
        # Insert a comment to be recognized by automake_sphinx.py such that it
        # can replace the default links by proper modified target= option.
        #filestr = '\n\n.. NOTE: Open external links in new windows.\n\n' + filestr
        # Use JavaScript instead
        filestr = """.. raw:: html

        <script type="text/javascript">
        $(document).ready(function() {
            $("a[href^='http']").attr('target','_blank');
        });
        </script>

""" + filestr


    # Remove too much vertical space
    filestr = re.sub(r'\n{3,}', '\n\n', filestr)

    return filestr
Пример #9
0
def sphinx_code(filestr, code_blocks, code_block_types,
                tex_blocks, format):
    # In rst syntax, code blocks are typeset with :: (verbatim)
    # followed by intended blocks. This function indents everything
    # inside code (or TeX) blocks.

    # default mappings of !bc environments and pygments languages:
    envir2lang = dict(
        cod='python', pro='python',
        pycod='python', cycod='cython',
        pypro='python', cypro='cython',
        fcod='fortran', fpro='fortran',
        ccod='c', cppcod='c++',
        cpro='c', cpppro='c++',
        mcod='matlab', mpro='matlab',
        plcod='perl', plpro='perl',
        shcod='bash', shpro='bash',
        rbcod='ruby', rbpro='ruby',
        #sys='console',
        sys='text',
        rst='rst',
        dat='text', csv='text', txt='text',
        cc='text', ccq='text',  # not possible with extra indent for ccq
        ipy='python',
        xmlcod='xml', xmlpro='xml', xml='xml',
        htmlcod='html', htmlpro='html', html='html',
        texcod='latex', texpro='latex', tex='latex',
        pyoptpro='python', pyscpro='python',
        )

    # grab line with: # Sphinx code-blocks: cod=python cpp=c++ etc
    # (do this before code is inserted in case verbatim blocks contain
    # such specifications for illustration)
    m = re.search(r'.. *[Ss]phinx +code-blocks?:(.+)', filestr)
    if m:
        defs_line = m.group(1)
        # turn specifications into a dictionary:
        for definition in defs_line.split():
            key, value = definition.split('=')
            envir2lang[key] = value

    # First indent all code blocks

    for i in range(len(code_blocks)):
        if code_block_types[i].startswith('pyoptpro'):
            code_blocks[i] = online_python_tutor(code_blocks[i],
                                                 return_tp='iframe')
        code_blocks[i] = indent_lines(code_blocks[i], format)

    # Treat math labels. Drop labels in environments with multiple
    # equations since these do not work in Sphinx. Method: keep
    # label if there is one and only one. Otherwise use old
    # method of removing labels. Do not use :nowrap: since this will
    # generate other labels that we cannot refer to.
    #
    # After transforming align environments to separate equations
    # the problem with multiple math labels has disappeared.
    # (doconce.py applies align2equations, which takes all align
    # envirs and translates them to separate equations, but align*
    # environments are allowed.
    # Any output of labels in align means an error in the
    # align -> equation transformation...)
    math_labels = []
    multiple_math_labels = []  # sphinx has problems with multiple math labels
    for i in range(len(tex_blocks)):
        tex_blocks[i] = indent_lines(tex_blocks[i], format)
        # extract all \label{}s inside tex blocks and typeset them
        # with :label: tags
        label_regex = fix_latex( r'label\{(.+?)\}', application='match')
        labels = re.findall(label_regex, tex_blocks[i])
        if len(labels) == 1:
            tex_blocks[i] = '   :label: %s\n' % labels[0] + tex_blocks[i]
        elif len(labels) > 1:
            multiple_math_labels.append(labels)
        if len(labels) > 0:
            math_labels.extend(labels)
        tex_blocks[i] = re.sub(label_regex, '', tex_blocks[i])

        # fix latex constructions that do not work with sphinx math
        commands = [r'\begin{equation}',
                    r'\end{equation}',
                    r'\begin{equation*}',
                    r'\end{equation*}',
                    r'\begin{eqnarray}',
                    r'\end{eqnarray}',
                    r'\begin{eqnarray*}',
                    r'\end{eqnarray*}',
                    r'\begin{align}',
                    r'\end{align}',
                    r'\begin{align*}',
                    r'\end{align*}',
                    r'\begin{multline}',
                    r'\end{multline}',
                    r'\begin{multline*}',
                    r'\end{multline*}',
                    r'\begin{split}',
                    r'\end{split}',
                    r'\begin{gather}',
                    r'\end{gather}',
                    r'\begin{gather*}',
                    r'\end{gather*}',
                    r'\[',
                    r'\]',
                    # some common abbreviations (newcommands):
                    r'\beqan',
                    r'\eeqan',
                    r'\beqa',
                    r'\eeqa',
                    r'\balnn',
                    r'\ealnn',
                    r'\baln',
                    r'\ealn',
                    r'\beq',
                    r'\eeq',  # the simplest, contained in others, must come last!
                    ]
        for command in commands:
            tex_blocks[i] = tex_blocks[i].replace(command, '')
        tex_blocks[i] = re.sub('&\s*=\s*&', ' &= ', tex_blocks[i])
        # provide warnings for problematic environments
        if '{alignat' in tex_blocks[i]:
            print '*** warning: the "alignat" environment will give errors in Sphinx:\n\n', tex_blocks[i], '\n'

    # Replace all references to equations that have labels in math environments:
    for label in math_labels:
        filestr = filestr.replace('(:ref:`%s`)' % label, ':eq:`%s`' % label)

    multiple_math_labels_with_refs = [] # collect the labels with references
    for labels in multiple_math_labels:
        for label in labels:
            ref = ':eq:`%s`' % label  # ref{} is translated to eq:``
            if ref in filestr:
                multiple_math_labels_with_refs.append(label)

    if multiple_math_labels_with_refs:
        print """
*** warning: detected non-align math environment with multiple labels
    (Sphinx cannot handle this equation system - labels will be removed
    and references to them will be empty):"""
        for label in multiple_math_labels_with_refs:
            print '    label{%s}' % label
        print

    filestr = insert_code_and_tex(filestr, code_blocks, tex_blocks, 'rst')

    # Remove all !bc ipy and !bc pyshell since interactive sessions
    # are automatically handled by sphinx without indentation
    # (just a blank line before and after)
    filestr = re.sub(r'^!bc +ipy *\n(.*?)^!ec *\n',
                     '\n\g<1>\n', filestr, re.DOTALL|re.MULTILINE)
    filestr = re.sub(r'^!bc +pyshell *\n(.*?)^!ec *\n',
                     '\n\g<1>\n', filestr, re.DOTALL|re.MULTILINE)

    # Make correct code-block:: language constructions
    for key in envir2lang:
        language = envir2lang[key]
        if not language in legal_pygments_languages:
            raise TypeError('%s is not a legal Pygments language '\
                            '(lexer) in line with:\n  %s' % \
                                (language, defs_line))
        #filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
        #                 '\n.. code-block:: %s\n\n' % envir2lang[key], filestr,
        #                 flags=re.MULTILINE)
        # Check that we have code installed to handle pyscpro
        if 'pyscpro' in filestr and key == 'pyscpro':
            try:
                import icsecontrib.sagecellserver
            except ImportError:
                print """
*** warning: pyscpro for computer code (sage cells) is requested, but'
    icsecontrib.sagecellserver from https://github.com/kriskda/sphinx-sagecell
    is not installed. Using plain Python typesetting instead."""
                key = 'pypro'

        if key == 'pyoptpro':
            if option('runestone'):
                global codelens_counter
                codelens_counter += 1
                filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
                                 '\n.. codelens:: codelens_%d\n   :showoutput:\n\n' % codelens_counter,
                                 filestr, flags=re.MULTILINE)
            else:
                filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
                                 '\n.. raw:: html\n\n',
                                 filestr, flags=re.MULTILINE)
        elif key == 'pyscpro':
            if option('runestone'):
                global activecode_counter
                activecode_counter += 1
                filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
                                 """
.. activecode:: activecode_%d
   :language: python

""" % (activecode_counter), filestr, flags=re.MULTILINE)
            else:
                filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
                                 '\n.. sagecellserver::\n\n',
                                 filestr, flags=re.MULTILINE)
        elif key == 'pysccod':
            if option('runestone'):
                global activecode_counter
                activecode_counter += 1
                # Include (i.e., run) all previous code segments...
                # NOTE: this is most likely not what we want
                include = ', '.join([i for i in range(1, activecode_counter)])
                filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
                                 """
.. activecode:: activecode_%d
   :language: python
   "include: %s
""" % (activecode_counter, include), filestr, flags=re.MULTILINE)
            else:
                print '*** error: pysccod is not supported without the --runestone flag'
                _abort()
        else:
            filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
                             '\n.. code-block:: %s\n\n' % \
                             envir2lang[key], filestr, flags=re.MULTILINE)

    # any !bc with/without argument becomes a text block:
    #filestr = re.sub(r'^!bc.+\n', '\n.. code-block:: text\n\n', filestr,
    #                 flags=re.MULTILINE)
    filestr = re.sub(r'^!bc.*$', '\n.. code-block:: text\n\n', filestr,
                     flags=re.MULTILINE)

    filestr = re.sub(r'^!ec *\n', '\n', filestr, flags=re.MULTILINE)
    #filestr = re.sub(r'^!ec\n', '\n', filestr, flags=re.MULTILINE)
    #filestr = re.sub(r'^!ec\n', '', filestr, flags=re.MULTILINE)
    filestr = re.sub(r'^!bt *\n', '\n.. math::\n', filestr, flags=re.MULTILINE)
    filestr = re.sub(r'^!et *\n', '\n', filestr, flags=re.MULTILINE)

    # Final fixes

    filestr = fix_underlines_in_headings(filestr)
    # Ensure blank line before and after comments
    filestr = re.sub(r'([.:;?!])\n^\.\. ', r'\g<1>\n\n.. ',
                     filestr, flags=re.MULTILINE)
    filestr = re.sub(r'(^\.\. .+)\n([^ \n]+)', r'\g<1>\n\n\g<2>',
                     filestr, flags=re.MULTILINE)
    # Line breaks interfer with tables and needs a final blank line too
    lines = filestr.splitlines()
    inside_block = False
    for i in range(len(lines)):
        if lines[i].startswith('<linebreakpipe>') and not inside_block:
            inside_block = True
            lines[i] = lines[i].replace('<linebreakpipe> ', '') + '\n'
            continue
        if lines[i].startswith('<linebreakpipe>') and inside_block:
            lines[i] = '|' + lines[i].replace('<linebreakpipe>', '')
            continue
        if inside_block and not lines[i].startswith('<linebreakpipe>'):
            inside_block = False
            lines[i] = '| ' + lines[i] + '\n'
    filestr = '\n'.join(lines)

    if option('html_links_in_new_window'):
        # Insert a comment to be recognized by automake_sphinx.py such that it
        # can replace the default links by proper modified target= option.
        filestr = '\n\n.. NOTE: Open external links in new windows.\n\n' + filestr

    # Remove too much vertical space
    filestr = re.sub(r'\n{3,}', '\n\n', filestr)

    return filestr
Пример #10
0
def sphinx_code_orig(filestr, format):
    # NOTE: THIS FUNCTION IS NOT USED!!!!!!

    # In rst syntax, code blocks are typeset with :: (verbatim)
    # followed by intended blocks. This function indents everything
    # inside code (or TeX) blocks.

    # grab #sphinx code-blocks: cod=python cpp=c++ etc line
    # (do this before code is inserted in case verbatim blocks contain
    # such specifications for illustration)
    m = re.search(r"#\s*[Ss]phinx\s+code-blocks?:(.+?)\n", filestr)
    if m:
        defs_line = m.group(1)
        # turn defs into a dictionary definition:
        defs = {}
        for definition in defs_line.split():
            key, value = definition.split("=")
            defs[key] = value
    else:
        # default mappings:
        defs = dict(
            cod="python",
            pro="python",
            pycod="python",
            cycod="cython",
            pypro="python",
            cypro="cython",
            fcod="fortran",
            fpro="fortran",
            ccod="c",
            cppcod="c++",
            cpro="c",
            cpppro="c++",
            mcod="matlab",
            mpro="matlab",
            plcod="perl",
            plpro="perl",
            shcod="bash",
            shpro="bash",
            rbcod="ruby",
            rbpro="ruby",
            sys="console",
            dat="python",
            ipy="python",
            xmlcod="xml",
            xmlpro="xml",
            xml="xml",
            htmlcod="html",
            htmlpro="html",
            html="html",
            texcod="latex",
            texpro="latex",
            tex="latex",
        )
        # (the "python" typesetting is neutral if the text
        # does not parse as python)

    # first indent all code/tex blocks by 1) extracting all blocks,
    # 2) intending each block, and 3) inserting the blocks:
    filestr, code_blocks, tex_blocks = remove_code_and_tex(filestr, format)
    for i in range(len(code_blocks)):
        code_blocks[i] = indent_lines(code_blocks[i], format)
    for i in range(len(tex_blocks)):
        tex_blocks[i] = indent_lines(tex_blocks[i], format)
        # remove all \label{}s inside tex blocks:
        tex_blocks[i] = re.sub(fix_latex(r"\label\{.+?\}", application="match"), "", tex_blocks[i])
        # remove those without \ if there are any:
        tex_blocks[i] = re.sub(r"label\{.+?\}", "", tex_blocks[i])
        # side effects: `label{eq1}` as verbatim, but this is mostly a
        # problem for doconce documentation and can be rephrased...

        # fix latex constructions that do not work with sphinx math
        commands = [
            r"\begin{equation}",
            r"\end{equation}",
            r"\begin{equation*}",
            r"\end{equation*}",
            r"\begin{eqnarray}",
            r"\end{eqnarray}",
            r"\begin{eqnarray*}",
            r"\end{eqnarray*}",
            r"\begin{align}",
            r"\end{align}",
            r"\begin{align*}",
            r"\end{align*}",
            r"\begin{multline}",
            r"\end{multline}",
            r"\begin{multline*}",
            r"\end{multline*}",
            r"\begin{split}",
            r"\end{split}",
            r"\begin{gather}",
            r"\end{gather}",
            r"\begin{gather*}",
            r"\end{gather*}",
            r"\[",
            r"\]",
            # some common abbreviations (newcommands):
            r"\beqan",
            r"\eeqan",
            r"\beqa",
            r"\eeqa",
            r"\balnn",
            r"\ealnn",
            r"\baln",
            r"\ealn",
            r"\beq",
            r"\eeq",  # the simplest, contained in others, must come last!
        ]
        for command in commands:
            tex_blocks[i] = tex_blocks[i].replace(command, "")
        tex_blocks[i] = re.sub("&\s*=\s*&", " &= ", tex_blocks[i])
        # provide warnings for problematic environments
        # if '{alignat' in tex_blocks[i]:
        #    errwarn('*** warning: the "alignat" environment will give errors in Sphinx:\n' + tex_blocks[i] + '\n')

    filestr = insert_code_and_tex(filestr, code_blocks, tex_blocks, "rst")

    for key in defs:
        language = defs[key]
        if not language in legal_pygments_languages:
            raise TypeError(
                "%s is not a legal Pygments language " "(lexer) in line with:\n  %s" % (language, defs_line)
            )
        # filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
        #                 '\n.. code-block:: %s\n\n' % defs[key], filestr,
        #                 flags=re.MULTILINE)
        cpattern = re.compile(r"^!bc\s+%s\s*\n" % key, flags=re.MULTILINE)
        filestr, n = cpattern.subn("\n.. code-block:: %s\n\n" % defs[key], filestr)
        errwarn(key + " " + n)
        if n > 0:
            errwarn("sphinx: %d subst %s by %s" % (n, key, defs[key]))

    # any !bc with/without argument becomes a py (python) block:
    # filestr = re.sub(r'^!bc.+\n', '\n.. code-block:: py\n\n', filestr,
    #                 flags=re.MULTILINE)
    cpattern = re.compile(r"^!bc.+$", flags=re.MULTILINE)
    filestr = cpattern.sub("\n.. code-block:: py\n\n", filestr)

    filestr = re.sub(r"^!ec *\n", "\n", filestr, flags=re.MULTILINE)
    # filestr = re.sub(r'^!ec\n', '\n', filestr, flags=re.MULTILINE)
    # filestr = re.sub(r'^!ec\n', '', filestr, flags=re.MULTILINE)
    filestr = re.sub(r"^!bt *\n", "\n.. math::\n\n", filestr, flags=re.MULTILINE)
    filestr = re.sub(r"^!et *\n", "\n\n", filestr, flags=re.MULTILINE)

    return filestr
Пример #11
0
def sphinx_code(filestr, code_blocks, code_block_types, tex_blocks, format):
    # In rst syntax, code blocks are typeset with :: (verbatim)
    # followed by intended blocks. This function indents everything
    # inside code (or TeX) blocks.

    # default mappings of !bc environments and pygments languages:
    envir2pygments = dict(
        cod="python",
        pro="python",
        pycod="python",
        cycod="cython",
        pypro="python",
        cypro="cython",
        fcod="fortran",
        fpro="fortran",
        ccod="c",
        cppcod="c++",
        cpro="c",
        cpppro="c++",
        mcod="matlab",
        mpro="matlab",
        plcod="perl",
        plpro="perl",
        shcod="bash",
        shpro="bash",
        rbcod="ruby",
        rbpro="ruby",
        # sys='console',
        sys="text",
        rst="rst",
        css="css",
        csspro="css",
        csscod="css",
        dat="text",
        csv="text",
        txt="text",
        cc="text",
        ccq="text",  # not possible with extra indent for ccq
        ipy="ipy",
        xmlcod="xml",
        xmlpro="xml",
        xml="xml",
        htmlcod="html",
        htmlpro="html",
        html="html",
        texcod="latex",
        texpro="latex",
        tex="latex",
        latexcod="latex",
        latexpro="latex",
        latex="latex",
        do="doconce",
        pyshell="python",
        pyoptpro="python",
        pyscpro="python",
    )

    # grab line with: # sphinx code-blocks: cod=python cpp=c++ etc
    # (do this before code is inserted in case verbatim blocks contain
    # such specifications for illustration)
    m = re.search(r".. *[Ss]phinx +code-blocks?:(.+)", filestr)
    if m:
        defs_line = m.group(1)
        # turn specifications into a dictionary:
        for definition in defs_line.split():
            key, value = definition.split("=")
            envir2pygments[key] = value

    # First indent all code blocks

    for i in range(len(code_blocks)):
        if code_block_types[i].startswith("pyoptpro") and not option("runestone"):
            code_blocks[i] = online_python_tutor(code_blocks[i], return_tp="iframe")
        if code_block_types[i].endswith("-h"):
            indentation = " " * 8
        else:
            indentation = " " * 4
        code_blocks[i] = indent_lines(code_blocks[i], format, indentation)

    # After transforming align environments to separate equations
    # the problem with math labels in multiple eqs has disappeared.
    # (doconce.py applies align2equations, which takes all align
    # envirs and translates them to separate equations, but align*
    # environments are allowed.
    # Any output of labels in align means an error in the
    # align -> equation transformation...)
    math_labels = []
    multiple_math_labels = []  # sphinx has problems with multiple math labels
    for i in range(len(tex_blocks)):
        tex_blocks[i] = indent_lines(tex_blocks[i], format)
        # extract all \label{}s inside tex blocks and typeset them
        # with :label: tags
        label_regex = fix_latex(r"label\{(.+?)\}", application="match")
        labels = re.findall(label_regex, tex_blocks[i])
        if len(labels) == 1:
            tex_blocks[i] = "   :label: %s\n" % labels[0] + tex_blocks[i]
        elif len(labels) > 1:
            multiple_math_labels.append(labels)
        if len(labels) > 0:
            math_labels.extend(labels)
        tex_blocks[i] = re.sub(label_regex, "", tex_blocks[i])

        # fix latex constructions that do not work with sphinx math
        # (just remove them)
        commands = [
            r"\begin{equation}",
            r"\end{equation}",
            r"\begin{equation*}",
            r"\end{equation*}",
            # r'\begin{eqnarray}',
            # r'\end{eqnarray}',
            # r'\begin{eqnarray*}',
            # r'\end{eqnarray*}',
            # r'\begin{align}',
            # r'\end{align}',
            # r'\begin{align*}',
            # r'\end{align*}',
            r"\begin{multline}",
            r"\end{multline}",
            r"\begin{multline*}",
            r"\end{multline*}",
            # r'\begin{split}',
            # r'\end{split}',
            # r'\begin{gather}',
            # r'\end{gather}',
            # r'\begin{gather*}',
            # r'\end{gather*}',
            r"\[",
            r"\]",
            # some common abbreviations (newcommands):
            r"\beqan",
            r"\eeqan",
            r"\beqa",
            r"\eeqa",
            r"\balnn",
            r"\ealnn",
            r"\baln",
            r"\ealn",
            r"\beq",
            r"\eeq",  # the simplest name, contained in others, must come last!
        ]
        for command in commands:
            tex_blocks[i] = tex_blocks[i].replace(command, "")
        # &=& -> &=
        tex_blocks[i] = re.sub("&\s*=\s*&", " &= ", tex_blocks[i])
        # provide warnings for problematic environments

    # Replace all references to equations that have labels in math environments:
    for label in math_labels:
        filestr = filestr.replace("(:ref:`%s`)" % label, ":eq:`%s`" % label)

    multiple_math_labels_with_refs = []  # collect the labels with references
    for labels in multiple_math_labels:
        for label in labels:
            ref = ":eq:`%s`" % label  # ref{} is translated to eq:``
            if ref in filestr:
                multiple_math_labels_with_refs.append(label)

    if multiple_math_labels_with_refs:
        errwarn(
            """
*** warning: detected non-align math environment with multiple labels
    (Sphinx cannot handle this equation system - labels will be removed
    and references to them will be empty):"""
        )
        for label in multiple_math_labels_with_refs:
            errwarn("    label{%s}" % label)
        print

    filestr = insert_code_and_tex(filestr, code_blocks, tex_blocks, "sphinx")

    # Remove all !bc ipy and !bc pyshell since interactive sessions
    # are automatically handled by sphinx without indentation
    # (just a blank line before and after)
    filestr = re.sub(r"^!bc +d?ipy *\n(.*?)^!ec *\n", "\n\g<1>\n", filestr, re.DOTALL | re.MULTILINE)
    filestr = re.sub(r"^!bc +d?pyshell *\n(.*?)^!ec *\n", "\n\g<1>\n", filestr, re.DOTALL | re.MULTILINE)

    # Check if we have custom pygments lexers
    if "ipy" in code_block_types:
        if not has_custom_pygments_lexer("ipy"):
            envir2pygments["ipy"] = "python"
    if "do" in code_block_types:
        if not has_custom_pygments_lexer("doconce"):
            envir2pygments["do"] = "text"

    # Make correct code-block:: language constructions
    legal_pygments_languages = get_legal_pygments_lexers()
    for key in set(code_block_types):
        if key in envir2pygments:
            if not envir2pygments[key] in legal_pygments_languages:
                errwarn(
                    """*** warning: %s is not a legal Pygments language (lexer)
found in line:
  %s

    The 'text' lexer will be used instead.
"""
                    % (envir2pygments[key], defs_line)
                )
                envir2pygments[key] = "text"

        # filestr = re.sub(r'^!bc\s+%s\s*\n' % key,
        #                 '\n.. code-block:: %s\n\n' % envir2pygments[key], filestr,
        #                 flags=re.MULTILINE)

        # Check that we have code installed to handle pyscpro
        if "pyscpro" in filestr and key == "pyscpro":
            try:
                import icsecontrib.sagecellserver
            except ImportError:
                errwarn(
                    """
*** warning: pyscpro for computer code (sage cells) is requested, but'
    icsecontrib.sagecellserver from https://github.com/kriskda/sphinx-sagecell
    is not installed. Using plain Python typesetting instead."""
                )
                key = "pypro"

        if key == "pyoptpro":
            if option("runestone"):
                filestr = re.sub(
                    r"^!bc\s+%s\s*\n" % key,
                    "\n.. codelens:: codelens_\n   :showoutput:\n\n",
                    filestr,
                    flags=re.MULTILINE,
                )
            else:
                filestr = re.sub(r"^!bc\s+%s\s*\n" % key, "\n.. raw:: html\n\n", filestr, flags=re.MULTILINE)
        elif key == "pyscpro":
            if option("runestone"):
                filestr = re.sub(
                    r"^!bc\s+%s\s*\n" % key,
                    """
.. activecode:: activecode_
   :language: python

""",
                    filestr,
                    flags=re.MULTILINE,
                )
            else:
                filestr = re.sub(r"^!bc\s+%s\s*\n" % key, "\n.. sagecellserver::\n\n", filestr, flags=re.MULTILINE)
        elif key == "pysccod":
            if option("runestone"):
                # Include (i.e., run) all previous code segments...
                # NOTE: this is most likely not what we want
                include = ", ".join([i for i in range(1, activecode_counter)])
                filestr = re.sub(
                    r"^!bc\s+%s\s*\n" % key,
                    """
.. activecode:: activecode_
   :language: python
   "include: %s
"""
                    % include,
                    filestr,
                    flags=re.MULTILINE,
                )
            else:
                errwarn(
                    "*** error: pysccod for sphinx is not supported without the --runestone flag\n    (but pyscpro is via Sage Cell Server)"
                )
                _abort()

        elif key == "":
            # any !bc with/without argument becomes a text block:
            filestr = re.sub(r"^!bc$", "\n.. code-block:: text\n\n", filestr, flags=re.MULTILINE)
        elif key.endswith("hid"):
            if key in ("pyhid", "jshid", "htmlhid") and option("runestone"):
                # Allow runestone books to run hidden code blocks
                # (replace pyhid by pycod, then remove all !bc *hid)
                for i in range(len(code_block_types)):
                    if code_block_types[i] == key:
                        code_block_types[i] = key.replace("hid", "cod")

                key2language = dict(py="python", js="javascript", html="html")
                language = key2language[key.replace("hid", "")]
                include = ", ".join([i for i in range(1, activecode_counter)])
                filestr = re.sub(
                    r"^!bc +%s\s*\n" % key,
                    """
.. activecode:: activecode_
   :language: %s
   :include: %s
   :hidecode:

"""
                    % (language, include),
                    filestr,
                    flags=re.MULTILINE,
                )
            else:
                # Remove hidden code block
                pattern = r"^!bc +%s\n.+?^!ec" % key
                filestr = re.sub(pattern, "", filestr, flags=re.MULTILINE | re.DOTALL)
        else:
            show_hide = False
            if key.endswith("-h"):
                key_orig = key
                key = key[:-2]
                show_hide = True
            # Use the standard sphinx code-block directive
            if key in envir2pygments:
                pygments_language = envir2pygments[key]
            elif key in legal_pygments_languages:
                pygments_language = key
            else:
                errwarn('*** error: detected code environment "%s"' % key)
                errwarn("    which is not registered in sphinx.py (sphinx_code)")
                errwarn("    or not a language registered in pygments")
                _abort()
            if show_hide:
                filestr = re.sub(
                    r"^!bc +%s\s*\n" % key_orig,
                    "\n.. container:: toggle\n\n    .. container:: header\n\n        **Show/Hide Code**\n\n    .. code-block:: %s\n\n"
                    % pygments_language,
                    filestr,
                    flags=re.MULTILINE,
                )
                # Must add 4 indent in corresponding code_blocks[i], done above
            else:
                filestr = re.sub(
                    r"^!bc +%s\s*\n" % key, "\n.. code-block:: %s\n\n" % pygments_language, filestr, flags=re.MULTILINE
                )

    # any !bc with/without argument becomes a text block:
    filestr = re.sub(r"^!bc.*$", "\n.. code-block:: text\n\n", filestr, flags=re.MULTILINE)
    filestr = re.sub(r"^!ec *\n", "\n", filestr, flags=re.MULTILINE)
    # filestr = re.sub(r'^!ec\n', '\n', filestr, flags=re.MULTILINE)
    # filestr = re.sub(r'^!ec\n', '', filestr, flags=re.MULTILINE)

    filestr = re.sub(r"^!bt *\n", "\n.. math::\n", filestr, flags=re.MULTILINE)
    filestr = re.sub(r"^!et *\n", "\n", filestr, flags=re.MULTILINE)
    # Fix lacking blank line after :label:
    filestr = re.sub(r"^(   :label: .+?)(\n *[^ ]+)", r"\g<1>\n\n\g<2>", filestr, flags=re.MULTILINE)

    # Insert counters for runestone blocks
    if option("runestone"):
        codelens_counter = 0
        activecode_counter = 0
        lines = filestr.splitlines()
        for i in range(len(lines)):
            if ".. codelens:: codelens_" in lines[i]:
                codelens_counter += 1
                lines[i] = lines[i].replace("codelens_", "codelens_%d" % codelens_counter)
            if ".. activecode:: activecode_" in lines[i]:
                activecode_counter += 1
                lines[i] = lines[i].replace("activecode_", "activecode_%d" % activecode_counter)
        filestr = "\n".join(lines)

    # Final fixes

    filestr = fix_underlines_in_headings(filestr)
    # Ensure blank line before and after comments
    filestr = re.sub(r"([.:;?!])\n^\.\. ", r"\g<1>\n\n.. ", filestr, flags=re.MULTILINE)
    filestr = re.sub(r"(^\.\. .+)\n([^ \n]+)", r"\g<1>\n\n\g<2>", filestr, flags=re.MULTILINE)

    # Line breaks interfer with tables and needs a final blank line too
    lines = filestr.splitlines()
    inside_block = False
    for i in range(len(lines)):
        if lines[i].startswith("<linebreakpipe>") and not inside_block:
            inside_block = True
            lines[i] = lines[i].replace("<linebreakpipe> ", "") + "\n"
            continue
        if lines[i].startswith("<linebreakpipe>") and inside_block:
            lines[i] = "|" + lines[i].replace("<linebreakpipe>", "")
            continue
        if inside_block and not lines[i].startswith("<linebreakpipe>"):
            inside_block = False
            lines[i] = "| " + lines[i] + "\n"
    filestr = "\n".join(lines)

    # Remove double !split (TOC with a prefix !split gives two !splits)
    pattern = "^.. !split\s+.. !split"
    filestr = re.sub(pattern, ".. !split", filestr, flags=re.MULTILINE)

    if option("html_links_in_new_window"):
        # Insert a comment to be recognized by automake_sphinx.py such that it
        # can replace the default links by proper modified target= option.
        # filestr = '\n\n.. NOTE: Open external links in new windows.\n\n' + filestr
        # Use JavaScript instead
        filestr = (
            """.. raw:: html

        <script type="text/javascript">
        $(document).ready(function() {
            $("a[href^='http']").attr('target','_blank');
        });
        </script>

"""
            + filestr
        )

    # Remove too much vertical space
    filestr = re.sub(r"\n{3,}", "\n\n", filestr)

    return filestr