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
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
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
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
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
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
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
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
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
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
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