@@ -230,7 +230,7 @@ def sphinx_plot(graphics, **kwds):
230
230
# console lexers. 'ipycon' is the IPython console, which is what we want
231
231
# for most code blocks: anything with "sage:" prompts. For other IPython,
232
232
# 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'( [.][.][.][.]:|[.][.][.]) ' )
234
234
highlighting .lexers ['ipython' ] = IPyLexer ()
235
235
highlight_language = 'ipycon'
236
236
@@ -790,6 +790,9 @@ class will be properly documented inside its surrounding class.
790
790
791
791
792
792
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
793
796
794
797
class SagecodeTransform (SphinxTransform ):
795
798
"""
@@ -828,29 +831,78 @@ def apply(self):
828
831
if self .app .builder .tags .has ('html' ) or self .app .builder .tags .has ('inventory' ):
829
832
for node in self .document .traverse (nodes .literal_block ):
830
833
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
834
855
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 )
854
906
855
907
# This replaces the setup() in sage.misc.sagedoc_conf
856
908
def setup (app ):
@@ -863,8 +915,7 @@ def setup(app):
863
915
app .connect ('autodoc-process-docstring' , skip_TESTS_block )
864
916
app .connect ('autodoc-skip-member' , skip_member )
865
917
app .add_transform (SagemathTransform )
866
- if os .environ .get ('SAGE_LIVE_DOC' , 'no' ) == 'yes' :
867
- app .add_transform (SagecodeTransform )
918
+ app .add_transform (SagecodeTransform )
868
919
869
920
# When building the standard docs, app.srcdir is set to SAGE_DOC_SRC +
870
921
# 'LANGUAGE/DOCNAME'.
0 commit comments