Skip to content

Commit d318a49

Browse files
author
Matthias Koeppe
committed
src/sage_docbuild/conf.py: Show preparsed doctests (and Jupyter cells) using inline tabs
1 parent 2fe88d0 commit d318a49

File tree

1 file changed

+76
-25
lines changed

1 file changed

+76
-25
lines changed

src/sage_docbuild/conf.py

Lines changed: 76 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ def sphinx_plot(graphics, **kwds):
230230
# console lexers. 'ipycon' is the IPython console, which is what we want
231231
# for most code blocks: anything with "sage:" prompts. For other IPython,
232232
# like blocks which might appear in a notebook cell, use 'ipython'.
233-
highlighting.lexers['ipycon'] = IPythonConsoleLexer(in1_regex=r'sage: ', in2_regex=r'[.][.][.][.]: ')
233+
highlighting.lexers['ipycon'] = IPythonConsoleLexer(in1_regex=r'(sage:|>>>)', in2_regex=r'([.][.][.][.]:|[.][.][.])')
234234
highlighting.lexers['ipython'] = IPyLexer()
235235
highlight_language = 'ipycon'
236236

@@ -790,6 +790,9 @@ class will be properly documented inside its surrounding class.
790790

791791

792792
from jupyter_sphinx.ast import JupyterCellNode, CellInputNode
793+
from docutils.nodes import container as Container, label as Label, literal_block as LiteralBlock, Text
794+
from sphinx_inline_tabs._impl import TabContainer
795+
from sage.repl.preparse import preparse
793796

794797
class SagecodeTransform(SphinxTransform):
795798
"""
@@ -828,29 +831,78 @@ def apply(self):
828831
if self.app.builder.tags.has('html') or self.app.builder.tags.has('inventory'):
829832
for node in self.document.traverse(nodes.literal_block):
830833
if node.get('language') is None and node.astext().startswith('sage:'):
831-
source = node.rawsource
832-
lines = []
833-
for line in source.splitlines():
834+
parent = node.parent
835+
index = parent.index(node)
836+
parent.remove(node)
837+
# Tab for Sage code
838+
container = TabContainer("", type="tab", new_set=False)
839+
textnodes = [Text('Sage')]
840+
label = Label("", "", *textnodes)
841+
container += label
842+
content = Container("", is_div=True, classes=["tab-content"])
843+
content += node
844+
container += content
845+
parent.insert(index, container)
846+
# Tab for preparsed version
847+
container = TabContainer("", type="tab", new_set=False)
848+
textnodes = [Text('Python')]
849+
label = Label("", "", *textnodes)
850+
container += label
851+
content = Container("", is_div=True, classes=["tab-content"])
852+
example_lines = []
853+
preparsed_lines = ['>>> from sage.all import *']
854+
for line in node.rawsource.splitlines() + ['']: # one extra to process last example
834855
newline = line.lstrip()
835-
if newline.startswith('sage: ') or newline.startswith('....: '):
836-
lines.append(newline[6:])
837-
cell_node = JupyterCellNode(
838-
execute=False,
839-
hide_code=True,
840-
hide_output=True,
841-
emphasize_lines=[],
842-
raises=False,
843-
stderr=True,
844-
code_below=False,
845-
classes=["jupyter_cell"])
846-
cell_input = CellInputNode(classes=['cell_input','live-doc'])
847-
cell_input += nodes.literal_block(
848-
text='\n'.join(lines),
849-
linenos=False,
850-
linenostart=1)
851-
cell_node += cell_input
852-
853-
node.parent.insert(node.parent.index(node) + 1, cell_node)
856+
if newline.startswith('....: '):
857+
example_lines.append(newline[6:])
858+
else:
859+
if example_lines:
860+
preparsed_example = preparse('\n'.join(example_lines))
861+
prompt = '>>> '
862+
for preparsed_line in preparsed_example.splitlines():
863+
preparsed_lines.append(prompt + preparsed_line)
864+
prompt = '... '
865+
example_lines = []
866+
if newline.startswith('sage: '):
867+
example_lines.append(newline[6:])
868+
else:
869+
preparsed_lines.append(line)
870+
preparsed = '\n'.join(preparsed_lines)
871+
preparsed_node = LiteralBlock(preparsed, preparsed, language='ipycon')
872+
content += preparsed_node
873+
container += content
874+
parent.insert(index + 1, container)
875+
if os.environ.get('SAGE_LIVE_DOC', 'no') == 'yes':
876+
# Tab for Jupyter-sphinx cell
877+
source = node.rawsource
878+
lines = []
879+
for line in source.splitlines():
880+
newline = line.lstrip()
881+
if newline.startswith('sage: ') or newline.startswith('....: '):
882+
lines.append(newline[6:])
883+
cell_node = JupyterCellNode(
884+
execute=False,
885+
hide_code=False,
886+
hide_output=True,
887+
emphasize_lines=[],
888+
raises=False,
889+
stderr=True,
890+
code_below=False,
891+
classes=["jupyter_cell"])
892+
cell_input = CellInputNode(classes=['cell_input','live-doc'])
893+
cell_input += nodes.literal_block(
894+
text='\n'.join(lines),
895+
linenos=False,
896+
linenostart=1)
897+
cell_node += cell_input
898+
container = TabContainer("", type="tab", new_set=False)
899+
textnodes = [Text('Sage (live)')]
900+
label = Label("", "", *textnodes)
901+
container += label
902+
content = Container("", is_div=True, classes=["tab-content"])
903+
content += cell_node
904+
container += content
905+
parent.insert(index + 1, container)
854906

855907
# This replaces the setup() in sage.misc.sagedoc_conf
856908
def setup(app):
@@ -863,8 +915,7 @@ def setup(app):
863915
app.connect('autodoc-process-docstring', skip_TESTS_block)
864916
app.connect('autodoc-skip-member', skip_member)
865917
app.add_transform(SagemathTransform)
866-
if os.environ.get('SAGE_LIVE_DOC', 'no') == 'yes':
867-
app.add_transform(SagecodeTransform)
918+
app.add_transform(SagecodeTransform)
868919

869920
# When building the standard docs, app.srcdir is set to SAGE_DOC_SRC +
870921
# 'LANGUAGE/DOCNAME'.

0 commit comments

Comments
 (0)