0

Is there a command similar to \lstinputlisting with sagetex, which would import directly a .sage file in the relevant block, and have it evaluated by sagetex?

If not, how would one write such a command?

The idea would be very similar to that of \lstinputlisting, ie, writing the source code in a sage development environment and having it directly interact with latex via sagetex.

I came up with the following code:

\newcommand{\sagesilentinput}[1]{%
    \newwrite\texfile
    \immediate\openout\texfile=#1.tex
    \immediate\write\texfile{\noexpand\begin{sagesilent}}
  %
      \newread\sagefile
      \openin\sagefile=#1
      \typeout{Reading #1}
      %
      % %% Taken from https://tex.stackexchange.com/q/63463/9517
      \begingroup\endlinechar=-1
      \loop\unless\ifeof\sagefile
      \read\sagefile to\fileline 
      \typeout\fileline % For debug purposes, but nothing is typed out either
      \immediate\write\texfile{\unexpanded\expandafter{\fileline}}  
      \repeat
      \endgroup
      %
      \immediate\write\texfile{\noexpand\end{sagesilent}}
      \immediate\closeout\texfile
      \closein\sagefile
  %
  \input{#1.tex}
}

which should take as argument the name of a file foo.sage, create a file foo.sage.tex with contents

\begin{sagesilent}
<contents of foo.sage>
\end{sagesilent}

and then input it.

However, it doesn't work, the file just contains

\begin{sagesilent}

\end{sagesilent}

and it's all like the loop didn't read a single line. The result is the same if I use \readline instead of \read.

MNWE with sagetex:

\documentclass{article}

\usepackage{sagetex} 

\usepackage{filecontents}

\begin{filecontents}{example.sage}
def myfunction(a,b):
    return a+b;       
\end{filecontents}

\newcommand{\sagesilentinput}[1]{%
  \newwrite\texfile
  \immediate\openout\texfile=#1.tex
  \immediate\write\texfile{\noexpand\begin{sagesilent}}
    \typeout{Writing #1.tex}
    %
    \newread\sagefile
    \openin\sagefile=#1
    \typeout{Reading #1}
    %
    % %% Taken from https://tex.stackexchange.com/q/63463/9517
    \begingroup\endlinechar=-1
    \loop\unless\ifeof\sagefile
    \read\sagefile to\fileline 
    \typeout\fileline % For debug purposes, but nothing is typed out either
    \immediate\write\texfile{\unexpanded\expandafter{\fileline}}  
    \repeat
    \endgroup
    %
    \immediate\write\texfile{\noexpand\end{sagesilent}}
  \immediate\closeout\texfile
  \closein\sagefile
  %
  \input{#1.tex}
}

\begin{document}

\sagesilentinput{example.sage}

\sage{myfunction(3,4)}

\end{document}

MNWE without sagetex (success can then be seen on the contents of example.sage.tex):

\documentclass{article}

%\usepackage{sagetex}

\usepackage{filecontents}

\begin{filecontents}{example.sage}
def myfunction(a,b):
    return a+b;       
\end{filecontents}

\newcommand{\sagesilentinput}[1]{%
  \newwrite\texfile
  \immediate\openout\texfile=#1.tex
  \immediate\write\texfile{\noexpand\begin{sagesilent}}
    \typeout{Writing #1.tex}
    %
    \newread\sagefile
    \openin\sagefile=#1
    \typeout{Reading #1}
    %
    % %% Taken from https://tex.stackexchange.com/q/63463/9517
    \begingroup\endlinechar=-1
    \loop\unless\ifeof\sagefile
    \read\sagefile to\fileline 
    \typeout\fileline % For debug purposes, but nothing is typed out either
    \immediate\write\texfile{\unexpanded\expandafter{\fileline}}  
    \repeat
    \endgroup
    %
    \immediate\write\texfile{\noexpand\end{sagesilent}}
  \immediate\closeout\texfile
  \closein\sagefile
  %
  %\input{#1.tex}
}

\begin{document}

\sagesilentinput{example.sage}

%\sage{myfunction(3,4)}

\end{document}
  • If nobody can help here, you might try going to the AskSagemath site. – DJP Jun 26 '19 at 22:37
  • @DJP Thanks for the suggestion. I have found a workaround which I will post here, but apparently it cannot be made into a macro. Anyway, I have no reason to believe that the problem I have is related to sage, it is about using (La)TeX to copy the contents of a file. Maybe I should edit the title to make it more clear. – T. Verron Jun 27 '19 at 15:49
0

This is not an answer, but at least a workaround. It does not solve the specific copying problem asked in the question, but it achieves the final purpose, and does not create an external file.

The problem is that one cannot use LaTeX's \input to load a sage file in the relevant blocks, because \input would not be expanded before the contents are evaluated by Sage. However, it is possible to use Sage syntax for the same outcome:

\begin{sagesilent}
  load("example.sage")
\end{sagesilent}

Due to internals of the sagetex package (source) sagesilent blocks cannot be included in a macro, but it's not really a problem given how simple the code is.

  • You should be able to put Sage related info into a macro provided that the macro doesn't exist until after Sage has run. I've got lots of sagetex related posts, such as this where the output relies on Sage but doesn't exists until the after Sage has run. First pass is LaTeX and document is empty. Second pass is Sage which creates the text which will form the document. Third pass process the no-longer-empty LaTeX file containing Sage output which can now be processed. – DJP Jun 27 '19 at 16:07
  • @DJP \sage related macros, yes, definitely. But it seems that sagetex environments (sagesilent in particular) have the same problem as the verbatim or comment environments, and cannot be put in a macro. – T. Verron Jun 27 '19 at 16:14
  • @DJP I didn't look too much to be honest, but the answer on the linked resource starts with "The internal definition of the sagesilent environment involves the use of verbatim text, which never can be written in a macro argument.", I found it convincing enough. – T. Verron Jun 27 '19 at 16:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.