summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/latex/runcode
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2023-09-09 20:09:19 +0000
committerKarl Berry <karl@freefriends.org>2023-09-09 20:09:19 +0000
commit0d22e428f9fc7235d13110f382e68b34d03b4294 (patch)
tree2f93e2aa6bd0de81da0619558149e5cc45e6ad0f /Master/texmf-dist/tex/latex/runcode
parent4ca20c86f05ea21a8f43cd4e3cea6028a7b472dc (diff)
runcode (9sep23)
git-svn-id: svn://tug.org/texlive/trunk@68223 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/latex/runcode')
-rw-r--r--Master/texmf-dist/tex/latex/runcode/runcode.sty322
1 files changed, 181 insertions, 141 deletions
diff --git a/Master/texmf-dist/tex/latex/runcode/runcode.sty b/Master/texmf-dist/tex/latex/runcode/runcode.sty
index 1fe5b079568..06c3d346e05 100644
--- a/Master/texmf-dist/tex/latex/runcode/runcode.sty
+++ b/Master/texmf-dist/tex/latex/runcode/runcode.sty
@@ -4,7 +4,9 @@
%
% This package is based on an ongoing work by Haim Bar and HaiYing Wang, and comments and questions are welcome!
-\ProvidesPackage{runcode}[2023/06/23 runcode v2.0]
+\ProvidesPackage{runcode}[2023/09/08 runcode v2.2]
+
+\def \langs {}
\newif\ifruncode
% Change to \runcodefalse if you want to suspend code execution
@@ -48,105 +50,73 @@
\notnohuptrue
\DeclareOption{nohup}{\notnohupfalse}
+\newcounter{portNo}
+\setcounter{portNo}{65430}
+
+\NewDocumentCommand{\InitLang}{m}{
+ % Create a configuration file for the server for the language provided
+ % in the argument, if it does not exist, and add to the serverslist.txt file.
+ \IfFileExists{#1.config}{}{
+ \newwrite\tempfile
+ \immediate\openout\tempfile=#1.config
+ \immediate\write\tempfile{[SERVERCONFIG]}
+ \immediate\write\tempfile{PORT = \theportNo}
+ \immediate\write\tempfile{DEBUGFILE = #1debug.txt}
+ \immediate\write\tempfile{PIPETIMEOUT = 60}
+ \immediate\closeout\tempfile
+ \edef\langs{\langs#1_}
+ \stepcounter{portNo}
+ }
+ % Start the server. Need to run just once. Can comment out after the first
+ % compilation, but remember to terminate the server
+ \ifnotnohup
+ {\immediate\write18{python3 -c 'from talk2stat.talk2stat import server,client; server("./","#1") if not client("./","#1","``` ```") else print("server is already running")'}}
+ \else
+ {\immediate\write18{nohup python3 -c 'from talk2stat.talk2stat import server,client; server("./","#1") if not client("./","#1","``` ```") else print("server is already running")' &}}
+ \fi
+}
+
\DeclareOption{R}{
- % create a configuration file for R server if it does not exist.
- \IfFileExists{R.config}{}{
- \newwrite\tempfile
- \immediate\openout\tempfile=R.config
- \immediate\write\tempfile{[SERVERCONFIG]}
- \immediate\write\tempfile{PORT = 65432}
- \immediate\write\tempfile{DEBUGFILE = Rdebug.txt}
- \immediate\write\tempfile{PIPETIMEOUT = 60}
- \immediate\closeout\tempfile
- }
- % Start the server. Need to run just once. Can comment out after the first
- % compilation, but remember to terminate the server
- \ifnotnohup
- {\immediate\write18{python3 -c 'from talk2stat.talk2stat import server,client; server("./","R") if not client("./","R","``` ```") else print("server is already running")'}}
- \else
- {\immediate\write18{nohup python3 -c 'from talk2stat.talk2stat import server,client; server("./","R") if not client("./","R","``` ```") else print("server is already running")' &}}
- \fi
+ \InitLang{R}
}
\DeclareOption{julia}{
- % create a configuration file for R server if it does not exist.
- \IfFileExists{julia.config}{}{
- \newwrite\tempfile
- \immediate\openout\tempfile=julia.config
- \immediate\write\tempfile{[SERVERCONFIG]}
- \immediate\write\tempfile{PORT = 65431}
- \immediate\write\tempfile{DEBUGFILE = juliadebug.txt}
- \immediate\write\tempfile{PIPETIMEOUT = 60}
- \immediate\closeout\tempfile
- }
- % Start the server. Need to run just once. Can comment out after the first
- % compilation, but remember to terminate the server
- \ifnotnohup
- {\immediate\write18{python3 -c 'from talk2stat.talk2stat import server,client; server("./","julia") if not client("./","julia","``` ```") else print("server is already running")'}}
- \else
- {\immediate\write18{nohup python3 -c 'from talk2stat.talk2stat import server,client; server("./","julia") if not client("./","julia","``` ```") else print("server is already running")' &}}
- \fi
+ \InitLang{julia}
}
\DeclareOption{matlab}{
- % create a configuration file for R server if it does not exist.
- \IfFileExists{matlab.config}{}{
- \newwrite\tempfile
- \immediate\openout\tempfile=matlab.config
- \immediate\write\tempfile{[SERVERCONFIG]}
- \immediate\write\tempfile{PORT = 65430}
- \immediate\write\tempfile{DEBUGFILE = matlabdebug.txt}
- \immediate\write\tempfile{PIPETIMEOUT = 60}
- \immediate\closeout\tempfile
- }
- % Start the server. Need to run just once. Can comment out after the first
- % compilation, but remember to terminate the server
- \ifnotnohup
- {\immediate\write18{python3 -c 'from talk2stat.talk2stat import server,client; server("./","matlab") if not client("./","matlab","``` ```") else print("server is already running")'}}
- \else
- {\immediate\write18{nohup python3 -c 'from talk2stat.talk2stat import server,client; server("./","matlab") if not client("./","matlab","``` ```") else print("server is already running")' &}}
- \fi
+ \InitLang{matlab}
}
\DeclareOption{python}{
- % create a configuration file for Python server if it does not exist.
- \IfFileExists{python.config}{}{
- \newwrite\tempfile
- \immediate\openout\tempfile=python.config
- \immediate\write\tempfile{[SERVERCONFIG]}
- \immediate\write\tempfile{PORT = 65433}
- \immediate\write\tempfile{DEBUGFILE = pythondebug.txt}
- \immediate\write\tempfile{PIPETIMEOUT = 60}
- \immediate\closeout\tempfile
- }
- % Start the server. Need to run just once. Can comment out after the first
- % compilation, but remember to terminate the server
- \ifnotnohup
- {\immediate\write18{python3 -c 'from talk2stat.talk2stat import server,client; server("./","python") if not client("./","python","``` ```") else print("server is already running")'}}
- \else
- {\immediate\write18{nohup python3 -c 'from talk2stat.talk2stat import server,client; server("./","python") if not client("./","python","``` ```") else print("server is already running")' &}}
- \fi
+ \InitLang{python}
}
+
\DeclareOption{stopserver}{
\AtEndDocument{
- %% stop the server when the pdf compilation is done.
- \IfFileExists{R.config}{
- \immediate\write18{python3 -c 'from talk2stat.talk2stat import client; client("./","R","QUIT")'}
- }{}
- \IfFileExists{julia.config}{
- \immediate\write18{python3 -c 'from talk2stat.talk2stat import client; client("./","julia","QUIT")'}
- }{}
- \IfFileExists{matlab.config}{
- \immediate\write18{python3 -c 'from talk2stat.talk2stat import client; client("./","matlab","QUIT")'}
- }{}
- \IfFileExists{python.config}{
- \immediate\write18{python3 -c 'from talk2stat.talk2stat import client; client("./","python","QUIT")'}
+ \IfFileExists{serverslist.txt}{
+ \newread\file
+ \openin\file=serverslist.txt
+ \immediate\readline\file to\lang
+ \closein\file
+ \StrCount{\lang}{\detokenize{_}}[\langNo]
+ \newcounter{x}
+ \forloop{x}{0}{\value{x} < \langNo}{
+ \StrBefore{\lang}{\detokenize{_}}[\curlang]
+ \StrBehind{\lang}{\detokenize{_}}[\lang]
+ %% stop the server when the pdf compilation is done.
+ \IfFileExists{\curlang.config}{
+ \immediate\write18{python3 -c 'from talk2stat.talk2stat import client; client("./","\curlang","QUIT")'}
+ }{}
+ }
}{}
-}}
+ }
+}
\ProcessOptions*
+\usepackage{etoolbox}
\usepackage{morewrites} % allow more than 16 \write
\usepackage[many]{tcolorbox} % to put boxes around text
\tcbset{colframe=blue!25,colback=blue!10} % default colors for box output
@@ -157,6 +127,15 @@
\usepackage{xifthen}
\usepackage{xparse}
\usepackage{xstring}
+\usepackage{forloop}
+
+%%%% check if \langs is empty !!
+\ifdefempty{\langs}{}{
+ \newwrite\outfile
+ \immediate\openout\outfile=serverslist.txt
+ \immediate\write\outfile{\langs}
+ \immediate\closeout\outfile}
+{}
% Use minted by default; but the user can change to listings or fvextra.
\ifminted
@@ -205,7 +184,6 @@
\setvalue{\tmpname}{} % initialize with a blank
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% \showCode prints the source code, using minted or listings for a pretty layout
% Arg #1 is the programming language,
@@ -320,8 +298,63 @@
}
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \writeChunk writes a selected chunk from source code as a .txt file.
+% Arg #1 is the source file name,
+% Arg #2 is the chunk identifier
+% Args #3 and #4 are the beginning and end markings of a chunk (optional).
+
+\NewDocumentCommand{\writeChunk}{m m O{label===} O{===end}} {
+ \IfFileExists{#1}{
+ \endlinechar=-1
+ \def\printcode{0} % don't print until we see the begin-block string
+ \newread\file
+ \openin\file=#1
+ \newwrite\outfile
+ \immediate\openout\outfile=\generated/#1-#2.txt
+ \loop\unless\ifeof\file
+ \immediate\readline\file to\fileline
+ \ifnum\printcode=1
+ \IfSubStr{\fileline}{\detokenize{#4}}{
+ \renewcommand{\printcode}{-1}}{\immediate\write\outfile{\fileline}}
+ \fi
+ \IfSubStr{\fileline}{\detokenize{#3}}{
+ \StrBehind{\fileline}{\detokenize{#3}}[\chunkname]
+ \IfStrEq*{\detokenize{#2}}{\chunkname}{\renewcommand{\printcode}{1}}{}
+ }
+ {}
+ \repeat
+ \closein\file
+ \immediate\closeout\outfile
+ \endlinechar=13
+ \ifnum\printcode=0
+ \textcolor{red}{\textbf{Label #2 not found in #1}}
+ \fi
+ }{\textcolor{red}{\textbf{Source file #1 not found}}}
+}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \showChunk prints a selected chunk from source code, using minted or listings for a pretty layout.
+% The chunk is identified in the source code by two strings that define the beginning and end of the chunk.
+% The default beginning is label===<name> where <name> should be a unique user-defined chunk ID.
+% The default end marker is ===end
+% In the code, these markers should appear after a comment character, so that the code will run.
+% Arg #1 is the programming language,
+% Arg #2 is the source file name,
+% Args #3 is the chunk identifier
+% Args #4 and #5 are the beginning and end markings of a chunk (optional).
+
+\NewDocumentCommand{\showChunk}{m m m O{label===} O{===end}}{
+ \IfFileExists{#2}{
+ \writeChunk{#2}{#3}[#4][#5]
+ \IfFileExists{\generated/#2-#3.txt}{\showCode{#1}{\generated/#2-#3.txt}}
+ {\textcolor{red}{\textbf{Label #3 not found in #2}}}
+ }{\textcolor{red}{\textbf{Source file #2 not found}}}
+}
+
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% \inln{Arg #1}{Arg #2}[Arg #3] is used to execute short source code
+% \inln{Arg #1}{Arg #2}[Arg #3][Arg #4] is used to execute short source code
% and embed resulting output.
% Arg #1 is the executable program;
% Arg #2 is the source code;
@@ -342,7 +375,7 @@
\IfBeginWith{#2}{```}{\ifruncode\immediate\write18{#1 > \tmpname.tex}\unskip\fi}
{\newwrite\tempfile
\immediate\openout\tempfile=\tmpname.txt
- \immediate\write\tempfile{#2}
+ \immediate\write\tempfile{\detokenize{#2}}
\immediate\closeout\tempfile
\ifruncode
\immediate\write18{#1 \tmpname.txt > \tmpname.tex}\unskip
@@ -367,7 +400,7 @@
{\textcolor{red}{\textbf{Output file \tmpname~ not found}}}}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Extended and language-specific comments:
+% Extended and language-specific commands:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% \runCodeIncOut: runs an external code and embeds the output.
@@ -388,77 +421,84 @@
\includeOutput{#4}[#5]
}
+\newcommand{\runcmd}[2]
+{python3 -c 'from talk2stat.talk2stat import client; client("./","#1",#2)'}
+
% R
-\NewDocumentCommand{\runR}{O{python3 -c 'from talk2stat.talk2stat import client; client("./","R","#2")'} m m O{}}
-{
- \def\runcmd{python3 -c 'from talk2stat.talk2stat import client; client("./","R","#2")'}
- \ifstrequal{#1}{\runcmd}
- {\runExtCode{#1}{}{#3}[#4]}
+% It will be used as a template for other languages
+\newcommand{\LANG}{R}
+\newcommand{\LANGcmd}{R}
+
+\expandafter\NewDocumentCommand\csname run\LANG\endcsname
+{O{} m m O{}}
+{\ifthenelse{\isempty{#1}}
+ {\runExtCode{\runcmd{\LANGcmd}{"#2"}}{#2}{#3}[#4]}
{\runExtCode{#1}{#2}{#3}[#4]}
}
-\NewDocumentCommand{\runRIncOut}
-{O{python3 -c 'from talk2stat.talk2stat import client; client("./","R","#2")'} m O{} O{} O{vbox}}
-{\def\runcmd{python3 -c 'from talk2stat.talk2stat import client; client("./","R","#2")'}
- \ifstrequal{#1}{\runcmd}
- {\runCodeIncOut{#1}{}[#3][#4][#5]}
- {\runCodeIncOut{#1}{#2}[#3][#4][#5]}}
+\expandafter\NewDocumentCommand\csname run\LANG IncOut\endcsname
+{O{} m O{} O{} O{vbox}}
+{\ifthenelse{\isempty{#1}}
+ {\runCodeIncOut{\runcmd{\LANGcmd}{"#2"}}{#2}[#3][#4][#5]}
+ {\runCodeIncOut{#1}{#2}[#3][#4][#5]}
+}
-\NewDocumentCommand{\inlnR}{O{python3 -c 'from talk2stat.talk2stat import client; client("./","R","\tmpname.txt")'} m O{} O{inline}}{\IfBeginWith{#2}{```}{\inln{python3 -c 'from talk2stat.talk2stat import client;rc0="""#2""";rc0=rc0.lstrip("```").rstrip("```");client("./","R",f"```{rc0}```")'}{#2}[#3][#4]}{\inln{#1}{#2}[#3][#4]}}
+\expandafter\NewDocumentCommand\csname inln\LANG\endcsname
+{O{} m O{} O{inline}}
+{\ifthenelse{\isempty{#1}}
+ {\IfBeginWith{#2}{```}
+ {\inln{\runcmd{\LANGcmd}{r"""\detokenize{#2}"""}}{#2}[#3][#4]}
+ {\inln{\runcmd{\LANGcmd}{"\tmpname.txt"}}{#2}[#3][#4]}
+ }
+ {\inln{#1}{#2}[#3][#4]}
+}
-% Julia
-\NewDocumentCommand{\runJulia}{O{python3 -c 'from talk2stat.talk2stat import client; client("./","julia","#2")'} m m O{}}
-{
- \def\runcmd{python3 -c 'from talk2stat.talk2stat import client; client("./","julia","#2")'}
- \ifstrequal{#1}{\runcmd}
- {\runExtCode{#1}{}{#3}[#4]}
- {\runExtCode{#1}{#2}{#3}[#4]}
+\expandafter\NewDocumentCommand\csname run\LANG Chunk\endcsname
+{O{} m m O{} O{} O{vbox}}
+{\IfFileExists{\generated/#2-#3.txt}{}{\writeChunk{#2}{#3}}
+ {\csname run\LANG IncOut\endcsname[#1]{\generated/#2-#3.txt}[#4][#2-#3][#6]}
}
-\NewDocumentCommand{\runJuliaIncOut}
-{O{python3 -c 'from talk2stat.talk2stat import client; client("./","julia","#2")'} m O{} O{} O{vbox}}
-{\def\runcmd{python3 -c 'from talk2stat.talk2stat import client; client("./","julia","#2")'}
- \ifstrequal{#1}{\runcmd}
- {\runCodeIncOut{#1}{}[#3][#4][#5]}
- {\runCodeIncOut{#1}{#2}[#3][#4][#5]}}
+% Julia
+\NewDocumentCommand{\runJulia}{O{} m m O{}}
+{\renewcommand{\LANGcmd}{julia} \runR[#1]{#2}{#3}[#4]}
+
+\NewDocumentCommand{\runJuliaIncOut}{O{} m O{} O{} O{vbox}}
+{\renewcommand{\LANGcmd}{julia} \runRIncOut[#1]{#2}[#3][#4][#5]}
+
+\NewDocumentCommand{\inlnJulia}{O{} m O{} O{inline}}
+{\renewcommand{\LANGcmd}{julia} \inlnR[#1]{#2}[#3][#4]}
+
+\NewDocumentCommand{\runJuliaChunk}{O{} m m O{} O{} O{vbox}}
+{\renewcommand{\LANGcmd}{julia} \runRChunk[#1]{#2}{#3}[#4][#5][#6]}
-\NewDocumentCommand{\inlnJulia}{O{python3 -c 'from talk2stat.talk2stat import client; client("./","julia","\tmpname.txt")'} m O{} O{inline}}{\IfBeginWith{#2}{```}{\inln{python3 -c 'from talk2stat.talk2stat import client;rc0="""#2""";rc0=rc0.lstrip("```").rstrip("```");client("./","julia",f"```{rc0}```")'}{#2}[#3][#4]}{\inln{#1}{#2}[#3][#4]}}
% Matlab
-\NewDocumentCommand{\runMatlab}{O{python3 -c 'from talk2stat.talk2stat import client; client("./","matlab","#2")'} m m O{}}
-{
- \def\runcmd{python3 -c 'from talk2stat.talk2stat import client; client("./","matlab","#2")'}
- \ifstrequal{#1}{\runcmd}
- {\runExtCode{#1}{}{#3}[#4]}
- {\runExtCode{#1}{#2}{#3}[#4]}
-}
+\NewDocumentCommand{\runMatLab}{O{} m m O{}}
+{\renewcommand{\LANGcmd}{matlab} \runR[#1]{#2}{#3}[#4]}
+
+\NewDocumentCommand{\runMatLabIncOut}{O{} m O{} O{} O{vbox}}
+{\renewcommand{\LANGcmd}{matlab} \runRIncOut[#1]{#2}[#3][#4][#5]}
+
+\NewDocumentCommand{\inlnMatLab}{O{} m O{} O{inline}}
+{\renewcommand{\LANGcmd}{matlab} \inlnR[#1]{#2}[#3][#4]}
-\NewDocumentCommand{\runMatlabIncOut}
-{O{python3 -c 'from talk2stat.talk2stat import client; client("./","matlab","#2")'} m O{} O{} O{vbox}}
-{\def\runcmd{python3 -c 'from talk2stat.talk2stat import client; client("./","matlab","#2")'}
- \ifstrequal{#1}{\runcmd}
- {\runCodeIncOut{#1}{}[#3][#4][#5]}
- {\runCodeIncOut{#1}{#2}[#3][#4][#5]}}
+\NewDocumentCommand{\runMatLabChunk}{O{} m m O{} O{} O{vbox}}
+{\renewcommand{\LANGcmd}{matlab} \runRChunk[#1]{#2}{#3}[#4][#5][#6]}
-\NewDocumentCommand{\inlnMatlab}{O{python3 -c 'from talk2stat.talk2stat import client; client("./","matlab","\tmpname.txt")'} m O{} O{inline}}{\IfBeginWith{#2}{```}{\inln{python3 -c 'from talk2stat.talk2stat import client;rc0="""#2""";rc0=rc0.lstrip("```").rstrip("```");client("./","matlab",f"```{rc0}```")'}{#2}[#3][#4]}{\inln{#1}{#2}[#3][#4]}}
% Python
-\NewDocumentCommand{\runPython}{O{python3 -c 'from talk2stat.talk2stat import client; client("./","python","#2")'} m m O{}}
-{
- \def\runcmd{python3 -c 'from talk2stat.talk2stat import client; client("./","python","#2")'}
- \ifstrequal{#1}{\runcmd}
- {\runExtCode{#1}{}{#3}[#4]}
- {\runExtCode{#1}{#2}{#3}[#4]}
-}
+\NewDocumentCommand{\runPython}{O{} m m O{}}
+{\renewcommand{\LANGcmd}{python} \runR[#1]{#2}{#3}[#4]}
+
+\NewDocumentCommand{\runPythonIncOut}{O{} m O{} O{} O{vbox}}
+{\renewcommand{\LANGcmd}{python} \runRIncOut[#1]{#2}[#3][#4][#5]}
-\NewDocumentCommand{\runPythonIncOut}
-{O{python3 -c 'from talk2stat.talk2stat import client; client("./","python","#2")'} m O{} O{} O{vbox}}
-{\def\runcmd{python3 -c 'from talk2stat.talk2stat import client; client("./","python","#2")'}
- \ifstrequal{#1}{\runcmd}
- {\runCodeIncOut{#1}{}[#3][#4][#5]}
- {\runCodeIncOut{#1}{#2}[#3][#4][#5]}}
+\NewDocumentCommand{\inlnPython}{O{} m O{} O{inline}}
+{\renewcommand{\LANGcmd}{python} \inlnR[#1]{#2}[#3][#4]}
-\NewDocumentCommand{\inlnPython}{O{python3 -c 'from talk2stat.talk2stat import client; client("./","python","\tmpname.txt")'} m O{} O{inline}}{\IfBeginWith{#2}{```}{\inln{python3 -c 'from talk2stat.talk2stat import client;rc0="""#2""";rc0=rc0.lstrip("```").rstrip("```");client("./","python",f"```{rc0}```")'}{#2}[#3][#4]}{\inln{#1}{#2}[#3][#4]}}
+\NewDocumentCommand{\runPythonChunk}{O{} m m O{} O{} O{vbox}}
+{\renewcommand{\LANGcmd}{python} \runRChunk[#1]{#2}{#3}[#4][#5][#6]}
%%%%%%%%
@@ -503,4 +543,4 @@
}
-\endinput \ No newline at end of file
+\endinput