diff options
Diffstat (limited to 'macros/luatex/latex/piton/piton.dtx')
-rw-r--r-- | macros/luatex/latex/piton/piton.dtx | 10673 |
1 files changed, 5499 insertions, 5174 deletions
diff --git a/macros/luatex/latex/piton/piton.dtx b/macros/luatex/latex/piton/piton.dtx index 4f1d4290a1..5202fea711 100644 --- a/macros/luatex/latex/piton/piton.dtx +++ b/macros/luatex/latex/piton/piton.dtx @@ -1,5174 +1,5499 @@ -% \iffalse -*- coding: utf-8 ; -*- \fi \iffalse meta-comment
-%
-% Copyright (C) 2023 by F. Pantigny
-% -----------------------------------
-%
-% This file may be distributed and/or modified under the
-% conditions of the LaTeX Project Public License, either version 1.3
-% of this license or (at your option) any later version.
-% The latest version of this license is in:
-%
-% http://www.latex-project.org/lppl.txt
-%
-% and version 1.3 or later is part of all distributions of LaTeX
-% version 2005/12/01 or later.
-%
-% \fi
-% \iffalse
-\def\myfileversion{1.5a}
-\def\myfiledate{2023/04/11}
-%
-%
-%<*batchfile>
-\begingroup
-\input l3docstrip.tex
-\keepsilent
-\usedir{tex/latex/cascade}
-\preamble
-
-Copyright (C) 2022-2023 by F. Pantigny
------------------------------------
-
-This file may be distributed and/or modified under the
-conditions of the LaTeX Project Public License, either version 1.3
-of this license or (at your option) any later version.
-The latest version of this license is in:
-
-http://www.latex-project.org/lppl.txt
-
-and version 1.3 or later is part of all distributions of LaTeX
-version 2005/12/01 or later.
-
-\endpreamble
-\askforoverwritefalse
-\endgroup
-%</batchfile>
-%
-%<@@=piton>
-%<*driver>
-\documentclass{l3doc}
-\usepackage{geometry}
-\geometry{left=2.8cm,right=2.8cm,top=2.5cm,bottom=2.5cm,papersize={21cm,29.7cm}}
-\usepackage{fontspec}
-\usepackage[dvipsnames]{xcolor}
-\usepackage{caption,tabularx,tcolorbox,luacolor,lua-ul}
-\def\emphase{\bgroup\color{RoyalPurple}\let\next=}
-\fvset{commandchars=\~\#\@,formatcom=\color{gray}}
-\captionsetup{labelfont = bf}
-\usepackage{ragged2e}
-\usepackage[footnotehyper,escape-inside=$$,math-comments]{piton} % $$
-
-\parindent 0pt
-\skip\footins = 2\bigskipamount
-
-\PitonOptions{gobble=2}
-
-\EnableCrossrefs
-
-\begin{document}
-\DocInput{piton.dtx}
-\end{document}
-%</driver>
-% \fi
-%
-% \catcode`\" = 11
-%
-% \title{The package \pkg{piton}\thanks{This document corresponds to the
-% version~\myfileversion\space of \pkg{piton}, at the date of~\myfiledate.}}
-% \author{F. Pantigny \\ \texttt{fpantigny@wanadoo.fr}}
-%
-% \maketitle
-%
-% \begin{abstract}
-% The package \pkg{piton} provides tools to typeset Python listings with
-% syntactic highlighting by using the Lua library LPEG. It requires LuaLaTeX.
-% \end{abstract}
-%
-%
-%
-% \section{Presentation}
-%
-%
-% The package \pkg{piton} uses the Lua library LPEG\footnote{LPEG is a
-% pattern-matching library for Lua, written in C, based on \emph{parsing
-% expression grammars}: \url{http://www.inf.puc-rio.br/~roberto/lpeg/}} for
-% parsing Python listings and typeset them with syntactic highlighting. Since it
-% uses Lua code, it works with |lualatex| only (and won't work with the other
-% engines: |latex|, |pdflatex| and |xelatex|). It does not use external program
-% and the compilation does not require |--shell-escape|. The compilation is very
-% fast since all the parsing is done by the library LPEG, written in C.
-%
-% \bigskip
-% Here is an example of code typeset by \pkg{piton}, with the environment |{Piton}|.
-%
-% \bigskip
-%
-% \begin{Piton}
-% from math import pi
-%
-% def arctan(x,n=10):
-% """Compute the mathematical value of arctan(x)
-%
-% n is the number of terms in the sum
-% """
-% if x < 0:
-% return -arctan(-x) # recursive call
-% elif x > 1:
-% return pi/2 - arctan(1/x)
-% #> (we have used that $\arctan(x)+\arctan(1/x)=\frac{\pi}{2}$ for $x>0$)\footnote{This LaTeX escape has been done by beginning the comment by \ttfamily\#>.}
-% else:
-% s = 0
-% for k in range(n):
-% s += (-1)**k/(2*k+1)*x**(2*k+1)
-% return s
-% \end{Piton}
-%
-%
-% \bigskip
-% The package \pkg{piton} is entirely contained in the file
-% |piton.sty|. This file may be put in the current directory or in a
-% |texmf| tree. However, the best is to install \pkg{piton} with a TeX
-% distribution such as MiKTeX, TeX Live or MacTeX.
-%
-%
-% \section{Use of the package}
-%
-%
-% \subsection{Loading the package}
-%
-% The package \pkg{piton} should be loaded with the classical command
-% |\usepackage|: |\usepackage{piton}|.
-%
-% \smallskip
-% Nevertheless, we have two remarks:
-% \begin{itemize}
-% \item the package \pkg{piton} uses the package \pkg{xcolor} (but \pkg{piton}
-% does \emph{not} load \pkg{xcolor}: if \pkg{xcolor} is not loaded before the
-% |\begin{document}|, a fatal error will be raised).
-% \item the package \pkg{piton} must be used with LuaLaTeX exclusively: if
-% another LaTeX engine (|latex|, |pdflatex|, |xelatex|,\dots ) is used, a
-% fatal error will be raised.
-% \end{itemize}
-%
-% \subsection{The tools provided to the user}
-%
-% The package \pkg{piton} provides several tools to typeset Python code: the
-% command |\piton|, the environment |{Piton}| and the command |\PitonInputFile|.
-%
-% \begin{itemize}\setlength{\fboxsep}{1pt}
-% \item The command \colorbox{gray!20}{\texttt\textbackslash piton} should be
-% used to typeset small pieces of code inside a paragraph. For example:
-%
-% {\color{gray}\verb|\piton{def square(x): return x*x}|}\qquad
-% \piton{def square(x): return x*x}
-%
-% The syntax and particularities of the command |\piton| are detailed below.
-%
-% \item The environment \colorbox{gray!20}{\ttfamily\{Piton\}} should be used to
-% typeset multi-lines code. Since it takes its argument in a verbatim mode, it
-% can't be used within the argument of a LaTeX command. For sake of
-% customization, it's possible to define new environments similar to the
-% environment |{Piton}| with the command |\NewPitonEnvironment|:
-% cf.~\ref{NewPitonEnvironment} p.~\pageref{NewPitonEnvironment}.
-%
-% \item The command \colorbox{gray!20}{\ttfamily\textbackslash PitonInputFile}
-% is used to insert and typeset a whole external file.
-%
-% That command takes in as optional argument (between square brackets) two keys
-% |first-line| and |last-line|: only the part between the corresponding lines
-% will be inserted.
-% \end{itemize}
-%
-% \subsection{The syntax of the command \textbackslash piton}
-%
-% In fact, the command |\piton| is provided with a double syntax. It may be used
-% as a standard command of LaTeX taking its argument between curly braces
-% (|\piton{...}|) but it may also be used with a syntax similar to the syntax of
-% the command
-% |\verb|, that is to say with the argument delimited by two identical characters (e.g.: \verb!\piton|...|!).
-%
-% \begin{itemize}
-% \item {\color{blue} \textsf{Syntax} \verb|\piton{...}|}\par\nobreak
-% When its argument is given between curly braces, the command |\piton| does not
-% take its argument in verbatim mode. In particular:
-% \begin{itemize}
-% \item several consecutive spaces will be replaced by only one space,
-%
-% {\color{cyan} but the command |\|␣ is provided to force the insertion of a space};
-%
-% \item it's not possible to use |%| inside the argument,
-%
-% {\color{cyan} but the command |\%| is provided to insert a |%|};
-%
-% \item the braces must be appear by pairs correctly nested
-%
-% {\color{cyan} but the commands |\{| and |\}| are also provided for individual braces};
-%
-% \item the LaTeX commands\footnote{That concerns the commands beginning with a
-% backslash but also the active characters.} are fully expanded and not
-% executed,
-%
-% {\color{cyan} so it's possible to use |\\| to insert a backslash}.
-% \end{itemize}
-%
-%
-% The other characters (including |#|, |^|, |_|, |&|, |$| and |@|)
-% must be inserted without backslash.
-%
-% \bigskip
-%\begin{tabular}{>{\color{gray}}w{l}{75mm}@{\hspace*{1cm}}l}
-% \omit Examples : \hfil \\
-% \noalign{\vskip1mm}
-% \verb|\piton{MyString = '\\n'}| &
-% \piton{MyString = '\\n'} \\
-% \verb|\piton{def even(n): return n\%2==0}| &
-% \piton{def even(n): return n\%2==0} \\
-% \verb|\piton{c="#" # an affectation }| &
-% \piton{c="#" # an affectation } \\
-% \verb|\piton{c="#" \ \ \ # an affectation }| &
-% \piton{c="#" \ \ \ # an affectation } \\
-% \verb|\piton{MyDict = {'a': 3, 'b': 4 }}| &
-% \piton{MyDict = {'a': 3, 'b': 4 }}
-% \end{tabular}
-%
-% \bigskip
-% It's possible to use the command |\piton| in the arguments of a
-% LaTeX command.\footnote{For example, it's possible to use the command
-% \texttt{\textbackslash piton} in a footnote. Example :
-% \piton{s = 'A string'}.}
-%
-% \bigskip
-% \item {\color{blue} \textsf{Syntaxe} \verb!\piton|...|!}\par\nobreak
-%
-% When the argument of the command |\piton| is provided between two identical
-% characters, that argument is taken in a \emph{verbatim mode}. Therefore, with
-% that syntax, the command |\piton| can't be used within the argument of another
-% command.
-%
-% \medskip
-%
-% \begin{tabular}{>{\color{gray}}w{l}{75mm}@{\hspace*{1cm}}l}
-% \omit Examples : \hfil \\
-% \noalign{\vskip1mm}
-% \verb!\piton|MyString = '\n'|! &
-% \piton|MyString = '\n'| \\
-% \verb|\piton!def even(n): return n%2==0!| &
-% \piton!def even(n): return n%2==0! \\
-% \verb|\piton+c="#" # an affectation +| &
-% \piton+c="#" # an affectation + \\
-% \verb|\piton?MyDict = {'a': 3, 'b': 4}?| &
-% \piton!MyDict = {'a': 3, 'b': 4}!
-% \end{tabular}
-%
-% \end{itemize}
-%
-% \section{Customization}
-%
-% \subsection{The command \textbackslash PitonOptions}
-%
-%
-% \NewDocumentCommand{\Definition}{m}
-% {{\setlength{\fboxsep}{1pt}\colorbox{gray!20}{\ttfamily \vphantom{gl}#1}}}
-%
-% The command |\PitonOptions| takes in as argument a comma-separated list of
-% \textsl{key=value} pairs. The scope of the settings done by that command is
-% the current TeX group.\footnote{We remind that a LaTeX environment is, in
-% particular, a TeX group.}
-%
-% \begin{itemize}
-% \item The key \Definition{gobble} takes in as value a
-% positive integer~$n$: the first $n$ characters are discarded (before the
-% process of highlightning of the code) for each line of the environment
-% |{Piton}|. These characters are not necessarily spaces.
-%
-% \item When the key \Definition{auto-gobble} is in force, the
-% extension \pkg{piton} computes the minimal value $n$ of the number of
-% consecutive spaces beginning each (non empty) line of the environment
-% |{Piton}| and applies |gobble| with that value of~$n$.
-%
-% \item When the key \Definition{env-gobble} is in force, \pkg{piton} analyzes the last
-% line of the environment |{Piton}|, that is to say the line which contains
-% |\end{Piton}| and determines whether that line contains only spaces followed
-% by the |\end{Piton}|. If we are in that situation, \pkg{piton} computes the
-% number~$n$ of spaces on that line and applies |gobble| with that value of~$n$.
-% The name of that key comes from \emph{environment gobble}: the effect of
-% gobble is set by the position of the commands |\begin{Piton}| and
-% |\end{Piton}| which delimit the current environment.
-%
-% \item With the key \Definition{line-numbers}, the \emph{non empty} lines (and
-% all the lines of the \emph{docstrings}, even the empty ones) are numbered in
-% the environments |{Piton}| and in the listings resulting from the use of
-% |\PitonInputFile|.
-%
-% \item With the key \Definition{all-line-numbers}, \emph{all} the lines are numbered,
-% including the empty ones.
-%
-% \item \colorbox{yellow!50}{\bfseries{New 1.5}}\par\nobreak
-%
-% The key \Definition{numbers-sep} is the horizontal distance between the
-% numbers of lines (inserted by |line-numbers| of |all-line-numbers|) and the
-% beginning of the lines of code. The initial value is 0.7~em.
-%
-% \item With the key \Definition{resume}, the counter of lines is not set to zero
-% at the beginning of each environment |{Piton}| or use of |\PitonInputFile| as
-% it is otherwise. That allows a numbering of the lines across several
-% environments.
-%
-% \item The key \Definition{left-margin} corresponds to a margin on the left.
-% That key may be useful in conjonction with the key |line-numbers| or the key
-% |line-all-numbers| if one does not want the numbers in an overlapping position
-% on the left.
-%
-% It's possible to use the key |left-margin| with the value |auto|. With that
-% value, if the key |line-numbers| or the key |all-line-numbers| is used, a
-% margin will be automatically inserted to fit the numbers of lines. See an
-% example part \ref{example-numbering} on page~\pageref{example-numbering}.
-%
-% \item The key \Definition{background-color} sets the background color of the
-% environments |{Piton}| and the listings produced by |\PitonInputFile| (that
-% background has a width of |\linewidth|).
-%
-% \smallskip
-% \colorbox{yellow!50}{\textbf{New 1.4}}\enskip The key |background-color|
-% supports also as value a \emph{list} of colors. In this case, the successive
-% rows are colored by using the colors of the list in a cyclic way.
-%
-% \emph{Example} : |\PitonOptions{background-color = {gray!5,white}}|
-%
-%
-% The key |background-color| accepts a color defined «on the fly». For example,
-% it's possible to write |background-color = [cmyk]{0.1,0.05,0,0}|.
-%
-% \item With the key \Definition{prompt-background-color}, \pkg{piton} adds a
-% color background to the lines beginning with the prompt ``|>>>|'' (and its
-% continuation ``|...|'') characteristic of the Python consoles with
-% \textsc{repl} (\emph{read-eval-print loop}).
-%
-% \item When the key \Definition{show-spaces-in-strings} is activated, the
-% spaces in the short strings (that is to say those delimited by |'| or |"|) are
-% replaced by the character~␣ (U+2423 : \textsc{open box}). Of course, that
-% character~U+2423 must be present in the monospaced font which is
-% used.\footnote{The package \pkg{piton} simply uses the current monospaced
-% font. The best way to change that font is to use the command
-% \texttt{\textbackslash setmonofont} of the package \pkg{fontspec}.}\par\nobreak
-% \begingroup \PitonOptions{show-spaces-in-strings} Example :
-% \piton|my_string = 'Very good answer'| \endgroup
-%
-% With the key \Definition{show-spaces}, all the spaces are replaced by U+2423
-% (and no line break can occur on those ``visible spaces'', even when the key
-% |break-lines|\footnote{cf. \ref{line-breaks} p.~\pageref{line-breaks}} is in
-% force).
-% \end{itemize}
-%
-% \bigskip
-%
-% \begingroup
-% \fvset{commandchars=\~\&\@,formatcom=\small\color{gray}}
-% \begin{Verbatim}
-% ~emphase&\PitonOptions{line-numbers,auto-gobble,background-color = gray!15}@
-% \begin{Piton}
-% from math import pi
-% def arctan(x,n=10):
-% """Compute the mathematical value of arctan(x)
-%
-% n is the number of terms in the sum
-% """
-% if x < 0:
-% return -arctan(-x) # recursive call
-% elif x > 1:
-% return pi/2 - arctan(1/x)
-% #> (we have used that $\arctan(x)+\arctan(1/x)=\frac{\pi}{2}$ pour $x>0$)
-% else
-% s = 0
-% for k in range(n):
-% s += (-1)**k/(2*k+1)*x**(2*k+1)
-% return s
-% \end{Piton}
-% \end{Verbatim}
-% \endgroup
-%
-% \begingroup
-% \PitonOptions{line-numbers,background-color = gray!15}
-% \begin{Piton}
-% from math import pi
-%
-% def arctan(x,n=10):
-% """Compute the mathematical value of arctan(x)
-%
-% n is the number of terms in the sum
-% """
-% if x < 0:
-% return -arctan(-x) # recursive call
-% elif x > 1:
-% return pi/2 - arctan(1/x)
-% #> (we have used that $\arctan(x)+\arctan(1/x)=\frac{\pi}{2}$ for $x>0$)
-% else
-% s = 0
-% for k in range(n):
-% s += (-1)**k/(2*k+1)*x**(2*k+1)
-% return s
-% \end{Piton}
-% \endgroup
-%
-% \bigskip
-% The command |\PitonOptions| provides in fact several other keys which will be
-% described further (see in particular the ``Pages breaks and line breaks''
-% p.~\pageref{breakable}).
-%
-% \subsection{The styles}
-%
-% \label{styles}
-%
-% The package \pkg{piton} provides the command |\SetPitonStyle| to customize the
-% different styles used to format the syntactic elements of the Python listings.
-% The customizations done by that command are limited to the current TeX
-% group.\footnote{We remind that a LaTeX environment is, in particular, a TeX group.}
-%
-% \bigskip
-% The command |\SetPitonStyle| takes in as argument a comma-separated list of
-% \textsl{key=value} pairs. The keys are names of styles and the value are LaTeX
-% formatting instructions.
-%
-% \bigskip
-% These LaTeX instructions must be formatting instructions such as
-% |\color{...}|, |\bfseries|, |\slshape|, etc. (the commands of this kind are
-% sometimes called \emph{semi-global} commands). It's also possible to put,
-% \emph{at the end of the list of instructions}, a LaTeX command taking exactly
-% one argument.
-%
-% \bigskip
-% Here an example which changes the style used to highlight, in the definition
-% of a Python function, the name of the function which is defined. That code
-% uses the command |\highLight| of \pkg{lua-ul} (that package requires also the
-% package \pkg{luacolor}).
-%
-% \begin{verbatim}
-% \SetPitonStyle{ Name.Function = \bfseries \highLight[red!50] }
-% \end{verbatim}
-%
-% In that example, |\highLight[red!50]| must be considered as the name of a
-% LaTeX command which takes in exactly one argument, since, usually, it is used
-% with |\highLight[red!50]{...}|.
-%
-% \medskip
-% \begingroup
-% \SetPitonStyle
-% { Name.Function = \bfseries \highLight[red!50] }
-% With that setting, we will have : \piton{def cube(x) : return x * x * x }
-% \endgroup
-%
-% \bigskip
-% The different styles are described in the table \ref{Semantic}. The initial
-% settings done by \pkg{piton} in |piton.sty| are inspired by the style
-% \pkg{manni} de Pygments.\footnote{See:
-% \url{https://pygments.org/styles/}. Remark that, by default, Pygments provides for its style \pkg{manni} a colored background whose color is the HTML color \texttt{\#F0F3F3}. It's possible to have the same color in \texttt{\{Pion\}} with the instruction \texttt{\textbackslash PitonOptions\{background-color = [HTML]\{F0F3F3\}\}}.}
-%
-% \bigskip
-% \colorbox{yellow!50}{\textbf{New 1.4}}\enskip The command |\PitonStyle| takes
-% in as argument the name of a style and allows to retrieve the value (as a list
-% of LaTeX instructions) of that style.
-%
-% \smallskip
-% For example, it's possible to write |{\PitonStyle{Keyword}{function}}| and we
-% will have the word {\PitonStyle{Keyword}{function}} formatted as a keyword.
-%
-% \smallskip
-% The syntax |{\PitonStyle{|\textsl{\texttt{style}}|}{...}}| is mandatory in
-% order to be able to deal both with the semi-global commands and the commands
-% with arguments which may be present in the definition of the style
-% \texttt{\textsl{style}}.
-%
-% \begin{table}[b]
-% \centering
-% \caption{Usage of the different styles}
-% \label{Semantic}
-% \begin{tabular}{@{}>{\ttfamily}l>{\RaggedRight\arraybackslash}p{9cm}@{}}
-% \toprule
-% \normalfont Style & Usage \\
-% \midrule
-% Number & the numbers \\
-% String.Short & the short strings (between \texttt{'} or \verb|"|) \\
-% String.Long & the long strings (between \texttt{'''} or \verb|"""|) except the
-% documentation strings \\
-% String & that keys sets both |String.Short| and |String.Long| \\
-% String.Doc & the documentation strings (only between \texttt{"""} following
-% PEP~257) \\
-% String.Interpol & the syntactic elements of the fields of the f-strings (that
-% is to say the characters \texttt{\{} and \texttt{\}}) \\
-% Operator & the following operators : \texttt{!= == << >> - \~{} + / * \% = < > \& .} \verb+|+ \verb|@|\\
-% Operator.Word & the following operators : \texttt{in}, \texttt{is},
-% \texttt{and}, \texttt{or} and \texttt{not} \\
-% Name.Builtin & the predefined functions of Python \\
-% Name.Function & the name of the functions defined by the user, at the point of
-% their definition (that is to say after the keyword |def|) \\
-% Name.Decorator & the decorators (instructions beginning by \verb|@|) \\
-% Name.Namespace & the name of the modules (= external libraries) \\
-% Name.Class & the name of the classes at the point of their definition (that is
-% to say after the keyword |class|) \\
-% Exception & the names of the exceptions (eg: \texttt{SyntaxError}) \\
-% Comment & the comments beginning with \verb|#| \\
-% Comment.LaTeX & the comments beginning by \verb|#>|, which are composed in LaTeX by
-% \pkg{piton} (and simply called ``LaTeX comments'' in this document) \\
-% Keyword.Constant & |True|, |False| and |None| \\
-% Keyword & the following keywords :
-% \ttfamily as, assert, break, case, continue, def, del,
-% elif, else, except, exec, finally, for, from,
-% global, if, import, lambda, non local,
-% pass, raise, return, try, while,
-% with, yield, yield from.\\
-% \bottomrule
-% \end{tabular}
-% \end{table}
-%
-%
-%
-%
-% \subsection{Creation of new environments}
-%
-% \label{NewPitonEnvironment}
-%
-% Since the environment |{Piton}| has to catch its body in a special way (more
-% or less as verbatim text), it's not possible to construct new environments
-% directly over the environment |{Piton}| with the classical commands
-% |\newenvironment| or |\NewDocumentEnvironment|.
-%
-% That's why \pkg{piton} provides a command |\NewPitonEnvironment|. That
-% command takes in three mandatory arguments.
-
-% That command has the same syntax as the classical environment
-% |\NewDocumentEnvironment|.
-%
-% \bigskip
-% With the following instruction, a new environment |{Python}| will be
-% constructed with the same behaviour as |{Piton}|:
-%
-% {\color{gray}\verb|\NewPitonEnvironment{Python}{}{}{}|}
-%
-% \bigskip
-% If one wishes an environment |{Python}| with takes in as optional argument
-% (between square brackets) the keys of the command |\PitonOptions|, it's
-% possible to program as follows:
-%
-% {\color{gray}\verb|\NewPitonEnvironment{Python}{O{}}{\PitonOptions{#1}}{}|}
-%
-% \bigskip
-% If one wishes to format Python code in a box of \pkg{tcolorbox}, it's possible
-% to define an environment |{Python}| with the following code (of course, the
-% package \pkg{tcolorbox} must be loaded).
-%
-%\begin{verbatim}
-% \NewPitonEnvironment{Python}{}
-% {\begin{tcolorbox}}
-% {\end{tcolorbox}}
-% \end{verbatim}
-%
-% \bigskip
-% With this new environment |{Python}|, it's possible to write:
-%
-% \begin{Verbatim}
-% ~emphase#\begin{Python}@
-% def square(x):
-% """Compute the square of a number"""
-% return x*x
-% ~emphase#\end{Python}@
-% \end{Verbatim}
-%
-% \NewPitonEnvironment{Python}{}
-% {\begin{tcolorbox}}
-% {\end{tcolorbox}}
-%
-% \begin{Python}
-% def square(x):
-% """Compute the square of a number"""
-% return x*x
-% \end{Python}
-%
-%
-% \section{Advanced features}
-%
-% \subsection{Highlighting some identifiers}
-%
-% \colorbox{yellow!50}{\textbf{New 1.4}} It's possible to require a changement
-% of formating for some identifiers with the key |identifiers| of
-% |\PitonOptions|.
-%
-% \smallskip
-% That key takes in as argument a value of the following format:
-%
-% \quad |{ names = |\textsl{\ttfamily names}|, style = |\textsl{\ttfamily
-% instructions}| }|
-%
-% \begin{itemize}
-% \item \textsl{\ttfamily names} is a (comma-separated) list of identifiers
-% names;
-%
-% \item \textsl{\ttfamily instructions} is a list of LaTeX instructions of the
-% same type that \pkg{piton} ``styles'' previously presented (cf~\ref{styles}
-% p.~\pageref{styles}).
-% \end{itemize}
-%
-% \emph{Caution}: Only the identifiers may be concerned by that key. The
-% keywords and the built-in functions won't be affected, even if their name is
-% in the list |\textsl{\ttfamily names}|.
-%
-% \begin{Verbatim}
-% \PitonOptions
-% {
-% ~emphase#identifiers@ =
-% {
-% ~emphase#names@ = { l1 , l2 } ,
-% ~emphase#style@ = \color{red}
-% }
-% }
-%
-% \begin{Piton}
-% def tri(l):
-% """Segmentation sort"""
-% if len(l) <= 1:
-% return l
-% else:
-% a = l[0]
-% l1 = [ x for x in l[1:] if x < a ]
-% l2 = [ x for x in l[1:] if x >= a ]
-% return tri(l1) + [a] + tri(l2)
-% \end{Piton}
-% \end{Verbatim}
-%
-%
-% \bigskip
-%
-% \begingroup
-%
-% \PitonOptions
-% {
-% identifiers =
-% {
-% names = { l1 , l2 } ,
-% style = \color{red}
-% }
-% }
-%
-% \begin{Piton}
-% def tri(l):
-% """Segmentation sort"""
-% if len(l) <= 1:
-% return l
-% else:
-% a = l[0]
-% l1 = [ x for x in l[1:] if x < a ]
-% l2 = [ x for x in l[1:] if x >= a ]
-% return tri(l1) + [a] + tri(l2)
-% \end{Piton}
-%
-% \endgroup
-%
-% \bigskip
-% By using the key |identifier|, it's possible to add other built-in functions
-% (or other new keywords, etc.) that will be detected by \pkg{piton}.
-%
-%
-% \begin{Verbatim}
-% \PitonOptions
-% {
-% ~emphase#identifiers@ =
-% {
-% names = { cos, sin, tan, floor, ceil, trunc, pow, exp, ln, factorial } ,
-% style = \PitonStyle{Name.Builtin}
-% }
-% }
-%
-% \begin{Piton}
-% from math import *
-% cos(pi/2)
-% factorial(5)
-% ceil(-2.3)
-% floor(5.4)
-% \end{Piton}
-% \end{Verbatim}
-%
-% \begingroup
-%
-% \PitonOptions
-% {
-% identifiers =
-% {
-% names = { cos, sin, tan, floor, ceil, trunc, pow, exp, ln, factorial } ,
-% style = \PitonStyle{Name.Builtin}
-% }
-% }
-%
-% \begin{Piton}
-% from math import *
-% cos(pi/2)
-% factorial(5)
-% ceil(-2.3)
-% floor(5.4)
-% \end{Piton}
-%
-%
-% \endgroup
-%
-%
-% \subsection{Mechanisms to escape to LaTeX}
-%
-% The package \pkg{piton} provides several mechanisms for escaping to LaTeX:
-% \begin{itemize}
-% \item It's possible to compose comments entirely in LaTeX.
-% \item It's possible to have the elements between \texttt{\$} in the comments
-% composed in LateX mathematical mode.
-% \item It's also possible to insert LaTeX code almost everywhere in a Python listing.
-% \end{itemize}
-%
-% One should aslo remark that, when the extension \pkg{piton} is used with the
-% class \cls{beamer}, \pkg{piton} detects in |{Piton}| many commands and
-% environments of Beamer: cf. \ref{beamer} p.~\pageref{beamer}.
-%
-% \subsubsection{The ``LaTeX comments''}
-%
-% In this document, we call ``LaTeX comments'' the comments which begins by
-% |#>|. The code following those characters, until the end of the line, will be
-% composed as standard LaTeX code. There is two tools to customize those
-% comments.
-%
-% \begin{itemize}
-% \item It's possible to change the syntatic mark (which, by default, is |#>|).
-% For this purpose, there is a key |comment-latex| available at load-time (that
-% is to say at the |\usepackage|) which allows to choice the characters which,
-% preceded by |#|, will be the syntatic marker.
-%
-% For example, with the following loading:
-%
-% \quad \verb|\usepackage[comment-latex = LaTeX]{piton}|
-%
-% the LaTeX comments will begin by |#LaTeX|.
-%
-% If the key |comment-latex| is used with the empty value, all the Python
-% comments (which begins by |#|) will, in fact, be ``LaTeX comments''.
-%
-% \smallskip
-% \item It's possible to change the formatting of the LaTeX comment itself by
-% changing the \pkg{piton} style |Comment.LaTeX|.
-%
-% For example, with |\SetPitonStyle{Comment.LaTeX = \normalfont\color{blue}}|,
-% the LaTeX comments will be composed in blue.
-%
-% If you want to have a character |#| at the beginning of the LaTeX comment in
-% the \textsc{pdf}, you can use set |Comment.LaTeX| as follows:
-%
-% \begin{Verbatim}
-% \SetPitonStyle{Comment.LaTeX = \color{gray}\~#\normalfont\space }
-% \end{Verbatim}
-%
-% For other examples of customization of the LaTeX comments, see the part
-% \ref{example-comments} p.~\pageref{example-comments}
-% \end{itemize}
-%
-% \bigskip
-% If the user has required line numbers in the left margin (with the
-% key |line-numbers| or the key |all-line-numbers| of |\PitonOptions|), it's
-% possible to refer to a number of line with the command |\label| used in a
-% LaTeX comment.\footnote{That feature is implemented by using a redefinition of
-% the standard command \texttt{\textbackslash label} in the environments
-% \texttt{\{Piton\}}. Therefore, incompatibilities may occur with extensions
-% which redefine (globally) that command \texttt{\textbackslash label} (for
-% example: \pkg{varioref}, \pkg{refcheck}, \pkg{showlabels}, etc.)}
-%
-% \subsubsection{The key ``math-comments''}
-%
-% It's possible to request that, in the standard Python comments (that is to say
-% those beginning by |#| and not |#>|), the elements between \texttt{\$} be
-% composed in LaTeX mathematical mode (the other elements of the comment being
-% composed verbatim).
-%
-% That feature is activated by the key |math-comments| at load-time (that is to
-% say with the |\usepackage|).
-%
-% \medskip
-% In the following example, we assume that the key |math-comments| has been used
-% when loading \pkg{piton}.
-%
-% \begin{Verbatim}
-% \begin{Piton}
-% def square(x):
-% return x*x ~# compute $x^2$
-% \end{Piton}
-% \end{Verbatim}
-%
-% \begin{Piton}
-% def square(x):
-% return x*x # compute $x^2$
-% \end{Piton}
-%
-% \subsubsection{The mechanism ``escape-inside''}
-%
-% It's also possible to overwrite the Python listings to insert LaTeX code
-% almost everywhere (but between lexical units, of course). By default,
-% \pkg{piton} does not fix any character for that kind of escape.
-%
-% In order to use this mechanism, it's necessary to specify two characters which
-% will delimit the escape (one for the beginning and one for the end) by using
-% the key |escape-inside| at load-time (that is to say at the
-% |\begin{docuemnt}|).
-%
-% \medskip
-% In the following example, we assume that the extension \pkg{piton} has been
-% loaded by the following instruction.
-%
-% \begin{Verbatim}
-% \usepackage[~emphase#escape-inside=$$@]{piton}
-% \end{Verbatim}
-%
-% \medskip
-% In the following code, which is a recursive programmation of the mathematical
-% factorial, we decide to highlight in yellow the instruction which contains the
-% recursive call. That example uses the command |\highLight| of \pkg{lua-ul}
-% (that package requires itself the package \pkg{luacolor}).
-% \begin{Verbatim}
-% \begin{Piton}
-% def fact(n):
-% if n==0:
-% return 1
-% else:
-% ~emphase#$\highLight{$@return n*fact(n-1)~emphase#$}$@
-% \end{Piton}
-% \end{Verbatim}
-%
-% \begin{Piton}
-% def fact(n):
-% if n==0:
-% return 1
-% else:
-% $\highLight{$return n*fact(n-1)$}$
-% \end{Piton}
-%
-% \bigskip
-% In fact, in that case, it's probably easier to use the command |\@highLight|
-% of \pkg{lua-ul}: that command sets a yellow background until the end of the
-% current TeX group. Since the name of that command contains the character |@|,
-% it's necessary to define a synonym without |@| in order to be able to use it
-% directly in |{Piton}|.
-% \begingroup
-% \fvset{commandchars=\~\#\+,formatcom=\color{gray}}
-% \begin{Verbatim}
-% \makeatletter
-% ~emphase#\let\Yellow\@highLight+
-% \makeatother
-% \end{Verbatim}
-% \endgroup
-%
-% \begin{Verbatim}
-% \begin{Piton}
-% def fact(n):
-% if n==0:
-% return 1
-% else:
-% ~emphase#$\Yellow$@return n*fact(n-1)
-% \end{Piton}
-% \end{Verbatim}
-%
-% \makeatletter
-% \let\Yellow\@highLight
-% \makeatother
-%
-%
-% \begin{Piton}
-% def fact(n):
-% if n==0:
-% return 1
-% else:
-% $\Yellow$return n*fact(n-1)
-% \end{Piton}
-%
-%
-%
-% \bigskip
-% \emph{Caution} : The escape to LaTeX allowed by the characters of
-% |escape-inside| is not active in the strings nor in the Python comments
-% (however, it's possible to have a whole Python comment composed in LaTeX by
-% beginning it with |#>|; such comments are merely called ``LaTeX comments'' in
-% this document).
-%
-%
-% \subsection{Behaviour in the class Beamer}
-%
-% \label{beamer}
-%
-% \emph{First remark}\par\nobreak
-% Since the environment |{Piton}| catches its body with a verbatim mode,
-% it's necessary to use the environments |{Piton}| within environments |{frame}|
-% of Beamer protected by the key |fragile|.\footnote{Remind that for an
-% environment \texttt{\{frame\}} of Beamer using the key |fragile|, the
-% instruction \texttt{\textbackslash end\{frame\}} must be alone on a single
-% line (except for any leading whitespace).}
-%
-%
-% \bigskip
-% When the package \pkg{piton} is used within the class
-% \cls{beamer}\footnote{The extension \pkg{piton} detects the class \cls{beamer}
-% but, if needed, it's also possible to activate that mechanism with the key
-% |beamer| provided by \pkg{piton} at load-time: |\textbackslash
-% usepackage[beamer]\{piton\}|}, the behaviour of \pkg{piton} is slightly
-% modified, as described now.
-%
-% \subsubsection{\{Piton\} et \textbackslash PitonInputFile are
-% ``overlay-aware''}
-%
-% When \pkg{piton} is used in the class \cls{beamer}, the environment |{Piton}|
-% and the command |\PitonInputFile| accept the optional argument |<...>| of
-% Beamer for the overlays which are involved.
-%
-% For example, it's possible to write:
-%
-% \begin{Verbatim}
-% \begin{Piton}~emphase#<2-5>@
-% ...
-% \end{Piton}
-% \end{Verbatim}
-%
-% and
-%
-% \begin{Verbatim}
-% \PitonInputFile~emphase#<2-5>@{my_file.py}
-% \end{Verbatim}
-%
-% \subsubsection{Commands of Beamer allowed in \{Piton\} and \textbackslash PitonInputFile}
-%
-% When \pkg{piton} is used in the class \cls{beamer} , the following commands of
-% \cls{beamer} (classified upon their number of arguments) are automatically
-% detected in the environments |{Piton}| (and in the listings processed by
-% |\PitonInputFile|):
-% \begin{itemize}
-% \item no mandatory argument : |\pause|\footnote{One should remark that it's
-% also possible to use the command \texttt{\textbackslash pause} in a ``LaTeX
-% comment'', that is to say by writing \texttt{\#> \textbackslash pause}. By
-% this way, if the Python code is copied, it's still executable by Python}. ;
-% \item one mandatory argument : |\action|, |\alert|, |\invisible|, |\only|, |\uncover| and |\visible| ;
-% \item two mandatory arguments : |\alt| ;
-% \item three mandatory arguments : |\temporal|.
-% \end{itemize}
-
-% \medskip
-% In the mandatory arguments of these commands, the braces must be balanced.
-% However, the braces included in short strings\footnote{The short strings of
-% Python are the strings delimited by characters \texttt{'} or the characters
-% \texttt{"} and not \texttt{'''} nor \texttt{"""}. In Python, the short strings
-% can't extend on several lines.} of Python are not considered.
-%
-% \medskip
-% Regarding the fonctions |\alt| and |\temporal| there should be no carriage
-% returns in the mandatory arguments of these functions.
-%
-% \medskip
-% Here is a complete example of file:
-%
-% \begin{Verbatim}[formatcom = \small\color{gray}]
-% \documentclass{beamer}
-% \usepackage{piton}
-% \begin{document}
-% \begin{frame}[fragile]
-% \begin{Piton}
-% def string_of_list(l):
-% """Convert a list of numbers in string"""
-% ~emphase# \only<2->{s = "{" + str(l[0])}@
-% ~emphase# \only<3->{for x in l[1:]: s = s + "," + str(x)}@
-% ~emphase# \only<4->{s = s + "}"}@
-% return s
-% \end{Piton}
-% \end{frame}
-% \end{document}
-% \end{Verbatim}
-%
-% In the previous example, the braces in the Python strings |"{"| and |"}"| are
-% correctly interpreted (without any escape character).
-%
-%
-%
-%
-% \bigskip
-% \subsubsection{Environments of Beamer allowed in \{Piton\} and \textbackslash PitonInputFile}
-%
-% When \pkg{piton} is used in the class \pkg{beamer}, the following environments
-% of Beamer are directly detected in the environments |{Piton}| (and in the
-% listings processed by |\PitonInputFile|): |{actionenv}|, |{alertenv}|,
-% |{invisibleenv}|, |{onlyenv}|, |{uncoverenv}| and |{visibleenv}|.
-%
-% However, there is a restriction: these environments must contain only \emph{whole
-% lines of Python code} in their body.
-%
-%\medskip
-% Here is an example:
-%
-% \begin{Verbatim}[formatcom = \small\color{gray}]
-% \documentclass{beamer}
-% \usepackage{piton}
-% \begin{document}
-% \begin{frame}[fragile]
-% \begin{Piton}
-% def square(x):
-% """Compure the square of its argument"""
-% ~emphase#\begin{uncoverenv}<2>@
-% return x*x
-% ~emphase#\end{uncoverenv}@
-% \end{Piton}
-% \end{frame}
-% \end{document}
-% \end{Verbatim}
-%
-%
-% \vspace{1cm}
-% \textbf{Remark concerning the command \textbackslash alert and the environment
-% \{alertenv\} of Beamer}\par\nobreak
-%
-% \smallskip
-% Beamer provides an easy way to change the color used by the environment
-% |{alertenv}| (and by the command |\alert| which relies upon it) to highlight
-% its argument. Here is an example:
-%
-% \begin{Verbatim}
-% \setbeamercolor{~emphase#alerted text@}{fg=blue}
-% \end{Verbatim}
-%
-% However, when used inside an environment |{Piton}|, such tuning will probably
-% not be the best choice because \pkg{piton} will, by design, change (most of
-% the time) the color the different elements of text. One may prefer an environment
-% |{alertenv}| that will change the background color for the elements to be
-% hightlighted.
-%
-% \smallskip
-% Here is a code that will do that job and add a yellow background. That code
-% uses the command |\@highLight| of \pkg{lua-ul} (that extension requires also
-% the package \pkg{luacolor}).
-%
-% \begingroup
-% \fvset{commandchars=\~\#\+,formatcom=\color{gray}}
-% \begin{Verbatim}
-% \setbeamercolor{alerted text}{bg=yellow!50}
-% \makeatletter
-% \AddToHook{env/Piton/begin}
-% {\renewenvironment<>{alertenv}{\only~#1{~emphase#\@highLight+[alerted text.bg]}}{}}
-% \makeatother
-% \end{Verbatim}
-% \endgroup
-%
-% That code redefines locally the environment |{alertenv}| within the
-% environments |{Piton}| (we recall that the command |\alert| relies upon that
-% environment |{alertenv}|).
-%
-% \subsection{Page breaks and line breaks}
-%
-% \label{breakable}
-%
-% \subsubsection{Page breaks}
-%
-% By default, the listings produced by the environment |{Piton}| and the command
-% |\PitonInputFile| are not breakable.
-%
-% However, the command |\PitonOptions| provides the key |splittable| to allow such
-% breaks.
-%
-% \begin{itemize}
-% \item If the key |splittable| is used without any value, the listings are
-% breakable everywhere.
-% \item If the key |splittable| is used with a numeric value~$n$ (which must be
-% a non-negative integer number), the listings are breakable but no break will
-% occur within the first $n$ lines and within the last $n$ lines. Therefore,
-% |splittable=1| is equivalent to |splittable|.
-% \end{itemize}
-%
-% \medskip
-% Even with a background color (set by the key |background-color|), the pages
-% breaks are allowed, as soon as the key |splittable| is in force.\footnote{With
-% the key |splittable|, the environments \texttt{\{Piton\}} are breakable, even
-% within a (breakable) environment of \pkg{tcolorbox}. Remind that an
-% environment of \pkg{tcolorbox} included in another environment of
-% \pkg{tcolorbox} is \emph{not} breakable, even when both environments use the
-% key |breakable| of \pkg{tcolorbox}.}
-%
-% \subsubsection{Line breaks}
-%
-% \label{line-breaks}
-%
-% By default, the elements produced by \pkg{piton} can't be broken by an end on
-% line. However, there are keys to allow such breaks (the possible breaking
-% points are the spaces, even the spaces in the Python strings).
-% \begin{itemize}
-% \item With the key |break-lines-in-piton|, the line breaks are allowed in the
-% command |\piton{...}| (but not in the command \verb+\piton|...|+, that is to say
-% the command |\piton| in verbatim mode).
-% \item With the key |break-lines-in-Piton|, the line breaks are allowed in the
-% environment |{Piton}| (hence the capital letter |P| in the name) and in the
-% listings produced by |\PitonInputFile|.
-% \item The key |break-lines| is a conjonction of the two previous keys.
-% \end{itemize}
-%
-% \bigskip
-% The package \pkg{piton} provides also several keys to control the appearance
-% on the line breaks allowed by |break-lines-in-Piton|.
-%
-% \begin{itemize}
-% \item With the key |indent-broken-lines|, the indentation of a broken line is
-% respected at carriage return.
-%
-% \item The key |end-of-broken-line| corresponds to the symbol placed at the end
-% of a broken line. The initial value is: |\hspace*{0.5em}\textbackslash|.
-%
-% \item The key |continuation-symbol| corresponds to the symbol placed at each
-% carriage return. The initial value is: |+\;|.
-%
-% \item The key |continuation-symbol-on-indentation| coresponds to the symbol
-% placed at each carriage return, on the position of the indentation (only when
-% the key |indent-broken-line| is in force). The initial value is:
-% |$\hookrightarrow\;$|.
-% \end{itemize}
-%
-%
-% \bigskip
-% The following code has been composed in a standard LaTeX |{minipage}| of width
-% 12~cm with the following tuning:
-%
-% \begin{Verbatim}
-% \PitonOptions{break-lines,indent-broken-lines,background-color=gray!15}
-% \end{Verbatim}
-%
-% \begin{center}
-% \PitonOptions{break-lines,indent-broken-lines,background-color=gray!15}
-% \begin{minipage}{12cm}
-% \begin{Piton}
-% def dict_of_list(l):
-% """Converts a list of subrs and descriptions of glyphs in a dictionary"""
-% our_dict = {}
-% for list_letter in l:
-% if (list_letter[0][0:3] == 'dup'): # if it's a subr
-% name = list_letter[0][4:-3]
-% print("We treat the subr of number " + name)
-% else:
-% name = list_letter[0][1:-3] # if it's a glyph
-% print("We treat the glyph of number " + name)
-% our_dict[name] = [treat_Postscript_line(k) for k in list_letter[1:-1]]
-% return dict
-% \end{Piton}
-% \end{minipage}
-% \end{center}
-%
-% \subsection{Footnotes in the environments of piton}
-%
-% \label{footnote}
-% If you want to put footnotes in an environment |{Piton}| or
-% (or, more unlikely, in a listing produced by |\PitonInputFile|), you can use a
-% pair |\footnotemark|--|\footnotetext|.
-%
-% \smallskip
-% However, it's also possible to extract the footnotes with the help of the
-% package \pkg{footnote} or the package \pkg{footnotehyper}.
-%
-% \smallskip
-% If \pkg{piton} is loaded with the option |footnote| (with
-% |\usepackage[footnote]{piton}| or with |\PassOptionsToPackage|), the
-% package \pkg{footnote} is loaded (if it is not yet loaded) and it is used to
-% extract the footnotes.
-%
-% \smallskip
-% If \pkg{piton} is loaded with the option |footnotehyper|, the package
-% \pkg{footnotehyper} is loaded (if it is not yet loaded) ant it is used to
-% extract footnotes.
-%
-% \smallskip
-% Caution: The packages \pkg{footnote} and \pkg{footnotehyper} are incompatible.
-% The package \pkg{footnotehyper} is the successor of the package \pkg{footnote}
-% and should be used preferently. The package \pkg{footnote} has some drawbacks,
-% in particular: it must be loaded after the package \pkg{xcolor} and it is not
-% perfectly compatible with \pkg{hyperref}.
-%
-% \medskip
-% In this document, the package \pkg{piton} has been loaded with the
-% option |footnotehyper|. For examples of notes, cf. \ref{notes-examples},
-% p.~\pageref{notes-examples}.
-%
-% \subsection{Tabulations}
-%
-% \smallskip
-% Even though it's recommended to indent the Python listings with spaces (see
-% PEP~8), \pkg{piton} accepts the characters of tabulation (that is to say the
-% characters U+0009) at the beginning of the lines. Each character U+0009 is
-% replaced by $n$~spaces. The initial value of $n$ is $4$ but it's possible to
-% change it with the key |tab-size| of |\PitonOptions|.
-%
-% \smallskip
-% There exists also a key |tabs-auto-gobble| which computes the minimal value
-% $n$ of the number of consecutive characters U+0009 beginning each (non empty)
-% line of the environment |{Piton}| and applies |gobble| with that value of~$n$
-% (before replacement of the tabulations by spaces, of course). Hence, that key
-% is similar to the key |auto-gobble| but acts on U+0009 instead of U+0020
-% (spaces).
-%
-% \section{Examples}
-%
-% \subsection{Line numbering}
-%
-% \label{example-numbering}
-%
-% We remind that it's possible to have an automatic numbering of the lines in
-% the Python listings by using the key |line-numbers| or the key |all-line-numbers|.
-%
-% By default, the numbers of the lines are composed by \pkg{piton} in an
-% overlapping position on the left (by using internally the command |\llap| of LaTeX).
-%
-% In order to avoid that overlapping, it's possible to use the option |left-margin=auto|
-% which will insert automatically a margin adapted to the numbers of lines that
-% will be written (that margin is larger when the numbers are greater than~10).
-%
-%
-% \begingroup
-% \fvset{commandchars=\~\&\@,formatcom=\small\color{gray}}
-% \begin{Verbatim}
-% ~emphase&\PitonOptions{background-color=gray!10, left-margin = auto, line-numbers}@
-% \begin{Piton}
-% def arctan(x,n=10):
-% if x < 0:
-% return -arctan(-x) #> (appel récursif)
-% elif x > 1:
-% return pi/2 - arctan(1/x) #> (autre appel récursif)
-% else:
-% return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) )
-% \end{Piton}
-% \end{Verbatim}
-% \endgroup
-%
-%
-%
-% \begingroup
-% \PitonOptions{background-color=gray!10,left-margin = auto, line-numbers}
-% \begin{Piton}
-% def arctan(x,n=10):
-% if x < 0:
-% return -arctan(-x) #> (appel récursif)
-% elif x > 1:
-% return pi/2 - arctan(1/x) #> (autre appel récursif)
-% else:
-% return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) )
-% \end{Piton}
-% \endgroup
-%
-%
-%
-% \bigskip
-% \subsection{Formatting of the LaTeX comments}
-%
-% \label{example-comments}
-%
-% It's possible to modify the style |Comment.LaTeX| (with |\SetPitonStyle|) in
-% order to display the LaTeX comments (which begin with |#>|) aligned on the
-% right margin.
-%
-%
-% \begingroup
-% \fvset{commandchars=\~\&\@,formatcom=\small\color{gray}}
-% \begin{Verbatim}
-% \PitonOptions{background-color=gray!10}
-% ~emphase&\SetPitonStyle{Comment.LaTeX = \hfill \normalfont\color{gray}}@
-% \begin{Piton}
-% def arctan(x,n=10):
-% if x < 0:
-% return -arctan(-x) #> appel récursif
-% elif x > 1:
-% return pi/2 - arctan(1/x) #> autre appel récursif
-% else:
-% return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) )
-% \end{Piton}
-% \end{Verbatim}
-% \endgroup
-%
-% \begingroup
-% \PitonOptions{background-color=gray!10}
-% \SetPitonStyle{Comment.LaTeX = \hfill \normalfont\color{gray}}
-% \begin{Piton}
-% def arctan(x,n=10):
-% if x < 0:
-% return -arctan(-x) #> appel récursif
-% elif x > 1:
-% return pi/2 - arctan(1/x) #> autre appel récursif
-% else:
-% return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) )
-% \end{Piton}
-% \endgroup
-%
-%
-% \vspace{1cm}
-% It's also possible to display these LaTeX comments in a kind of second column
-% by limiting the width of the Python code by an environment |{minipage}| of LaTeX.
-%
-%
-% \begingroup
-% \fvset{commandchars=\~\&\@,formatcom=\small\color{gray}}
-% \begin{Verbatim}
-% \PitonOptions{background-color=gray!10}
-% ~emphase&\NewDocumentCommand{\MyLaTeXCommand}{m}{\hfill \normalfont\itshape\rlap{\quad #1}}@
-% ~emphase&\SetPitonStyle{Comment.LaTeX = \MyLaTeXCommand}@
-% ~emphase&\begin{minipage}{12cm}@
-% \begin{Piton}
-% def arctan(x,n=10):
-% if x < 0:
-% return -arctan(-x) #> appel récursif
-% elif x > 1:
-% return pi/2 - arctan(1/x) #> autre appel récursif
-% else:
-% s = 0
-% for k in range(n):
-% s += (-1)**k/(2*k+1)*x**(2*k+1)
-% return s
-% \end{Piton}
-% ~emphase&\end{minipage}@
-% \end{Verbatim}
-% \endgroup
-%
-%
-%
-% \begingroup
-% \PitonOptions{background-color=gray!10}
-% \NewDocumentCommand{\MyLaTeXCommand}{m}{\hfill \normalfont\itshape\rlap{\quad #1}}
-% \SetPitonStyle{Comment.LaTeX = \MyLaTeXCommand}
-% \begin{minipage}{12cm}
-% \begin{Piton}
-% def arctan(x,n=10):
-% if x < 0:
-% return -arctan(-x) #> appel récursif
-% elif x > 1:
-% return pi/2 - arctan(1/x) #> autre appel récursif
-% else:
-% s = 0
-% for k in range(n):
-% s += (-1)**k/(2*k+1)*x**(2*k+1)
-% return s
-% \end{Piton}
-% \end{minipage}
-% \endgroup
-%
-%
-% \bigskip
-% \subsection{Notes in the listings}
-%
-% \label{notes-examples}
-%
-% In order to be able to extract the notes (which are typeset with the command
-% |\footnote|), the extension \pkg{piton} must be loaded with the key |footnote|
-% or the key |footenotehyper| as explained in the section \ref{footnote}
-% p.~\pageref{footnote}. In this document, the extension \pkg{piton} has been
-% loaded with the key |footnotehyper|.
-%
-% Of course, in an environment |{Piton}|, a command |\footnote| may appear only
-% within a LaTeX comment (which begins with |#>|). It's possible to have comments
-% which contain only that command |\footnote|. That's the case in the following example.
-%
-%
-%
-% \begingroup
-% \fvset{commandchars=\~\&\@,formatcom=\small\color{gray}}
-% \begin{Verbatim}
-% \PitonOptions{background-color=gray!10}
-% \begin{Piton}
-% def arctan(x,n=10):
-% if x < 0:
-% return -arctan(-x)~emphase&#>\footnote{First recursive call.}]@
-% elif x > 1:
-% return pi/2 - arctan(1/x)~emphase&#>\footnote{Second recursive call.}@
-% else:
-% return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) )
-% \end{Piton}
-% \end{Verbatim}
-% \endgroup
-%
-% \begingroup
-% \PitonOptions{background-color=gray!10}
-% \begin{Piton}
-% def arctan(x,n=10):
-% if x < 0:
-% return -arctan(-x)#>\footnote{First recursive call.}
-% elif x > 1:
-% return pi/2 - arctan(1/x)#>\footnote{Second recursive call.}
-% else:
-% return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) )
-% \end{Piton}
-% \endgroup
-%
-%
-% \vspace{1cm}
-%
-% If an environment |{Piton}| is used in an environment |{minipage}| of LaTeX,
-% the notes are composed, of course, at the foot of the environment
-% |{minipage}|. Recall that such |{minipage}| can't be broken by a page break.
-%
-%
-% \begingroup
-% \fvset{commandchars=\~\&\@,formatcom=\small\color{gray}}
-% \begin{Verbatim}
-% \PitonOptions{background-color=gray!10}
-% \emphase\begin{minipage}{\linewidth}
-% \begin{Piton}
-% def arctan(x,n=10):
-% if x < 0:
-% return -arctan(-x)~emphase&#>\footnote{First recursive call.}@
-% elif x > 1:
-% return pi/2 - arctan(1/x)~emphase&#>\footnote{Second recursive call.}@
-% else:
-% return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) )
-% \end{Piton}
-% \end{minipage}
-% \end{Verbatim}
-% \endgroup
-%
-% \begingroup
-% \PitonOptions{background-color=gray!10}
-% \begin{minipage}{\linewidth}
-% \begin{Piton}
-% def arctan(x,n=10):
-% if x < 0:
-% return -arctan(-x)#>\footnote{First recursive call.}
-% elif x > 1:
-% return pi/2 - arctan(1/x)#>\footnote{Second recursive call.}
-% else:
-% return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) )
-% \end{Piton}
-% \end{minipage}
-% \endgroup
-%
-%
-% \vspace{1cm}
-% If we embed an environment |{Piton}| in an environment |{minipage}|
-% (typically in order to limit the width of a colored background), it's
-% necessary to embed the whole environment |{minipage}| in an environment
-% |{savenotes}| (of \pkg{footnote} or \pkg{footnotehyper}) in order to have the
-% footnotes composed at the bottom of the page.
-%
-% \begingroup
-% \fvset{commandchars=\~\&\@,formatcom=\small\color{gray}}
-% \begin{Verbatim}
-% \PitonOptions{background-color=gray!10}
-% ~emphase&\begin{savenotes}@
-% \begin{minipage}{13cm}
-% \begin{Piton}
-% def arctan(x,n=10):
-% if x < 0:
-% return -arctan(-x)~emphase&#>\footnote{First recursive call.}@
-% elif x > 1:
-% return pi/2 - arctan(1/x)~emphase&#>\footnote{Second recursive call.}@
-% else:
-% return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) )
-% \end{Piton}
-% \end{minipage}
-% ~emphase&\end{savenotes}@
-% \end{Verbatim}
-% \endgroup
-%
-%
-%
-% \begin{savenotes}
-% \PitonOptions{background-color=gray!10}
-% \begin{minipage}{13cm}
-% \begin{Piton}
-% def arctan(x,n=10):
-% if x < 0:
-% return -arctan(-x)#>\footnote{First recursive call.}
-% elif x > 1:
-% return pi/2 - arctan(1/x)#>\footnote{Second recursive call.}
-% else:
-% return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) )
-% \end{Piton}
-% \end{minipage}
-% \end{savenotes}
-%
-% \bigskip
-%
-% \subsection{An example of tuning of the styles}
-%
-% The graphical styles have been presented in the section \ref{styles},
-% p.~\pageref{styles}.
-%
-% \smallskip
-% We present now an example of tuning of these styles adapted to the documents
-% in black and white. We use the font \emph{DejaVu Sans Mono}\footnote{See:
-% \url{https://dejavu-fonts.github.io}} specified by the command |\setmonofont| of
-% \pkg{fontspec}.
-%
-% That tuning uses the command |\highLight| of \pkg{lua-ul} (that package
-% requires itself the package \pkg{luacolor}).
-%
-% \begin{Verbatim}
-% \setmonofont[Scale=0.85]{DejaVu Sans Mono}
-%
-% \SetPitonStyle
-% {
-% Number = ,
-% String = \itshape ,
-% String.Doc = \color{gray} \slshape ,
-% Operator = ,
-% Operator.Word = \bfseries ,
-% Name.Builtin = ,
-% Name.Function = \bfseries \highLight[gray!20] ,
-% Comment = \color{gray} ,
-% Comment.LaTeX = \normalfont \color{gray},
-% Keyword = \bfseries ,
-% Name.Namespace = ,
-% Name.Class = ,
-% Name.Type = ,
-% InitialValues = \color{gray}
-% }
-% \end{Verbatim}
-%
-%
-% \begingroup
-%
-% \setmonofont[Scale=0.85]{DejaVu Sans Mono}
-%
-% \PitonOptions{splittable}
-%
-% \SetPitonStyle
-% {
-% Number = ,
-% String = \itshape ,
-% String.Doc = \color{gray} \slshape ,
-% Operator.Word = \bfseries ,
-% Operator = ,
-% Name.Builtin = ,
-% Name.Function = \bfseries \highLight[gray!20] ,
-% Comment = \color{gray} ,
-% Comment.LaTeX = \normalfont \color{gray} ,
-% Keyword = \bfseries ,
-% Name.Namespace = ,
-% Name.Class = ,
-% Name.Type = ,
-% InitialValues = \color{gray}
-% }
-%
-%
-% \bigskip
-%
-% \begin{Piton}
-% from math import pi
-%
-% def arctan(x,n=10):
-% """Compute the mathematical value of arctan(x)
-%
-% n is the number of terms in the sum
-% """
-% if x < 0:
-% return -arctan(-x) # appel récursif
-% elif x > 1:
-% return pi/2 - arctan(1/x)
-% #> (we have used that $\arctan(x)+\arctan(1/x)=\pi/2$ for $x>0$)
-% else:
-% s = 0
-% for k in range(n):
-% s += (-1)**k/(2*k+1)*x**(2*k+1)
-% return s
-% \end{Piton}
-%
-% \endgroup
-%
-% \subsection{Use with pyluatex}
-%
-% The package \pkg{pyluatex} is an extension which allows the execution of some
-% Python code from |lualatex| (provided that Python is installed on the machine
-% and that the compilation is done with |lualatex| and |--shell-escape|).
-%
-% Here is, for example, an environment |{PitonExecute}| which formats a Python
-% listing (with \pkg{piton}) but display also the output of the execution of the
-% code with Python (for technical reasons, the |!| is mandatory in the signature
-% of the environment).
-%
-%
-% \begin{Verbatim}
-% \ExplSyntaxOn
-% \NewDocumentEnvironment { ~emphase#PitonExecute@ } { ! O { } } % the ! is mandatory
-% {
-% \PyLTVerbatimEnv
-% \begin{pythonq}
-% }
-% {
-% \end{pythonq}
-% \directlua
-% {
-% tex.print("\\PitonOptions{~#1}")
-% tex.print("\\begin{Piton}")
-% tex.print(pyluatex.get_last_code())
-% tex.print("\\end{Piton}")
-% tex.print("")
-% }
-% \begin{center}
-% \directlua{tex.print(pyluatex.get_last_output())}
-% \end{center}
-% }
-% \ExplSyntaxOff
-% \end{Verbatim}
-%
-% \ExplSyntaxOn
-% \NewDocumentEnvironment { PitonExecute } { ! O { } }
-% {
-% \PyLTVerbatimEnv
-% \begin{pythonq}
-% }
-% {
-% \end{pythonq}
-% \directlua
-% {
-% tex.print("\\PitonOptions{#1}")
-% tex.print("\\begin{Piton}")
-% tex.print(pyluatex.get_last_code())
-% tex.print("\\end{Piton}")
-% tex.print("")
-% }
-% \begin{center}
-% \directlua{tex.print(pyluatex.get_last_output())}
-% \end{center}
-% }
-% \ExplSyntaxOff
-%
-% This environment |{PitonExecute}| takes in as optional argument (between
-% square brackets) the options of the command |\PitonOptions|.
-%
-%
-% \bigskip
-% \clearpage
-%
-% \section{Implementation}
-%
-% \subsection{Introduction}
-%
-% The main job of the package \pkg{piton} is to take in as input a Python
-% listing and to send back to LaTeX as output that code \emph{with interlaced LaTeX
-% instructions of formatting}.
-%
-% In fact, all that job is done by a \textsc{lpeg} called |python|. That
-% \textsc{lpeg}, when matched against the string of a Python listing,
-% returns as capture a Lua table containing data to send to LaTeX.
-% The only thing to do after will be to apply |tex.tprint| to each element of
-% that table.\footnote{Recall that |tex.tprint| takes in as argument a Lua table whose
-% first component is a ``catcode table'' and the second element a string. The
-% string will be sent to LaTeX with the regime of catcodes specified by the
-% catcode table. If no catcode table is provided, the standard catcodes of LaTeX
-% will be used.}
-%
-% \bigskip
-% Consider, for example, the following Python code:
-%
-% \begin{Piton}
-% def parity(x):
-% return x%2
-% \end{Piton}
-%
-% The capture returned by the \pkg{lpeg} |python| against that code is the
-% Lua table containing the following elements :
-%
-% \bigskip
-% \begin{minipage}{\linewidth}
-% \color{gray}
-%
-% |{ "\\__piton_begin_line:" }|\footnote{Each line of the Python listings will
-% be encapsulated in a pair: \texttt{\textbackslash_@@_begin_line:} --
-% \texttt{\textbackslash@@_end_line:}. The token
-% \texttt{\textbackslash@@_end_line:} must be explicit because it will be used as
-% marker in order to delimit the argument of the command \texttt{\textbackslash
-% @@\_begin\_line:}. Both tokens \texttt{\textbackslash_@@_begin_line:} and
-% \texttt{\textbackslash@@_end_line:} will be nullified in the command
-% \texttt{\textbackslash piton} (since there can't be lines breaks in the
-% argument of a command \texttt{\textbackslash piton}).}
-%
-% \texttt{\{ "\{\textbackslash PitonStyle\{Keyword\}\{" \}}\footnote{The
-% lexical elements of Python for which we have a \pkg{piton} style will be
-% formatted via the use of the command \texttt{\textbackslash PitonStyle}.
-% Such an element is typeset in LaTeX via the syntax \texttt{\{\textbackslash
-% PitonStyle\{\textsl{style}\}\{...\}\}} because the instructions inside an \texttt{\textbackslash
-% PitonStyle} may be both semi-global declarations like
-% \texttt{\textbackslash bfseries} and commands with one argument like
-% \texttt{\textbackslash fbox}.}
-%
-% \texttt{\{
-% luatexbase.catcodetables.CatcodeTableOther\footnote{\texttt{luatexbase.catcodetables.CatcodeTableOther} is a mere number which corresponds to the ``catcode table'' whose all characters have the catcode ``other'' (which means that they will be typeset by LaTeX verbatim).}, "def" \} }
-%
-% |{ "}}" }|
-%
-% |{ luatexbase.catcodetables.CatcodeTableOther, " " }|
-%
-% |{ "{\PitonStyle{Name.Function}{" }|
-%
-% |{ luatexbase.catcodetables.CatcodeTableOther, "parity" }|
-%
-% |{ "}}" }|
-%
-% |{ luatexbase.catcodetables.CatcodeTableOther, "(" }|
-%
-% |{ luatexbase.catcodetables.CatcodeTableOther, "x" }|
-%
-% |{ luatexbase.catcodetables.CatcodeTableOther, ")" }|
-%
-% |{ luatexbase.catcodetables.CatcodeTableOther, ":" }|
-%
-% |{ "\\__piton_end_line: \\__piton_newline: \\__piton_begin_line:" }|
-%
-% |{ luatexbase.catcodetables.CatcodeTableOther, " " }|
-%
-% |{ "{\PitonStyle{Keyword}{" }|
-%
-% |{ luatexbase.catcodetables.CatcodeTableOther, "return" }|
-%
-% |{ "}}" }|
-%
-% |{ luatexbase.catcodetables.CatcodeTableOther, " " }|
-%
-% |{ luatexbase.catcodetables.CatcodeTableOther, "x" }|
-%
-% |{ "{\PitonStyle{Operator}{" }|
-%
-% |{ luatexbase.catcodetables.CatcodeTableOther, "&" }|
-%
-% |{ "}}" }|
-%
-% |{ "{\PitonStyle{Number}{" }|
-%
-% |{ luatexbase.catcodetables.CatcodeTableOther, "2" }|
-%
-% |{ "}}" }|
-%
-% |{ "\\__piton_end_line:" }|
-%
-% \end{minipage}
-%
-% \bigskip
-% We give now the LaTeX code which is sent back by Lua to TeX (we have written
-% on several lines for legibility but no character |\r| will be sent to LaTeX). The
-% characters which are greyed-out are sent to LaTeX with the catcode ``other''
-% (=12). All the others characters are sent with the regime of catcodes of L3
-% (as set by |\ExplSyntaxOn|)
-%
-%
-% \begingroup
-% \def\gbox#1{\colorbox{gray!20}{\strut #1}}
-% \setlength{\fboxsep}{1pt}
-%
-% \begin{Verbatim*}[formatcom = \color{black}]
-% \__piton_begin_line:{\PitonStyle{Keyword}{~gbox#def@}}
-% ~gbox# @{\PitonStyle{Name.Function}{~gbox#parity@}}~gbox#(x):@\__piton_end_line:\__piton_newline:
-% \__piton_begin_line:~gbox# @{\PitonStyle{Keyword}{~gbox#return@}}
-% ~gbox# x@{\PitonStyle{Operator}{~gbox#%@}}{\PitonStyle{Number}{~gbox#2@}}\__piton_end_line:
-% \end{Verbatim*}
-% \endgroup
-%
-%
-%
-%
-% \subsection{The L3 part of the implementation}
-%
-% \subsubsection{Declaration of the package}
-% \begin{macrocode}
-\NeedsTeXFormat{LaTeX2e}
-\RequirePackage{l3keys2e}
-\ProvidesExplPackage
- {piton}
- {\myfiledate}
- {\myfileversion}
- {Highlight Python codes with LPEG on LuaLaTeX}
-% \end{macrocode}
-%
-% \bigskip
-% \begin{macrocode}
-\msg_new:nnn { piton } { LuaLaTeX~mandatory }
- {
- LuaLaTeX~is~mandatory.\\
- The~package~'piton'~requires~the~engine~LuaLaTeX.\\
- \str_if_eq:VnT \c_sys_jobname_str { output }
- { If~you~use~Overleaf,~you~can~switch~to~LuaLaTeX~in~the~"Menu". \\}
- If~you~go~on,~the~package~'piton'~won't~be~loaded.
- }
-\sys_if_engine_luatex:F { \msg_critical:nn { piton } { LuaLaTeX~mandatory } }
-% \end{macrocode}
-%
-% \bigskip
-% \begin{macrocode}
-\RequirePackage { luatexbase }
-% \end{macrocode}
-%
-% \bigskip
-% The boolean |\c_@@_footnotehyper_bool| will indicate if the option
-% |footnotehyper| is used.
-% \begin{macrocode}
-\bool_new:N \c_@@_footnotehyper_bool
-% \end{macrocode}
-%
-% \medskip
-% The boolean |\c_@@_footnote_bool| will indicate if the option |footnote| is
-% used, but quicky, it will also be set to |true| if the option |footnotehyper|
-% is used.
-% \begin{macrocode}
-\bool_new:N \c_@@_footnote_bool
-% \end{macrocode}
-%
-% \medskip
-% The following boolean corresponds to the key |math-comments| (only at load-time).
-% \begin{macrocode}
-\bool_new:N \c_@@_math_comments_bool
-% \end{macrocode}
-%
-% \medskip
-% The following boolean corresponds to the key |beamer|.
-% \begin{macrocode}
-\bool_new:N \c_@@_beamer_bool
-% \end{macrocode}
-%
-% \bigskip
-% We define a set of keys for the options at load-time.
-% \begin{macrocode}
-\keys_define:nn { piton / package }
- {
- footnote .bool_set:N = \c_@@_footnote_bool ,
- footnotehyper .bool_set:N = \c_@@_footnotehyper_bool ,
- escape-inside .tl_set:N = \c_@@_escape_inside_tl ,
- escape-inside .initial:n = ,
- comment-latex .code:n = { \lua_now:n { comment_latex = "#1" } } ,
- comment-latex .value_required:n = true ,
- math-comments .bool_set:N = \c_@@_math_comments_bool ,
- math-comments .default:n = true ,
- beamer .bool_set:N = \c_@@_beamer_bool ,
- beamer .default:n = true ,
- unknown .code:n = \msg_error:nn { piton } { unknown~key~for~package }
- }
-% \end{macrocode}
-%
-% \begin{macrocode}
-\msg_new:nnn { piton } { unknown~key~for~package }
- {
- Unknown~key.\\
- You~have~used~the~key~'\l_keys_key_str'~but~the~only~keys~available~here~
- are~'beamer',~'comment-latex',~'escape-inside',~'footnote',~'footnotehyper'~and~
- 'math-comments'.~Other~keys~are~available~in~\token_to_str:N \PitonOptions.\\
- That~key~will~be~ignored.
- }
-% \end{macrocode}
-%
-% \bigskip
-% We process the options provided by the user at load-time.
-% \begin{macrocode}
-\ProcessKeysOptions { piton / package }
-% \end{macrocode}
-%
-% \bigskip
-% \begin{macrocode}
-\begingroup
-\cs_new_protected:Npn \@@_set_escape_char:nn #1 #2
- {
- \lua_now:n { piton_begin_escape = "#1" }
- \lua_now:n { piton_end_escape = "#2" }
- }
-\cs_generate_variant:Nn \@@_set_escape_char:nn { x x }
-\@@_set_escape_char:xx
- { \tl_head:V \c_@@_escape_inside_tl }
- { \tl_tail:V \c_@@_escape_inside_tl }
-\endgroup
-% \end{macrocode}
-%
-% \bigskip
-% \begin{macrocode}
-\@ifclassloaded { beamer } { \bool_set_true:N \c_@@_beamer_bool } { }
-\bool_if:NT \c_@@_beamer_bool { \lua_now:n { piton_beamer = true } }
-% \end{macrocode}
-%
-% \bigskip
-% \begin{macrocode}
-\hook_gput_code:nnn { begindocument } { . }
- {
- \@ifpackageloaded { xcolor }
- { }
- { \msg_fatal:nn { piton } { xcolor~not~loaded } }
- }
-% \end{macrocode}
-%
-% \begin{macrocode}
-\msg_new:nnn { piton } { xcolor~not~loaded }
- {
- xcolor~not~loaded \\
- The~package~'xcolor'~is~required~by~'piton'.\\
- This~error~is~fatal.
- }
-% \end{macrocode}
-%
-%
-% \begin{macrocode}
-\msg_new:nnn { piton } { footnote~with~footnotehyper~package }
- {
- Footnote~forbidden.\\
- You~can't~use~the~option~'footnote'~because~the~package~
- footnotehyper~has~already~been~loaded.~
- If~you~want,~you~can~use~the~option~'footnotehyper'~and~the~footnotes~
- within~the~environments~of~piton~will~be~extracted~with~the~tools~
- of~the~package~footnotehyper.\\
- If~you~go~on,~the~package~footnote~won't~be~loaded.
- }
-% \end{macrocode}
-%
-% \begin{macrocode}
-\msg_new:nnn { piton } { footnotehyper~with~footnote~package }
- {
- You~can't~use~the~option~'footnotehyper'~because~the~package~
- footnote~has~already~been~loaded.~
- If~you~want,~you~can~use~the~option~'footnote'~and~the~footnotes~
- within~the~environments~of~piton~will~be~extracted~with~the~tools~
- of~the~package~footnote.\\
- If~you~go~on,~the~package~footnotehyper~won't~be~loaded.
- }
-% \end{macrocode}
-%
-% \medskip
-% \begin{macrocode}
-\bool_if:NT \c_@@_footnote_bool
- {
-% \end{macrocode}
-% The class \cls{beamer} has its own system to extract footnotes and that's why
-% we have nothing to do if \cls{beamer} is used.
-% \begin{macrocode}
- \@ifclassloaded { beamer }
- { \bool_set_false:N \c_@@_footnote_bool }
- {
- \@ifpackageloaded { footnotehyper }
- { \@@_error:n { footnote~with~footnotehyper~package } }
- { \usepackage { footnote } }
- }
- }
-% \end{macrocode}
-%
-% \begin{macrocode}
-\bool_if:NT \c_@@_footnotehyper_bool
- {
-% \end{macrocode}
-% The class \cls{beamer} has its own system to extract footnotes and that's why
-% we have nothing to do if \cls{beamer} is used.
-% \begin{macrocode}
- \@ifclassloaded { beamer }
- { \bool_set_false:N \c_@@_footnote_bool }
- {
- \@ifpackageloaded { footnote }
- { \@@_error:n { footnotehyper~with~footnote~package } }
- { \usepackage { footnotehyper } }
- \bool_set_true:N \c_@@_footnote_bool
- }
- }
-% \end{macrocode}
-% The flag |\c_@@_footnote_bool| is raised and so, we will only have to test
-% |\c_@@_footnote_bool| in order to know if we have to insert an environment
-% |{savenotes}|.
-%
-% \bigskip
-% \subsubsection{Parameters and technical definitions}
-%
-% The following string will contain the name of the informatic language
-% considered (the initial value is |python|).
-%
-% \begin{macrocode}
-\str_new:N \l_@@_language_str
-\str_set:Nn \l_@@_language_str { python }
-% \end{macrocode}
-%
-% We will compute (with Lua) the numbers of lines of the Python code and store
-% it in the following counter.
-% \begin{macrocode}
-\int_new:N \l_@@_nb_lines_int
-% \end{macrocode}
-%
-% The same for the number of non-empty lines of the Python codes.
-% \begin{macrocode}
-\int_new:N \l_@@_nb_non_empty_lines_int
-% \end{macrocode}
-%
-% The following counter will be used to count the lines during the composition.
-% It will count all the lines, empty or not empty. It won't be used to print the
-% numbers of the lines.
-% \begin{macrocode}
-\int_new:N \g_@@_line_int
-% \end{macrocode}
-%
-% \medskip
-% The following token list will contains the (potential) informations to write
-% on the |aux| (to be used in the next compilation).
-% \begin{macrocode}
-\tl_new:N \g_@@_aux_tl
-% \end{macrocode}
-%
-% \medskip
-% The following counter corresponds to the key |splittable| of |\PitonOptions|.
-% If the value of |\l_@@_splittable_int| is equal to $n$, then no line break can
-% occur within the first $n$~lines or the last $n$~lines of the listings.
-% \begin{macrocode}
-\int_new:N \l_@@_splittable_int
-% \end{macrocode}
-%
-% \medskip
-% An initial value of |splittable| equal to 100 is equivalent to say that the
-% environments |{Piton}| are unbreakable.
-% \begin{macrocode}
-\int_set:Nn \l_@@_splittable_int { 100 }
-% \end{macrocode}
-%
-% \medskip
-% The following string corresponds to the key |background-color| of |\PitonOptions|.
-% \begin{macrocode}
-\clist_new:N \l_@@_bg_color_clist
-% \end{macrocode}
-%
-% \medskip
-% The package \pkg{piton} will also detect the lines of code which correspond to
-% the user input in a Python console, that is to say the lines of code beginning
-% with |>>>| and |...|. It's possible, with the key |prompt-background-color|,
-% to require a background for these lines of code (and the other lines of code
-% will have the standard background color specified by |background-color|).
-% \begin{macrocode}
-\tl_new:N \l_@@_prompt_bg_color_tl
-% \end{macrocode}
-%
-% \medskip
-% We will compute the maximal width of the lines of an environment |{Piton}| in
-% |\g_@@_width_dim|. We need a global variable because, when the key |footnote|
-% is in force, each line when be composed in an environment |{savenotes}| and
-% (when |slim| is in force) we need to exit |\g_@@_width_dim| from that
-% environment.
-% \begin{macrocode}
-\dim_new:N \g_@@_width_dim
-% \end{macrocode}
-% The value of that dimension as written on the |aux| file will be stored in
-% |\l_@@_width_on_aux_dim|.
-% \begin{macrocode}
-\dim_new:N \l_@@_width_on_aux_dim
-% \end{macrocode}
-%
-% \medskip
-% We will count the environments |{Piton}| (and, in fact, also the commands
-% |\PitonInputFile|, despite the name |\g_@@_env_int|).
-% \begin{macrocode}
-\int_new:N \g_@@_env_int
-% \end{macrocode}
-%
-% \medskip
-% The following boolean corresponds to the key |show-spaces|.
-% \begin{macrocode}
-\bool_new:N \l_@@_show_spaces_bool
-% \end{macrocode}
-%
-% \medskip
-% The following booleans correspond to the keys |break-lines| and
-% |indent-broken-lines|.
-% \begin{macrocode}
-\bool_new:N \l_@@_break_lines_in_Piton_bool
-\bool_new:N \l_@@_indent_broken_lines_bool
-% \end{macrocode}
-%
-% \medskip
-% The following token list corresponds to the key |continuation-symbol|.
-% \begin{macrocode}
-\tl_new:N \l_@@_continuation_symbol_tl
-\tl_set:Nn \l_@@_continuation_symbol_tl { + }
-% \end{macrocode}
-%
-% \medskip
-% \begin{macrocode}
-% The following token list corresponds to the key
-% |continuation-symbol-on-indentation|. The name has been shorten to |csoi|.
-\tl_new:N \l_@@_csoi_tl
-\tl_set:Nn \l_@@_csoi_tl { $ \hookrightarrow \; $ }
-% \end{macrocode}
-%
-% \medskip
-% The following token list corresponds to the key |end-of-broken-line|.
-% \begin{macrocode}
-\tl_new:N \l_@@_end_of_broken_line_tl
-\tl_set:Nn \l_@@_end_of_broken_line_tl { \hspace*{0.5em} \textbackslash }
-% \end{macrocode}
-%
-% \medskip
-% The following boolean corresponds to the key |break-lines-in-piton|.
-% \begin{macrocode}
-\bool_new:N \l_@@_break_lines_in_piton_bool
-% \end{macrocode}
-%
-% \medskip
-% The following boolean corresponds to the key |slim| of |\PitonOptions|.
-% \begin{macrocode}
-\bool_new:N \l_@@_slim_bool
-% \end{macrocode}
-%
-% \medskip
-% The following dimension corresponds to the key |left-margin| of |\PitonOptions|.
-% \begin{macrocode}
-\dim_new:N \l_@@_left_margin_dim
-% \end{macrocode}
-%
-% \medskip
-% The following boolean will be set when the key |left-margin=auto|
-% is used.
-% \begin{macrocode}
-\bool_new:N \l_@@_left_margin_auto_bool
-% \end{macrocode}
-%
-% \medskip
-% The following dimension corresponds to the key |numbers-sep| of
-% |\PitonOptions|.
-% \begin{macrocode}
-\dim_new:N \l_@@_numbers_sep_dim
-\dim_set:Nn \l_@@_numbers_sep_dim { 0.7 em }
-% \end{macrocode}
-%
-% \medskip
-% The tabulators will be replaced by the content of the following token list.
-% \begin{macrocode}
-\tl_new:N \l_@@_tab_tl
-% \end{macrocode}
-%
-% \medskip
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_set_tab_tl:n #1
- {
- \tl_clear:N \l_@@_tab_tl
- \prg_replicate:nn { #1 }
- { \tl_put_right:Nn \l_@@_tab_tl { ~ } }
- }
-\@@_set_tab_tl:n { 4 }
-% \end{macrocode}
-%
-% \medskip
-% The following integer corresponds to the key |gobble|.
-% \begin{macrocode}
-\int_new:N \l_@@_gobble_int
-% \end{macrocode}
-%
-% \medskip
-% \begin{macrocode}
-\tl_new:N \l_@@_space_tl
-\tl_set:Nn \l_@@_space_tl { ~ }
-% \end{macrocode}
-%
-%
-% \medskip
-% At each line, the following counter will count the spaces at the beginning.
-% \begin{macrocode}
-\int_new:N \g_@@_indentation_int
-% \end{macrocode}
-%
-% \medskip
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_an_indentation_space:
- { \int_gincr:N \g_@@_indentation_int }
-% \end{macrocode}
-%
-% \medskip
-% The following command |\@@_beamer_command:n| executes the argument
-% corresponding to its argument but also stores it in |\l_@@_beamer_command_str|.
-% That string is used only in the error message ``|cr~not~allowed|'' raised when
-% there is a carriage return in the mandatory argument of that command.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_beamer_command:n #1
- {
- \str_set:Nn \l_@@_beamer_command_str { #1 }
- \use:c { #1 }
- }
-% \end{macrocode}
-%
-% \bigskip
-% In the environment |{Piton}|, the command |\label| will be linked to the
-% following command.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_label:n #1
- {
- \bool_if:NTF \l_@@_line_numbers_bool
- {
- \@bsphack
- \protected@write \@auxout { }
- {
- \string \newlabel { #1 }
- {
-% \end{macrocode}
-% Remember that the content of a line is typeset in a box \emph{before} the
-% composition of the potential number of line.
-% \begin{macrocode}
- { \int_eval:n { \g_@@_visual_line_int + 1 } }
- { \thepage }
- }
- }
- \@esphack
- }
- { \msg_error:nn { piton } { label~with~lines~numbers } }
- }
-% \end{macrocode}
-%
-%
-% \bigskip
-% The following commands are a easy way to insert safely braces (|{| and |}|) in
-% the TeX flow.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_open_brace:
- { \directlua { piton.open_brace() } }
-\cs_new_protected:Npn \@@_close_brace:
- { \directlua { piton.close_brace() } }
-% \end{macrocode}
-%
-% \bigskip
-% The following token list will be evaluated at the beginning of
-% |\@@_begin_line:|... |\@@_end_line:| and cleared at the end. It will be used
-% by LPEG acting between the lines of the Python code in order to add
-% instructions to be executed at the beginning of the line.
-% \begin{macrocode}
-\tl_new:N \g_@@_begin_line_hook_tl
-% \end{macrocode}
-%
-% \smallskip
-% For example, the LPEG |Prompt| will trigger the following command which will
-% insert an instruction in the hook |\g_@@_begin_line_hook| to specify that a
-% background must be inserted to the current line of code.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_prompt:
- {
- \tl_gset:Nn \g_@@_begin_line_hook_tl
- { \clist_set:NV \l_@@_bg_color_clist \l_@@_prompt_bg_color_tl }
- }
-% \end{macrocode}
-%
-%
-% \bigskip
-% You will keep track of the current style for the treatment of EOL (for the
-% multi-line syntactic elements).
-% \begin{macrocode}
-\clist_new:N \g_@@_current_style_clist
-\clist_set:Nn \g_@@_current_style_clist { __end }
-% \end{macrocode}
-% The element |__end| is an arbitrary syntactic marker.
-%
-% \medskip
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_close_current_styles:
- {
- \int_set:Nn \l_tmpa_int { \clist_count:N \g_@@_current_style_clist - 1 }
- \exp_args:NV \@@_close_n_styles:n \l_tmpa_int
- }
-% \end{macrocode}
-%
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_close_n_styles:n #1
- {
- \int_compare:nNnT { #1 } > 0
- {
- \@@_close_brace:
- \@@_close_brace:
- \@@_close_n_styles:n { #1 - 1 }
- }
- }
-% \end{macrocode}
-%
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_open_current_styles:
- { \exp_last_unbraced:NV \@@_open_styles:w \g_@@_current_style_clist , }
-% \end{macrocode}
-%
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_open_styles:w #1 ,
- {
- \tl_if_eq:nnF { #1 } { __end }
- { \@@_open_brace: #1 \@@_open_brace: \@@_open_styles:w }
- }
-% \end{macrocode}
-%
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_pop_style:
- {
- \clist_greverse:N \g_@@_current_style_clist
- \clist_gpop:NN \g_@@_current_style_clist \l_tmpa_tl
- \clist_gpop:NN \g_@@_current_style_clist \l_tmpa_tl
- \clist_gpush:Nn \g_@@_current_style_clist { __end }
- \clist_greverse:N \g_@@_current_style_clist
- }
-% \end{macrocode}
-%
-% \medskip
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_push_style:n #1
- {
- \clist_greverse:N \g_@@_current_style_clist
- \clist_gpop:NN \g_@@_current_style_clist \l_tmpa_tl
- \clist_gpush:Nn \g_@@_current_style_clist { #1 }
- \clist_gpush:Nn \g_@@_current_style_clist { __end }
- \clist_greverse:N \g_@@_current_style_clist
- }
-% \end{macrocode}
-%
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_push_and_exec:n #1
- {
- \@@_push_style:n { #1 }
- \@@_open_brace: #1 \@@_open_brace:
- }
-% \end{macrocode}
-%
-% \bigskip
-% \subsubsection{Treatment of a line of code}
-%
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_replace_spaces:n #1
- {
- \tl_set:Nn \l_tmpa_tl { #1 }
- \bool_if:NTF \l_@@_show_spaces_bool
- { \regex_replace_all:nnN { \x20 } { ␣ } \l_tmpa_tl } % U+2423
- {
-% \end{macrocode}
-% If the key |break-lines-in-Piton| is in force, we replace all the characters
-% U+0020 (that is to say the spaces) by |\@@_breakable_space:|. Remark that,
-% except the spaces inserted in the LaTeX comments (and maybe in the math
-% comments), all these spaces are of catcode ``other'' (=12) and are
-% unbreakable.
-% \begin{macrocode}
- \bool_if:NT \l_@@_break_lines_in_Piton_bool
- {
- \regex_replace_all:nnN
- { \x20 }
- { \c { @@_breakable_space: } }
- \l_tmpa_tl
- }
- }
- \l_tmpa_tl
- }
-\cs_generate_variant:Nn \@@_replace_spaces:n { x }
-% \end{macrocode}
-%
-% \bigskip
-% In the contents provided by Lua, each line of the Python code will be
-% surrounded by |\@@_begin_line:| and |\@@_end_line:|. |\@@_begin_line:| is a
-% LaTeX command that we will define now but |\@@_end_line:| is only a syntactic
-% marker that has no definition.
-%
-% \begin{macrocode}
-\cs_set_protected:Npn \@@_begin_line: #1 \@@_end_line:
- {
- \group_begin:
- \g_@@_begin_line_hook_tl
- \int_gzero:N \g_@@_indentation_int
-% \end{macrocode}
-%
-%
-% Be careful: there is curryfication in the following lines.
-% \begin{macrocode}
- \bool_if:NTF \l_@@_slim_bool
- { \hcoffin_set:Nn \l_tmpa_coffin }
- {
- \clist_if_empty:NTF \l_@@_bg_color_clist
- {
- \vcoffin_set:Nnn \l_tmpa_coffin
- { \dim_eval:n { \linewidth - \l_@@_left_margin_dim } }
- }
- {
- \vcoffin_set:Nnn \l_tmpa_coffin
- { \dim_eval:n { \linewidth - \l_@@_left_margin_dim - 0.5 em } }
- }
- }
- {
- \language = -1
- \raggedright
- \strut
- \@@_replace_spaces:n { #1 }
- \strut \hfil
- }
- \hbox_set:Nn \l_tmpa_box
- {
- \skip_horizontal:N \l_@@_left_margin_dim
- \bool_if:NT \l_@@_line_numbers_bool
- {
- \bool_if:NF \l_@@_all_line_numbers_bool
- { \tl_if_eq:nnF { #1 } { \PitonStyle {Prompt}{} } } % corrected 2023/04/10
- \@@_print_number:
- }
- \clist_if_empty:NF \l_@@_bg_color_clist
- {
- \dim_compare:nNnT \l_@@_left_margin_dim = \c_zero_dim
- {
- \bool_if:NF \l_@@_left_margin_auto_bool
- { \skip_horizontal:n { 0.5 em } }
- }
- }
- \coffin_typeset:Nnnnn \l_tmpa_coffin T l \c_zero_dim \c_zero_dim
- }
-% \end{macrocode}
-% We compute in |\g_@@_width_dim| the maximal width of the lines of the
-% environment.
-% \begin{macrocode}
- \dim_compare:nNnT { \box_wd:N \l_tmpa_box } > \g_@@_width_dim
- { \dim_gset:Nn \g_@@_width_dim { \box_wd:N \l_tmpa_box } }
- \box_set_dp:Nn \l_tmpa_box { \box_dp:N \l_tmpa_box + 1.25 pt }
- \box_set_ht:Nn \l_tmpa_box { \box_ht:N \l_tmpa_box + 1.25 pt }
- \clist_if_empty:NTF \l_@@_bg_color_clist
- { \box_use_drop:N \l_tmpa_box }
- {
- \vbox_top:n
- {
- \hbox:n
- {
- \@@_color:N \l_@@_bg_color_clist
- \vrule height \box_ht:N \l_tmpa_box
- depth \box_dp:N \l_tmpa_box
- width \l_@@_width_on_aux_dim
- }
- \skip_vertical:n { - \box_ht_plus_dp:N \l_tmpa_box }
- \box_set_wd:Nn \l_tmpa_box \l_@@_width_on_aux_dim
- \box_use_drop:N \l_tmpa_box
- }
- }
- \vspace { - 2.5 pt }
- \group_end:
- \tl_gclear:N \g_@@_begin_line_hook_tl
- }
-% \end{macrocode}
-%
-% \bigskip
-% The command |\@@_color:N| will take in as argument a reference to a
-% comma-separated list of colors. A color will be picked by using the value of
-% |\g_@@_line_int| (modulo the number of colors in the list).
-% \begin{macrocode}
-\cs_set_protected:Npn \@@_color:N #1
- {
- \int_set:Nn \l_tmpa_int { \clist_count:N #1 }
- \int_set:Nn \l_tmpb_int { \int_mod:nn \g_@@_line_int \l_tmpa_int + 1 }
- \tl_set:Nx \l_tmpa_tl { \clist_item:Nn #1 \l_tmpb_int }
- \tl_if_eq:NnTF \l_tmpa_tl { none }
-% \end{macrocode}
-% By setting |\l_@@_width_on_aux_dim| to zero, the colored rectangle will be
-% drawn with zero width and, thus, it will be a mere strut (and we need that strut).
-% \begin{macrocode}
- { \dim_zero:N \l_@@_width_on_aux_dim }
- { \exp_args:NV \@@_color_i:n \l_tmpa_tl }
- }
-% \end{macrocode}
-%
-% The following command |\@@_color:n| will accept both the instruction
-% |\@@_color:n { red!15 }| and the instruction |\@@_color:n { [rgb]{0.9,0.9,0} }|.
-% \begin{macrocode}
-\cs_set_protected:Npn \@@_color_i:n #1
- {
- \tl_if_head_eq_meaning:nNTF { #1 } [
- {
- \tl_set:Nn \l_tmpa_tl { #1 }
- \tl_set_rescan:Nno \l_tmpa_tl { } \l_tmpa_tl
- \exp_last_unbraced:NV \color \l_tmpa_tl
- }
- { \color { #1 } }
- }
-\cs_generate_variant:Nn \@@_color:n { V }
-% \end{macrocode}
-%
-% \bigskip
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_newline:
- {
- \int_gincr:N \g_@@_line_int
- \int_compare:nNnT \g_@@_line_int > { \l_@@_splittable_int - 1 }
- {
- \int_compare:nNnT
- { \l_@@_nb_lines_int - \g_@@_line_int } > \l_@@_splittable_int
- {
- \egroup
- \bool_if:NT \c_@@_footnote_bool { \end { savenotes } }
- \newline
- \bool_if:NT \c_@@_footnote_bool { \begin { savenotes } }
- \vtop \bgroup
- }
- }
- }
-% \end{macrocode}
-%
-% \bigskip
-% \begin{macrocode}
-\cs_set_protected:Npn \@@_breakable_space:
- {
- \discretionary
- { \hbox:n { \color { gray } \l_@@_end_of_broken_line_tl } }
- {
- \hbox_overlap_left:n
- {
- {
- \normalfont \footnotesize \color { gray }
- \l_@@_continuation_symbol_tl
- }
- \skip_horizontal:n { 0.3 em }
- \clist_if_empty:NF \l_@@_bg_color_clist
- { \skip_horizontal:n { 0.5 em } }
- }
- \bool_if:NT \l_@@_indent_broken_lines_bool
- {
- \hbox:n
- {
- \prg_replicate:nn { \g_@@_indentation_int } { ~ }
- { \color { gray } \l_@@_csoi_tl }
- }
- }
- }
- { \hbox { ~ } }
- }
-% \end{macrocode}
-%
-% \bigskip
-% \subsubsection{PitonOptions}
-%
-% \medskip
-% The following parameters correspond to the keys |line-numbers| and
-% |all-line-numbers|.
-% \begin{macrocode}
-\bool_new:N \l_@@_line_numbers_bool
-\bool_new:N \l_@@_all_line_numbers_bool
-% \end{macrocode}
-%
-% \medskip
-% The following flag corresponds to the key |resume|.
-% \begin{macrocode}
-\bool_new:N \l_@@_resume_bool
-% \end{macrocode}
-%
-% \bigskip
-% Be careful! The name of the following set of keys must be considered as
-% public! Hence, it should \emph{not} be changed.
-%
-% \begin{macrocode}
-\keys_define:nn { PitonOptions }
- {
- language .str_set:N = \l_@@_language_str ,
- language .value_required:n = true ,
- gobble .int_set:N = \l_@@_gobble_int ,
- gobble .value_required:n = true ,
- auto-gobble .code:n = \int_set:Nn \l_@@_gobble_int { -1 } ,
- auto-gobble .value_forbidden:n = true ,
- env-gobble .code:n = \int_set:Nn \l_@@_gobble_int { -2 } ,
- env-gobble .value_forbidden:n = true ,
- tabs-auto-gobble .code:n = \int_set:Nn \l_@@_gobble_int { -3 } ,
- tabs-auto-gobble .value_forbidden:n = true ,
- line-numbers .bool_set:N = \l_@@_line_numbers_bool ,
- line-numbers .default:n = true ,
- all-line-numbers .code:n =
- \bool_set_true:N \l_@@_line_numbers_bool
- \bool_set_true:N \l_@@_all_line_numbers_bool ,
- all-line-numbers .value_forbidden:n = true ,
- resume .bool_set:N = \l_@@_resume_bool ,
- resume .value_forbidden:n = true ,
- splittable .int_set:N = \l_@@_splittable_int ,
- splittable .default:n = 1 ,
- background-color .clist_set:N = \l_@@_bg_color_clist ,
- background-color .value_required:n = true ,
- prompt-background-color .tl_set:N = \l_@@_prompt_bg_color_tl ,
- prompt-background-color .value_required:n = true ,
- slim .bool_set:N = \l_@@_slim_bool ,
- slim .default:n = true ,
- left-margin .code:n =
- \str_if_eq:nnTF { #1 } { auto }
- {
- \dim_zero:N \l_@@_left_margin_dim
- \bool_set_true:N \l_@@_left_margin_auto_bool
- }
- { \dim_set:Nn \l_@@_left_margin_dim { #1 } } ,
- left-margin .value_required:n = true ,
- numbers-sep .dim_set:N = \l_@@_numbers_sep_dim ,
- numbers-sep .value_required:n = true ,
- tab-size .code:n = \@@_set_tab_tl:n { #1 } ,
- tab-size .value_required:n = true ,
- show-spaces .bool_set:N = \l_@@_show_spaces_bool ,
- show-spaces .default:n = true ,
- show-spaces-in-strings .code:n = \tl_set:Nn \l_@@_space_tl { ␣ } , % U+2423
- show-spaces-in-strings .value_forbidden:n = true ,
- break-lines-in-Piton .bool_set:N = \l_@@_break_lines_in_Piton_bool ,
- break-lines-in-Piton .default:n = true ,
- break-lines-in-piton .bool_set:N = \l_@@_break_lines_in_piton_bool ,
- break-lines-in-piton .default:n = true ,
- break-lines .meta:n = { break-lines-in-piton , break-lines-in-Piton } ,
- break-lines .value_forbidden:n = true ,
- indent-broken-lines .bool_set:N = \l_@@_indent_broken_lines_bool ,
- indent-broken-lines .default:n = true ,
- end-of-broken-line .tl_set:N = \l_@@_end_of_broken_line_tl ,
- end-of-broken-line .value_required:n = true ,
- continuation-symbol .tl_set:N = \l_@@_continuation_symbol_tl ,
- continuation-symbol .value_required:n = true ,
- continuation-symbol-on-indentation .tl_set:N = \l_@@_csoi_tl ,
- continuation-symbol-on-indentation .value_required:n = true ,
- unknown .code:n =
- \msg_error:nn { piton } { Unknown~key~for~PitonOptions }
- }
-% \end{macrocode}
-%
-%
-% \bigskip
-%
-% \bigskip
-% The argument of |\PitonOptions| is provided by curryfication.
-% \begin{macrocode}
-\NewDocumentCommand \PitonOptions { } { \keys_set:nn { PitonOptions } }
-% \end{macrocode}
-%
-% \bigskip
-% \subsubsection{The numbers of the lines}
-%
-% \medskip
-% The following counter will be used to count the lines in the code when the
-% user requires the numbers of the lines to be printed (with |line-numbers| or
-% |all-line-numbers|).
-%
-% \begin{macrocode}
-\int_new:N \g_@@_visual_line_int
-% \end{macrocode}
-%
-%
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_print_number:
- {
- \int_gincr:N \g_@@_visual_line_int
- \hbox_overlap_left:n
- {
- { \color { gray } \footnotesize \int_to_arabic:n \g_@@_visual_line_int }
- \skip_horizontal:N \l_@@_numbers_sep_dim
- }
- }
-% \end{macrocode}
-%
-%
-% \bigskip
-% \subsubsection{The command to write on the aux file}
-%
-%
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_write_aux:
- {
- \tl_if_empty:NF \g_@@_aux_tl
- {
- \iow_now:Nn \@mainaux { \ExplSyntaxOn }
- \iow_now:Nx \@mainaux
- {
- \tl_gset:cn { c_@@_ \int_use:N \g_@@_env_int _ tl }
- { \exp_not:V \g_@@_aux_tl }
- }
- \iow_now:Nn \@mainaux { \ExplSyntaxOff }
- }
- \tl_gclear:N \g_@@_aux_tl
- }
-% \end{macrocode}
-%
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_width_to_aux:
- {
- \bool_if:NT \l_@@_slim_bool
- {
- \clist_if_empty:NF \l_@@_bg_color_clist
- {
- \tl_gput_right:Nx \g_@@_aux_tl
- {
- \dim_set:Nn \l_@@_width_on_aux_dim
- { \dim_eval:n { \g_@@_width_dim + 0.5 em } }
- }
- }
- }
- }
-% \end{macrocode}
-%
-% \bigskip
-% \subsubsection{The main commands and environments for the final user}
-%
-% \bigskip
-% \begin{macrocode}
-\NewDocumentCommand { \piton } { }
- { \peek_meaning:NTF \bgroup \@@_piton_standard \@@_piton_verbatim }
-% \end{macrocode}
-%
-% \begin{macrocode}
-\NewDocumentCommand { \@@_piton_standard } { m }
- {
- \group_begin:
- \ttfamily
-% \end{macrocode}
-% The following tuning of LuaTeX in order to avoid all break of lines on the
-% hyphens.
-% \begin{macrocode}
- \automatichyphenmode = 1
- \cs_set_eq:NN \\ \c_backslash_str
- \cs_set_eq:NN \% \c_percent_str
- \cs_set_eq:NN \{ \c_left_brace_str
- \cs_set_eq:NN \} \c_right_brace_str
- \cs_set_eq:NN \$ \c_dollar_str
- \cs_set_eq:cN { ~ } \space
- \cs_set_protected:Npn \@@_begin_line: { }
- \cs_set_protected:Npn \@@_end_line: { }
- \tl_set:Nx \l_tmpa_tl
- {
- \lua_now:e
- { piton.ParseBis('\l_@@_language_str',token.scan_string()) }
- { #1 }
- }
- \bool_if:NTF \l_@@_show_spaces_bool
- { \regex_replace_all:nnN { \x20 } { ␣ } \l_tmpa_tl } % U+2423
-% \end{macrocode}
-% The following code replaces the characters U+0020 (spaces) by characters
-% U+0020 of catcode~10: thus, they become breakable by an end of line.
-% \begin{macrocode}
- {
- \bool_if:NT \l_@@_break_lines_in_piton_bool
- { \regex_replace_all:nnN { \x20 } { \x20 } \l_tmpa_tl }
- }
- \l_tmpa_tl
- \group_end:
- }
-% \end{macrocode}
-%
-%
-% \begin{macrocode}
-\NewDocumentCommand { \@@_piton_verbatim } { v }
- {
- \group_begin:
- \ttfamily
- \automatichyphenmode = 1
- \cs_set_protected:Npn \@@_begin_line: { }
- \cs_set_protected:Npn \@@_end_line: { }
- \tl_set:Nx \l_tmpa_tl
- {
- \lua_now:e
- { piton.Parse('\l_@@_language_str',token.scan_string()) }
- { #1 }
- }
- \bool_if:NT \l_@@_show_spaces_bool
- { \regex_replace_all:nnN { \x20 } { ␣ } \l_tmpa_tl } % U+2423
- \l_tmpa_tl
- \group_end:
- }
-% \end{macrocode}
-%
-
-% \bigskip
-%
-%
-% \bigskip
-% The following command is not a user command. It will be used when we will
-% have to ``rescan'' some chunks of Python code. For example, it will be the
-% initial value of the Piton style |InitialValues| (the default values of the
-% arguments of a Python function).
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_piton:n #1
- {
- \group_begin:
- \cs_set_protected:Npn \@@_begin_line: { }
- \cs_set_protected:Npn \@@_end_line: { }
- \bool_lazy_or:nnTF
- \l_@@_break_lines_in_piton_bool
- \l_@@_break_lines_in_Piton_bool
- {
- \tl_set:Nx \l_tmpa_tl
- {
- \lua_now:e
- { piton.ParseTer('\l_@@_language_str',token.scan_string()) }
- { #1 }
- }
- }
- {
- \tl_set:Nx \l_tmpa_tl
- {
- \lua_now:e
- { piton.Parse('\l_@@_language_str',token.scan_string()) }
- { #1 }
- }
- }
- \bool_if:NT \l_@@_show_spaces_bool
- { \regex_replace_all:nnN { \x20 } { ␣ } \l_tmpa_tl } % U+2423
- \l_tmpa_tl
- \group_end:
- }
-% \end{macrocode}
-%
-% \bigskip
-% The following command is similar to the previous one but raise a fatal error if
-% its argument contains a carriage return.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_piton_no_cr:n #1
- {
- \group_begin:
- \cs_set_protected:Npn \@@_begin_line: { }
- \cs_set_protected:Npn \@@_end_line: { }
- \cs_set_protected:Npn \@@_newline:
- { \msg_fatal:nn { piton } { cr~not~allowed } }
- \bool_lazy_or:nnTF
- \l_@@_break_lines_in_piton_bool
- \l_@@_break_lines_in_Piton_bool
- {
- \tl_set:Nx \l_tmpa_tl
- {
- \lua_now:e
- { piton.ParseTer('\l_@@_language_str',token.scan_string()) }
- { #1 }
- }
- }
- {
- \tl_set:Nx \l_tmpa_tl
- {
- \lua_now:e
- { piton.Parse('\l_@@_language_str',token.scan_string()) }
- { #1 }
- }
- }
- \bool_if:NT \l_@@_show_spaces_bool
- { \regex_replace_all:nnN { \x20 } { ␣ } \l_tmpa_tl } % U+2423
- \l_tmpa_tl
- \group_end:
- }
-% \end{macrocode}
-%
-% \bigskip
-% Despite its name, |\@@_pre_env:| will be used both in |\PitonInputFile| and
-% in the environments such as |{Piton}|.
-% \begin{macrocode}
-\cs_new:Npn \@@_pre_env:
- {
- \automatichyphenmode = 1
- \int_gincr:N \g_@@_env_int
- \tl_gclear:N \g_@@_aux_tl
- \cs_if_exist_use:c { c_@@ _ \int_use:N \g_@@_env_int _ tl }
- \dim_compare:nNnT \l_@@_width_on_aux_dim = \c_zero_dim
- { \dim_set_eq:NN \l_@@_width_on_aux_dim \linewidth }
- \bool_if:NF \l_@@_resume_bool { \int_gzero:N \g_@@_visual_line_int }
- \dim_gzero:N \g_@@_width_dim
- \int_gzero:N \g_@@_line_int
- \dim_zero:N \parindent
- \dim_zero:N \lineskip
- \dim_zero:N \parindent
- \cs_set_eq:NN \label \@@_label:n
- }
-% \end{macrocode}
-%
-% \bigskip
-% \begin{macrocode}
-\keys_define:nn { PitonInputFile }
- {
- first-line .int_set:N = \l_@@_first_line_int ,
- first-line .value_required:n = true ,
- last-line .int_set:N = \l_@@_last_line_int ,
- last-line .value_required:n = true ,
- }
-% \end{macrocode}
-%
-% \bigskip
-% \begin{macrocode}
-\NewDocumentCommand { \PitonInputFile } { d < > O { } m }
- {
- \tl_if_novalue:nF { #1 }
- {
- \bool_if:NTF \c_@@_beamer_bool
- { \begin { uncoverenv } < #1 > }
- { \msg_error:nn { piton } { overlay~without~beamer } }
- }
- \group_begin:
- \int_zero_new:N \l_@@_first_line_int
- \int_zero_new:N \l_@@_last_line_int
- \int_set_eq:NN \l_@@_last_line_int \c_max_int
- \keys_set:nn { PitonInputFile } { #2 }
- \@@_pre_env:
- \mode_if_vertical:TF \mode_leave_vertical: \newline
-% \end{macrocode}
-% We count with Lua the number of lines of the argument. The result will be
-% stored by Lua in |\l_@@_nb_lines_int|. That information will be used to allow
-% or disallow page breaks.
-% \begin{macrocode}
- \lua_now:n { piton.CountLinesFile(token.scan_argument()) } { #3 }
-% \end{macrocode}
-% If the final user has used both |left-margin=auto| and |line-numbers| or
-% |all-line-numbers|, we have to compute the width of the maximal number of
-% lines at the end of the composition of the listing to fix the correct value to
-% |left-margin|.
-% \begin{macrocode}
- \bool_lazy_and:nnT \l_@@_left_margin_auto_bool \l_@@_line_numbers_bool
- {
- \hbox_set:Nn \l_tmpa_box
- {
- \footnotesize
- \bool_if:NTF \l_@@_all_line_numbers_bool
- {
- \int_to_arabic:n
- { \g_@@_visual_line_int + \l_@@_nb_lines_int }
- }
- {
- \lua_now:n
- { piton.CountNonEmptyLinesFile(token.scan_argument()) }
- { #3 }
- \int_to_arabic:n
- { \g_@@_visual_line_int + \l_@@_nb_non_empty_lines_int }
- }
- }
- \dim_set:Nn \l_@@_left_margin_dim
- { \box_wd:N \l_tmpa_box + \l_@@_numbers_sep_dim + 0.1 em }
- }
-% \end{macrocode}
-% Now, the main job.
-% \begin{macrocode}
- \ttfamily
- \bool_if:NT \c_@@_footnote_bool { \begin { savenotes } }
- \vtop \bgroup
- \lua_now:e
- {
- piton.ParseFile('\l_@@_language_str',token.scan_argument() ,
- \int_use:N \l_@@_first_line_int ,
- \int_use:N \l_@@_last_line_int )
- }
- { #3 }
- \egroup
- \bool_if:NT \c_@@_footnote_bool { \end { savenotes } }
- \@@_width_to_aux:
- \group_end:
- \tl_if_novalue:nF { #1 }
- { \bool_if:NT \c_@@_beamer_bool { \end { uncoverenv } } }
- \@@_write_aux:
- }
-% \end{macrocode}
-%
-%
-% \bigskip
-% \begin{macrocode}
-\NewDocumentCommand { \NewPitonEnvironment } { m m m m }
- {
-% \end{macrocode}
-% We construct a TeX macro which will catch as argument all the tokens until
-% |\end{|\texttt{\textsl{name_env}}|}| with, in that
-% |\end{|\texttt{\textsl{name_env}}|}|, the catcodes of |\|, |{| and |}| equal to
-% 12 (``\texttt{other}''). The latter explains why the definition of that
-% function is a bit complicated.
-% \begin{macrocode}
- \use:x
- {
- \cs_set_protected:Npn
- \use:c { _@@_collect_ #1 :w }
- ####1
- \c_backslash_str end \c_left_brace_str #1 \c_right_brace_str
- }
- {
- \group_end:
- \mode_if_vertical:TF \mode_leave_vertical: \newline
-% \end{macrocode}
-% We count with Lua the number of lines of the argument. The result will be
-% stored by Lua in |\l_@@_nb_lines_int|. That information will be used to allow
-% or disallow page breaks.
-% \begin{macrocode}
- \lua_now:n { piton.CountLines(token.scan_argument()) } { ##1 }
-% \end{macrocode}
-% If the final user has used both |left-margin=auto| and |line-numbers|, we have
-% to compute the width of the maximal number of lines at the end of the
-% environment to fix the correct value to |left-margin|.
-% \begin{macrocode}
- \bool_lazy_and:nnT \l_@@_left_margin_auto_bool \l_@@_line_numbers_bool
- {
- \bool_if:NTF \l_@@_all_line_numbers_bool
- {
- \hbox_set:Nn \l_tmpa_box
- {
- \footnotesize
- \int_to_arabic:n
- { \g_@@_visual_line_int + \l_@@_nb_lines_int }
- }
- }
- {
- \lua_now:n
- { piton.CountNonEmptyLines(token.scan_argument()) }
- { ##1 }
- \hbox_set:Nn \l_tmpa_box
- {
- \footnotesize
- \int_to_arabic:n
- { \g_@@_visual_line_int + \l_@@_nb_non_empty_lines_int }
- }
- }
- \dim_set:Nn \l_@@_left_margin_dim
- { \box_wd:N \l_tmpa_box + \l_@@_numbers_sep_dim + 0.1 em }
- }
-% \end{macrocode}
-% Now, the main job.
-% \begin{macrocode}
- \ttfamily
- \bool_if:NT \c_@@_footnote_bool { \begin { savenotes } }
- \vtop \bgroup
- \lua_now:e
- {
- piton.GobbleParse
- (
- '\l_@@_language_str' ,
- \int_use:N \l_@@_gobble_int ,
- token.scan_argument()
- )
- }
- { ##1 }
- \vspace { 2.5 pt }
- \egroup
- \bool_if:NT \c_@@_footnote_bool { \end { savenotes } }
- \@@_width_to_aux:
-% \end{macrocode}
-% The following |\end{#1}| is only for the groups and the stack of environments
-% of LaTeX.
-% \begin{macrocode}
- \end { #1 }
- \@@_write_aux:
- }
-% \end{macrocode}
-%
-%
-% \bigskip
-% We can now define the new environment.
-%
-% We are still in the definition of the command |\NewPitonEnvironment|...
-% \begin{macrocode}
- \NewDocumentEnvironment { #1 } { #2 }
- {
- #3
- \@@_pre_env:
- \group_begin:
- \tl_map_function:nN
- { \ \\ \{ \} \$ \& \# \^ \_ \% \~ \^^I }
- \char_set_catcode_other:N
- \use:c { _@@_collect_ #1 :w }
- }
- { #4 }
-% \end{macrocode}
-%
-% \medskip
-% The following code is for technical reasons. We want to change the catcode of
-% |^^M| before catching the arguments of the new environment we are defining.
-% Indeed, if not, we will have problems if there is a final optional argument in
-% our environment (if that final argument is not used by the user in an
-% instance of the environment, a spurious space is inserted, probably because
-% the |^^M| is converted to space).
-% \begin{macrocode}
- \AddToHook { env / #1 / begin } { \char_set_catcode_other:N \^^M }
- }
-% \end{macrocode}
-% This is the end of the definition of the command |\NewPitonEnvironment|.
-%
-% \bigskip
-% Now, we define the environment |{Piton}|, which is the main environment
-% provided by the package \pkg{piton}. Of course, you use
-% |\NewPitonEnvironment|.
-% \begin{macrocode}
-\bool_if:NTF \c_@@_beamer_bool
- {
- \NewPitonEnvironment { Piton } { d < > }
- {
- \IfValueTF { #1 }
- { \begin { uncoverenv } < #1 > }
- { \begin { uncoverenv } }
- }
- { \end { uncoverenv } }
- }
- { \NewPitonEnvironment { Piton } { } { } { } }
-% \end{macrocode}
-%
-%
-%
-% \bigskip
-% \subsubsection{The styles}
-%
-% \medskip
-% The following command is fundamental: it will be used by the Lua code.
-% \begin{macrocode}
-\NewDocumentCommand { \PitonStyle } { m } { \use:c { pitonStyle #1 } }
-% \end{macrocode}
-%
-% \medskip
-% The following command takes in its argument by curryfication.
-% \begin{macrocode}
-\NewDocumentCommand { \SetPitonStyle } { } { \keys_set:nn { piton / Styles } }
-% \end{macrocode}
-%
-% \medskip
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_math_scantokens:n #1
- { \normalfont \scantextokens { $#1$ } }
-% \end{macrocode}
-%
-% \medskip
-% \begin{macrocode}
-\keys_define:nn { piton / Styles }
- {
- String.Interpol .tl_set:c = pitonStyle String.Interpol ,
- String.Interpol .value_required:n = true ,
- FormattingType .tl_set:c = pitonStyle FormattingType ,
- FormattingType .value_required:n = true ,
- Dict.Value .tl_set:c = pitonStyle Dict.Value ,
- Dict.Value .value_required:n = true ,
- Name.Decorator .tl_set:c = pitonStyle Name.Decorator ,
- Name.Decorator .value_required:n = true ,
- Name.Function .tl_set:c = pitonStyle Name.Function ,
- Name.Function .value_required:n = true ,
- Name.UserFunction .tl_set:c = pitonStyle Name.UserFunction ,
- Name.UserFunction .value_required:n = true ,
- Keyword .tl_set:c = pitonStyle Keyword ,
- Keyword .value_required:n = true ,
- Keyword.Constant .tl_set:c = pitonStyle Keyword.Constant ,
- Keyword.constant .value_required:n = true ,
- String.Doc .tl_set:c = pitonStyle String.Doc ,
- String.Doc .value_required:n = true ,
- Interpol.Inside .tl_set:c = pitonStyle Interpol.Inside ,
- Interpol.Inside .value_required:n = true ,
- String.Long .tl_set:c = pitonStyle String.Long ,
- String.Long .value_required:n = true ,
- String.Short .tl_set:c = pitonStyle String.Short ,
- String.Short .value_required:n = true ,
- String .meta:n = { String.Long = #1 , String.Short = #1 } ,
- Comment.Math .tl_set:c = pitonStyle Comment.Math ,
- Comment.Math .default:n = \@@_math_scantokens:n ,
- Comment.Math .initial:n = ,
- Comment .tl_set:c = pitonStyle Comment ,
- Comment .value_required:n = true ,
- InitialValues .tl_set:c = pitonStyle InitialValues ,
- InitialValues .value_required:n = true ,
- Number .tl_set:c = pitonStyle Number ,
- Number .value_required:n = true ,
- Name.Namespace .tl_set:c = pitonStyle Name.Namespace ,
- Name.Namespace .value_required:n = true ,
- Name.Class .tl_set:c = pitonStyle Name.Class ,
- Name.Class .value_required:n = true ,
- Name.Builtin .tl_set:c = pitonStyle Name.Builtin ,
- Name.Builtin .value_required:n = true ,
- TypeParameter .tl_set:c = pitonStyle TypeParameter ,
- TypeParameter .value_required:n = true ,
- Name.Type .tl_set:c = pitonStyle Name.Type ,
- Name.Type .value_required:n = true ,
- Operator .tl_set:c = pitonStyle Operator ,
- Operator .value_required:n = true ,
- Operator.Word .tl_set:c = pitonStyle Operator.Word ,
- Operator.Word .value_required:n = true ,
- Exception .tl_set:c = pitonStyle Exception ,
- Exception .value_required:n = true ,
- Comment.LaTeX .tl_set:c = pitonStyle Comment.LaTeX ,
- Comment.LaTeX .value_required:n = true ,
- Identifier .tl_set:c = pitonStyle Identifier ,
- Comment.LaTeX .value_required:n = true ,
- ParseAgain.noCR .tl_set:c = pitonStyle ParseAgain.noCR ,
- ParseAgain.noCR .value_required:n = true ,
- ParseAgain .tl_set:c = pitonStyle ParseAgain ,
- ParseAgain .value_required:n = true ,
- Prompt .tl_set:c = pitonStyle Prompt ,
- Prompt .value_required:n = true ,
- unknown .code:n =
- \msg_error:nn { piton } { Unknown~key~for~SetPitonStyle }
- }
-% \end{macrocode}
-%
-%
-% \bigskip
-% \begin{macrocode}
-\msg_new:nnn { piton } { Unknown~key~for~SetPitonStyle }
- {
- The~style~'\l_keys_key_str'~is~unknown.\\
- This~key~will~be~ignored.\\
- The~available~styles~are~(in~alphabetic~order):~
- Comment,~
- Comment.LaTeX,~
- Dict.Value,~
- Exception,~
- Identifier,~
- InitialValues,~
- Keyword,~
- Keyword.Constant,~
- Name.Builtin,~
- Name.Class,~
- Name.Decorator,~
- Name.Function,~
- Name.Namespace,~
- Number,~
- Operator,~
- Operator.Word,~
- Prompt,~
- String,~
- String.Doc,~
- String.Long,~
- String.Short,~and~
- String.Interpol.
- }
-% \end{macrocode}
-%
-% \bigskip
-% \subsubsection{The initial style}
-%
-% The initial style is inspired by the style ``manni'' of Pygments.
-%
-% \medskip
-% \begin{macrocode}
-\SetPitonStyle
- {
- Comment = \color[HTML]{0099FF} \itshape ,
- Exception = \color[HTML]{CC0000} ,
- Keyword = \color[HTML]{006699} \bfseries ,
- Keyword.Constant = \color[HTML]{006699} \bfseries ,
- Name.Builtin = \color[HTML]{336666} ,
- Name.Decorator = \color[HTML]{9999FF},
- Name.Class = \color[HTML]{00AA88} \bfseries ,
- Name.Function = \color[HTML]{CC00FF} ,
- Name.Namespace = \color[HTML]{00CCFF} ,
- Number = \color[HTML]{FF6600} ,
- Operator = \color[HTML]{555555} ,
- Operator.Word = \bfseries ,
- String = \color[HTML]{CC3300} ,
- String.Doc = \color[HTML]{CC3300} \itshape ,
- String.Interpol = \color[HTML]{AA0000} ,
- Comment.LaTeX = \normalfont \color[rgb]{.468,.532,.6} ,
- Name.Type = \color[HTML]{336666} ,
- InitialValues = \@@_piton:n ,
- Dict.Value = \@@_piton:n ,
- Interpol.Inside = \color{black}\@@_piton:n ,
- TypeParameter = \color[HTML]{008800} \itshape ,
- Identifier = \@@_identifier:n ,
- Name.UserFunction = ,
- Prompt = ,
- ParseAgain.noCR = \@@_piton_no_cr:n ,
- ParseAgain = \@@_piton:n ,
- }
-% \end{macrocode}
-% The last styles |ParseAgain.noCR| and |ParseAgain| should be considered as
-% ``internal style'' (not available for the final user). However, maybe we will
-% change that and document these styles for the final user (why not?).
-%
-% \medskip
-% If the key |math-comments| has been used at load-time, we change the style
-% |Comment.Math| which should be considered only at an ``internal style''.
-% However, maybe we will document in a future version the possibility to write
-% change the style \emph{locally} in a document)].
-% \begin{macrocode}
-\bool_if:NT \c_@@_math_comments_bool { \SetPitonStyle { Comment.Math } }
-% \end{macrocode}
-%
-% \bigskip
-%
-% \bigskip
-% \subsubsection{Highlighting some identifiers}
-%
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_identifier:n #1
- { \cs_if_exist_use:c { PitonIdentifier _ \l_@@_language_str _ #1 } { #1 } }
-% \end{macrocode}
-%
-% \bigskip
-% \begin{macrocode}
-\keys_define:nn { PitonOptions }
- { identifiers .code:n = \@@_set_identifiers:n { #1 } }
-% \end{macrocode}
-%
-% \bigskip
-% \begin{macrocode}
-\keys_define:nn { Piton / identifiers }
- {
- names .clist_set:N = \l_@@_identifiers_names_tl ,
- style .tl_set:N = \l_@@_style_tl ,
- }
-% \end{macrocode}
-%
-% \bigskip
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_set_identifiers:n #1
- {
- \clist_clear_new:N \l_@@_identifiers_names_tl
- \tl_clear_new:N \l_@@_style_tl
- \keys_set:nn { Piton / identifiers } { #1 }
- \clist_map_inline:Nn \l_@@_identifiers_names_tl
- {
- \tl_set_eq:cN
- { PitonIdentifier _ \l_@@_language_str _ ##1 }
- \l_@@_style_tl
- }
- }
-% \end{macrocode}
-%
-%
-% \bigskip
-% In particular, we have an hightlighting of the indentifiers which are the
-% names of Python functions previously defined by the user. Indeed, when a
-% Python function is defined, the style |Name.Function.Internal| is applied to
-% that name. We define now that style (you define it directly and you short-cut
-% the function |\SetPitonStyle|).
-% \begin{macrocode}
-\cs_new_protected:cpn { pitonStyle Name.Function.Internal } #1
- {
-% \end{macrocode}
-% First, the element is composed in the TeX flow with the style |Name.Function|
-% which is provided to the final user.
-% \begin{macrocode}
- { \PitonStyle { Name.Function } { #1 } }
-% \end{macrocode}
-% Now, we specify that the name of the new Python function is a known identifier
-% that will be formated with the Piton style |Name.UserFunction|. Of course,
-% here the affectation is global because we have to exit many groups and even
-% the environments |{Piton}|).
-% \begin{macrocode}
- \cs_gset_protected:cpn { PitonIdentifier _ \l_@@_language_str _ #1 }
- { \PitonStyle{ Name.UserFunction } }
-% \end{macrocode}
-% Now, we put the name of that new user function in the dedicated sequence
-% (specific of the current language). That sequence will be used only by
-% |\PitonClearUserFunctions|.
-% \begin{macrocode}
- \seq_if_exist:cF { g_@@_functions _ \l_@@_language_str _ seq }
- { \seq_new:c { g_@@_functions _ \l_@@_language_str _ seq } }
- \seq_gput_right:cn { g_@@_functions _ \l_@@_language_str _ seq } { #1 }
- }
-% \end{macrocode}
-%
-% \bigskip
-% \begin{macrocode}
-\NewDocumentCommand \PitonClearUserFunctions { ! O { \l_@@_language_str } }
- {
- \seq_if_exist:cT { g_@@_functions _ #1 _ seq }
- {
- \seq_map_inline:cn { g_@@_functions _ #1 _ seq }
- { \cs_undefine:c { PitonIdentifier _ #1 _ ##1} }
- \seq_gclear:c { g_@@_functions _ #1 _ seq }
- }
- }
-% \end{macrocode}
-%
-% \bigskip
-% \subsubsection{Security}
-%
-% \begin{macrocode}
-\AddToHook { env / piton / begin }
- { \msg_fatal:nn { piton } { No~environment~piton } }
-
-\msg_new:nnn { piton } { No~environment~piton }
- {
- There~is~no~environment~piton!\\
- There~is~an~environment~{Piton}~and~a~command~
- \token_to_str:N \piton\ but~there~is~no~environment~
- {piton}.~This~error~is~fatal.
- }
-% \end{macrocode}
-%
-% \bigskip
-% \subsubsection{The error messages of the package}
-%
-% \begin{macrocode}
-\msg_new:nnnn { piton } { Unknown~key~for~PitonOptions }
- {
- Unknown~key. \\
- The~key~'\l_keys_key_str'~is~unknown~for~\token_to_str:N \PitonOptions.~
- It~will~be~ignored.\\
- For~a~list~of~the~available~keys,~type~H~<return>.
- }
- {
- The~available~keys~are~(in~alphabetic~order):~
- all-line-numbers,~
- auto-gobble,~
- background-color,~
- break-lines,~
- break-lines-in-piton,~
- break-lines-in-Piton,~
- continuation-symbol,~
- continuation-symbol-on-indentation,~
- end-of-broken-line,~
- env-gobble,~
- gobble,~
- identifiers,~
- indent-broken-lines,~
- language,~
- left-margin,~
- line-numbers,~
- prompt-background-color,~
- resume,~
- show-spaces,~
- show-spaces-in-strings,~
- slim,~
- splittable,~
- tabs-auto-gobble~
- and~tab-size.
- }
-% \end{macrocode}
-%
-% \bigskip
-% \begin{macrocode}
-\msg_new:nnn { piton } { label~with~lines~numbers }
- {
- You~can't~use~the~command~\token_to_str:N \label\
- because~the~key~'line-numbers'~(or~'all-line-numbers')~
- is~not~active.\\
- If~you~go~on,~that~command~will~ignored.
- }
-% \end{macrocode}
-%
-% \bigskip
-% \begin{macrocode}
-\msg_new:nnn { piton } { cr~not~allowed }
- {
- You~can't~put~any~carriage~return~in~the~argument~
- of~a~command~\c_backslash_str
- \l_@@_beamer_command_str\ within~an~
- environment~of~'piton'.~You~should~consider~using~the~
- corresponding~environment.\\
- That~error~is~fatal.
- }
-% \end{macrocode}
-%
-% \bigskip
-% \begin{macrocode}
-\msg_new:nnn { piton } { overlay~without~beamer }
- {
- You~can't~use~an~argument~<...>~for~your~command~
- \token_to_str:N \PitonInputFile\ because~you~are~not~
- in~Beamer.\\
- If~you~go~on,~that~argument~will~be~ignored.
- }
-% \end{macrocode}
-%
-% \bigskip
-% \begin{macrocode}
-\msg_new:nnn { Piton } { Python~error }
- { A~Python~error~has~been~detected. }
-% \end{macrocode}
-%
-% \bigskip
-% \subsection{The Lua part of the implementation}
-%
-% \bigskip
-% \begin{macrocode}
-\ExplSyntaxOff
-\RequirePackage{luacode}
-% \end{macrocode}
-%
-%
-% \bigskip
-% The Lua code will be loaded via a |{luacode*}| environment. The environment
-% is by itself a Lua block and the local declarations will be local to that
-% block. All the global functions (used by the L3 parts of the implementation)
-% will be put in a Lua table |piton|.
-%
-% \medskip
-% \begin{macrocode}
-\begin{luacode*}
-piton = piton or { }
-% \end{macrocode}
-%
-% \begin{macrocode}
-if piton.comment_latex == nil then piton.comment_latex = ">" end
-piton.comment_latex = "#" .. piton.comment_latex
-% \end{macrocode}
-%
-%
-% \bigskip
-% The following functions are an easy way to safely insert braces (|{| and |}|)
-% in the TeX flow.
-% \begin{macrocode}
-function piton.open_brace ()
- tex.sprint("{")
-end
-function piton.close_brace ()
- tex.sprint("}")
-end
-% \end{macrocode}
-%
-% \bigskip
-% \subsubsection{Special functions dealing with LPEG}
-%
-% \medskip
-% We will use the Lua library \pkg{lpeg} which is built in LuaTeX. That's why we
-% define first aliases for several functions of that library.
-% \begin{macrocode}
-local P, S, V, C, Ct, Cc = lpeg.P, lpeg.S, lpeg.V, lpeg.C, lpeg.Ct, lpeg.Cc
-local Cf, Cs , Cg , Cmt , Cb = lpeg.Cf, lpeg.Cs, lpeg.Cg , lpeg.Cmt , lpeg.Cb
-local R = lpeg.R
-% \end{macrocode}
-%
-%
-%
-% \bigskip
-% The function |Q| takes in as argument a pattern and returns a \textsc{lpeg}
-% \emph{which does a capture} of the pattern. That capture will be sent to LaTeX
-% with the catcode ``other'' for all the characters: it's suitable for elements
-% of the Python listings that \pkg{piton} will typeset verbatim (thanks to the
-% catcode ``other'').
-% \begin{macrocode}
-local function Q(pattern)
- return Ct ( Cc ( luatexbase.catcodetables.CatcodeTableOther ) * C ( pattern ) )
-end
-% \end{macrocode}
-%
-%
-% \bigskip
-% The function |L| takes in as argument a pattern and returns a \textsc{lpeg}
-% \emph{which does a capture} of the pattern. That capture will be sent to LaTeX
-% with standard LaTeX catcodes for all the characters: the elements captured
-% will be formatted as normal LaTeX codes. It's suitable for the ``LaTeX
-% comments'' in the environments |{Piton}| and the elements beetween
-% ``|escape-inside|''. That function won't be much used.
-% \begin{macrocode}
-local function L(pattern)
- return Ct ( C ( pattern ) )
-end
-% \end{macrocode}
-%
-% \bigskip
-% The function |Lc| (the c is for \emph{constant}) takes in as argument a string
-% and returns a \textsc{lpeg} \emph{with does a constant capture} which returns
-% that string. The elements captured will be formatted as L3 code. It will be
-% used to send to LaTeX all the formatting LaTeX instructions we have to insert
-% in order to do the syntactic highlighting (that's the main job of
-% \pkg{piton}). That function will be widely used.
-% \begin{macrocode}
-local function Lc(string)
- return Cc ( { luatexbase.catcodetables.expl , string } )
-end
-% \end{macrocode}
-%
-% \bigskip
-% The function |K| creates a \textsc{lpeg} which will return as capture the
-% whole LaTeX code corresponding to a Python chunk (that is to say with the
-% LaTeX formatting instructions corresponding to the syntactic nature of that
-% Python chunk). The first argument is a Lua string corresponding to the name of
-% a \pkg{piton} style and the second element is a pattern (that is to say a
-% \textsc{lpeg} without capture)
-% \begin{macrocode}
-local function K(style, pattern)
- return
- Lc ( "{\\PitonStyle{" .. style .. "}{" )
- * Q ( pattern )
- * Lc ( "}}" )
-end
-% \end{macrocode}
-% The formatting commands in a given \pkg{piton} style (eg. the style |Keyword|)
-% may be semi-global declarations (such as |\bfseries| or |\slshape|) or LaTeX
-% macros with an argument (such as |\fbox| or |\colorbox{yellow}|). In order to
-% deal with both syntaxes, we have used two pairs of braces:
-% |{\PitonStyle{Keyword}{|\texttt{\slshape text to format}|}}|.
-%
-%
-% \bigskip
-% \begin{macrocode}
-local function WithStyle(style,pattern)
- return
- Ct ( Cc "Open" * Cc ( "{\\PitonStyle{" .. style .. "}{" ) * Cc "}}" )
- * pattern
- * Ct ( Cc "Close" )
-end
-% \end{macrocode}
-%
-% \bigskip
-% The following \textsc{lpeg} catches the Python chunks which are in LaTeX
-% escapes (and that chunks will be considered as normal LaTeX constructions). We
-% recall that |piton.begin_espace| and |piton_end_escape| are Lua strings
-% corresponding to the key |escape-inside|\footnote{The \pkg{piton} key
-% |escape-inside| is available at load-time only.}. Since the elements that will
-% be catched must be sent to LaTeX with standard LaTeX catcodes, we put the
-% capture (done by the function |C|) in a table (by using |Ct|, which is an
-% alias for |lpeg.Ct|) without number of catcode table at the first component of
-% the table.
-% \begin{macrocode}
-local Escape =
- P(piton_begin_escape)
- * L ( ( 1 - P(piton_end_escape) ) ^ 1 )
- * P(piton_end_escape)
-% \end{macrocode}
-%
-% \vspace{1cm}
-% The following line is mandatory.
-% \begin{macrocode}
-lpeg.locale(lpeg)
-% \end{macrocode}
-%
-% \bigskip
-% \paragraph{The basic syntactic LPEG}
-%
-% \begin{macrocode}
-local alpha, digit = lpeg.alpha, lpeg.digit
-local space = P " "
-% \end{macrocode}
-%
-% Remember that, for \textsc{lpeg}, the Unicode characters such as |à|, |â|,
-% |ç|, etc. are in fact strings of length 2 (2 bytes) because \pkg{lpeg} is not
-% Unicode-aware.
-% \begin{macrocode}
-local letter = alpha + P "_"
- + P "â" + P "à" + P "ç" + P "é" + P "è" + P "ê" + P "ë" + P "ï" + P "î"
- + P "ô" + P "û" + P "ü" + P "Â" + P "À" + P "Ç" + P "É" + P "È" + P "Ê"
- + P "Ë" + P "Ï" + P "Î" + P "Ô" + P "Û" + P "Ü"
-
-local alphanum = letter + digit
-% \end{macrocode}
-%
-% \bigskip
-% The following \textsc{lpeg} |identifier| is a mere pattern (that is to say
-% more or less a regular expression) which matches the Python identifiers (hence
-% the name).
-% \begin{macrocode}
-local identifier = letter * alphanum ^ 0
-% \end{macrocode}
-%
-% \medskip
-% On the other hand, the \textsc{lpeg} |Identifier| (with a capital) also returns
-% a \emph{capture}.
-% \begin{macrocode}
-local Identifier = K ( 'Identifier' , identifier)
-% \end{macrocode}
-%
-% \bigskip
-% By convention, we will use names with an initial capital for \textsc{lpeg}
-% which return captures.
-%
-%
-% \bigskip
-% Here is the first use of our function~|K|. That function will be used to
-% construct \textsc{lpeg} which capture Python chunks for which we have a
-% dedicated \pkg{piton} style. For example, for the numbers, \pkg{piton}
-% provides a style which is called |Number|. The name of the style is provided
-% as a Lua string in the second argument of the function~|K|. By convention, we
-% use single quotes for delimiting the Lua strings which are names of
-% \pkg{piton} styles (but this is only a convention).
-% \begin{macrocode}
-local Number =
- K ( 'Number' ,
- ( digit^1 * P "." * digit^0 + digit^0 * P "." * digit^1 + digit^1 )
- * ( S "eE" * S "+-" ^ -1 * digit^1 ) ^ -1
- + digit^1
- )
-% \end{macrocode}
-%
-% \bigskip
-% We recall that |piton.begin_espace| and |piton_end_escape| are Lua strings
-% corresponding to the key |escape-inside|\footnote{The \pkg{piton} key
-% |escape-inside| is available at load-time only.}. Of course, if the final user
-% has not used the key |escape-inside|, these strings are empty.
-% \begin{macrocode}
-local Word
-if piton_begin_escape ~= ''
-then Word = Q ( ( ( 1 - space - P(piton_begin_escape) - P(piton_end_escape) )
- - S "'\"\r[()]" - digit ) ^ 1 )
-else Word = Q ( ( ( 1 - space ) - S "'\"\r[()]" - digit ) ^ 1 )
-end
-% \end{macrocode}
-%
-% \bigskip
-% \begin{macrocode}
-local Space = ( Q " " ) ^ 1
-
-local SkipSpace = ( Q " " ) ^ 0
-
-local Punct = Q ( S ".,:;!" )
-
-local Tab = P "\t" * Lc ( '\\l_@@_tab_tl' )
-% \end{macrocode}
-%
-% \bigskip
-% \begin{macrocode}
-local SpaceIndentation = Lc ( '\\@@_an_indentation_space:' ) * ( Q " " )
-% \end{macrocode}
-%
-%
-% \bigskip
-% \begin{macrocode}
-local Delim = Q ( S "[()]" )
-% \end{macrocode}
-%
-% \bigskip
-% The following \textsc{lpeg} catches a space (U+0020) and replace it by
-% |\l_@@_space_tl|. It will be used in the strings. Usually,
-% |\l_@@_space_tl| will contain a space and therefore there won't be difference.
-% However, when the key |show-spaces-in-strings| is in force, |\\l_@@_space_tl| will
-% contain ␣ (U+2423) in order to visualize the spaces.
-% \begin{macrocode}
-local VisualSpace = space * Lc "\\l_@@_space_tl"
-% \end{macrocode}
-%
-%
-% \bigskip
-% \subsubsection{The LPEG python}
-%
-% \bigskip
-% Some strings of length 2 are explicit because we want the corresponding
-% ligatures available in some fonts such as \emph{Fira Code} to be active.
-% \begin{macrocode}
-local Operator =
- K ( 'Operator' ,
- P "!=" + P "<>" + P "==" + P "<<" + P ">>" + P "<=" + P ">=" + P ":="
- + P "//" + P "**" + S "-~+/*%=<>&.@|"
- )
-
-local OperatorWord =
- K ( 'Operator.Word' ,P "in" + P "is" + P "and" + P "or" + P "not" )
-
-local Keyword =
- K ( 'Keyword' ,
- P "as" + P "assert" + P "break" + P "case" + P "class" + P "continue"
- + P "def" + P "del" + P "elif" + P "else" + P "except" + P "exec"
- + P "finally" + P "for" + P "from" + P "global" + P "if" + P "import"
- + P "lambda" + P "non local" + P "pass" + P "return" + P "try"
- + P "while" + P "with" + P "yield" + P "yield from" )
- + K ( 'Keyword.Constant' ,P "True" + P "False" + P "None" )
-
-local Builtin =
- K ( 'Name.Builtin' ,
- P "__import__" + P "abs" + P "all" + P "any" + P "bin" + P "bool"
- + P "bytearray" + P "bytes" + P "chr" + P "classmethod" + P "compile"
- + P "complex" + P "delattr" + P "dict" + P "dir" + P "divmod"
- + P "enumerate" + P "eval" + P "filter" + P "float" + P "format"
- + P "frozenset" + P "getattr" + P "globals" + P "hasattr" + P "hash"
- + P "hex" + P "id" + P "input" + P "int" + P "isinstance" + P "issubclass"
- + P "iter" + P "len" + P "list" + P "locals" + P "map" + P "max"
- + P "memoryview" + P "min" + P "next" + P "object" + P "oct" + P "open"
- + P "ord" + P "pow" + P "print" + P "property" + P "range" + P "repr"
- + P "reversed" + P "round" + P "set" + P "setattr" + P "slice" + P "sorted"
- + P "staticmethod" + P "str" + P "sum" + P "super" + P "tuple" + P "type"
- + P "vars" + P "zip" )
-
-
-local Exception =
- K ( 'Exception' ,
- P "ArithmeticError" + P "AssertionError" + P "AttributeError"
- + P "BaseException" + P "BufferError" + P "BytesWarning" + P "DeprecationWarning"
- + P "EOFError" + P "EnvironmentError" + P "Exception" + P "FloatingPointError"
- + P "FutureWarning" + P "GeneratorExit" + P "IOError" + P "ImportError"
- + P "ImportWarning" + P "IndentationError" + P "IndexError" + P "KeyError"
- + P "KeyboardInterrupt" + P "LookupError" + P "MemoryError" + P "NameError"
- + P "NotImplementedError" + P "OSError" + P "OverflowError"
- + P "PendingDeprecationWarning" + P "ReferenceError" + P "ResourceWarning"
- + P "RuntimeError" + P "RuntimeWarning" + P "StopIteration"
- + P "SyntaxError" + P "SyntaxWarning" + P "SystemError" + P "SystemExit"
- + P "TabError" + P "TypeError" + P "UnboundLocalError" + P "UnicodeDecodeError"
- + P "UnicodeEncodeError" + P "UnicodeError" + P "UnicodeTranslateError"
- + P "UnicodeWarning" + P "UserWarning" + P "ValueError" + P "VMSError"
- + P "Warning" + P "WindowsError" + P "ZeroDivisionError"
- + P "BlockingIOError" + P "ChildProcessError" + P "ConnectionError"
- + P "BrokenPipeError" + P "ConnectionAbortedError" + P "ConnectionRefusedError"
- + P "ConnectionResetError" + P "FileExistsError" + P "FileNotFoundError"
- + P "InterruptedError" + P "IsADirectoryError" + P "NotADirectoryError"
- + P "PermissionError" + P "ProcessLookupError" + P "TimeoutError"
- + P "StopAsyncIteration" + P "ModuleNotFoundError" + P "RecursionError" )
-
-
-local RaiseException = K ( 'Keyword' , P "raise" ) * SkipSpace * Exception * Q ( P "(" )
-
-% \end{macrocode}
-%
-% \bigskip
-% In Python, a ``decorator'' is a statement whose begins by |@| which patches
-% the function defined in the following statement.
-% \begin{macrocode}
-local Decorator = K ( 'Name.Decorator' , P "@" * letter^1 )
-% \end{macrocode}
-%
-% \bigskip
-% The following \textsc{lpeg} |DefClass| will be used to detect the definition of a
-% new class (the name of that new class will be formatted with the \pkg{piton}
-% style |Name.Class|).
-%
-% \smallskip
-% Example:\enskip \piton{class myclass:}
-% \begin{macrocode}
-local DefClass =
- K ( 'Keyword' , P "class" ) * Space * K ( 'Name.Class' , identifier )
-% \end{macrocode}
-%
-% If the word |class| is not followed by a identifier, it will be catched as
-% keyword by the \textsc{lpeg} |Keyword| (useful if we want to type a
-% list of keywords).
-%
-%
-% \bigskip
-% The following \textsc{lpeg} |ImportAs| is used for the lines beginning by |import|.
-% % We have to detect the potential keyword |as| because both the name of the
-% module and its alias must be formatted with the \pkg{piton} style |Name.Namespace|.
-%
-% \smallskip
-% Example:\enskip \piton{import numpy as np}
-%
-% \smallskip
-% Moreover, after the keyword |import|, it's possible to have a comma-separated
-% list of modules (if the keyword |as| is not used).
-%
-% \smallskip
-% Example:\enskip \piton{import math, numpy}
-% \begin{macrocode}
-local ImportAs =
- K ( 'Keyword' , P "import" )
- * Space
- * K ( 'Name.Namespace' ,
- identifier * ( P "." * identifier ) ^ 0 )
- * (
- ( Space * K ( 'Keyword' , P "as" ) * Space
- * K ( 'Name.Namespace' , identifier ) )
- +
- ( SkipSpace * Q ( P "," ) * SkipSpace
- * K ( 'Name.Namespace' , identifier ) ) ^ 0
- )
-% \end{macrocode}
-% Be careful: there is no commutativity of |+| in the previous expression.
-%
-% \bigskip
-% The \textsc{lpeg} |FromImport| is used for the lines beginning by |from|. We
-% need a special treatment because the identifier following the keyword |from|
-% must be formatted with the \pkg{piton} style |Name.Namespace| and the
-% following keyword |import| must be formatted with the \pkg{piton} style
-% |Keyword| and must \emph{not} be catched by the \textsc{lpeg} |ImportAs|.
-%
-% \smallskip
-% Example:\enskip \piton{from math import pi}
-%
-% \smallskip
-% \begin{macrocode}
-local FromImport =
- K ( 'Keyword' , P "from" )
- * Space * K ( 'Name.Namespace' , identifier )
- * Space * K ( 'Keyword' , P "import" )
-% \end{macrocode}
-%
-% \bigskip
-% \paragraph{The strings of Python}
-%
-% For the strings in Python, there are four categories of delimiters (without
-% counting the prefixes for f-strings and raw strings). We will use, in the
-% names of our \textsc{lpeg}, prefixes to distinguish the \textsc{lpeg} dealing
-% with that categories of strings, as presented in the following tabular.
-% \begin{center}
-% \begin{tabular}{ccc}
-% \toprule
-% & |Single| & |Double| \\
-% \midrule
-% |Short| & |'text'| & |"text"| \\
-% |Long| & |'''test'''| & |"""text"""| \\
-% \bottomrule
-% \end{tabular}
-% \end{center}
-%
-%
-% \bigskip
-% We have also to deal with the interpolations in the f-strings. Here
-% is an example of a f-string with an interpolation and a format
-% instruction\footnote{There is no special \pkg{piton} style for the formatting
-% instruction (after the colon): the style which will be applied will be the
-% style of the encompassing string, that is to say |String.Short| or
-% |String.Long|.} in that interpolation:
-%
-% \piton{f'Total price: {total+1:.2f} €'}
-%
-%
-% \bigskip
-% The interpolations beginning by |%| (even though there is more modern
-% technics now in Python).
-% \begin{macrocode}
-local PercentInterpol =
- K ( 'String.Interpol' ,
- P "%"
- * ( P "(" * alphanum ^ 1 * P ")" ) ^ -1
- * ( S "-#0 +" ) ^ 0
- * ( digit ^ 1 + P "*" ) ^ -1
- * ( P "." * ( digit ^ 1 + P "*" ) ) ^ -1
- * ( S "HlL" ) ^ -1
- * S "sdfFeExXorgiGauc%"
- )
-% \end{macrocode}
-%
-% \bigskip
-% We can now define the \textsc{lpeg} for the four kinds of strings. It's not
-% possible to use our function~|K| because of the interpolations which must be
-% formatted with another \pkg{piton} style that the rest of the
-% string.\footnote{The interpolations are formatted with the \pkg{piton} style
-% |Interpol.Inside|. The initial value of that style is \texttt{\textbackslash
-% @@\_piton:n} wich means that the interpolations are parsed once again by \pkg{piton}.}
-% \begin{macrocode}
-local SingleShortString =
- WithStyle ( 'String.Short' ,
-% \end{macrocode}
-% First, we deal with the f-strings of Python, which are prefixed by |f| or |F|.
-% \begin{macrocode}
- Q ( P "f'" + P "F'" )
- * (
- K ( 'String.Interpol' , P "{" )
- * K ( 'Interpol.Inside' , ( 1 - S "}':" ) ^ 0 )
- * Q ( P ":" * (1 - S "}:'") ^ 0 ) ^ -1
- * K ( 'String.Interpol' , P "}" )
- +
- VisualSpace
- +
- Q ( ( P "\\'" + P "{{" + P "}}" + 1 - S " {}'" ) ^ 1 )
- ) ^ 0
- * Q ( P "'" )
- +
-% \end{macrocode}
-% Now, we deal with the standard strings of Python, but also the ``raw strings''.
-% \begin{macrocode}
- Q ( P "'" + P "r'" + P "R'" )
- * ( Q ( ( P "\\'" + 1 - S " '\r%" ) ^ 1 )
- + VisualSpace
- + PercentInterpol
- + Q ( P "%" )
- ) ^ 0
- * Q ( P "'" ) )
-
-
-local DoubleShortString =
- WithStyle ( 'String.Short' ,
- Q ( P "f\"" + P "F\"" )
- * (
- K ( 'String.Interpol' , P "{" )
- * Q ( ( 1 - S "}\":" ) ^ 0 , 'Interpol.Inside' )
- * ( K ( 'String.Interpol' , P ":" ) * Q ( (1 - S "}:\"") ^ 0 ) ) ^ -1
- * K ( 'String.Interpol' , P "}" )
- +
- VisualSpace
- +
- Q ( ( P "\\\"" + P "{{" + P "}}" + 1 - S " {}\"" ) ^ 1 )
- ) ^ 0
- * Q ( P "\"" )
- +
- Q ( P "\"" + P "r\"" + P "R\"" )
- * ( Q ( ( P "\\\"" + 1 - S " \"\r%" ) ^ 1 )
- + VisualSpace
- + PercentInterpol
- + Q ( P "%" )
- ) ^ 0
- * Q ( P "\"" ) )
-
-local ShortString = SingleShortString + DoubleShortString
-% \end{macrocode}
-%
-% \bigskip
-% \paragraph{Beamer}
-%
-% The following \textsc{lpeg} |BalancedBraces| will be used for the (mandatory)
-% argument of the commands |\only| and \emph{al.} of Beamer. It's necessary to
-% use a \emph{grammar} because that pattern mainly checks the correct nesting of
-% the delimiters (and it's known in the theory of formal languages that this
-% can't be done with regular expressions \emph{stricto sensu} only).
-% \begin{macrocode}
-local BalancedBraces =
- P { "E" ,
- E =
- (
- P "{" * V "E" * P "}"
- +
- ShortString
- +
- ( 1 - S "{}" )
- ) ^ 0
- }
-% \end{macrocode}
-%
-%
-% \bigskip
-% If Beamer is used (or if the key |beamer| is used at load-time), the following
-% LPEG will be redefined.
-% \begin{macrocode}
-local Beamer = P ( false )
-local BeamerBeginEnvironments = P ( true )
-local BeamerEndEnvironments = P ( true )
-local BeamerNamesEnvironments =
- P "uncoverenv" + P "onlyenv" + P "visibleenv" + P "invisibleenv"
- + P "alertenv" + P "actionenv"
-
-% \end{macrocode}
-%
-% \begin{macrocode}
-UserCommands =
- Ct ( Cc "Open" * C ( "\\emph{" ) * Cc "}" )
- * ( C ( BalancedBraces ) / (function (s) return MainLoopPython:match(s) end ) )
- * P "}" * Ct ( Cc "Close" )
-% \end{macrocode}
-%
-% \begin{macrocode}
-function OneBeamerEnvironment(name)
- return
- Ct ( Cc "Open"
- * C (
- P ( "\\begin{" .. name .. "}" )
- * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1
- )
- * Cc ( "\\end{" .. name .. "}" )
- )
- * (
- C ( ( 1 - P ( "\\end{" .. name .. "}" ) ) ^ 0 )
- / (function (s) return MainLoopPython:match(s) end )
- )
- * P ( "\\end{" .. name .. "}" ) * Ct ( Cc "Close" )
-end
-% \end{macrocode}
-%
-%
-% \bigskip
-% \begin{macrocode}
-if piton_beamer
-then
- Beamer =
- L ( P "\\pause" * ( P "[" * (1 - P "]") ^ 0 * P "]" ) ^ -1 )
- +
- Ct ( Cc "Open"
- * C (
- (
- P "\\uncover" + P "\\only" + P "\\alert" + P "\\visible"
- + P "\\invisible" + P "\\action"
- )
- * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1
- * P "{"
- )
- * Cc "}"
- )
- * ( C ( BalancedBraces ) / (function (s) return MainLoopPython:match(s) end ) )
- * P "}" * Ct ( Cc "Close" )
- +
- OneBeamerEnvironment "uncoverenv"
- + OneBeamerEnvironment "onlyenv"
- + OneBeamerEnvironment "visibleenv"
- + OneBeamerEnvironment "invisibleenv"
- + OneBeamerEnvironment "alertenv"
- + OneBeamerEnvironment "actionenv"
- +
- L (
-% \end{macrocode}
-% For |\\alt|, the specification of the overlays (between angular brackets) is mandatory.
-% \begin{macrocode}
- ( P "\\alt" )
- * P "<" * (1 - P ">") ^ 0 * P ">"
- * P "{"
- )
- * K ( 'ParseAgain.noCR' , BalancedBraces )
- * L ( P "}{" )
- * K ( 'ParseAgain.noCR' , BalancedBraces )
- * L ( P "}" )
- +
- L (
-% \end{macrocode}
-% For |\\alt|, the specification of the overlays (between angular brackets) is mandatory.
-% \begin{macrocode}
- ( P "\\temporal" )
- * P "<" * (1 - P ">") ^ 0 * P ">"
- * P "{"
- )
- * K ( 'ParseAgain.noCR' , BalancedBraces )
- * L ( P "}{" )
- * K ( 'ParseAgain.noCR' , BalancedBraces )
- * L ( P "}{" )
- * K ( 'ParseAgain.noCR' , BalancedBraces )
- * L ( P "}" )
-% \end{macrocode}
-% Now for the environemnts.
-% \begin{macrocode}
- BeamerBeginEnvironments =
- ( space ^ 0 *
- L
- (
- P "\\begin{" * BeamerNamesEnvironments * "}"
- * ( P "<" * ( 1 - P ">") ^ 0 * P ">" ) ^ -1
- )
- * P "\r"
- ) ^ 0
- BeamerEndEnvironments =
- ( space ^ 0 *
- L ( P "\\end{" * BeamerNamesEnvironments * P "}" )
- * P "\r"
- ) ^ 0
-end
-% \end{macrocode}
-%
-% \bigskip
-% \paragraph{EOL}
-%
-% \bigskip
-% The following LPEG will detect the Python prompts when the user is typesetting
-% an interactive session of Python (directly or through |{pyconsole}| of
-% \pkg{pyluatex}). We have to detect that prompt twice. The first detection
-% (called \emph{hasty detection}) will be before the |\@@_begin_line:| because
-% you want to trigger a special background color for that row (and, after the
-% |\@@_begin_line:|, it's too late to change de background).
-% \begin{macrocode}
-local PromptHastyDetection = ( # ( P ">>>" + P "..." ) * Lc ( '\\@@_prompt:' ) ) ^ -1
-% \end{macrocode}
-% We remind that the marker |#| of \textsc{lpeg} specifies that the pattern will be
-% detected but won't consume any character.
-%
-% \medskip
-% With the following \textsc{lpeg}, a style will actually be applied to the
-% prompt (for instance, it's possible to decide to discard these prompts).
-% \begin{macrocode}
-local Prompt = K ( 'Prompt' , ( ( P ">>>" + P "..." ) * P " " ^ -1 ) ^ -1 )
-% \end{macrocode}
-%
-%
-%
-% \bigskip
-% The following \textsc{lpeg} |EOL| is for the end of lines.
-% \begin{macrocode}
-local EOL =
- P "\r"
- *
- (
- ( space^0 * -1 )
- +
-% \end{macrocode}
-% We recall that each line in the Python code we have to parse will be sent
-% back to LaTeX between a pair |\@@_begin_line:| --
-% |\@@_end_line:|\footnote{Remember that the \texttt{\textbackslash
-% @@\_end\_line:} must be explicit because it will be used as marker in order to
-% delimit the argument of the command \texttt{\textbackslash @@\_begin\_line:}}.
-% \begin{macrocode}
- Ct (
- Cc "EOL"
- *
- Ct (
- Lc "\\@@_end_line:"
- * BeamerEndEnvironments
- * BeamerBeginEnvironments
- * PromptHastyDetection
- * Lc "\\@@_newline: \\@@_begin_line:"
- * Prompt
- )
- )
- )
- *
- SpaceIndentation ^ 0
-% \end{macrocode}
-%
-%
-% \bigskip
-% \paragraph{The long strings}
-%
-%
-% \begin{macrocode}
-local SingleLongString =
- WithStyle ( 'String.Long' ,
- ( Q ( S "fF" * P "'''" )
- * (
- K ( 'String.Interpol' , P "{" )
- * K ( 'Interpol.Inside' , ( 1 - S "}:\r" - P "'''" ) ^ 0 )
- * Q ( P ":" * (1 - S "}:\r" - P "'''" ) ^ 0 ) ^ -1
- * K ( 'String.Interpol' , P "}" )
- +
- Q ( ( 1 - P "'''" - S "{}'\r" ) ^ 1 )
- +
- EOL
- ) ^ 0
- +
- Q ( ( S "rR" ) ^ -1 * P "'''" )
- * (
- Q ( ( 1 - P "'''" - S "\r%" ) ^ 1 )
- +
- PercentInterpol
- +
- P "%"
- +
- EOL
- ) ^ 0
- )
- * Q ( P "'''" ) )
-
-
-local DoubleLongString =
- WithStyle ( 'String.Long' ,
- (
- Q ( S "fF" * P "\"\"\"" )
- * (
- K ( 'String.Interpol', P "{" )
- * K ( 'Interpol.Inside' , ( 1 - S "}:\r" - P "\"\"\"" ) ^ 0 )
- * Q ( P ":" * (1 - S "}:\r" - P "\"\"\"" ) ^ 0 ) ^ -1
- * K ( 'String.Interpol' , P "}" )
- +
- Q ( ( 1 - P "\"\"\"" - S "{}\"\r" ) ^ 1 )
- +
- EOL
- ) ^ 0
- +
- Q ( ( S "rR" ) ^ -1 * P "\"\"\"" )
- * (
- Q ( ( 1 - P "\"\"\"" - S "%\r" ) ^ 1 )
- +
- PercentInterpol
- +
- P "%"
- +
- EOL
- ) ^ 0
- )
- * Q ( P "\"\"\"" )
- )
-% \end{macrocode}
-%
-% \begin{macrocode}
-local LongString = SingleLongString + DoubleLongString
-% \end{macrocode}
-%
-% \bigskip
-% We have a \textsc{lpeg} for the Python docstrings. That \textsc{lpeg} will
-% be used in the \textsc{lpeg} |DefFunction| which deals with the whole preamble
-% of a function definition (which begins with |def|).
-% \begin{macrocode}
-local StringDoc =
- K ( 'String.Doc' , P "\"\"\"" )
- * ( K ( 'String.Doc' , (1 - P "\"\"\"" - P "\r" ) ^ 0 ) * EOL
- * Tab ^ 0
- ) ^ 0
- * K ( 'String.Doc' , ( 1 - P "\"\"\"" - P "\r" ) ^ 0 * P "\"\"\"" )
-% \end{macrocode}
-%
-% \bigskip
-% \paragraph{The comments in the Python listings}
-%
-% We define different \textsc{lpeg} dealing with comments in the Python
-% listings.
-% \begin{macrocode}
-local CommentMath =
- P "$" * K ( 'Comment.Math' , ( 1 - S "$\r" ) ^ 1 ) * P "$"
-
-local Comment =
- WithStyle ( 'Comment' ,
- Q ( P "#" )
- * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0 )
- * ( EOL + -1 )
-% \end{macrocode}
-%
-%
-%
-% \bigskip
-% The following \textsc{lpeg} |CommentLaTeX| is for what is called in that
-% document the ``LaTeX comments''. Since the elements that will be catched must
-% be sent to LaTeX with standard LaTeX catcodes, we put the capture (done by
-% the function~|C|) in a table (by using~|Ct|, which is an alias for |lpeg.Ct|).
-% \begin{macrocode}
-local CommentLaTeX =
- P(piton.comment_latex)
- * Lc "{\\PitonStyle{Comment.LaTeX}{\\ignorespaces"
- * L ( ( 1 - P "\r" ) ^ 0 )
- * Lc "}}"
- * ( EOL + -1 ) -- you could put EOL instead of EOL
-% \end{macrocode}
-%
-% \bigskip
-% \paragraph{DefFunction}
-%
-% The following \textsc{lpeg} |Expression| will be used for the parameters in
-% the \emph{argspec} of a Python function. It's necessary to use a \emph{grammar}
-% because that pattern mainly checks the correct nesting of the delimiters
-% (and it's known in the theory of formal languages that this can't be done with
-% regular expressions \emph{stricto sensu} only).
-% \begin{macrocode}
-local Expression =
- P { "E" ,
- E = ( 1 - S "{}()[]\r," ) ^ 0
- * (
- ( P "{" * V "F" * P "}"
- + P "(" * V "F" * P ")"
- + P "[" * V "F" * P "]" ) * ( 1 - S "{}()[]\r," ) ^ 0
- ) ^ 0 ,
- F = ( 1 - S "{}()[]\r\"'" ) ^ 0
- * ( (
- P "'" * (P "\\'" + 1 - S"'\r" )^0 * P "'"
- + P "\"" * (P "\\\"" + 1 - S"\"\r" )^0 * P "\""
- + P "{" * V "F" * P "}"
- + P "(" * V "F" * P ")"
- + P "[" * V "F" * P "]"
- ) * ( 1 - S "{}()[]\r\"'" ) ^ 0 ) ^ 0 ,
- }
-% \end{macrocode}
-%
-% \bigskip
-% We will now define a \textsc{lpeg} |Params| that will catch the list of
-% parameters (that is to say the \emph{argspec}) in the definition of a Python
-% function. For example, in the line of code
-% \begin{center}
-% \piton{def MyFunction(a,b,x=10,n:int): return n}
-% \end{center}
-% the \textsc{lpeg} |Params| will be used to catch the chunk\enskip |a,b,x=10,n:int|.
-%
-% Or course, a |Params| is simply a comma-separated list of |Param|, and that's
-% why we define first the \textsc{lpeg} |Param|.
-%
-% \medskip
-% \begin{macrocode}
-local Param =
- SkipSpace * Identifier * SkipSpace
- * (
- K ( 'InitialValues' , P "=" * Expression )
- + Q ( P ":" ) * SkipSpace * K ( 'Name.Type' , letter^1 )
- ) ^ -1
-% \end{macrocode}
-%
-% \medskip
-% \begin{macrocode}
-local Params = ( Param * ( Q "," * Param ) ^ 0 ) ^ -1
-% \end{macrocode}
-%
-% \bigskip
-% The following \textsc{lpeg} |DefFunction| catches a keyword |def| and the
-% following name of function \emph{but also everything else until a potential
-% docstring}. That's why this definition of \textsc{lpeg} must occur (in the file
-% |piton.sty|) after the definition of several other \textsc{lpeg} such as
-% |Comment|, |CommentLaTeX|, |Params|, |StringDoc|...
-% \begin{macrocode}
-local DefFunction =
- K ( 'Keyword' , P "def" )
- * Space
- * K ( 'Name.Function.Internal' , identifier )
- * SkipSpace
- * Q ( P "(" ) * Params * Q ( P ")" )
- * SkipSpace
- * ( Q ( P "->" ) * SkipSpace * K ( 'Name.Type' , identifier ) ) ^ -1
-% \end{macrocode}
-% Here, we need a \pkg{piton} style |ParseAgain| which will be linked to
-% |\@@_piton:n| (that means that the capture will be parsed once again by
-% \pkg{piton}). We could avoid that kind of trick by using a non-terminal of a
-% grammar but we have probably here a better legibility.
-% \begin{macrocode}
- * K ( 'ParseAgain' , ( 1 - S ":\r" )^0 )
- * Q ( P ":" )
- * ( SkipSpace
- * ( EOL + CommentLaTeX + Comment ) -- in all cases, that contains an EOL
- * Tab ^ 0
- * SkipSpace
- * StringDoc ^ 0 -- there may be additionnal docstrings
- ) ^ -1
-% \end{macrocode}
-% Remark that, in the previous code, |CommentLaTeX| \emph{must} appear
-% before |Comment|: there is no commutativity of the addition for the
-% \emph{parsing expression grammars} (\textsc{peg}).
-%
-% \smallskip
-% If the word |def| is not followed by an identifier and parenthesis, it will be
-% catched as keyword by the \textsc{lpeg} |Keyword| (useful if, for example, the
-% final user wants to speak of the keyword \piton{def}).
-%
-% \bigskip
-% \paragraph{The dictionaries of Python}
-%
-% We have \textsc{lpeg} dealing with dictionaries of Python because, in
-% typesettings of explicit Python dictionaries, one may prefer to have all the
-% values formatted in black (in order to see more clearly the keys which are
-% usually Python strings). That's why we have a \pkg{piton} style |Dict.Value|.
-%
-% The initial value of that \pkg{piton} style is |\@@_piton:n|, which means that
-% the value of the entry of the dictionary is parsed once again by \pkg{piton}
-% (and nothing special is done for the dictionary). In the following example, we
-% have set the \pkg{piton} style |Dict.Value| to |\color{black}|:
-%
-% \medskip
-% \begingroup
-% \SetPitonStyle{Dict.Value = \color{black}}
-% \piton{mydict = { 'name' : 'Paul', 'sex' : 'male', 'age' : 31 } }
-% \endgroup
-%
-% \medskip
-% At this time, this mechanism works only for explicit dictionaries on a single line!
-%
-% \begin{macrocode}
-local ItemDict =
- ShortString * SkipSpace * Q ( P ":" ) * K ( 'Dict.Value' , Expression )
-
-local ItemOfSet = SkipSpace * ( ItemDict + ShortString ) * SkipSpace
-
-local Set =
- Q ( P "{" )
- * ItemOfSet * ( Q ( P "," ) * ItemOfSet ) ^ 0
- * Q ( P "}" )
-% \end{macrocode}
-%
-% \paragraph{Miscellaneous}
-%
-% \begin{macrocode}
-local ExceptionInConsole = Exception * Q ( ( 1 - P "\r" ) ^ 0 ) * EOL
-% \end{macrocode}
-%
-%
-% \bigskip
-% \paragraph{The main LPEG}
-%
-% First, the main loop :
-% \begin{macrocode}
-MainLoopPython =
- ( ( space^1 * -1 )
- + EOL
- + Space
- + Tab
- + Escape
- + CommentLaTeX
- + Beamer
- + UserCommands
- + LongString
- + Comment
- + ExceptionInConsole
- + Set
- + Delim
-% \end{macrocode}
-% |Operator| must be before |Punct|.
-% \begin{macrocode}
- + Operator
- + ShortString
- + Punct
- + FromImport
- + RaiseException
- + DefFunction
- + DefClass
- + Keyword * ( Space + Punct + Delim + EOL+ -1 )
- + Decorator
- + OperatorWord * ( Space + Punct + Delim + EOL+ -1 )
- + Builtin * ( Space + Punct + Delim + EOL+ -1 )
- + Identifier
- + Number
- + Word
- ) ^ 0
-% \end{macrocode}
-%
-% \bigskip
-% We recall that each line in the Python code to parse will be sent back to
-% LaTeX between a pair |\@@_begin_line:| -- |\@@_end_line:|\footnote{Remember
-% that the \texttt{\textbackslash @@\_end\_line:} must be explicit because it
-% will be used as marker in order to delimit the argument of the command
-% \texttt{\textbackslash @@\_begin\_line:}}.
-% \begin{macrocode}
-local python = P ( true )
-
-python =
- Ct (
- ( ( space - P "\r" ) ^0 * P "\r" ) ^ -1
- * BeamerBeginEnvironments
- * PromptHastyDetection
- * Lc '\\@@_begin_line:'
- * Prompt
- * SpaceIndentation ^ 0
- * MainLoopPython
- * -1
- * Lc '\\@@_end_line:'
- )
-% \end{macrocode}
-%
-% \begin{macrocode}
-local languages = { }
-languages['python'] = python
-% \end{macrocode}
-%
-% % \bigskip
-% \subsubsection{The LPEG ocaml}
-%
-% \begin{macrocode}
-local Delim = Q ( P "[|" + P "|]" + S "[()]" )
-% \end{macrocode}
-%
-% \begin{macrocode}
-local Punct = Q ( S ",:;!" )
-% \end{macrocode}
-%
-% \begin{macrocode}
-local identifier =
- ( R "az" + R "AZ" + P "_") * ( R "az" + R "AZ" + S "_'" + digit ) ^ 0
-
-local Identifier = K ( 'Identifier' , identifier )
-
-local Operator =
- K ( 'Operator' ,
- P "!=" + P "<>" + P "==" + P "<<" + P ">>" + P "<=" + P ">=" + P ":="
- + P "||" + P "&&" + P "//" + P "**" + P ";;" + P "::" + P "->"
- + P "+." + P "-." + P "*." + P "/."
- + S "-~+/*%=<>&@|"
- )
-
-local OperatorWord =
- K ( 'Operator.Word' ,
- P "and" + P "asr" + P "land" + P "lor" + P "lsl" + P "lxor"
- + P "mod" + P "or" )
-
-local Keyword =
- K ( 'Keyword' ,
- P "as" + P "assert" + P "begin" + P "class" + P "constraint" + P "done"
- + P "do" + P "downto" + P "else" + P "end" + P "exception" + P "external"
- + P "false" + P "for" + P "function" + P "fun" + P "functor" + P "if"
- + P "in" + P "include" + P "inherit" + P "initializer" + P "lazy" + P "let"
- + P "match" + P "method" + P "module" + P "mutable" + P "new" + P "object"
- + P "of" + P "open" + P "private" + P "raise" + P "rec" + P "sig"
- + P "struct" + P "then" + P "to" + P "true" + P "try" + P "type"
- + P "value" + P "val" + P "virtual" + P "when" + P "while" + P "with" )
- + K ( 'Keyword.Constant' , P "true" + P "false" )
-
-
-local Builtin =
- K ( 'Name.Builtin' ,
- P "not" + P "incr" + P "decr" + P "fst" + P "snd"
- + P "String.length"
- + P "List.tl" + P "List.hd" + P "List.mem" + P "List.exists"
- + P "List.for_all" + P "List.filter" + P "List.length" + P "List.map"
- + P "List.iter"
- + P "Array.length" + P "Array.make" + P "Array.make_matrix"
- + P "Array.init" + P "Array.copy" + P "Array.copy" + P "Array.mem"
- + P "Array.exists" + P "Array.for_all" + P "Array.map" + P "Array.iter"
- + P "Queue.create" + P "Queue.is_empty" + P "Queue.push" + P "Queue.pop"
- + P "Stack.create" + P "Stack.is_empty" + P "Stack.push" + P "Stack.pop"
- + P "Hashtbl.create" + P "Hashtbl.add" + P "Hashtbl.remove"
- + P "Hashtbl.mem" + P "Hashtbl.find" + P "Hashtbl.find_opt"
- + P "Hashtbl.iter" )
-% \end{macrocode}
-%
-% \bigskip
-% The following exceptions are exceptions in the standard library of OCaml (Stdlib).
-% \begin{macrocode}
-local Exception =
- K ( 'Exception' ,
- P "Division_by_zero" + P "End_of_File" + P "Failure"
- + P "Invalid_argument" + P "Match_failure" + P "Not_found"
- + P "Out_of_memory" + P "Stack_overflow" + P "Sys_blocked_io"
- + P "Sys_error" + P "Undefined_recursive_module" )
-% \end{macrocode}
-%
-% \bigskip
-% \paragraph{The characters in OCaml}
-%
-% \begin{macrocode}
-local Char =
- K ( 'String.Short' , P "'" * ( ( 1 - P "'" ) ^ 0 + P "\\'" ) * P "'" )
-% \end{macrocode}
-%
-%
-% \bigskip
-% \paragraph{Beamer}
-%
-% \begin{macrocode}
-local BalancedBraces =
- P { "E" ,
- E =
- (
- P "{" * V "E" * P "}"
- +
- P "\"" * ( 1 - S "\"" ) ^ 0 * P "\"" -- OCaml strings
- +
- ( 1 - S "{}" )
- ) ^ 0
- }
-% \end{macrocode}
-%
-%
-% \begin{macrocode}
-if piton_beamer
-then
- Beamer =
- L ( P "\\pause" * ( P "[" * (1 - P "]") ^ 0 * P "]" ) ^ -1 )
- +
- ( P "\\uncover" * Lc ( '\\@@_beamer_command:n{uncover}' )
- + P "\\only" * Lc ( '\\@@_beamer_command:n{only}' )
- + P "\\alert" * Lc ( '\\@@_beamer_command:n{alert}' )
- + P "\\visible" * Lc ( '\\@@_beamer_command:n{visible}' )
- + P "\\invisible" * Lc ( '\\@@_beamer_command:n{invisible}' )
- + P "\\action" * Lc ( '\\@@_beamer_command:n{action}' )
- )
- *
- L ( ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1 * P "{" )
- * K ( 'ParseAgain.noCR' , BalancedBraces )
- * L ( P "}" )
- +
- L (
- ( P "\\alt" )
- * P "<" * (1 - P ">") ^ 0 * P ">"
- * P "{"
- )
- * K ( 'ParseAgain.noCR' , BalancedBraces )
- * L ( P "}{" )
- * K ( 'ParseAgain.noCR' , BalancedBraces )
- * L ( P "}" )
- +
- L (
- ( P "\\temporal" )
- * P "<" * (1 - P ">") ^ 0 * P ">"
- * P "{"
- )
- * K ( 'ParseAgain.noCR' , BalancedBraces )
- * L ( P "}{" )
- * K ( 'ParseAgain.noCR' , BalancedBraces )
- * L ( P "}{" )
- * K ( 'ParseAgain.noCR' , BalancedBraces )
- * L ( P "}" )
- BeamerBeginEnvironments =
- ( space ^ 0 *
- L
- (
- P "\\begin{" * BeamerNamesEnvironments * "}"
- * ( P "<" * ( 1 - P ">") ^ 0 * P ">" ) ^ -1
- )
- * P "\r"
- ) ^ 0
- BeamerEndEnvironments =
- ( space ^ 0 *
- L ( P "\\end{" * BeamerNamesEnvironments * P "}" )
- * P "\r"
- ) ^ 0
-end
-% \end{macrocode}
-%
-% \bigskip
-% \paragraph{EOL}
-% \begin{macrocode}
-local EOL =
- P "\r"
- *
- (
- ( space^0 * -1 )
- +
- Ct (
- Cc "EOL"
- *
- Ct (
- Lc "\\@@_end_line:"
- * BeamerEndEnvironments
- * BeamerBeginEnvironments
- * PromptHastyDetection
- * Lc "\\@@_newline: \\@@_begin_line:"
- * Prompt
- )
- )
- )
- *
- SpaceIndentation ^ 0
-% \end{macrocode}
-%
-%
-% \begin{macrocode}
-%
-% \paragraph{The strings}
-%
-% We need a pattern |string| without captures because it will be used within the
-% comments of OCaml.
-% \begin{macrocode}
-local string =
- Q ( P "\"" )
- * (
- VisualSpace
- +
- Q ( ( 1 - S " \"\r" ) ^ 1 )
- +
- EOL
- ) ^ 0
- * Q ( P "\"" )
-% \end{macrocode}
-%
-% \begin{macrocode}
-local String = WithStyle ( 'String.Long' , string )
-% \end{macrocode}
-%
-%
-% \bigskip
-% Now, the ``quoted strings'' of OCaml (for example \verb+{ext|Essai|ext}+).
-%
-% For those strings, we will do two consecutive analysis. First an analysis to
-% determine the whole string and, then, an analysis for the potential visual
-% spaces and the EOL in the string.
-%
-% The first analysis require a match-time capture. For explanations about that
-% programmation, see the paragraphe \emph{Lua's long % strings} in
-% |www.inf.puc-rio.br/~roberto/lpeg|.
-% \begin{macrocode}
-local ext = ( R "az" + P "_" ) ^ 0
-local open = "{" * Cg(ext, 'init') * "|"
-local close = "|" * C(ext) * "}"
-local closeeq =
- Cmt ( close * Cb('init'),
- function (s, i, a, b) return a==b end )
-% \end{macrocode}
-%
-% \medskip
-% The \textsc{lpeg} |QuotedStringBis| will do the second analysis.
-% \begin{macrocode}
-local QuotedStringBis =
- WithStyle ( 'String.Long' ,
- (
- VisualSpace
- +
- Q ( ( 1 - S " \r" ) ^ 1 )
- +
- EOL
- ) ^ 0 )
-
-% \end{macrocode}
-%
-% \medskip
-% We use a ``function capture'' (as called in the official documentation of the
-% \textsc{lpeg}) in order to do the second analysis on the result of the first one.
-% \begin{macrocode}
-local QuotedString =
- C ( open * ( 1 - closeeq ) ^ 0 * close ) /
- ( function (s) return QuotedStringBis : match(s) end )
-% \end{macrocode}
-%
-%
-% \bigskip
-% \paragraph{The comments in the OCaml listings}
-%
-% In OCaml, the delimiters for the comments are |(*| and |*)|. There are
-% unsymmetrical and, therefore, the comments may be nested. That's why we need a
-% grammar.
-%
-% In these comments, we embed the math comments (between |$| and |$|) and we
-% embed also a treatment for the end of lines (since the comments may be multi-lines).
-%
-% \begin{macrocode}
-local Comment =
- WithStyle ( 'Comment' ,
- P {
- "A" ,
- A = Q "(*"
- * ( V "A"
- + Q ( ( 1 - P "(*" - P "*)" - S "\r$\"" ) ^ 1 ) -- $
- + string
- + P "$" * K ( 'Comment.Math' , ( 1 - S "$\r" ) ^ 1 ) * P "$" -- $
- + EOL
- ) ^ 0
- * Q "*)"
- } )
-% \end{macrocode}
-%
-% \bigskip
-% \paragraph{The DefFunction}
-%
-% \begin{macrocode}
-local DefFunction =
- K ( 'Keyword' , P "let rec" + P "let" + P "and" )
- * Space
- * K ( 'Name.Function.Internal' , identifier )
- * Space
- * # ( P "=" * space * P "function" + ( 1 - P "=" ) )
-% \end{macrocode}
-%
-% \bigskip
-% \paragraph{The parameters of the types}
-%
-% \begin{macrocode}
-local TypeParameter = K ( 'TypeParameter' , P "'" * alpha * # ( 1 - P "'" ) )
-% \end{macrocode}
-%
-% \bigskip
-% \paragraph{The main LPEG}
-%
-% First, the main loop :
-% \begin{macrocode}
-MainLoopOCaml =
- ( ( space^1 * -1 )
- + EOL
- + Space
- + Tab
- + Escape
- + Beamer
- + TypeParameter
- + String + QuotedString + Char
- + Comment
- + Delim
- + Operator
- + Punct
- + FromImport
- + ImportAs
- + Exception
- + DefFunction
- + Keyword * ( Space + Punct + Delim + EOL + -1 )
- + OperatorWord * ( Space + Punct + Delim + EOL + -1 )
- + Builtin * ( Space + Punct + Delim + EOL + -1 )
- + Identifier
- + Number
- + Word
- ) ^ 0
-% \end{macrocode}
-%
-% \bigskip
-% We recall that each line in the Python code to parse will be sent back to
-% LaTeX between a pair |\@@_begin_line:| -- |\@@_end_line:|\footnote{Remember
-% that the \texttt{\textbackslash @@\_end\_line:} must be explicit because it
-% will be used as marker in order to delimit the argument of the command
-% \texttt{\textbackslash @@\_begin\_line:}}.
-% \begin{macrocode}
-local ocaml = P ( true )
-
-ocaml =
- Ct (
- ( ( space - P "\r" ) ^0 * P "\r" ) ^ -1
- * BeamerBeginEnvironments
- * Lc ( '\\@@_begin_line:' )
- * SpaceIndentation ^ 0
- * MainLoopOCaml
- * -1
- * Lc ( '\\@@_end_line:' )
- )
-% \end{macrocode}
-%
-% \begin{macrocode}
-languages['ocaml'] = ocaml
-% \end{macrocode}
-%
-% \bigskip
-% \subsubsection{The function Parse}
-%
-%
-% The function |Parse| is the main function of the package \pkg{piton}.
-% It parses its argument and sends back to LaTeX the code with interlaced
-% formatting LaTeX instructions. In fact, everything is done by the
-% \textsc{lpeg} |python| which returns as capture a Lua table containing
-% data to send to LaTeX.
-%
-% \bigskip
-% \begin{macrocode}
-function piton.Parse(language,code)
- local t = languages[language] : match ( code )
- local left_stack = {}
- local right_stack = {}
- for _ , one_item in ipairs(t)
- do
- if one_item[1] == "EOL"
- then
- for _ , s in ipairs(right_stack)
- do tex.sprint( s )
- end
- for _ , s in ipairs(one_item[2])
- do tex.tprint(s)
- end
- for _ , s in ipairs(left_stack)
- do tex.sprint( s )
- end
- else
- if one_item[1] == "Open"
- then
- tex.sprint( one_item[2] )
- table.insert(left_stack,one_item[2])
- table.insert(right_stack,one_item[3])
- else
- if one_item[1] == "Close"
- then
- tex.sprint( right_stack[#right_stack] )
- left_stack[#left_stack] = nil
- right_stack[#right_stack] = nil
- else
- tex.tprint(one_item)
- end
- end
- end
- end
-end
-% \end{macrocode}
-%
-%
-%
-% \bigskip
-% The function |ParseFile| will be used by the LaTeX command |\PitonInputFile|.
-% That function merely reads the whole file (that is to say all its lines) and
-% then apply the function~|Parse| to the resulting Lua string.
-% \begin{macrocode}
-function piton.ParseFile(language,name,first_line,last_line)
- s = ''
- local i = 0
- for line in io.lines(name)
- do i = i + 1
- if i >= first_line
- then s = s .. '\r' .. line
- end
- if i >= last_line then break end
- end
- piton.Parse(language,s)
-end
-% \end{macrocode}
-%
-% \bigskip
-% \subsubsection{Two variants of the function Parse with integrated preprocessors}
-%
-% The following command will be used by the user command |\piton|.
-% For that command, we have to undo the duplication of the symbols |#|.
-% \begin{macrocode}
-function piton.ParseBis(language,code)
- local s = ( Cs ( ( P '##' / '#' + 1 ) ^ 0 ) ) : match ( code )
- return piton.Parse(language,s)
-end
-% \end{macrocode}
-%
-% \bigskip
-% The following command will be used when we have to parse some small chunks of
-% code that have yet been parsed. They are re-scanned by LaTeX because it has
-% been required by |\@@_piton:n| in the \pkg{piton} style of the syntaxic
-% element. In that case, you have to remove the potential |\@@_breakable_space:|
-% that have been inserted when the key |break-lines| is in force.
-% \begin{macrocode}
-function piton.ParseTer(language,code)
- local s = ( Cs ( ( P '\\@@_breakable_space:' / ' ' + 1 ) ^ 0 ) )
- : match ( code )
- return piton.Parse(language,s)
-end
-% \end{macrocode}
-%
-%
-% \bigskip
-% \subsubsection{Preprocessors of the function Parse for gobble}
-%
-% We deal now with preprocessors of the function |Parse| which are needed when
-% the ``gobble mechanism'' is used.
-%
-%
-% \bigskip
-% The function |gobble| gobbles $n$ characters on the left of the code. It uses
-% a \textsc{lpeg} that we have to compute dynamically because if depends on the
-% value of~$n$.
-% \begin{macrocode}
-local function gobble(n,code)
- function concat(acc,new_value)
- return acc .. new_value
- end
- if n==0
- then return code
- else
- return Cf (
- Cc ( "" ) *
- ( 1 - P "\r" ) ^ (-n) * C ( ( 1 - P "\r" ) ^ 0 )
- * ( C ( P "\r" )
- * ( 1 - P "\r" ) ^ (-n)
- * C ( ( 1 - P "\r" ) ^ 0 )
- ) ^ 0 ,
- concat
- ) : match ( code )
- end
-end
-% \end{macrocode}
-%
-%
-%
-% \bigskip
-% The following function |add| will be used in the following \textsc{lpeg}
-% |AutoGobbleLPEG|, |TabsAutoGobbleLPEG| and |EnvGobbleLPEG|.
-% \begin{macrocode}
-local function add(acc,new_value)
- return acc + new_value
-end
-% \end{macrocode}
-%
-% \bigskip
-% The following \textsc{lpeg} returns as capture the minimal number of spaces at
-% the beginning of the lines of code. The main work is done by two \emph{fold
-% captures} (|lpeg.Cf|), one using |add| and the other (encompassing the
-% previous one) using |math.min| as folding operator.
-% \begin{macrocode}
-local AutoGobbleLPEG =
- ( space ^ 0 * P "\r" ) ^ -1
- * Cf (
- (
-% \end{macrocode}
-% We don't take into account the empty lines (with only spaces).
-% \begin{macrocode}
- ( P " " ) ^ 0 * P "\r"
- +
- Cf ( Cc(0) * ( P " " * Cc(1) ) ^ 0 , add )
- * ( 1 - P " " ) * ( 1 - P "\r" ) ^ 0 * P "\r"
- ) ^ 0
-% \end{macrocode}
-% Now for the last line of the Python code...
-% \begin{macrocode}
- *
- ( Cf ( Cc(0) * ( P " " * Cc(1) ) ^ 0 , add )
- * ( 1 - P " " ) * ( 1 - P "\r" ) ^ 0 ) ^ -1 ,
- math.min
- )
-% \end{macrocode}
-%
-% \bigskip
-% The following \textsc{lpeg} is similar but works with the indentations.
-% \begin{macrocode}
-local TabsAutoGobbleLPEG =
- ( space ^ 0 * P "\r" ) ^ -1
- * Cf (
- (
- ( P "\t" ) ^ 0 * P "\r"
- +
- Cf ( Cc(0) * ( P "\t" * Cc(1) ) ^ 0 , add )
- * ( 1 - P "\t" ) * ( 1 - P "\r" ) ^ 0 * P "\r"
- ) ^ 0
- *
- ( Cf ( Cc(0) * ( P "\t" * Cc(1) ) ^ 0 , add )
- * ( 1 - P "\t" ) * ( 1 - P "\r" ) ^ 0 ) ^ -1 ,
- math.min
- )
-% \end{macrocode}
-%
-%
-%
-% \bigskip
-% The following \textsc{lpeg} returns as capture the number of spaces at the
-% last line, that is to say before the |\end{Piton}| (and usually it's also the
-% number of spaces before the corresponding |\begin{Piton}| because that's the
-% traditionnal way to indent in LaTeX). The main work is done by a \emph{fold
-% capture} (|lpeg.Cf|) using the function |add| as folding operator.
-% \begin{macrocode}
-local EnvGobbleLPEG =
- ( ( 1 - P "\r" ) ^ 0 * P "\r" ) ^ 0
- * Cf ( Cc(0) * ( P " " * Cc(1) ) ^ 0 , add ) * -1
-% \end{macrocode}
-%
-% \bigskip
-% \begin{macrocode}
-function piton.GobbleParse(language,n,code)
- if n==-1
- then n = AutoGobbleLPEG : match(code)
- else if n==-2
- then n = EnvGobbleLPEG : match(code)
- else if n==-3
- then n = TabsAutoGobbleLPEG : match(code)
- end
- end
- end
- piton.Parse(language,gobble(n,code))
-end
-% \end{macrocode}
-%
-% \bigskip
-% \subsubsection{To count the number of lines}
-%
-% \medskip
-% \begin{macrocode}
-function piton.CountLines(code)
- local count = 0
- for i in code : gmatch ( "\r" ) do count = count + 1 end
- tex.sprint(
- luatexbase.catcodetables.expl ,
- '\\int_set:Nn \\l_@@_nb_lines_int {' .. count .. '}' )
-end
-% \end{macrocode}
-%
-% \begin{macrocode}
-function piton.CountNonEmptyLines(code)
- local count = 0
- count =
- ( Cf ( Cc(0) *
- (
- ( P " " ) ^ 0 * P "\r"
- + ( 1 - P "\r" ) ^ 0 * P "\r" * Cc(1)
- ) ^ 0
- * (1 - P "\r" ) ^ 0 ,
- add
- ) * -1 ) : match (code)
- tex.sprint(
- luatexbase.catcodetables.expl ,
- '\\int_set:Nn \\l_@@_nb_non_empty_lines_int {' .. count .. '}' )
-end
-% \end{macrocode}
-%
-% \bigskip
-% \begin{macrocode}
-function piton.CountLinesFile(name)
- local count = 0
- for line in io.lines(name) do count = count + 1 end
- tex.sprint(
- luatexbase.catcodetables.expl ,
- '\\int_set:Nn \\l_@@_nb_lines_int {' .. count .. '}' )
-end
-% \end{macrocode}
-%
-%
-% \bigskip
-% \begin{macrocode}
-function piton.CountNonEmptyLinesFile(name)
- local count = 0
- for line in io.lines(name)
- do if not ( ( ( P " " ) ^ 0 * -1 ) : match ( line ) )
- then count = count + 1
- end
- end
- tex.sprint(
- luatexbase.catcodetables.expl ,
- '\\int_set:Nn \\l_@@_nb_non_empty_lines_int {' .. count .. '}' )
-end
-% \end{macrocode}
-%
-% \begin{macrocode}
-\end{luacode*}
-% \end{macrocode}
-%
-%
-% \vspace{1cm}
-% \section{History}
-%
-% The successive versions of the file |piton.sty| provided by TeXLive are available on the
-% \textsc{svn} server of TeXLive:\par\nobreak
-%
-% \smallskip
-% {
-% \small
-% \nolinkurl{https://tug.org/svn/texlive/trunk/Master/texmf-dist/tex/lualatex/piton/piton.sty}
-% }
-%
-% % \subsection*{Changes between versions 1.4 and 1.5}
-%
-% New key |numbers-sep|.
-%
-%
-% \subsection*{Changes between versions 1.3 and 1.4}
-%
-% New key |identifiers| in |\PitonOptions|.
-%
-% New command |\PitonStyle|.
-%
-% |background-color| now accepts as value a \emph{list} of colors.
-%
-% \subsection*{Changes between versions 1.2 and 1.3}
-%
-% When the class Beamer is used, the environment |{Piton}| and the command
-% |\PitonInputFile| are ``overlay-aware'' (that is to say, they accept a
-% specification of overlays between angular brackets).
-%
-% New key |prompt-background-color|
-%
-% It's now possible to use the command |\label| to reference a line of code in
-% an environment |{Piton}|.
-%
-% A new command |\|␣ is available in the argument of the command |\piton{...}| to
-% insert a space (otherwise, several spaces are replaced by a single space).
-%
-% \subsection*{Changes between versions 1.1 and 1.2}
-%
-% New keys |break-lines-in-piton| and |break-lines-in-Piton|.
-%
-% New key |show-spaces-in-string| and modification of the key |show-spaces|.
-%
-% When the class \cls{beamer} is used, the environements |{uncoverenv}|,
-% |{onlyenv}|, |{visibleenv}| and |{invisibleenv}|
-%
-%
-% \subsection*{Changes between versions 1.0 and 1.1}
-%
-% The extension \pkg{piton} detects the class \cls{beamer} and activates the
-% commands |\action|, |\alert|, |\invisible|, |\only|, |\uncover| and |\visible|
-% in the environments |{Piton}| when the class \cls{beamer} is used.
-%
-% \subsection*{Changes between versions 0.99 and 1.0}
-%
-% New key |tabs-auto-gobble|.
-%
-% \subsection*{Changes between versions 0.95 and 0.99}
-%
-% New key |break-lines| to allow breaks of the lines of code (and other keys to
-% customize the appearance).
-%
-% \subsection*{Changes between versions 0.9 and 0.95}
-%
-% New key |show-spaces|.
-%
-% The key |left-margin| now accepts the special value |auto|.
-%
-% New key |latex-comment| at load-time and replacement of |##| by |#>|
-%
-% New key |math-comments| at load-time.
-%
-% New keys |first-line| and |last-line| for the command |\InputPitonFile|.
-%
-% \subsection*{Changes between versions 0.8 and 0.9}
-%
-% New key |tab-size|.
-%
-% Integer value for the key |splittable|.
-%
-% \subsection*{Changes between versions 0.7 and 0.8}
-%
-% New keys |footnote| and |footnotehyper| at load-time.
-%
-% New key |left-margin|.
-%
-% \subsection*{Changes between versions 0.6 and 0.7}
-%
-% New keys |resume|, |splittable| and |background-color| in |\PitonOptions|.
-%
-% The file |piton.lua| has been embedded in the file |piton.sty|. That means
-% that the extension \pkg{piton} is now entirely contained in the file |piton.sty|.
-%
-%
-%
-% \tableofcontents
-%
-% \end{document}
-%
-%
-% Local Variables:
-% TeX-fold-mode: t
-% TeX-fold-preserve-comments: nil
-% flyspell-mode: nil
-% fill-column: 80
-% End:
-
-
-
-
-
-
+% \iffalse -*- coding: utf-8 ; -*- \fi \iffalse meta-comment +% +% Copyright (C) 2023 by F. Pantigny +% ----------------------------------- +% +% This file may be distributed and/or modified under the +% conditions of the LaTeX Project Public License, either version 1.3 +% of this license or (at your option) any later version. +% The latest version of this license is in: +% +% http://www.latex-project.org/lppl.txt +% +% and version 1.3 or later is part of all distributions of LaTeX +% version 2005/12/01 or later. +% +% \fi +% \iffalse +\def\myfileversion{1.6} +\def\myfiledate{2023/05/03} +% +% +%<*batchfile> +\begingroup +\input l3docstrip.tex +\keepsilent +\usedir{tex/latex/cascade} +\preamble + +Copyright (C) 2022-2023 by F. Pantigny +----------------------------------- + +This file may be distributed and/or modified under the +conditions of the LaTeX Project Public License, either version 1.3 +of this license or (at your option) any later version. +The latest version of this license is in: + +http://www.latex-project.org/lppl.txt + +and version 1.3 or later is part of all distributions of LaTeX +version 2005/12/01 or later. + +\endpreamble +\askforoverwritefalse +\endgroup +%</batchfile> +% +%<@@=piton> +%<*driver> +\documentclass{l3doc} +\usepackage{geometry} +\geometry{left=2.8cm,right=2.8cm,top=2.5cm,bottom=2.5cm,papersize={21cm,29.7cm}} +\usepackage{fontspec} +\usepackage[dvipsnames]{xcolor} +\usepackage{caption,tabularx,tcolorbox,luacolor,lua-ul} +\def\emphase{\bgroup\color{RoyalPurple}\let\next=} +\fvset{commandchars=\~\#\@,formatcom=\color{gray}} +\captionsetup{labelfont = bf} +\usepackage{ragged2e} +\usepackage[footnotehyper,escape-inside=$$,math-comments]{piton} % $$ + +\parindent 0pt +\skip\footins = 2\bigskipamount + +\PitonOptions{gobble=2} + +\EnableCrossrefs + +\begin{document} +\DocInput{piton.dtx} +\end{document} +%</driver> +% \fi +% +% \catcode`\" = 11 +% +% \title{The package \pkg{piton}\thanks{This document corresponds to the +% version~\myfileversion\space of \pkg{piton}, at the date of~\myfiledate.}} +% \author{F. Pantigny \\ \texttt{fpantigny@wanadoo.fr}} +% +% \maketitle +% +% \begin{abstract} +% The package \pkg{piton} provides tools to typeset Python listings with +% syntactic highlighting by using the Lua library LPEG. It requires LuaLaTeX. +% \end{abstract} +% +% +% +% \section{Presentation} +% +% +% The package \pkg{piton} uses the Lua library LPEG\footnote{LPEG is a +% pattern-matching library for Lua, written in C, based on \emph{parsing +% expression grammars}: \url{http://www.inf.puc-rio.br/~roberto/lpeg/}} for +% parsing Python listings and typeset them with syntactic highlighting. Since it +% uses Lua code, it works with |lualatex| only (and won't work with the other +% engines: |latex|, |pdflatex| and |xelatex|). It does not use external program +% and the compilation does not require |--shell-escape|. The compilation is very +% fast since all the parsing is done by the library LPEG, written in C. +% +% \bigskip +% Here is an example of code typeset by \pkg{piton}, with the environment |{Piton}|. +% +% \bigskip +% +% \begin{Piton} +% from math import pi +% +% def arctan(x,n=10): +% """Compute the mathematical value of arctan(x) +% +% n is the number of terms in the sum +% """ +% if x < 0: +% return -arctan(-x) # recursive call +% elif x > 1: +% return pi/2 - arctan(1/x) +% #> (we have used that $\arctan(x)+\arctan(1/x)=\frac{\pi}{2}$ for $x>0$)\footnote{This LaTeX escape has been done by beginning the comment by \ttfamily\#>.} +% else: +% s = 0 +% for k in range(n): +% s += (-1)**k/(2*k+1)*x**(2*k+1) +% return s +% \end{Piton} +% +% +% \bigskip +% The package \pkg{piton} is entirely contained in the file +% |piton.sty|. This file may be put in the current directory or in a +% |texmf| tree. However, the best is to install \pkg{piton} with a TeX +% distribution such as MiKTeX, TeX Live or MacTeX. +% +% +% \section{Use of the package} +% +% +% \subsection{Loading the package} +% +% The package \pkg{piton} should be loaded with the classical command +% |\usepackage|: |\usepackage{piton}|. +% +% \smallskip +% Nevertheless, we have two remarks: +% \begin{itemize} +% \item the package \pkg{piton} uses the package \pkg{xcolor} (but \pkg{piton} +% does \emph{not} load \pkg{xcolor}: if \pkg{xcolor} is not loaded before the +% |\begin{document}|, a fatal error will be raised). +% \item the package \pkg{piton} must be used with LuaLaTeX exclusively: if +% another LaTeX engine (|latex|, |pdflatex|, |xelatex|,\dots ) is used, a +% fatal error will be raised. +% \end{itemize} +% +% \subsection{The tools provided to the user} +% +% The package \pkg{piton} provides several tools to typeset Python code: the +% command |\piton|, the environment |{Piton}| and the command |\PitonInputFile|. +% +% \begin{itemize}\setlength{\fboxsep}{1pt} +% \item The command \colorbox{gray!20}{\texttt\textbackslash piton} should be +% used to typeset small pieces of code inside a paragraph. For example: +% +% {\color{gray}\verb|\piton{def square(x): return x*x}|}\qquad +% \piton{def square(x): return x*x} +% +% The syntax and particularities of the command |\piton| are detailed below. +% +% \item The environment \colorbox{gray!20}{\ttfamily\{Piton\}} should be used to +% typeset multi-lines code. Since it takes its argument in a verbatim mode, it +% can't be used within the argument of a LaTeX command. For sake of +% customization, it's possible to define new environments similar to the +% environment |{Piton}| with the command |\NewPitonEnvironment|: +% cf.~\ref{NewPitonEnvironment} p.~\pageref{NewPitonEnvironment}. +% +% \item The command \colorbox{gray!20}{\ttfamily\textbackslash PitonInputFile} +% is used to insert and typeset a whole external file. +% +% That command takes in as optional argument (between square brackets) two keys +% |first-line| and |last-line|: only the part between the corresponding lines +% will be inserted. +% \end{itemize} +% +% \subsection{The syntax of the command \textbackslash piton} +% +% In fact, the command |\piton| is provided with a double syntax. It may be used +% as a standard command of LaTeX taking its argument between curly braces +% (|\piton{...}|) but it may also be used with a syntax similar to the syntax of +% the command +% |\verb|, that is to say with the argument delimited by two identical characters (e.g.: \verb!\piton|...|!). +% +% \begin{itemize} +% \item {\color{blue} \textsf{Syntax} \verb|\piton{...}|}\par\nobreak +% When its argument is given between curly braces, the command |\piton| does not +% take its argument in verbatim mode. In particular: +% \begin{itemize} +% \item several consecutive spaces will be replaced by only one space, +% +% {\color{cyan} but the command |\|␣ is provided to force the insertion of a space}; +% +% \item it's not possible to use |%| inside the argument, +% +% {\color{cyan} but the command |\%| is provided to insert a |%|}; +% +% \item the braces must be appear by pairs correctly nested +% +% {\color{cyan} but the commands |\{| and |\}| are also provided for individual braces}; +% +% \item the LaTeX commands\footnote{That concerns the commands beginning with a +% backslash but also the active characters (with catcode equal to 13).} are +% fully expanded and not executed, +% +% {\color{cyan} so it's possible to use |\\| to insert a backslash}. +% \end{itemize} +% +% +% The other characters (including |#|, |^|, |_|, |&|, |$| and |@|) +% must be inserted without backslash. +% +% \bigskip +%\begin{tabular}{>{\color{gray}}w{l}{75mm}@{\hspace*{1cm}}l} +% \omit Examples : \hfil \\ +% \noalign{\vskip1mm} +% \verb|\piton{MyString = '\\n'}| & +% \piton{MyString = '\\n'} \\ +% \verb|\piton{def even(n): return n\%2==0}| & +% \piton{def even(n): return n\%2==0} \\ +% \verb|\piton{c="#" # an affectation }| & +% \piton{c="#" # an affectation } \\ +% \verb|\piton{c="#" \ \ \ # an affectation }| & +% \piton{c="#" \ \ \ # an affectation } \\ +% \verb|\piton{MyDict = {'a': 3, 'b': 4 }}| & +% \piton{MyDict = {'a': 3, 'b': 4 }} +% \end{tabular} +% +% \bigskip +% It's possible to use the command |\piton| in the arguments of a +% LaTeX command.\footnote{For example, it's possible to use the command +% \texttt{\textbackslash piton} in a footnote. Example : +% \piton{s = 'A string'}.} +% +% \bigskip +% \item {\color{blue} \textsf{Syntaxe} \verb!\piton|...|!}\par\nobreak +% +% When the argument of the command |\piton| is provided between two identical +% characters, that argument is taken in a \emph{verbatim mode}. Therefore, with +% that syntax, the command |\piton| can't be used within the argument of another +% command. +% +% \medskip +% +% \begin{tabular}{>{\color{gray}}w{l}{75mm}@{\hspace*{1cm}}l} +% \omit Examples : \hfil \\ +% \noalign{\vskip1mm} +% \verb!\piton|MyString = '\n'|! & +% \piton|MyString = '\n'| \\ +% \verb|\piton!def even(n): return n%2==0!| & +% \piton!def even(n): return n%2==0! \\ +% \verb|\piton+c="#" # an affectation +| & +% \piton+c="#" # an affectation + \\ +% \verb|\piton?MyDict = {'a': 3, 'b': 4}?| & +% \piton!MyDict = {'a': 3, 'b': 4}! +% \end{tabular} +% +% \end{itemize} +% +% \section{Customization} +% +% \subsection{The command \textbackslash PitonOptions} +% +% +% \NewDocumentCommand{\Definition}{m} +% {{\setlength{\fboxsep}{1pt}\colorbox{gray!20}{\ttfamily \vphantom{gl}#1}}} +% +% The command |\PitonOptions| takes in as argument a comma-separated list of +% \textsl{key=value} pairs. The scope of the settings done by that command is +% the current TeX group.\footnote{We remind that a LaTeX environment is, in +% particular, a TeX group.} +% +% \begin{itemize} +% \item The key \Definition{gobble} takes in as value a +% positive integer~$n$: the first $n$ characters are discarded (before the +% process of highlightning of the code) for each line of the environment +% |{Piton}|. These characters are not necessarily spaces. +% +% \item When the key \Definition{auto-gobble} is in force, the +% extension \pkg{piton} computes the minimal value $n$ of the number of +% consecutive spaces beginning each (non empty) line of the environment +% |{Piton}| and applies |gobble| with that value of~$n$. +% +% \item When the key \Definition{env-gobble} is in force, \pkg{piton} analyzes the last +% line of the environment |{Piton}|, that is to say the line which contains +% |\end{Piton}| and determines whether that line contains only spaces followed +% by the |\end{Piton}|. If we are in that situation, \pkg{piton} computes the +% number~$n$ of spaces on that line and applies |gobble| with that value of~$n$. +% The name of that key comes from \emph{environment gobble}: the effect of +% gobble is set by the position of the commands |\begin{Piton}| and +% |\end{Piton}| which delimit the current environment. +% +% \item With the key \Definition{line-numbers}, the \emph{non empty} lines (and +% all the lines of the \emph{docstrings}, even the empty ones) are numbered in +% the environments |{Piton}| and in the listings resulting from the use of +% |\PitonInputFile|. +% +% \item With the key \Definition{all-line-numbers}, \emph{all} the lines are numbered, +% including the empty ones. +% +% \item \colorbox{yellow!50}{\bfseries{New 1.5}}\par\nobreak +% +% The key \Definition{numbers-sep} is the horizontal distance between the +% numbers of lines (inserted by |line-numbers| of |all-line-numbers|) and the +% beginning of the lines of code. The initial value is 0.7~em. +% +% \item With the key \Definition{resume}, the counter of lines is not set to zero +% at the beginning of each environment |{Piton}| or use of |\PitonInputFile| as +% it is otherwise. That allows a numbering of the lines across several +% environments. +% +% \item The key \Definition{left-margin} corresponds to a margin on the left. +% That key may be useful in conjonction with the key |line-numbers| or the key +% |line-all-numbers| if one does not want the numbers in an overlapping position +% on the left. +% +% It's possible to use the key |left-margin| with the value |auto|. With that +% value, if the key |line-numbers| or the key |all-line-numbers| is used, a +% margin will be automatically inserted to fit the numbers of lines. See an +% example part \ref{example-numbering} on page~\pageref{example-numbering}. +% +% \item The key \Definition{background-color} sets the background color of the +% environments |{Piton}| and the listings produced by |\PitonInputFile| (it's +% possible to fix the width of that background with the key |width| described +% below). +% +% \smallskip +% The key |background-color| supports also as value a \emph{list} of colors. In +% this case, the successive rows are colored by using the colors of the list in +% a cyclic way. +% +% \emph{Example} : |\PitonOptions{background-color = {gray!5,white}}| +% +% The key |background-color| accepts a color defined «on the fly». For example, +% it's possible to write |background-color = [cmyk]{0.1,0.05,0,0}|. +% +% \item With the key \Definition{prompt-background-color}, \pkg{piton} adds a +% color background to the lines beginning with the prompt ``|>>>|'' (and its +% continuation ``|...|'') characteristic of the Python consoles with +% \textsc{repl} (\emph{read-eval-print loop}). +% +% \item \colorbox{yellow!50}{\textbf{New 1.6}}\enskip The key |width| will fix +% the width of the listing. That width applies to the colored backgrounds +% specified by |background-color| and |prompt-background-color| but also for the +% automatic breaking of the lines (when required by |break-lines|: +% cf.~\ref{line-breaks}, p.~\pageref{line-breaks}). +% +% That key may take in as value a numeric value but also the special +% value~|min|. With that value, the width will be computed from the maximal +% width of the lines of code. Caution: the special value~|min| requires two +% compilations with LuaLaTeX\footnote{The maximal width is computed during the +% first compilation, written on the |aux| file and re-used during the second +% compilation. Several tools such as |latexmk| (used by Overleaf) do +% automatically a sufficient number of compilations.}. +% +% For an example of use of |width=min|, see the section~\ref{example-comments}, +% p.~\pageref{example-comments}. +% +% +% \item When the key \Definition{show-spaces-in-strings} is activated, the +% spaces in the short strings (that is to say those delimited by |'| or |"|) are +% replaced by the character~␣ (U+2423 : \textsc{open box}). Of course, that +% character~U+2423 must be present in the monospaced font which is +% used.\footnote{The package \pkg{piton} simply uses the current monospaced +% font. The best way to change that font is to use the command +% \texttt{\textbackslash setmonofont} of the package \pkg{fontspec}.}\par\nobreak +% \begingroup \PitonOptions{show-spaces-in-strings} Example : +% \piton|my_string = 'Very good answer'| \endgroup +% +% With the key \Definition{show-spaces}, all the spaces are replaced by U+2423 +% (and no line break can occur on those ``visible spaces'', even when the key +% |break-lines|\footnote{cf. \ref{line-breaks} p.~\pageref{line-breaks}} is in +% force). +% \end{itemize} +% +% \bigskip +% +% \begingroup +% \fvset{commandchars=\~\&\@,formatcom=\small\color{gray}} +% \begin{Verbatim} +% ~emphase&\PitonOptions{line-numbers,auto-gobble,background-color = gray!15}@ +% \begin{Piton} +% from math import pi +% def arctan(x,n=10): +% """Compute the mathematical value of arctan(x) +% +% n is the number of terms in the sum +% """ +% if x < 0: +% return -arctan(-x) # recursive call +% elif x > 1: +% return pi/2 - arctan(1/x) +% #> (we have used that $\arctan(x)+\arctan(1/x)=\frac{\pi}{2}$ pour $x>0$) +% else +% s = 0 +% for k in range(n): +% s += (-1)**k/(2*k+1)*x**(2*k+1) +% return s +% \end{Piton} +% \end{Verbatim} +% \endgroup +% +% \begingroup +% \PitonOptions{line-numbers,background-color = gray!15} +% \begin{Piton} +% from math import pi +% +% def arctan(x,n=10): +% """Compute the mathematical value of arctan(x) +% +% n is the number of terms in the sum +% """ +% if x < 0: +% return -arctan(-x) # recursive call +% elif x > 1: +% return pi/2 - arctan(1/x) +% #> (we have used that $\arctan(x)+\arctan(1/x)=\frac{\pi}{2}$ for $x>0$) +% else +% s = 0 +% for k in range(n): +% s += (-1)**k/(2*k+1)*x**(2*k+1) +% return s +% \end{Piton} +% \endgroup +% +% \bigskip +% The command |\PitonOptions| provides in fact several other keys which will be +% described further (see in particular the ``Pages breaks and line breaks'' +% p.~\pageref{breakable}). +% +% \subsection{The styles} +% +% \label{styles} +% +% The package \pkg{piton} provides the command |\SetPitonStyle| to customize the +% different styles used to format the syntactic elements of the Python listings. +% The customizations done by that command are limited to the current TeX +% group.\footnote{We remind that a LaTeX environment is, in particular, a TeX group.} +% +% \bigskip +% The command |\SetPitonStyle| takes in as argument a comma-separated list of +% \textsl{key=value} pairs. The keys are names of styles and the value are LaTeX +% formatting instructions. +% +% \bigskip +% These LaTeX instructions must be formatting instructions such as +% |\color{...}|, |\bfseries|, |\slshape|, etc. (the commands of this kind are +% sometimes called \emph{semi-global} commands). It's also possible to put, +% \emph{at the end of the list of instructions}, a LaTeX command taking exactly +% one argument. +% +% \bigskip +% Here an example which changes the style used to highlight, in the definition +% of a Python function, the name of the function which is defined. That code +% uses the command |\highLight| of \pkg{lua-ul} (that package requires also the +% package \pkg{luacolor}). +% +% \begin{verbatim} +% \SetPitonStyle{ Name.Function = \bfseries \highLight[red!50] } +% \end{verbatim} +% +% In that example, |\highLight[red!50]| must be considered as the name of a +% LaTeX command which takes in exactly one argument, since, usually, it is used +% with |\highLight[red!50]{...}|. +% +% \medskip +% \begingroup +% \SetPitonStyle +% { Name.Function = \bfseries \highLight[red!50] } +% With that setting, we will have : \piton{def cube(x) : return x * x * x } +% \endgroup +% +% \bigskip +% The different styles are described in the table \ref{Semantic}. The initial +% settings done by \pkg{piton} in |piton.sty| are inspired by the style +% \pkg{manni} de Pygments.\footnote{See: +% \url{https://pygments.org/styles/}. Remark that, by default, Pygments provides for its style \pkg{manni} a colored background whose color is the HTML color \texttt{\#F0F3F3}. It's possible to have the same color in \texttt{\{Pion\}} with the instruction \texttt{\textbackslash PitonOptions\{background-color = [HTML]\{F0F3F3\}\}}.} +% +% \bigskip +% The command |\PitonStyle| takes in as argument the name of a style and allows +% to retrieve the value (as a list of LaTeX instructions) of that style. +% +% \smallskip +% For example, it's possible to write |{\PitonStyle{Keyword}{function}}| and we +% will have the word {\PitonStyle{Keyword}{function}} formatted as a keyword. +% +% \smallskip +% The syntax |{\PitonStyle{|\textsl{\texttt{style}}|}{...}}| is mandatory in +% order to be able to deal both with the semi-global commands and the commands +% with arguments which may be present in the definition of the style +% \texttt{\textsl{style}}. +% +% \begin{table}[b] +% \centering +% \caption{Usage of the different styles} +% \label{Semantic} +% \begin{tabular}{@{}>{\ttfamily}l>{\RaggedRight\arraybackslash}p{9cm}@{}} +% \toprule +% \normalfont Style & Usage \\ +% \midrule +% Number & the numbers \\ +% String.Short & the short strings (between \texttt{'} or \verb|"|) \\ +% String.Long & the long strings (between \texttt{'''} or \verb|"""|) except the +% documentation strings \\ +% String & that keys sets both |String.Short| and |String.Long| \\ +% String.Doc & the documentation strings (only between \texttt{"""} following +% PEP~257) \\ +% String.Interpol & the syntactic elements of the fields of the f-strings (that +% is to say the characters \texttt{\{} and \texttt{\}}) \\ +% Operator & the following operators : \texttt{!= == << >> - \~{} + / * \% = < > \& .} \verb+|+ \verb|@|\\ +% Operator.Word & the following operators : \texttt{in}, \texttt{is}, +% \texttt{and}, \texttt{or} and \texttt{not} \\ +% Name.Builtin & the predefined functions of Python \\ +% Name.Function & the name of the functions defined by the user, at the point of +% their definition (that is to say after the keyword |def|) \\ +% Name.Decorator & the decorators (instructions beginning by \verb|@|) \\ +% Name.Namespace & the name of the modules (= external libraries) \\ +% Name.Class & the name of the classes at the point of their definition (that is +% to say after the keyword |class|) \\ +% Exception & the names of the exceptions (eg: \texttt{SyntaxError}) \\ +% Comment & the comments beginning with \verb|#| \\ +% Comment.LaTeX & the comments beginning by \verb|#>|, which are composed in LaTeX by +% \pkg{piton} (and simply called ``LaTeX comments'' in this document) \\ +% Keyword.Constant & |True|, |False| and |None| \\ +% Keyword & the following keywords : +% \ttfamily as, assert, break, case, continue, def, del, +% elif, else, except, exec, finally, for, from, +% global, if, import, lambda, non local, +% pass, raise, return, try, while, +% with, yield, yield from.\\ +% \bottomrule +% \end{tabular} +% \end{table} +% +% +% \vspace{1cm} \colorbox{yellow!50}{\textbf{New 1.6}}\par\nobreak +% +% The extension \pkg{piton} provides a special style called~|UserFunction|. That +% style applies to the names of the functions previously defined by the user via +% an instruction Python \piton{def} in one of the previous listings. The initial +% value of that style is empty, and, therefore, the names of the functions are +% formatted as standard text (in black). However, it's possible to change the +% value of that style, as any other style, with the command |\PitonSetStyle|. +% +% \medskip +% In the following example, we fix as value for that style |UserFunction| the +% initial value of the the style |Name.Function| (which applies to the name of +% the functions, \emph{at the moment of their definition}). +% +% \begingroup +% +% \begin{Verbatim} +% \PitonSetStyle{~emphase#UserFunction@ = \color[HTML]{CC00FF}} +% \end{Verbatim} +% +% \SetPitonStyle{UserFunction = \color[HTML]{CC00FF}} +% +% \begin{Piton} +% def transpose(v,i,j): +% x = v[i] +% v[i] = v[j] +% v[j] = x +% +% def passe(v): +% for in in range(0,len(v)-1): +% if v[i] > v[i+1]: +% transpose(v,i,i+1) +% \end{Piton} +% +% \endgroup +% +% As one see, the name |transpse| has been highlighted because it's the name of +% a Python function previously defined by the user (hence the name +% |UserFunction| for that style). +% +% \PitonClearUserFunctions +% +% \bigskip +% Of course, the list of the names of Python functions previously défined is +% kept in the memory of LuaLaTeX (in a global way, that is to say independtly of +% the TeX groups). The extension \pkg{piton} provides a command to clear that +% list : it's the command |\PitonClearUserFunctions|. +% +% \subsection{Creation of new environments} +% +% \label{NewPitonEnvironment} +% +% Since the environment |{Piton}| has to catch its body in a special way (more +% or less as verbatim text), it's not possible to construct new environments +% directly over the environment |{Piton}| with the classical commands +% |\newenvironment| or |\NewDocumentEnvironment|. +% +% That's why \pkg{piton} provides a command |\NewPitonEnvironment|. That +% command takes in three mandatory arguments. + +% That command has the same syntax as the classical environment +% |\NewDocumentEnvironment|. +% +% \bigskip +% With the following instruction, a new environment |{Python}| will be +% constructed with the same behaviour as |{Piton}|: +% +% {\color{gray}\verb|\NewPitonEnvironment{Python}{}{}{}|} +% +% \bigskip +% If one wishes an environment |{Python}| with takes in as optional argument +% (between square brackets) the keys of the command |\PitonOptions|, it's +% possible to program as follows: +% +% {\color{gray}\verb|\NewPitonEnvironment{Python}{O{}}{\PitonOptions{#1}}{}|} +% +% \bigskip +% If one wishes to format Python code in a box of \pkg{tcolorbox}, it's possible +% to define an environment |{Python}| with the following code (of course, the +% package \pkg{tcolorbox} must be loaded). +% +%\begin{verbatim} +% \NewPitonEnvironment{Python}{} +% {\begin{tcolorbox}} +% {\end{tcolorbox}} +% \end{verbatim} +% +% \bigskip +% With this new environment |{Python}|, it's possible to write: +% +% \begin{Verbatim} +% ~emphase#\begin{Python}@ +% def square(x): +% """Compute the square of a number""" +% return x*x +% ~emphase#\end{Python}@ +% \end{Verbatim} +% +% \NewPitonEnvironment{Python}{} +% {\begin{tcolorbox}} +% {\end{tcolorbox}} +% +% \begin{Python} +% def square(x): +% """Compute the square of a number""" +% return x*x +% \end{Python} +% +% +% \section{Advanced features} +% +% \subsection{Highlighting some identifiers} +% +% It's possible to require a changement of formating for some identifiers with +% the key |identifiers| of |\PitonOptions|. +% +% \smallskip +% That key takes in as argument a value of the following format: +% +% \quad |{ names = |\textsl{\ttfamily names}|, style = |\textsl{\ttfamily +% instructions}| }| +% +% \begin{itemize} +% \item \textsl{\ttfamily names} is a (comma-separated) list of identifiers +% names; +% +% \item \textsl{\ttfamily instructions} is a list of LaTeX instructions of the +% same type that \pkg{piton} ``styles'' previously presented (cf~\ref{styles} +% p.~\pageref{styles}). +% \end{itemize} +% +% \emph{Caution}: Only the identifiers may be concerned by that key. The +% keywords and the built-in functions won't be affected, even if their name is +% in the list |\textsl{\ttfamily names}|. +% +% \begin{Verbatim} +% \PitonOptions +% { +% ~emphase#identifiers@ = +% { +% ~emphase#names@ = { l1 , l2 } , +% ~emphase#style@ = \color{red} +% } +% } +% +% \begin{Piton} +% def tri(l): +% """Segmentation sort""" +% if len(l) <= 1: +% return l +% else: +% a = l[0] +% l1 = [ x for x in l[1:] if x < a ] +% l2 = [ x for x in l[1:] if x >= a ] +% return tri(l1) + [a] + tri(l2) +% \end{Piton} +% \end{Verbatim} +% +% +% \bigskip +% +% \begingroup +% +% \PitonOptions +% { +% identifiers = +% { +% names = { l1 , l2 } , +% style = \color{red} +% } +% } +% +% \begin{Piton} +% def tri(l): +% """Segmentation sort""" +% if len(l) <= 1: +% return l +% else: +% a = l[0] +% l1 = [ x for x in l[1:] if x < a ] +% l2 = [ x for x in l[1:] if x >= a ] +% return tri(l1) + [a] + tri(l2) +% \end{Piton} +% +% \endgroup +% +% \bigskip +% By using the key |identifier|, it's possible to add other built-in functions +% (or other new keywords, etc.) that will be detected by \pkg{piton}. +% +% +% \begin{Verbatim} +% \PitonOptions +% { +% ~emphase#identifiers@ = +% { +% names = { cos, sin, tan, floor, ceil, trunc, pow, exp, ln, factorial } , +% style = \PitonStyle{Name.Builtin} +% } +% } +% +% \begin{Piton} +% from math import * +% cos(pi/2) +% factorial(5) +% ceil(-2.3) +% floor(5.4) +% \end{Piton} +% \end{Verbatim} +% +% \begingroup +% +% \PitonOptions +% { +% identifiers = +% { +% names = { cos, sin, tan, floor, ceil, trunc, pow, exp, ln, factorial } , +% style = \PitonStyle{Name.Builtin} +% } +% } +% +% \begin{Piton} +% from math import * +% cos(pi/2) +% factorial(5) +% ceil(-2.3) +% floor(5.4) +% \end{Piton} +% +% +% \endgroup +% +% +% \subsection{Mechanisms to escape to LaTeX} +% +% The package \pkg{piton} provides several mechanisms for escaping to LaTeX: +% \begin{itemize} +% \item It's possible to compose comments entirely in LaTeX. +% \item It's possible to have the elements between \texttt{\$} in the comments +% composed in LateX mathematical mode. +% \item It's also possible to insert LaTeX code almost everywhere in a Python listing. +% \end{itemize} +% +% One should aslo remark that, when the extension \pkg{piton} is used with the +% class \cls{beamer}, \pkg{piton} detects in |{Piton}| many commands and +% environments of Beamer: cf. \ref{beamer} p.~\pageref{beamer}. +% +% \subsubsection{The ``LaTeX comments''} +% +% In this document, we call ``LaTeX comments'' the comments which begins by +% |#>|. The code following those characters, until the end of the line, will be +% composed as standard LaTeX code. There is two tools to customize those +% comments. +% +% \begin{itemize} +% \item It's possible to change the syntatic mark (which, by default, is |#>|). +% For this purpose, there is a key |comment-latex| available at load-time (that +% is to say at the |\usepackage|) which allows to choice the characters which, +% preceded by |#|, will be the syntatic marker. +% +% For example, with the following loading: +% +% \quad \verb|\usepackage[comment-latex = LaTeX]{piton}| +% +% the LaTeX comments will begin by |#LaTeX|. +% +% If the key |comment-latex| is used with the empty value, all the Python +% comments (which begins by |#|) will, in fact, be ``LaTeX comments''. +% +% \smallskip +% \item It's possible to change the formatting of the LaTeX comment itself by +% changing the \pkg{piton} style |Comment.LaTeX|. +% +% For example, with |\SetPitonStyle{Comment.LaTeX = \normalfont\color{blue}}|, +% the LaTeX comments will be composed in blue. +% +% If you want to have a character |#| at the beginning of the LaTeX comment in +% the \textsc{pdf}, you can use set |Comment.LaTeX| as follows: +% +% \begin{Verbatim} +% \SetPitonStyle{Comment.LaTeX = \color{gray}\~#\normalfont\space } +% \end{Verbatim} +% +% For other examples of customization of the LaTeX comments, see the part +% \ref{example-comments} p.~\pageref{example-comments} +% \end{itemize} +% +% \bigskip +% If the user has required line numbers in the left margin (with the +% key |line-numbers| or the key |all-line-numbers| of |\PitonOptions|), it's +% possible to refer to a number of line with the command |\label| used in a +% LaTeX comment.\footnote{That feature is implemented by using a redefinition of +% the standard command \texttt{\textbackslash label} in the environments +% \texttt{\{Piton\}}. Therefore, incompatibilities may occur with extensions +% which redefine (globally) that command \texttt{\textbackslash label} (for +% example: \pkg{varioref}, \pkg{refcheck}, \pkg{showlabels}, etc.)} +% +% \subsubsection{The key ``math-comments''} +% +% It's possible to request that, in the standard Python comments (that is to say +% those beginning by |#| and not |#>|), the elements between \texttt{\$} be +% composed in LaTeX mathematical mode (the other elements of the comment being +% composed verbatim). +% +% That feature is activated by the key |math-comments| at load-time (that is to +% say with the |\usepackage|). +% +% \medskip +% In the following example, we assume that the key |math-comments| has been used +% when loading \pkg{piton}. +% +% \begin{Verbatim} +% \begin{Piton} +% def square(x): +% return x*x ~# compute $x^2$ +% \end{Piton} +% \end{Verbatim} +% +% \begin{Piton} +% def square(x): +% return x*x # compute $x^2$ +% \end{Piton} +% +% \subsubsection{The mechanism ``escape-inside''} +% +% It's also possible to overwrite the Python listings to insert LaTeX code +% almost everywhere (but between lexical units, of course). By default, +% \pkg{piton} does not fix any character for that kind of escape. +% +% In order to use this mechanism, it's necessary to specify two characters which +% will delimit the escape (one for the beginning and one for the end) by using +% the key |escape-inside| at load-time (that is to say at the +% |\begin{docuemnt}|). +% +% \medskip +% In the following example, we assume that the extension \pkg{piton} has been +% loaded by the following instruction. +% +% \begin{Verbatim} +% \usepackage[~emphase#escape-inside=$$@]{piton} +% \end{Verbatim} +% +% \medskip +% In the following code, which is a recursive programmation of the mathematical +% factorial, we decide to highlight in yellow the instruction which contains the +% recursive call. That example uses the command |\highLight| of \pkg{lua-ul} +% (that package requires itself the package \pkg{luacolor}). +% \begin{Verbatim} +% \begin{Piton} +% def fact(n): +% if n==0: +% return 1 +% else: +% ~emphase#$\highLight{$@return n*fact(n-1)~emphase#$}$@ +% \end{Piton} +% \end{Verbatim} +% +% \begin{Piton} +% def fact(n): +% if n==0: +% return 1 +% else: +% $\highLight{$return n*fact(n-1)$}$ +% \end{Piton} +% +% \bigskip +% In fact, in that case, it's probably easier to use the command |\@highLight| +% of \pkg{lua-ul}: that command sets a yellow background until the end of the +% current TeX group. Since the name of that command contains the character |@|, +% it's necessary to define a synonym without |@| in order to be able to use it +% directly in |{Piton}|. +% \begingroup +% \fvset{commandchars=\~\#\+,formatcom=\color{gray}} +% \begin{Verbatim} +% \makeatletter +% ~emphase#\let\Yellow\@highLight+ +% \makeatother +% \end{Verbatim} +% \endgroup +% +% \begin{Verbatim} +% \begin{Piton} +% def fact(n): +% if n==0: +% return 1 +% else: +% ~emphase#$\Yellow$@return n*fact(n-1) +% \end{Piton} +% \end{Verbatim} +% +% \makeatletter +% \let\Yellow\@highLight +% \makeatother +% +% +% \begin{Piton} +% def fact(n): +% if n==0: +% return 1 +% else: +% $\Yellow$return n*fact(n-1) +% \end{Piton} +% +% +% +% \bigskip +% \emph{Caution} : The escape to LaTeX allowed by the characters of +% |escape-inside| is not active in the strings nor in the Python comments +% (however, it's possible to have a whole Python comment composed in LaTeX by +% beginning it with |#>|; such comments are merely called ``LaTeX comments'' in +% this document). +% +% +% \subsection{Behaviour in the class Beamer} +% +% \label{beamer} +% +% \emph{First remark}\par\nobreak +% Since the environment |{Piton}| catches its body with a verbatim mode, it's +% necessary to use the environments |{Piton}| within environments |{frame}| of +% Beamer protected by the key |fragile|, i.e. with +% |\begin{frame}[fragile]|.\footnote{Remind that for an environment +% \texttt{\{frame\}} of Beamer using the key |fragile|, the instruction +% \texttt{\textbackslash end\{frame\}} must be alone on a single line (except +% for any leading whitespace).} +% +% +% \bigskip +% When the package \pkg{piton} is used within the class +% \cls{beamer}\footnote{The extension \pkg{piton} detects the class \cls{beamer} +% but, if needed, it's also possible to activate that mechanism with the key +% |beamer| provided by \pkg{piton} at load-time: |\textbackslash +% usepackage[beamer]\{piton\}|}, the behaviour of \pkg{piton} is slightly +% modified, as described now. +% +% \subsubsection{\{Piton\} et \textbackslash PitonInputFile are +% ``overlay-aware''} +% +% When \pkg{piton} is used in the class \cls{beamer}, the environment |{Piton}| +% and the command |\PitonInputFile| accept the optional argument |<...>| of +% Beamer for the overlays which are involved. +% +% For example, it's possible to write: +% +% \begin{Verbatim} +% \begin{Piton}~emphase#<2-5>@ +% ... +% \end{Piton} +% \end{Verbatim} +% +% and +% +% \begin{Verbatim} +% \PitonInputFile~emphase#<2-5>@{my_file.py} +% \end{Verbatim} +% +% \subsubsection{Commands of Beamer allowed in \{Piton\} and \textbackslash PitonInputFile} +% +% When \pkg{piton} is used in the class \cls{beamer} , the following commands of +% \cls{beamer} (classified upon their number of arguments) are automatically +% detected in the environments |{Piton}| (and in the listings processed by +% |\PitonInputFile|): +% \begin{itemize} +% \item no mandatory argument : |\pause|\footnote{One should remark that it's +% also possible to use the command \texttt{\textbackslash pause} in a ``LaTeX +% comment'', that is to say by writing \texttt{\#> \textbackslash pause}. By +% this way, if the Python code is copied, it's still executable by Python}. ; +% \item one mandatory argument : |\action|, |\alert|, |\invisible|, |\only|, |\uncover| and |\visible| ; +% \item two mandatory arguments : |\alt| ; +% \item three mandatory arguments : |\temporal|. +% \end{itemize} + +% \medskip +% In the mandatory arguments of these commands, the braces must be balanced. +% However, the braces included in short strings\footnote{The short strings of +% Python are the strings delimited by characters \texttt{'} or the characters +% \texttt{"} and not \texttt{'''} nor \texttt{"""}. In Python, the short strings +% can't extend on several lines.} of Python are not considered. +% +% \medskip +% Regarding the fonctions |\alt| and |\temporal| there should be no carriage +% returns in the mandatory arguments of these functions. +% +% \medskip +% Here is a complete example of file: +% +% \begin{Verbatim}[formatcom = \small\color{gray}] +% \documentclass{beamer} +% \usepackage{piton} +% \begin{document} +% \begin{frame}[fragile] +% \begin{Piton} +% def string_of_list(l): +% """Convert a list of numbers in string""" +% ~emphase# \only<2->{s = "{" + str(l[0])}@ +% ~emphase# \only<3->{for x in l[1:]: s = s + "," + str(x)}@ +% ~emphase# \only<4->{s = s + "}"}@ +% return s +% \end{Piton} +% \end{frame} +% \end{document} +% \end{Verbatim} +% +% In the previous example, the braces in the Python strings |"{"| and |"}"| are +% correctly interpreted (without any escape character). +% +% +% +% +% \bigskip +% \subsubsection{Environments of Beamer allowed in \{Piton\} and \textbackslash PitonInputFile} +% +% When \pkg{piton} is used in the class \pkg{beamer}, the following environments +% of Beamer are directly detected in the environments |{Piton}| (and in the +% listings processed by |\PitonInputFile|): |{actionenv}|, |{alertenv}|, +% |{invisibleenv}|, |{onlyenv}|, |{uncoverenv}| and |{visibleenv}|. +% +% However, there is a restriction: these environments must contain only \emph{whole +% lines of Python code} in their body. +% +%\medskip +% Here is an example: +% +% \begin{Verbatim}[formatcom = \small\color{gray}] +% \documentclass{beamer} +% \usepackage{piton} +% \begin{document} +% \begin{frame}[fragile] +% \begin{Piton} +% def square(x): +% """Compure the square of its argument""" +% ~emphase#\begin{uncoverenv}<2>@ +% return x*x +% ~emphase#\end{uncoverenv}@ +% \end{Piton} +% \end{frame} +% \end{document} +% \end{Verbatim} +% +% +% \vspace{1cm} +% \textbf{Remark concerning the command \textbackslash alert and the environment +% \{alertenv\} of Beamer}\par\nobreak +% +% \smallskip +% Beamer provides an easy way to change the color used by the environment +% |{alertenv}| (and by the command |\alert| which relies upon it) to highlight +% its argument. Here is an example: +% +% \begin{Verbatim} +% \setbeamercolor{~emphase#alerted text@}{fg=blue} +% \end{Verbatim} +% +% However, when used inside an environment |{Piton}|, such tuning will probably +% not be the best choice because \pkg{piton} will, by design, change (most of +% the time) the color the different elements of text. One may prefer an environment +% |{alertenv}| that will change the background color for the elements to be +% hightlighted. +% +% \smallskip +% Here is a code that will do that job and add a yellow background. That code +% uses the command |\@highLight| of \pkg{lua-ul} (that extension requires also +% the package \pkg{luacolor}). +% +% \begingroup +% \fvset{commandchars=\~\#\+,formatcom=\color{gray}} +% \begin{Verbatim} +% \setbeamercolor{alerted text}{bg=yellow!50} +% \makeatletter +% \AddToHook{env/Piton/begin} +% {\renewenvironment<>{alertenv}{\only~#1{~emphase#\@highLight+[alerted text.bg]}}{}} +% \makeatother +% \end{Verbatim} +% \endgroup +% +% That code redefines locally the environment |{alertenv}| within the +% environments |{Piton}| (we recall that the command |\alert| relies upon that +% environment |{alertenv}|). +% +% \subsection{Page breaks and line breaks} +% +% \label{breakable} +% +% \subsubsection{Page breaks} +% +% By default, the listings produced by the environment |{Piton}| and the command +% |\PitonInputFile| are not breakable. +% +% However, the command |\PitonOptions| provides the key |splittable| to allow such +% breaks. +% +% \begin{itemize} +% \item If the key |splittable| is used without any value, the listings are +% breakable everywhere. +% \item If the key |splittable| is used with a numeric value~$n$ (which must be +% a non-negative integer number), the listings are breakable but no break will +% occur within the first $n$ lines and within the last $n$ lines. Therefore, +% |splittable=1| is equivalent to |splittable|. +% \end{itemize} +% +% \medskip +% Even with a background color (set by the key |background-color|), the pages +% breaks are allowed, as soon as the key |splittable| is in force.\footnote{With +% the key |splittable|, the environments \texttt{\{Piton\}} are breakable, even +% within a (breakable) environment of \pkg{tcolorbox}. Remind that an +% environment of \pkg{tcolorbox} included in another environment of +% \pkg{tcolorbox} is \emph{not} breakable, even when both environments use the +% key |breakable| of \pkg{tcolorbox}.} +% +% \subsubsection{Line breaks} +% +% \label{line-breaks} +% +% By default, the elements produced by \pkg{piton} can't be broken by an end on +% line. However, there are keys to allow such breaks (the possible breaking +% points are the spaces, even the spaces in the Python strings). +% \begin{itemize} +% \item With the key |break-lines-in-piton|, the line breaks are allowed in the +% command |\piton{...}| (but not in the command \verb+\piton|...|+, that is to say +% the command |\piton| in verbatim mode). +% \item With the key |break-lines-in-Piton|, the line breaks are allowed in the +% environment |{Piton}| (hence the capital letter |P| in the name) and in the +% listings produced by |\PitonInputFile|. +% \item The key |break-lines| is a conjonction of the two previous keys. +% \end{itemize} +% +% \bigskip +% The package \pkg{piton} provides also several keys to control the appearance +% on the line breaks allowed by |break-lines-in-Piton|. +% +% \begin{itemize} +% \item With the key |indent-broken-lines|, the indentation of a broken line is +% respected at carriage return. +% +% \item The key |end-of-broken-line| corresponds to the symbol placed at the end +% of a broken line. The initial value is: |\hspace*{0.5em}\textbackslash|. +% +% \item The key |continuation-symbol| corresponds to the symbol placed at each +% carriage return. The initial value is: |+\;|. +% +% \item The key |continuation-symbol-on-indentation| coresponds to the symbol +% placed at each carriage return, on the position of the indentation (only when +% the key |indent-broken-line| is in force). The initial value is: +% |$\hookrightarrow\;$|. +% \end{itemize} +% +% +% \bigskip +% The following code has been composed with the following tuning: +% +% \begin{Verbatim} +% \PitonOptions{width=12cm,break-lines,indent-broken-lines,background-color=gray!15} +% \end{Verbatim} +% +% \begin{center} +% \PitonOptions{width=12cm,break-lines,indent-broken-lines,background-color=gray!15} +% \begin{Piton} +% def dict_of_list(l): +% """Converts a list of subrs and descriptions of glyphs in a dictionary""" +% our_dict = {} +% for list_letter in l: +% if (list_letter[0][0:3] == 'dup'): # if it's a subr +% name = list_letter[0][4:-3] +% print("We treat the subr of number " + name) +% else: +% name = list_letter[0][1:-3] # if it's a glyph +% print("We treat the glyph of number " + name) +% our_dict[name] = [treat_Postscript_line(k) for k in list_letter[1:-1]] +% return dict +% \end{Piton} +% \end{center} +% +% \subsection{Footnotes in the environments of piton} +% +% \label{footnote} +% If you want to put footnotes in an environment |{Piton}| or +% (or, more unlikely, in a listing produced by |\PitonInputFile|), you can use a +% pair |\footnotemark|--|\footnotetext|. +% +% \smallskip +% However, it's also possible to extract the footnotes with the help of the +% package \pkg{footnote} or the package \pkg{footnotehyper}. +% +% \smallskip +% If \pkg{piton} is loaded with the option |footnote| (with +% |\usepackage[footnote]{piton}| or with |\PassOptionsToPackage|), the +% package \pkg{footnote} is loaded (if it is not yet loaded) and it is used to +% extract the footnotes. +% +% \smallskip +% If \pkg{piton} is loaded with the option |footnotehyper|, the package +% \pkg{footnotehyper} is loaded (if it is not yet loaded) ant it is used to +% extract footnotes. +% +% \smallskip +% Caution: The packages \pkg{footnote} and \pkg{footnotehyper} are incompatible. +% The package \pkg{footnotehyper} is the successor of the package \pkg{footnote} +% and should be used preferently. The package \pkg{footnote} has some drawbacks, +% in particular: it must be loaded after the package \pkg{xcolor} and it is not +% perfectly compatible with \pkg{hyperref}. +% +% \medskip +% In this document, the package \pkg{piton} has been loaded with the +% option |footnotehyper|. For examples of notes, cf. \ref{notes-examples}, +% p.~\pageref{notes-examples}. +% +% \subsection{Tabulations} +% +% \smallskip +% Even though it's recommended to indent the Python listings with spaces (see +% PEP~8), \pkg{piton} accepts the characters of tabulation (that is to say the +% characters U+0009) at the beginning of the lines. Each character U+0009 is +% replaced by $n$~spaces. The initial value of $n$ is $4$ but it's possible to +% change it with the key |tab-size| of |\PitonOptions|. +% +% \smallskip +% There exists also a key |tabs-auto-gobble| which computes the minimal value +% $n$ of the number of consecutive characters U+0009 beginning each (non empty) +% line of the environment |{Piton}| and applies |gobble| with that value of~$n$ +% (before replacement of the tabulations by spaces, of course). Hence, that key +% is similar to the key |auto-gobble| but acts on U+0009 instead of U+0020 +% (spaces). +% +% \section{Examples} +% +% \subsection{Line numbering} +% +% \label{example-numbering} +% +% We remind that it's possible to have an automatic numbering of the lines in +% the Python listings by using the key |line-numbers| or the key |all-line-numbers|. +% +% By default, the numbers of the lines are composed by \pkg{piton} in an +% overlapping position on the left (by using internally the command |\llap| of LaTeX). +% +% In order to avoid that overlapping, it's possible to use the option |left-margin=auto| +% which will insert automatically a margin adapted to the numbers of lines that +% will be written (that margin is larger when the numbers are greater than~10). +% +% +% \begingroup +% \fvset{commandchars=\~\&\@,formatcom=\small\color{gray}} +% \begin{Verbatim} +% ~emphase&\PitonOptions{background-color=gray!10, left-margin = auto, line-numbers}@ +% \begin{Piton} +% def arctan(x,n=10): +% if x < 0: +% return -arctan(-x) #> (recursive call) +% elif x > 1: +% return pi/2 - arctan(1/x) #> (other recursive call) +% else: +% return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) +% \end{Piton} +% \end{Verbatim} +% \endgroup +% +% +% +% \begingroup +% \PitonOptions{background-color=gray!10,left-margin = auto, line-numbers} +% \begin{Piton} +% def arctan(x,n=10): +% if x < 0: +% return -arctan(-x) #> (recursive call) +% elif x > 1: +% return pi/2 - arctan(1/x) #> (other recursive call) +% else: +% return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) +% \end{Piton} +% \endgroup +% +% +% +% \bigskip +% \subsection{Formatting of the LaTeX comments} +% +% \label{example-comments} +% +% It's possible to modify the style |Comment.LaTeX| (with |\SetPitonStyle|) in +% order to display the LaTeX comments (which begin with |#>|) aligned on the +% right margin. +% +% +% \begingroup +% \fvset{commandchars=\~\&\@,formatcom=\small\color{gray}} +% \begin{Verbatim} +% \PitonOptions{background-color=gray!10} +% ~emphase&\SetPitonStyle{Comment.LaTeX = \hfill \normalfont\color{gray}}@ +% \begin{Piton} +% def arctan(x,n=10): +% if x < 0: +% return -arctan(-x) #> recursive call +% elif x > 1: +% return pi/2 - arctan(1/x) #> other recursive call +% else: +% return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) +% \end{Piton} +% \end{Verbatim} +% \endgroup +% +% \begingroup +% \PitonOptions{background-color=gray!10} +% \SetPitonStyle{Comment.LaTeX = \hfill \normalfont\color{gray}} +% \begin{Piton} +% def arctan(x,n=10): +% if x < 0: +% return -arctan(-x) #> recursive call +% elif x > 1: +% return pi/2 - arctan(1/x) #> another recursive call +% else: +% return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) +% \end{Piton} +% \endgroup +% +% +% \vspace{1cm} +% It's also possible to display these LaTeX comments in a kind of second column +% by limiting the width of the Python code with the key |width|. In the +% following example, we use the key |width| with the special value~|min|. +% +% +% \begingroup +% \fvset{commandchars=\~\&\@,formatcom=\small\color{gray}} +% \begin{Verbatim} +% \PitonOptions{background-color=gray!10, width=min} +% ~emphase&\NewDocumentCommand{\MyLaTeXCommand}{m}{\hfill \normalfont\itshape\rlap{\quad #1}}@ +% ~emphase&\SetPitonStyle{Comment.LaTeX = \MyLaTeXCommand}@ +% \begin{Piton} +% def arctan(x,n=10): +% if x < 0: +% return -arctan(-x) #> recursive call +% elif x > 1: +% return pi/2 - arctan(1/x) #> anoother recursive call +% else: +% s = 0 +% for k in range(n): +% s += (-1)**k/(2*k+1)*x**(2*k+1) +% return s +% \end{Piton} +% \end{Verbatim} +% \endgroup +% +% +% +% \begingroup +% \PitonOptions{background-color=gray!10, width=min} +% \NewDocumentCommand{\MyLaTeXCommand}{m}{\hfill \normalfont\itshape\rlap{\quad #1}} +% \SetPitonStyle{Comment.LaTeX = \MyLaTeXCommand} +% \begin{Piton} +% def arctan(x,n=10): +% if x < 0: +% return -arctan(-x) #> recursive call +% elif x > 1: +% return pi/2 - arctan(1/x) #> another recursive call +% else: +% s = 0 +% for k in range(n): +% s += (-1)**k/(2*k+1)*x**(2*k+1) +% return s +% \end{Piton} +% \endgroup +% +% +% \bigskip +% \subsection{Notes in the listings} +% +% \label{notes-examples} +% +% In order to be able to extract the notes (which are typeset with the command +% |\footnote|), the extension \pkg{piton} must be loaded with the key |footnote| +% or the key |footenotehyper| as explained in the section \ref{footnote} +% p.~\pageref{footnote}. In this document, the extension \pkg{piton} has been +% loaded with the key |footnotehyper|. +% +% Of course, in an environment |{Piton}|, a command |\footnote| may appear only +% within a LaTeX comment (which begins with |#>|). It's possible to have comments +% which contain only that command |\footnote|. That's the case in the following example. +% +% +% +% \begingroup +% \fvset{commandchars=\~\&\@,formatcom=\small\color{gray}} +% \begin{Verbatim} +% \PitonOptions{background-color=gray!10} +% \begin{Piton} +% def arctan(x,n=10): +% if x < 0: +% return -arctan(-x)~emphase&#>\footnote{First recursive call.}]@ +% elif x > 1: +% return pi/2 - arctan(1/x)~emphase&#>\footnote{Second recursive call.}@ +% else: +% return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) +% \end{Piton} +% \end{Verbatim} +% \endgroup +% +% \begingroup +% \PitonOptions{background-color=gray!10} +% \begin{Piton} +% def arctan(x,n=10): +% if x < 0: +% return -arctan(-x)#>\footnote{First recursive call.} +% elif x > 1: +% return pi/2 - arctan(1/x)#>\footnote{Second recursive call.} +% else: +% return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) +% \end{Piton} +% \endgroup +% +% +% \vspace{1cm} +% +% If an environment |{Piton}| is used in an environment |{minipage}| of LaTeX, +% the notes are composed, of course, at the foot of the environment +% |{minipage}|. Recall that such |{minipage}| can't be broken by a page break. +% +% +% \begingroup +% \fvset{commandchars=\~\&\@,formatcom=\small\color{gray}} +% \begin{Verbatim} +% \PitonOptions{background-color=gray!10} +% \emphase\begin{minipage}{\linewidth} +% \begin{Piton} +% def arctan(x,n=10): +% if x < 0: +% return -arctan(-x)~emphase&#>\footnote{First recursive call.}@ +% elif x > 1: +% return pi/2 - arctan(1/x)~emphase&#>\footnote{Second recursive call.}@ +% else: +% return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) +% \end{Piton} +% \end{minipage} +% \end{Verbatim} +% \endgroup +% +% \begingroup +% \PitonOptions{background-color=gray!10} +% \begin{minipage}{\linewidth} +% \begin{Piton} +% def arctan(x,n=10): +% if x < 0: +% return -arctan(-x)#>\footnote{First recursive call.} +% elif x > 1: +% return pi/2 - arctan(1/x)#>\footnote{Second recursive call.} +% else: +% return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) +% \end{Piton} +% \end{minipage} +% \endgroup +% +% +% +% \bigskip +% +% \subsection{An example of tuning of the styles} +% +% The graphical styles have been presented in the section \ref{styles}, +% p.~\pageref{styles}. +% +% \smallskip +% We present now an example of tuning of these styles adapted to the documents +% in black and white. We use the font \emph{DejaVu Sans Mono}\footnote{See: +% \url{https://dejavu-fonts.github.io}} specified by the command |\setmonofont| of +% \pkg{fontspec}. +% +% That tuning uses the command |\highLight| of \pkg{lua-ul} (that package +% requires itself the package \pkg{luacolor}). +% +% \begin{Verbatim} +% \setmonofont[Scale=0.85]{DejaVu Sans Mono} +% +% \SetPitonStyle +% { +% Number = , +% String = \itshape , +% String.Doc = \color{gray} \slshape , +% Operator = , +% Operator.Word = \bfseries , +% Name.Builtin = , +% Name.Function = \bfseries \highLight[gray!20] , +% Comment = \color{gray} , +% Comment.LaTeX = \normalfont \color{gray}, +% Keyword = \bfseries , +% Name.Namespace = , +% Name.Class = , +% Name.Type = , +% InitialValues = \color{gray} +% } +% \end{Verbatim} +% +% +% \begingroup +% +% \setmonofont[Scale=0.85]{DejaVu Sans Mono} +% +% \PitonOptions{splittable} +% +% \SetPitonStyle +% { +% Number = , +% String = \itshape , +% String.Doc = \color{gray} \slshape , +% Operator.Word = \bfseries , +% Operator = , +% Name.Builtin = , +% Name.Function = \bfseries \highLight[gray!20] , +% Comment = \color{gray} , +% Comment.LaTeX = \normalfont \color{gray} , +% Keyword = \bfseries , +% Name.Namespace = , +% Name.Class = , +% Name.Type = , +% InitialValues = \color{gray} +% } +% +% +% \bigskip +% +% \begin{Piton} +% from math import pi +% +% def arctan(x,n=10): +% """Compute the mathematical value of arctan(x) +% +% n is the number of terms in the sum +% """ +% if x < 0: +% return -arctan(-x) # recursive call +% elif x > 1: +% return pi/2 - arctan(1/x) +% #> (we have used that $\arctan(x)+\arctan(1/x)=\pi/2$ for $x>0$) +% else: +% s = 0 +% for k in range(n): +% s += (-1)**k/(2*k+1)*x**(2*k+1) +% return s +% \end{Piton} +% +% \endgroup +% +% \subsection{Use with pyluatex} +% +% The package \pkg{pyluatex} is an extension which allows the execution of some +% Python code from |lualatex| (provided that Python is installed on the machine +% and that the compilation is done with |lualatex| and |--shell-escape|). +% +% Here is, for example, an environment |{PitonExecute}| which formats a Python +% listing (with \pkg{piton}) but display also the output of the execution of the +% code with Python (for technical reasons, the |!| is mandatory in the signature +% of the environment). +% +% +% \begin{Verbatim} +% \ExplSyntaxOn +% \NewDocumentEnvironment { ~emphase#PitonExecute@ } { ! O { } } % the ! is mandatory +% { +% \PyLTVerbatimEnv +% \begin{pythonq} +% } +% { +% \end{pythonq} +% \directlua +% { +% tex.print("\\PitonOptions{~#1}") +% tex.print("\\begin{Piton}") +% tex.print(pyluatex.get_last_code()) +% tex.print("\\end{Piton}") +% tex.print("") +% } +% \begin{center} +% \directlua{tex.print(pyluatex.get_last_output())} +% \end{center} +% } +% \ExplSyntaxOff +% \end{Verbatim} +% +% \ExplSyntaxOn +% \NewDocumentEnvironment { PitonExecute } { ! O { } } +% { +% \PyLTVerbatimEnv +% \begin{pythonq} +% } +% { +% \end{pythonq} +% \directlua +% { +% tex.print("\\PitonOptions{#1}") +% tex.print("\\begin{Piton}") +% tex.print(pyluatex.get_last_code()) +% tex.print("\\end{Piton}") +% tex.print("") +% } +% \begin{center} +% \directlua{tex.print(pyluatex.get_last_output())} +% \end{center} +% } +% \ExplSyntaxOff +% +% This environment |{PitonExecute}| takes in as optional argument (between +% square brackets) the options of the command |\PitonOptions|. +% +% +% \bigskip +% \clearpage +% +% \section{Implementation} +% +% % \medskip +% The development of the extension \pkg{piton} is done on the following GitHub +% depot: +% +% \verb|https://github.com/fpantigny/piton| +% +% \subsection{Introduction} +% +% The main job of the package \pkg{piton} is to take in as input a Python +% listing and to send back to LaTeX as output that code \emph{with interlaced LaTeX +% instructions of formatting}. +% +% In fact, all that job is done by a \textsc{lpeg} called |python|. That +% \textsc{lpeg}, when matched against the string of a Python listing, +% returns as capture a Lua table containing data to send to LaTeX. +% The only thing to do after will be to apply |tex.tprint| to each element of +% that table.\footnote{Recall that |tex.tprint| takes in as argument a Lua table whose +% first component is a ``catcode table'' and the second element a string. The +% string will be sent to LaTeX with the regime of catcodes specified by the +% catcode table. If no catcode table is provided, the standard catcodes of LaTeX +% will be used.} +% +% \bigskip +% Consider, for example, the following Python code: +% +% \begin{Piton} +% def parity(x): +% return x%2 +% \end{Piton} +% +% The capture returned by the \pkg{lpeg} |python| against that code is the +% Lua table containing the following elements : +% +% \bigskip +% \begin{minipage}{\linewidth} +% \color{gray} +% +% |{ "\\__piton_begin_line:" }|\footnote{Each line of the Python listings will +% be encapsulated in a pair: \texttt{\textbackslash_@@_begin_line:} -- +% \texttt{\textbackslash@@_end_line:}. The token +% \texttt{\textbackslash@@_end_line:} must be explicit because it will be used as +% marker in order to delimit the argument of the command \texttt{\textbackslash +% @@\_begin\_line:}. Both tokens \texttt{\textbackslash_@@_begin_line:} and +% \texttt{\textbackslash@@_end_line:} will be nullified in the command +% \texttt{\textbackslash piton} (since there can't be lines breaks in the +% argument of a command \texttt{\textbackslash piton}).} +% +% \texttt{\{ "\{\textbackslash PitonStyle\{Keyword\}\{" \}}\footnote{The +% lexical elements of Python for which we have a \pkg{piton} style will be +% formatted via the use of the command \texttt{\textbackslash PitonStyle}. +% Such an element is typeset in LaTeX via the syntax \texttt{\{\textbackslash +% PitonStyle\{\textsl{style}\}\{...\}\}} because the instructions inside an \texttt{\textbackslash +% PitonStyle} may be both semi-global declarations like +% \texttt{\textbackslash bfseries} and commands with one argument like +% \texttt{\textbackslash fbox}.} +% +% \texttt{\{ +% luatexbase.catcodetables.CatcodeTableOther\footnote{\texttt{luatexbase.catcodetables.CatcodeTableOther} is a mere number which corresponds to the ``catcode table'' whose all characters have the catcode ``other'' (which means that they will be typeset by LaTeX verbatim).}, "def" \} } +% +% |{ "}}" }| +% +% |{ luatexbase.catcodetables.CatcodeTableOther, " " }| +% +% |{ "{\PitonStyle{Name.Function}{" }| +% +% |{ luatexbase.catcodetables.CatcodeTableOther, "parity" }| +% +% |{ "}}" }| +% +% |{ luatexbase.catcodetables.CatcodeTableOther, "(" }| +% +% |{ luatexbase.catcodetables.CatcodeTableOther, "x" }| +% +% |{ luatexbase.catcodetables.CatcodeTableOther, ")" }| +% +% |{ luatexbase.catcodetables.CatcodeTableOther, ":" }| +% +% |{ "\\__piton_end_line: \\__piton_newline: \\__piton_begin_line:" }| +% +% |{ luatexbase.catcodetables.CatcodeTableOther, " " }| +% +% |{ "{\PitonStyle{Keyword}{" }| +% +% |{ luatexbase.catcodetables.CatcodeTableOther, "return" }| +% +% |{ "}}" }| +% +% |{ luatexbase.catcodetables.CatcodeTableOther, " " }| +% +% |{ luatexbase.catcodetables.CatcodeTableOther, "x" }| +% +% |{ "{\PitonStyle{Operator}{" }| +% +% |{ luatexbase.catcodetables.CatcodeTableOther, "&" }| +% +% |{ "}}" }| +% +% |{ "{\PitonStyle{Number}{" }| +% +% |{ luatexbase.catcodetables.CatcodeTableOther, "2" }| +% +% |{ "}}" }| +% +% |{ "\\__piton_end_line:" }| +% +% \end{minipage} +% +% \bigskip +% We give now the LaTeX code which is sent back by Lua to TeX (we have written +% on several lines for legibility but no character |\r| will be sent to LaTeX). The +% characters which are greyed-out are sent to LaTeX with the catcode ``other'' +% (=12). All the others characters are sent with the regime of catcodes of L3 +% (as set by |\ExplSyntaxOn|) +% +% +% \begingroup +% \def\gbox#1{\colorbox{gray!20}{\strut #1}} +% \setlength{\fboxsep}{1pt} +% +% \begin{Verbatim*}[formatcom = \color{black}] +% \__piton_begin_line:{\PitonStyle{Keyword}{~gbox#def@}} +% ~gbox# @{\PitonStyle{Name.Function}{~gbox#parity@}}~gbox#(x):@\__piton_end_line:\__piton_newline: +% \__piton_begin_line:~gbox# @{\PitonStyle{Keyword}{~gbox#return@}} +% ~gbox# x@{\PitonStyle{Operator}{~gbox#%@}}{\PitonStyle{Number}{~gbox#2@}}\__piton_end_line: +% \end{Verbatim*} +% \endgroup +% +% +% +% +% \subsection{The L3 part of the implementation} +% +% \subsubsection{Declaration of the package} +% \begin{macrocode} +\NeedsTeXFormat{LaTeX2e} +\RequirePackage{l3keys2e} +\ProvidesExplPackage + {piton} + {\myfiledate} + {\myfileversion} + {Highlight Python codes with LPEG on LuaLaTeX} +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\msg_new:nnn { piton } { LuaLaTeX~mandatory } + { + LuaLaTeX~is~mandatory.\\ + The~package~'piton'~requires~the~engine~LuaLaTeX.\\ + \str_if_eq:VnT \c_sys_jobname_str { output } + { If~you~use~Overleaf,~you~can~switch~to~LuaLaTeX~in~the~"Menu". \\} + If~you~go~on,~the~package~'piton'~won't~be~loaded. + } +\sys_if_engine_luatex:F { \msg_critical:nn { piton } { LuaLaTeX~mandatory } } +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\RequirePackage { luatexbase } +% \end{macrocode} +% +% \bigskip +% The boolean |\c_@@_footnotehyper_bool| will indicate if the option +% |footnotehyper| is used. +% \begin{macrocode} +\bool_new:N \c_@@_footnotehyper_bool +% \end{macrocode} +% +% \medskip +% The boolean |\c_@@_footnote_bool| will indicate if the option |footnote| is +% used, but quicky, it will also be set to |true| if the option |footnotehyper| +% is used. +% \begin{macrocode} +\bool_new:N \c_@@_footnote_bool +% \end{macrocode} +% +% \medskip +% The following boolean corresponds to the key |math-comments| (only at load-time). +% \begin{macrocode} +\bool_new:N \c_@@_math_comments_bool +% \end{macrocode} +% +% \medskip +% The following boolean corresponds to the key |beamer|. +% \begin{macrocode} +\bool_new:N \c_@@_beamer_bool +% \end{macrocode} +% +% \bigskip +% We define a set of keys for the options at load-time. +% \begin{macrocode} +\keys_define:nn { piton / package } + { + footnote .bool_set:N = \c_@@_footnote_bool , + footnotehyper .bool_set:N = \c_@@_footnotehyper_bool , + escape-inside .tl_set:N = \c_@@_escape_inside_tl , + escape-inside .initial:n = , + comment-latex .code:n = { \lua_now:n { comment_latex = "#1" } } , + comment-latex .value_required:n = true , + math-comments .bool_set:N = \c_@@_math_comments_bool , + math-comments .default:n = true , + beamer .bool_set:N = \c_@@_beamer_bool , + beamer .default:n = true , + unknown .code:n = \msg_error:nn { piton } { unknown~key~for~package } + } +% \end{macrocode} +% +% \begin{macrocode} +\msg_new:nnn { piton } { unknown~key~for~package } + { + Unknown~key.\\ + You~have~used~the~key~'\l_keys_key_str'~but~the~only~keys~available~here~ + are~'beamer',~'comment-latex',~'escape-inside',~'footnote',~'footnotehyper'~and~ + 'math-comments'.~Other~keys~are~available~in~\token_to_str:N \PitonOptions.\\ + That~key~will~be~ignored. + } +% \end{macrocode} +% +% \bigskip +% We process the options provided by the user at load-time. +% \begin{macrocode} +\ProcessKeysOptions { piton / package } +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\begingroup +\cs_new_protected:Npn \@@_set_escape_char:nn #1 #2 + { + \lua_now:n { piton_begin_escape = "#1" } + \lua_now:n { piton_end_escape = "#2" } + } +\cs_generate_variant:Nn \@@_set_escape_char:nn { x x } +\@@_set_escape_char:xx + { \tl_head:V \c_@@_escape_inside_tl } + { \tl_tail:V \c_@@_escape_inside_tl } +\endgroup +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\@ifclassloaded { beamer } { \bool_set_true:N \c_@@_beamer_bool } { } +\bool_if:NT \c_@@_beamer_bool { \lua_now:n { piton_beamer = true } } +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\hook_gput_code:nnn { begindocument } { . } + { + \@ifpackageloaded { xcolor } + { } + { \msg_fatal:nn { piton } { xcolor~not~loaded } } + } +% \end{macrocode} +% +% \begin{macrocode} +\msg_new:nnn { piton } { xcolor~not~loaded } + { + xcolor~not~loaded \\ + The~package~'xcolor'~is~required~by~'piton'.\\ + This~error~is~fatal. + } +% \end{macrocode} +% +% +% \begin{macrocode} +\msg_new:nnn { piton } { footnote~with~footnotehyper~package } + { + Footnote~forbidden.\\ + You~can't~use~the~option~'footnote'~because~the~package~ + footnotehyper~has~already~been~loaded.~ + If~you~want,~you~can~use~the~option~'footnotehyper'~and~the~footnotes~ + within~the~environments~of~piton~will~be~extracted~with~the~tools~ + of~the~package~footnotehyper.\\ + If~you~go~on,~the~package~footnote~won't~be~loaded. + } +% \end{macrocode} +% +% \begin{macrocode} +\msg_new:nnn { piton } { footnotehyper~with~footnote~package } + { + You~can't~use~the~option~'footnotehyper'~because~the~package~ + footnote~has~already~been~loaded.~ + If~you~want,~you~can~use~the~option~'footnote'~and~the~footnotes~ + within~the~environments~of~piton~will~be~extracted~with~the~tools~ + of~the~package~footnote.\\ + If~you~go~on,~the~package~footnotehyper~won't~be~loaded. + } +% \end{macrocode} +% +% \medskip +% \begin{macrocode} +\bool_if:NT \c_@@_footnote_bool + { +% \end{macrocode} +% The class \cls{beamer} has its own system to extract footnotes and that's why +% we have nothing to do if \cls{beamer} is used. +% \begin{macrocode} + \@ifclassloaded { beamer } + { \bool_set_false:N \c_@@_footnote_bool } + { + \@ifpackageloaded { footnotehyper } + { \@@_error:n { footnote~with~footnotehyper~package } } + { \usepackage { footnote } } + } + } +% \end{macrocode} +% +% \begin{macrocode} +\bool_if:NT \c_@@_footnotehyper_bool + { +% \end{macrocode} +% The class \cls{beamer} has its own system to extract footnotes and that's why +% we have nothing to do if \cls{beamer} is used. +% \begin{macrocode} + \@ifclassloaded { beamer } + { \bool_set_false:N \c_@@_footnote_bool } + { + \@ifpackageloaded { footnote } + { \@@_error:n { footnotehyper~with~footnote~package } } + { \usepackage { footnotehyper } } + \bool_set_true:N \c_@@_footnote_bool + } + } +% \end{macrocode} +% The flag |\c_@@_footnote_bool| is raised and so, we will only have to test +% |\c_@@_footnote_bool| in order to know if we have to insert an environment +% |{savenotes}|. +% +% \bigskip +% \subsubsection{Parameters and technical definitions} +% +% The following string will contain the name of the informatic language +% considered (the initial value is |python|). +% +% \begin{macrocode} +\str_new:N \l_@@_language_str +\str_set:Nn \l_@@_language_str { python } +% \end{macrocode} +% +% We will compute (with Lua) the numbers of lines of the Python code and store +% it in the following counter. +% \begin{macrocode} +\int_new:N \l_@@_nb_lines_int +% \end{macrocode} +% +% The same for the number of non-empty lines of the Python codes. +% \begin{macrocode} +\int_new:N \l_@@_nb_non_empty_lines_int +% \end{macrocode} +% +% The following counter will be used to count the lines during the composition. +% It will count all the lines, empty or not empty. It won't be used to print the +% numbers of the lines. +% \begin{macrocode} +\int_new:N \g_@@_line_int +% \end{macrocode} +% +% \medskip +% The following token list will contains the (potential) informations to write +% on the |aux| (to be used in the next compilation). +% \begin{macrocode} +\tl_new:N \g_@@_aux_tl +% \end{macrocode} +% +% \medskip +% The following counter corresponds to the key |splittable| of |\PitonOptions|. +% If the value of |\l_@@_splittable_int| is equal to $n$, then no line break can +% occur within the first $n$~lines or the last $n$~lines of the listings. +% \begin{macrocode} +\int_new:N \l_@@_splittable_int +% \end{macrocode} +% +% \medskip +% An initial value of |splittable| equal to 100 is equivalent to say that the +% environments |{Piton}| are unbreakable. +% \begin{macrocode} +\int_set:Nn \l_@@_splittable_int { 100 } +% \end{macrocode} +% +% \medskip +% The following string corresponds to the key |background-color| of |\PitonOptions|. +% \begin{macrocode} +\clist_new:N \l_@@_bg_color_clist +% \end{macrocode} +% +% \medskip +% The package \pkg{piton} will also detect the lines of code which correspond to +% the user input in a Python console, that is to say the lines of code beginning +% with |>>>| and |...|. It's possible, with the key |prompt-background-color|, +% to require a background for these lines of code (and the other lines of code +% will have the standard background color specified by |background-color|). +% \begin{macrocode} +\tl_new:N \l_@@_prompt_bg_color_tl +% \end{macrocode} +% +% +% \medskip +% We will count the environments |{Piton}| (and, in fact, also the commands +% |\PitonInputFile|, despite the name |\g_@@_env_int|). +% \begin{macrocode} +\int_new:N \g_@@_env_int +% \end{macrocode} +% +% \medskip +% The following boolean corresponds to the key |show-spaces|. +% \begin{macrocode} +\bool_new:N \l_@@_show_spaces_bool +% \end{macrocode} +% +% \medskip +% The following booleans correspond to the keys |break-lines| and +% |indent-broken-lines|. +% \begin{macrocode} +\bool_new:N \l_@@_break_lines_in_Piton_bool +\bool_new:N \l_@@_indent_broken_lines_bool +% \end{macrocode} +% +% \medskip +% The following token list corresponds to the key |continuation-symbol|. +% \begin{macrocode} +\tl_new:N \l_@@_continuation_symbol_tl +\tl_set:Nn \l_@@_continuation_symbol_tl { + } +% \end{macrocode} +% +% \medskip +% \begin{macrocode} +% The following token list corresponds to the key +% |continuation-symbol-on-indentation|. The name has been shorten to |csoi|. +\tl_new:N \l_@@_csoi_tl +\tl_set:Nn \l_@@_csoi_tl { $ \hookrightarrow \; $ } +% \end{macrocode} +% +% \medskip +% The following token list corresponds to the key |end-of-broken-line|. +% \begin{macrocode} +\tl_new:N \l_@@_end_of_broken_line_tl +\tl_set:Nn \l_@@_end_of_broken_line_tl { \hspace*{0.5em} \textbackslash } +% \end{macrocode} +% +% \medskip +% The following boolean corresponds to the key |break-lines-in-piton|. +% \begin{macrocode} +\bool_new:N \l_@@_break_lines_in_piton_bool +% \end{macrocode} +% +% \bigskip +% The following dimension will be the width of the listing constructed by +% |{Piton}| or |\PitonInputFile|. +% \begin{itemize} +% \item If the user uses the key |width| of |\PitonOptions| with a numerical +% value, that value will be stored in |\l_@@_width_dim|. +% \item If the user uses the key |width| with the special value~|min|, the +% dimension |\l_@@_width_dim| will, \emph{in the second run}, be computed from +% the value of |\l_@@_line_width_dim| stored in the |aux| file +% (computed during the first run the maximal width of the lines of the listing). +% During the first run, |\l_@@_width_line_dim| will be set equal to |\linewidth|. +% \item Elsewhere, |\l_@@_width_dim| will be set at the beginning of the listing +% (in |\@@_pre_env:|) equal to the current value of |\linewidth|. +% \end{itemize} +% +% \begin{macrocode} +\dim_new:N \l_@@_width_dim +% \end{macrocode} +% +% \medskip +% We will also use another dimension called |\l_@@_line_width_dim|. That +% will the width of the actual lines of code. That dimension may be lower than +% the whole |\l_@@_width_dim| because we have to take into account the value of +% |\l_@@_left_margin_dim| (for the numbers of lines when |line-numbers| is in +% force) and another small margin when a background color is used (with the key +% |background-color|). +% \begin{macrocode} +\dim_new:N \l_@@_line_width_dim +% \end{macrocode} +% +% \medskip +% The following flag will be raised with the key |width| is used with the +% special value |min|. +% \begin{macrocode} +\bool_new:N \l_@@_width_min_bool +% \end{macrocode} +% +% \medskip +% If the key |width| is used with the special value~|min|, we will compute the +% maximal width of the lines of an environment |{Piton}| in |\g_@@_tmp_width_dim| +% because we need it for the case of the key |width| is used with the spacial +% value |min|. We need a global variable because, when the key |footnote| is in +% force, each line when be composed in an environment |{savenotes}| and we need +% to exit our |\g_@@_tmp_width_dim| from that environment. +% \begin{macrocode} +\dim_new:N \g_@@_tmp_width_dim +% \end{macrocode} +% +% \medskip +% The following dimension corresponds to the key |left-margin| of |\PitonOptions|. +% \begin{macrocode} +\dim_new:N \l_@@_left_margin_dim +% \end{macrocode} +% +% \medskip +% The following boolean will be set when the key |left-margin=auto| +% is used. +% \begin{macrocode} +\bool_new:N \l_@@_left_margin_auto_bool +% \end{macrocode} +% +% \medskip +% The following dimension corresponds to the key |numbers-sep| of +% |\PitonOptions|. +% \begin{macrocode} +\dim_new:N \l_@@_numbers_sep_dim +\dim_set:Nn \l_@@_numbers_sep_dim { 0.7 em } +% \end{macrocode} +% +% \medskip +% The tabulators will be replaced by the content of the following token list. +% \begin{macrocode} +\tl_new:N \l_@@_tab_tl +% \end{macrocode} +% +% \medskip +% \begin{macrocode} +\cs_new_protected:Npn \@@_set_tab_tl:n #1 + { + \tl_clear:N \l_@@_tab_tl + \prg_replicate:nn { #1 } + { \tl_put_right:Nn \l_@@_tab_tl { ~ } } + } +\@@_set_tab_tl:n { 4 } +% \end{macrocode} +% +% \medskip +% The following integer corresponds to the key |gobble|. +% \begin{macrocode} +\int_new:N \l_@@_gobble_int +% \end{macrocode} +% +% \medskip +% \begin{macrocode} +\tl_new:N \l_@@_space_tl +\tl_set:Nn \l_@@_space_tl { ~ } +% \end{macrocode} +% +% +% \medskip +% At each line, the following counter will count the spaces at the beginning. +% \begin{macrocode} +\int_new:N \g_@@_indentation_int +% \end{macrocode} +% +% \medskip +% \begin{macrocode} +\cs_new_protected:Npn \@@_an_indentation_space: + { \int_gincr:N \g_@@_indentation_int } +% \end{macrocode} +% +% \medskip +% The following command |\@@_beamer_command:n| executes the argument +% corresponding to its argument but also stores it in |\l_@@_beamer_command_str|. +% That string is used only in the error message ``|cr~not~allowed|'' raised when +% there is a carriage return in the mandatory argument of that command. +% \begin{macrocode} +\cs_new_protected:Npn \@@_beamer_command:n #1 + { + \str_set:Nn \l_@@_beamer_command_str { #1 } + \use:c { #1 } + } +% \end{macrocode} +% +% \bigskip +% In the environment |{Piton}|, the command |\label| will be linked to the +% following command. +% \begin{macrocode} +\cs_new_protected:Npn \@@_label:n #1 + { + \bool_if:NTF \l_@@_line_numbers_bool + { + \@bsphack + \protected@write \@auxout { } + { + \string \newlabel { #1 } + { +% \end{macrocode} +% Remember that the content of a line is typeset in a box \emph{before} the +% composition of the potential number of line. +% \begin{macrocode} + { \int_eval:n { \g_@@_visual_line_int + 1 } } + { \thepage } + } + } + \@esphack + } + { \msg_error:nn { piton } { label~with~lines~numbers } } + } +% \end{macrocode} +% +% +% \bigskip +% The following commands are a easy way to insert safely braces (|{| and |}|) in +% the TeX flow. +% \begin{macrocode} +\cs_new_protected:Npn \@@_open_brace: + { \directlua { piton.open_brace() } } +\cs_new_protected:Npn \@@_close_brace: + { \directlua { piton.close_brace() } } +% \end{macrocode} +% +% \bigskip +% The following token list will be evaluated at the beginning of +% |\@@_begin_line:|... |\@@_end_line:| and cleared at the end. It will be used +% by LPEG acting between the lines of the Python code in order to add +% instructions to be executed at the beginning of the line. +% \begin{macrocode} +\tl_new:N \g_@@_begin_line_hook_tl +% \end{macrocode} +% +% \smallskip +% For example, the LPEG |Prompt| will trigger the following command which will +% insert an instruction in the hook |\g_@@_begin_line_hook| to specify that a +% background must be inserted to the current line of code. +% \begin{macrocode} +\cs_new_protected:Npn \@@_prompt: + { + \tl_gset:Nn \g_@@_begin_line_hook_tl + { + \tl_if_empty:NF \l_@@_prompt_bg_color_tl % added 2023-04-24 + { \clist_set:NV \l_@@_bg_color_clist \l_@@_prompt_bg_color_tl } + } + } +% \end{macrocode} +% +% +% \bigskip +% \subsubsection{Treatment of a line of code} +% +% \begin{macrocode} +\cs_new_protected:Npn \@@_replace_spaces:n #1 + { + \tl_set:Nn \l_tmpa_tl { #1 } + \bool_if:NTF \l_@@_show_spaces_bool + { \regex_replace_all:nnN { \x20 } { ␣ } \l_tmpa_tl } % U+2423 + { +% \end{macrocode} +% If the key |break-lines-in-Piton| is in force, we replace all the characters +% U+0020 (that is to say the spaces) by |\@@_breakable_space:|. Remark that, +% except the spaces inserted in the LaTeX comments (and maybe in the math +% comments), all these spaces are of catcode ``other'' (=12) and are +% unbreakable. +% \begin{macrocode} + \bool_if:NT \l_@@_break_lines_in_Piton_bool + { + \regex_replace_all:nnN + { \x20 } + { \c { @@_breakable_space: } } + \l_tmpa_tl + } + } + \l_tmpa_tl + } +\cs_generate_variant:Nn \@@_replace_spaces:n { x } +% \end{macrocode} +% +% \bigskip +% In the contents provided by Lua, each line of the Python code will be +% surrounded by |\@@_begin_line:| and |\@@_end_line:|. |\@@_begin_line:| is a +% LaTeX command that we will define now but |\@@_end_line:| is only a syntactic +% marker that has no definition. +% +% \begin{macrocode} +\cs_set_protected:Npn \@@_begin_line: #1 \@@_end_line: + { + \group_begin: + \g_@@_begin_line_hook_tl + \int_gzero:N \g_@@_indentation_int +% \end{macrocode} +% +% \medskip +% First, we will put in the coffin |\l_tmpa_coffin| the actual content of a line +% of the code (without the potential number of line). +% +% Be careful: There is curryfication in the following code. +% \begin{macrocode} + \bool_if:NTF \l_@@_width_min_bool + \@@_put_in_coffin_ii:n + \@@_put_in_coffin_i:n + { + \language = -1 + \raggedright + \strut + \@@_replace_spaces:n { #1 } + \strut \hfil + } +% \end{macrocode} +% Now, we add the potential number of line, the potential left margin and the +% potential background. +% \begin{macrocode} + \hbox_set:Nn \l_tmpa_box + { + \skip_horizontal:N \l_@@_left_margin_dim + \bool_if:NT \l_@@_line_numbers_bool + { + \bool_if:NF \l_@@_all_line_numbers_bool + { \tl_if_eq:nnF { #1 } { \PitonStyle {Prompt}{} } } +% \end{macrocode} +% Remember that |\@@_print_number:| always uses |\hbox_overlap_left:n|. +% \begin{macrocode} + \@@_print_number: + } +% \end{macrocode} +% If there is a background, we must remind that there is a left margin of 0.5~em +% for the background... +% \begin{macrocode} + \clist_if_empty:NF \l_@@_bg_color_clist + { +% \end{macrocode} +% ... but if only if the key |left-margin| is not used ! +% \begin{macrocode} + \dim_compare:nNnT \l_@@_left_margin_dim = \c_zero_dim + { \skip_horizontal:n { 0.5 em } } + } + \coffin_typeset:Nnnnn \l_tmpa_coffin T l \c_zero_dim \c_zero_dim + } + \box_set_dp:Nn \l_tmpa_box { \box_dp:N \l_tmpa_box + 1.25 pt } + \box_set_ht:Nn \l_tmpa_box { \box_ht:N \l_tmpa_box + 1.25 pt } + \clist_if_empty:NTF \l_@@_bg_color_clist + { \box_use_drop:N \l_tmpa_box } + { + \vtop + { + \hbox:n + { + \@@_color:N \l_@@_bg_color_clist + \vrule height \box_ht:N \l_tmpa_box + depth \box_dp:N \l_tmpa_box + width \l_@@_width_dim + } + \skip_vertical:n { - \box_ht_plus_dp:N \l_tmpa_box } + \box_use_drop:N \l_tmpa_box + } + } + \vspace { - 2.5 pt } + \group_end: + \tl_gclear:N \g_@@_begin_line_hook_tl + } +% \end{macrocode} +% +% \bigskip +% In the general case (which is also the simpler), the key |width| is not used, +% or (if used) it is not used with the special value~|min|. +% In that case, the content of a line of code is composed in a vertical coffin +% with a width equal to |\l_@@_line_width_dim|. That coffin may, +% eventually, contains several lines when the key |broken-lines-in-Piton| (or +% |broken-lines|) is used. +% +% That commands takes in its argument by curryfication. +% \begin{macrocode} +\cs_set_protected:Npn \@@_put_in_coffin_i:n + { \vcoffin_set:Nnn \l_tmpa_coffin \l_@@_line_width_dim } +% \end{macrocode} +% +% \bigskip +% The second case is the case when the key |width| is used with the special +% value~|min|. +% \begin{macrocode} +\cs_set_protected:Npn \@@_put_in_coffin_ii:n #1 + { +% \end{macrocode} +% First, we compute the natural width of the line of code because we have to +% compute the natural width of the whole listing (and it will be written on the +% |aux| file in the variable |\l_@@_width_dim|). +% \begin{macrocode} + \hbox_set:Nn \l_tmpa_box { #1 } +% \end{macrocode} +% Now, you can actualize the value of |\g_@@_tmp_width_dim| (it will be used to +% write on the |aux| file the natural width of the environment). +% \begin{macrocode} + \dim_compare:nNnT { \box_wd:N \l_tmpa_box } > \g_@@_tmp_width_dim + { \dim_gset:Nn \g_@@_tmp_width_dim { \box_wd:N \l_tmpa_box } } +% \end{macrocode} +% +% \begin{macrocode} + \hcoffin_set:Nn \l_tmpa_coffin + { + \hbox_to_wd:nn \l_@@_line_width_dim +% \end{macrocode} +% We unpack the bock in order to free the potential |\hfill| springs present in +% the LaTeX comments (cf. section~\ref{example-comments}, p.~\pageref{example-comments}). +% \begin{macrocode} + { \hbox_unpack:N \l_tmpa_box \hfil } + } + } +% \end{macrocode} +% +% +% \bigskip +% The command |\@@_color:N| will take in as argument a reference to a +% comma-separated list of colors. A color will be picked by using the value of +% |\g_@@_line_int| (modulo the number of colors in the list). +% \begin{macrocode} +\cs_set_protected:Npn \@@_color:N #1 + { + \int_set:Nn \l_tmpa_int { \clist_count:N #1 } + \int_set:Nn \l_tmpb_int { \int_mod:nn \g_@@_line_int \l_tmpa_int + 1 } + \tl_set:Nx \l_tmpa_tl { \clist_item:Nn #1 \l_tmpb_int } + \tl_if_eq:NnTF \l_tmpa_tl { none } +% \end{macrocode} +% By setting |\l_@@_width_dim| to zero, the colored rectangle will be +% drawn with zero width and, thus, it will be a mere strut (and we need that strut). +% \begin{macrocode} + { \dim_zero:N \l_@@_width_dim } + { \exp_args:NV \@@_color_i:n \l_tmpa_tl } + } +% \end{macrocode} +% +% The following command |\@@_color:n| will accept both the instruction +% |\@@_color:n { red!15 }| and the instruction |\@@_color:n { [rgb]{0.9,0.9,0} }|. +% \begin{macrocode} +\cs_set_protected:Npn \@@_color_i:n #1 + { + \tl_if_head_eq_meaning:nNTF { #1 } [ + { + \tl_set:Nn \l_tmpa_tl { #1 } + \tl_set_rescan:Nno \l_tmpa_tl { } \l_tmpa_tl + \exp_last_unbraced:NV \color \l_tmpa_tl + } + { \color { #1 } } + } +\cs_generate_variant:Nn \@@_color:n { V } +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\cs_new_protected:Npn \@@_newline: + { + \int_gincr:N \g_@@_line_int + \int_compare:nNnT \g_@@_line_int > { \l_@@_splittable_int - 1 } + { + \int_compare:nNnT + { \l_@@_nb_lines_int - \g_@@_line_int } > \l_@@_splittable_int + { + \egroup + \bool_if:NT \c_@@_footnote_bool { \end { savenotes } } + \par \mode_leave_vertical: % \newline + \bool_if:NT \c_@@_footnote_bool { \begin { savenotes } } + \vtop \bgroup + } + } + } +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\cs_set_protected:Npn \@@_breakable_space: + { + \discretionary + { \hbox:n { \color { gray } \l_@@_end_of_broken_line_tl } } + { + \hbox_overlap_left:n + { + { + \normalfont \footnotesize \color { gray } + \l_@@_continuation_symbol_tl + } + \skip_horizontal:n { 0.3 em } + \clist_if_empty:NF \l_@@_bg_color_clist + { \skip_horizontal:n { 0.5 em } } + } + \bool_if:NT \l_@@_indent_broken_lines_bool + { + \hbox:n + { + \prg_replicate:nn { \g_@@_indentation_int } { ~ } + { \color { gray } \l_@@_csoi_tl } + } + } + } + { \hbox { ~ } } + } +% \end{macrocode} +% +% \bigskip +% \subsubsection{PitonOptions} +% +% \medskip +% The following parameters correspond to the keys |line-numbers| and +% |all-line-numbers|. +% \begin{macrocode} +\bool_new:N \l_@@_line_numbers_bool +\bool_new:N \l_@@_all_line_numbers_bool +% \end{macrocode} +% +% \medskip +% The following flag corresponds to the key |resume|. +% \begin{macrocode} +\bool_new:N \l_@@_resume_bool +% \end{macrocode} +% +% \bigskip +% Be careful! The name of the following set of keys must be considered as +% public! Hence, it should \emph{not} be changed. +% +% \begin{macrocode} +\keys_define:nn { PitonOptions } + { + language .str_set:N = \l_@@_language_str , + language .value_required:n = true , + gobble .int_set:N = \l_@@_gobble_int , + gobble .value_required:n = true , + auto-gobble .code:n = \int_set:Nn \l_@@_gobble_int { -1 } , + auto-gobble .value_forbidden:n = true , + env-gobble .code:n = \int_set:Nn \l_@@_gobble_int { -2 } , + env-gobble .value_forbidden:n = true , + tabs-auto-gobble .code:n = \int_set:Nn \l_@@_gobble_int { -3 } , + tabs-auto-gobble .value_forbidden:n = true , + line-numbers .bool_set:N = \l_@@_line_numbers_bool , + line-numbers .default:n = true , + all-line-numbers .code:n = + \bool_set_true:N \l_@@_line_numbers_bool + \bool_set_true:N \l_@@_all_line_numbers_bool , + all-line-numbers .value_forbidden:n = true , + resume .bool_set:N = \l_@@_resume_bool , + resume .value_forbidden:n = true , + splittable .int_set:N = \l_@@_splittable_int , + splittable .default:n = 1 , + background-color .clist_set:N = \l_@@_bg_color_clist , + background-color .value_required:n = true , + prompt-background-color .tl_set:N = \l_@@_prompt_bg_color_tl , + prompt-background-color .value_required:n = true , + width .code:n = + \str_if_eq:nnTF { #1 } { min } + { + \bool_set_true:N \l_@@_width_min_bool + \dim_zero:N \l_@@_width_dim + } + { + \bool_set_false:N \l_@@_width_min_bool + \dim_set:Nn \l_@@_width_dim { #1 } + } , + width .value_required:n = true , + left-margin .code:n = + \str_if_eq:nnTF { #1 } { auto } + { + \dim_zero:N \l_@@_left_margin_dim + \bool_set_true:N \l_@@_left_margin_auto_bool + } + { + \dim_set:Nn \l_@@_left_margin_dim { #1 } + \bool_set_false:N \l_@@_left_margin_auto_bool + } , + left-margin .value_required:n = true , + numbers-sep .dim_set:N = \l_@@_numbers_sep_dim , + numbers-sep .value_required:n = true , + tab-size .code:n = \@@_set_tab_tl:n { #1 } , + tab-size .value_required:n = true , + show-spaces .bool_set:N = \l_@@_show_spaces_bool , + show-spaces .default:n = true , + show-spaces-in-strings .code:n = \tl_set:Nn \l_@@_space_tl { ␣ } , % U+2423 + show-spaces-in-strings .value_forbidden:n = true , + break-lines-in-Piton .bool_set:N = \l_@@_break_lines_in_Piton_bool , + break-lines-in-Piton .default:n = true , + break-lines-in-piton .bool_set:N = \l_@@_break_lines_in_piton_bool , + break-lines-in-piton .default:n = true , + break-lines .meta:n = { break-lines-in-piton , break-lines-in-Piton } , + break-lines .value_forbidden:n = true , + indent-broken-lines .bool_set:N = \l_@@_indent_broken_lines_bool , + indent-broken-lines .default:n = true , + end-of-broken-line .tl_set:N = \l_@@_end_of_broken_line_tl , + end-of-broken-line .value_required:n = true , + continuation-symbol .tl_set:N = \l_@@_continuation_symbol_tl , + continuation-symbol .value_required:n = true , + continuation-symbol-on-indentation .tl_set:N = \l_@@_csoi_tl , + continuation-symbol-on-indentation .value_required:n = true , + unknown .code:n = + \msg_error:nn { piton } { Unknown~key~for~PitonOptions } + } +% \end{macrocode} +% +% +% \bigskip +% +% \bigskip +% The argument of |\PitonOptions| is provided by curryfication. +% \begin{macrocode} +\NewDocumentCommand \PitonOptions { } { \keys_set:nn { PitonOptions } } +% \end{macrocode} +% +% \bigskip +% \subsubsection{The numbers of the lines} +% +% \medskip +% The following counter will be used to count the lines in the code when the +% user requires the numbers of the lines to be printed (with |line-numbers| or +% |all-line-numbers|). +% +% \begin{macrocode} +\int_new:N \g_@@_visual_line_int +% \end{macrocode} +% +% +% \begin{macrocode} +\cs_new_protected:Npn \@@_print_number: + { + \int_gincr:N \g_@@_visual_line_int + \hbox_overlap_left:n + { + { \color { gray } \footnotesize \int_to_arabic:n \g_@@_visual_line_int } + \skip_horizontal:N \l_@@_numbers_sep_dim + } + } +% \end{macrocode} +% +% +% \bigskip +% \subsubsection{The command to write on the aux file} +% +% +% \begin{macrocode} +\cs_new_protected:Npn \@@_write_aux: + { + \tl_if_empty:NF \g_@@_aux_tl + { + \iow_now:Nn \@mainaux { \ExplSyntaxOn } + \iow_now:Nx \@mainaux + { + \tl_gset:cn { c_@@_ \int_use:N \g_@@_env_int _ tl } + { \exp_not:V \g_@@_aux_tl } + } + \iow_now:Nn \@mainaux { \ExplSyntaxOff } + } + \tl_gclear:N \g_@@_aux_tl + } +% \end{macrocode} +% +% \bigskip +% The following macro with be used only when the key |width| is used with the +% special value~|min|. +% \begin{macrocode} +\cs_new_protected:Npn \@@_width_to_aux: + { + \tl_gput_right:Nx \g_@@_aux_tl + { + \dim_set:Nn \l_@@_line_width_dim + { \dim_eval:n { \g_@@_tmp_width_dim } } + } + } +% \end{macrocode} +% +% \bigskip +% \subsubsection{The main commands and environments for the final user} +% +% \bigskip +% \begin{macrocode} +\NewDocumentCommand { \piton } { } + { \peek_meaning:NTF \bgroup \@@_piton_standard \@@_piton_verbatim } +% \end{macrocode} +% +% \begin{macrocode} +\NewDocumentCommand { \@@_piton_standard } { m } + { + \group_begin: + \ttfamily +% \end{macrocode} +% The following tuning of LuaTeX in order to avoid all break of lines on the +% hyphens. +% \begin{macrocode} + \automatichyphenmode = 1 + \cs_set_eq:NN \\ \c_backslash_str + \cs_set_eq:NN \% \c_percent_str + \cs_set_eq:NN \{ \c_left_brace_str + \cs_set_eq:NN \} \c_right_brace_str + \cs_set_eq:NN \$ \c_dollar_str + \cs_set_eq:cN { ~ } \space + \cs_set_protected:Npn \@@_begin_line: { } + \cs_set_protected:Npn \@@_end_line: { } + \tl_set:Nx \l_tmpa_tl + { + \lua_now:e + { piton.ParseBis('\l_@@_language_str',token.scan_string()) } + { #1 } + } + \bool_if:NTF \l_@@_show_spaces_bool + { \regex_replace_all:nnN { \x20 } { ␣ } \l_tmpa_tl } % U+2423 +% \end{macrocode} +% The following code replaces the characters U+0020 (spaces) by characters +% U+0020 of catcode~10: thus, they become breakable by an end of line. +% \begin{macrocode} + { + \bool_if:NT \l_@@_break_lines_in_piton_bool + { \regex_replace_all:nnN { \x20 } { \x20 } \l_tmpa_tl } + } + \l_tmpa_tl + \group_end: + } +% \end{macrocode} +% +% +% \begin{macrocode} +\NewDocumentCommand { \@@_piton_verbatim } { v } + { + \group_begin: + \ttfamily + \automatichyphenmode = 1 + \cs_set_protected:Npn \@@_begin_line: { } + \cs_set_protected:Npn \@@_end_line: { } + \tl_set:Nx \l_tmpa_tl + { + \lua_now:e + { piton.Parse('\l_@@_language_str',token.scan_string()) } + { #1 } + } + \bool_if:NT \l_@@_show_spaces_bool + { \regex_replace_all:nnN { \x20 } { ␣ } \l_tmpa_tl } % U+2423 + \l_tmpa_tl + \group_end: + } +% \end{macrocode} +% + +% \bigskip +% +% +% \bigskip +% The following command is not a user command. It will be used when we will +% have to ``rescan'' some chunks of Python code. For example, it will be the +% initial value of the Piton style |InitialValues| (the default values of the +% arguments of a Python function). +% \begin{macrocode} +\cs_new_protected:Npn \@@_piton:n #1 + { + \group_begin: + \cs_set_protected:Npn \@@_begin_line: { } + \cs_set_protected:Npn \@@_end_line: { } + \bool_lazy_or:nnTF + \l_@@_break_lines_in_piton_bool + \l_@@_break_lines_in_Piton_bool + { + \tl_set:Nx \l_tmpa_tl + { + \lua_now:e + { piton.ParseTer('\l_@@_language_str',token.scan_string()) } + { #1 } + } + } + { + \tl_set:Nx \l_tmpa_tl + { + \lua_now:e + { piton.Parse('\l_@@_language_str',token.scan_string()) } + { #1 } + } + } + \bool_if:NT \l_@@_show_spaces_bool + { \regex_replace_all:nnN { \x20 } { ␣ } \l_tmpa_tl } % U+2423 + \l_tmpa_tl + \group_end: + } +% \end{macrocode} +% +% \bigskip +% The following command is similar to the previous one but raise a fatal error if +% its argument contains a carriage return. +% \begin{macrocode} +\cs_new_protected:Npn \@@_piton_no_cr:n #1 + { + \group_begin: + \cs_set_protected:Npn \@@_begin_line: { } + \cs_set_protected:Npn \@@_end_line: { } + \cs_set_protected:Npn \@@_newline: + { \msg_fatal:nn { piton } { cr~not~allowed } } + \bool_lazy_or:nnTF + \l_@@_break_lines_in_piton_bool + \l_@@_break_lines_in_Piton_bool + { + \tl_set:Nx \l_tmpa_tl + { + \lua_now:e + { piton.ParseTer('\l_@@_language_str',token.scan_string()) } + { #1 } + } + } + { + \tl_set:Nx \l_tmpa_tl + { + \lua_now:e + { piton.Parse('\l_@@_language_str',token.scan_string()) } + { #1 } + } + } + \bool_if:NT \l_@@_show_spaces_bool + { \regex_replace_all:nnN { \x20 } { ␣ } \l_tmpa_tl } % U+2423 + \l_tmpa_tl + \group_end: + } +% \end{macrocode} +% +% \bigskip +% Despite its name, |\@@_pre_env:| will be used both in |\PitonInputFile| and +% in the environments such as |{Piton}|. +% \begin{macrocode} +\cs_new:Npn \@@_pre_env: + { + \automatichyphenmode = 1 + \int_gincr:N \g_@@_env_int + \tl_gclear:N \g_@@_aux_tl + \dim_compare:nNnT \l_@@_width_dim = \c_zero_dim + { \dim_set_eq:NN \l_@@_width_dim \linewidth } +% \end{macrocode} +% We read the information written on the |aux| file by previous run (when the +% key |width| is used with the special value~|min|). At this time, the only +% potential information written on the |aux| file is the value of +% |\l_@@_line_width_dim| when the key |width| has been used with the special +% value~|min|). +% \begin{macrocode} + \cs_if_exist_use:c { c_@@ _ \int_use:N \g_@@_env_int _ tl } + \bool_if:NF \l_@@_resume_bool { \int_gzero:N \g_@@_visual_line_int } + \dim_gzero:N \g_@@_tmp_width_dim + \int_gzero:N \g_@@_line_int + \dim_zero:N \parindent + \dim_zero:N \lineskip + \dim_zero:N \parindent + \cs_set_eq:NN \label \@@_label:n + } +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\keys_define:nn { PitonInputFile } + { + first-line .int_set:N = \l_@@_first_line_int , + first-line .value_required:n = true , + last-line .int_set:N = \l_@@_last_line_int , + last-line .value_required:n = true , + } +% \end{macrocode} +% +% +% \bigskip +% If the final user has used both |left-margin=auto| and |line-numbers|, we have +% to compute the width of the maximal number of lines at the end of the +% environment to fix the correct value to |left-margin|. The first argument of +% the following function is the name of the Lua function that will be applied to +% the second argument in order to count the number of lines. +% \begin{macrocode} +\cs_new_protected:Npn \@@_compute_left_margin:nn #1 #2 + { + \bool_lazy_and:nnT \l_@@_left_margin_auto_bool \l_@@_line_numbers_bool + { + \hbox_set:Nn \l_tmpa_box + { + \footnotesize + \bool_if:NTF \l_@@_all_line_numbers_bool + { + \int_to_arabic:n + { \g_@@_visual_line_int + \l_@@_nb_lines_int } + } + { + \lua_now:n + { piton.#1(token.scan_argument()) } + { #2 } + \int_to_arabic:n + { \g_@@_visual_line_int + \l_@@_nb_non_empty_lines_int } + } + } + \dim_set:Nn \l_@@_left_margin_dim + { \box_wd:N \l_tmpa_box + \l_@@_numbers_sep_dim + 0.1 em } + } + } +% \end{macrocode} +% +% +% +% \bigskip +% Whereas |\l_@@_with_dim| is the width of the environment, +% |\l_@@_line_width_dim| is the width of the lines of code without the +% potential margins for the numbers of lines and the background. Depending on +% the case, you have to compute |\l_@@_line_width_dim| from |\l_@@_width_dim| or +% we have to do the opposite. +% \begin{macrocode} +\cs_new_protected:Npn \@@_compute_width: + { + \dim_compare:nNnTF \l_@@_line_width_dim = \c_zero_dim + { + \dim_set_eq:NN \l_@@_line_width_dim \l_@@_width_dim + \clist_if_empty:NTF \l_@@_bg_color_clist +% \end{macrocode} +% If there is no background, we only subtract the left margin. +% \begin{macrocode} + { \dim_sub:Nn \l_@@_line_width_dim \l_@@_left_margin_dim } +% \end{macrocode} +% If there is a background, we subtract 0.5~em for the margin on the right. +% \begin{macrocode} + { + \dim_sub:Nn \l_@@_line_width_dim { 0.5 em } +% \end{macrocode} +% And we subtract also for the left margin. If the key |left-margin| has been +% used (with a numerical value or with the special value~|min|), +% |\l_@@_left_margin_dim| has a non-zero value\footnote{If the key +% \texttt{left-margin} has been used with the special value \texttt{min}, the +% actual value of \texttt{\textbackslash l_\@\@_left_margin_dim} has yet been +% computed when we use the current command.} and we use that value. Elsewhere, +% we use a value of 0.5~em. +% \begin{macrocode} + \dim_compare:nNnTF \l_@@_left_margin_dim = \c_zero_dim + { \dim_sub:Nn \l_@@_line_width_dim { 0.5 em } } + { \dim_sub:Nn \l_@@_line_width_dim \l_@@_left_margin_dim } + } + } +% \end{macrocode} +% If |\l_@@_line_width_dim| has yet a non-empty value, that means that it has +% been read on the |aux| file: it has been written on a previous run because the +% key |width| is used with the special value~|min|). We compute now the width of +% the environment by computations opposite to the preceding ones. +% \begin{macrocode} + { + \dim_set_eq:NN \l_@@_width_dim \l_@@_line_width_dim + \clist_if_empty:NTF \l_@@_bg_color_clist + { \dim_add:Nn \l_@@_width_dim \l_@@_left_margin_dim } + { + \dim_add:Nn \l_@@_width_dim { 0.5 em } + \dim_compare:nNnTF \l_@@_left_margin_dim = \c_zero_dim + { \dim_add:Nn \l_@@_width_dim { 0.5 em } } + { \dim_add:Nn \l_@@_width_dim \l_@@_left_margin_dim } + } + } + } +% \end{macrocode} +% +% +% +% \bigskip +% \begin{macrocode} +\NewDocumentCommand { \NewPitonEnvironment } { m m m m } + { +% \end{macrocode} +% We construct a TeX macro which will catch as argument all the tokens until +% |\end{|\texttt{\textsl{name_env}}|}| with, in that +% |\end{|\texttt{\textsl{name_env}}|}|, the catcodes of |\|, |{| and |}| equal to +% 12 (``\texttt{other}''). The latter explains why the definition of that +% function is a bit complicated. +% \begin{macrocode} + \use:x + { + \cs_set_protected:Npn + \use:c { _@@_collect_ #1 :w } + ####1 + \c_backslash_str end \c_left_brace_str #1 \c_right_brace_str + } + { + \group_end: + \mode_if_vertical:TF \mode_leave_vertical: \newline +% \end{macrocode} +% We count with Lua the number of lines of the argument. The result will be +% stored by Lua in |\l_@@_nb_lines_int|. That information will be used to allow +% or disallow page breaks. +% \begin{macrocode} + \lua_now:n { piton.CountLines(token.scan_argument()) } { ##1 } +% \end{macrocode} +% The first argument of the following function is the name of the Lua function +% that will be applied to the second argument in order to count the number of lines. +% \begin{macrocode} + \@@_compute_left_margin:nn { CountNonEmptyLines } { ##1 } + \@@_compute_width: + \ttfamily +% \end{macrocode} +% |\c_@@_footnote_bool| is raised when the package \pkg{piton} has been load +% with the key |footnote| \emph{or} the key |footnotehyper|. +% \begin{macrocode} + \bool_if:NT \c_@@_footnote_bool { \begin { savenotes } } + \vtop \bgroup + \lua_now:e + { + piton.GobbleParse + ( + '\l_@@_language_str' , + \int_use:N \l_@@_gobble_int , + token.scan_argument() + ) + } + { ##1 } + \vspace { 2.5 pt } + \egroup + \bool_if:NT \c_@@_footnote_bool { \end { savenotes } } +% \end{macrocode} +% If the user has used the key |width| with the special value~|min|, we write on +% the |aux| file the value of |\l_@@_line_width_dim| (largest width of the lines +% of code of the environment). +% \begin{macrocode} + \bool_if:NT \l_@@_width_min_bool \@@_width_to_aux: +% \end{macrocode} +% The following |\end{#1}| is only for the stack of environments of LaTeX. +% \begin{macrocode} + \end { #1 } + \@@_write_aux: + } +% \end{macrocode} +% +% +% \bigskip +% We can now define the new environment. +% +% We are still in the definition of the command |\NewPitonEnvironment|... +% \begin{macrocode} + \NewDocumentEnvironment { #1 } { #2 } + { + #3 + \@@_pre_env: + \group_begin: + \tl_map_function:nN + { \ \\ \{ \} \$ \& \# \^ \_ \% \~ \^^I } + \char_set_catcode_other:N + \use:c { _@@_collect_ #1 :w } + } + { #4 } +% \end{macrocode} +% +% \medskip +% The following code is for technical reasons. We want to change the catcode of +% |^^M| before catching the arguments of the new environment we are defining. +% Indeed, if not, we will have problems if there is a final optional argument in +% our environment (if that final argument is not used by the user in an +% instance of the environment, a spurious space is inserted, probably because +% the |^^M| is converted to space). +% \begin{macrocode} + \AddToHook { env / #1 / begin } { \char_set_catcode_other:N \^^M } + } +% \end{macrocode} +% This is the end of the definition of the command |\NewPitonEnvironment|. +% +% \bigskip +% Now, we define the environment |{Piton}|, which is the main environment +% provided by the package \pkg{piton}. Of course, you use +% |\NewPitonEnvironment|. +% \begin{macrocode} +\bool_if:NTF \c_@@_beamer_bool + { + \NewPitonEnvironment { Piton } { d < > } + { + \IfValueTF { #1 } + { \begin { uncoverenv } < #1 > } + { \begin { uncoverenv } } + } + { \end { uncoverenv } } + } + { \NewPitonEnvironment { Piton } { } { } { } } +% \end{macrocode} +% +% +% \bigskip +% The code of the command |\PitonInputFile| is somewhat similar to the code of +% the environment |{Piton}|. In fact, it's simpler because there isn't the +% problem of catching the content of the environment in a verbatim mode. +% \begin{macrocode} +\NewDocumentCommand { \PitonInputFile } { d < > O { } m } + { + \file_if_exist:nTF { #3 } + { \@@_input_file:nnn { #1 } { #2 } { #3 } } + { \msg_error:nnn { piton } { unknown~file } { #3 } } + } +% \end{macrocode} +% +% \begin{macrocode} +\cs_new_protected:Npn \@@_input_file:nnn #1 #2 #3 + { +% \end{macrocode} +% We recall that, if we are in Beamer, the command |\PitonInputFile| is +% ``overlay-aware'' and that's why there is an optional argument between angular +% brackets (|<| and |>|). +% \begin{macrocode} + \tl_if_novalue:nF { #1 } + { + \bool_if:NTF \c_@@_beamer_bool + { \begin { uncoverenv } < #1 > } + { \msg_error:nn { piton } { overlay~without~beamer } } + } + \group_begin: + \int_zero_new:N \l_@@_first_line_int + \int_zero_new:N \l_@@_last_line_int + \int_set_eq:NN \l_@@_last_line_int \c_max_int + \keys_set:nn { PitonInputFile } { #2 } + \@@_pre_env: + \mode_if_vertical:TF \mode_leave_vertical: \newline +% \end{macrocode} +% We count with Lua the number of lines of the argument. The result will be +% stored by Lua in |\l_@@_nb_lines_int|. That information will be used to allow +% or disallow page breaks. +% \begin{macrocode} + \lua_now:n { piton.CountLinesFile(token.scan_argument()) } { #3 } +% \end{macrocode} +% The first argument of the following function is the name of the Lua function +% that will be applied to the second argument in order to count the number of lines. +% \begin{macrocode} + \@@_compute_left_margin:nn { CountNonEmptyLinesFile } { #3 } + \@@_compute_width: + \ttfamily + \bool_if:NT \c_@@_footnote_bool { \begin { savenotes } } + \vtop \bgroup + \lua_now:e + { + piton.ParseFile( + '\l_@@_language_str', + token.scan_argument() , + \int_use:N \l_@@_first_line_int , + \int_use:N \l_@@_last_line_int ) + } + { #3 } + \egroup + \bool_if:NT \c_@@_footnote_bool { \end { savenotes } } + \bool_if:NT \l_@@_width_min_bool \@@_width_to_aux: + \group_end: +% \end{macrocode} +% We recall that, if we are in Beamer, the command |\PitonInputFile| is +% ``overlay-aware'' and that's why we close now an environment |{uncoverenv}| +% that we have opened at the beginning of the command. +% \begin{macrocode} + \tl_if_novalue:nF { #1 } + { \bool_if:NT \c_@@_beamer_bool { \end { uncoverenv } } } + \@@_write_aux: + } +% \end{macrocode} +% +% \bigskip +% \subsubsection{The styles} +% +% \medskip +% The following command is fundamental: it will be used by the Lua code. +% \begin{macrocode} +\NewDocumentCommand { \PitonStyle } { m } { \use:c { pitonStyle #1 } } +% \end{macrocode} +% +% \medskip +% The following command takes in its argument by curryfication. +% \begin{macrocode} +\NewDocumentCommand { \SetPitonStyle } { } { \keys_set:nn { piton / Styles } } +% \end{macrocode} +% +% \medskip +% \begin{macrocode} +\cs_new_protected:Npn \@@_math_scantokens:n #1 + { \normalfont \scantextokens { $#1$ } } +% \end{macrocode} +% +% \medskip +% \begin{macrocode} +\keys_define:nn { piton / Styles } + { + String.Interpol .tl_set:c = pitonStyle String.Interpol , + String.Interpol .value_required:n = true , + FormattingType .tl_set:c = pitonStyle FormattingType , + FormattingType .value_required:n = true , + Dict.Value .tl_set:c = pitonStyle Dict.Value , + Dict.Value .value_required:n = true , + Name.Decorator .tl_set:c = pitonStyle Name.Decorator , + Name.Decorator .value_required:n = true , + Name.Field .tl_set:c = pitonStyle Name.Field , + Name.Field .value_required:n = true , + Name.Function .tl_set:c = pitonStyle Name.Function , + Name.Function .value_required:n = true , + UserFunction .tl_set:c = pitonStyle UserFunction , + UserFunction .value_required:n = true , + Keyword .tl_set:c = pitonStyle Keyword , + Keyword .value_required:n = true , + Keyword.Constant .tl_set:c = pitonStyle Keyword.Constant , + Keyword.constant .value_required:n = true , + String.Doc .tl_set:c = pitonStyle String.Doc , + String.Doc .value_required:n = true , + Interpol.Inside .tl_set:c = pitonStyle Interpol.Inside , + Interpol.Inside .value_required:n = true , + String.Long .tl_set:c = pitonStyle String.Long , + String.Long .value_required:n = true , + String.Short .tl_set:c = pitonStyle String.Short , + String.Short .value_required:n = true , + String .meta:n = { String.Long = #1 , String.Short = #1 } , + Comment.Math .tl_set:c = pitonStyle Comment.Math , + Comment.Math .default:n = \@@_math_scantokens:n , + Comment.Math .initial:n = , + Comment .tl_set:c = pitonStyle Comment , + Comment .value_required:n = true , + Name.Constructor .tl_set:c = pitonStyle Name.Constructor , + Name.Constructor .value_required:n = true , + InitialValues .tl_set:c = pitonStyle InitialValues , + InitialValues .value_required:n = true , + Number .tl_set:c = pitonStyle Number , + Number .value_required:n = true , + Name.Namespace .tl_set:c = pitonStyle Name.Namespace , + Name.Namespace .value_required:n = true , + Name.Module .tl_set:c = pitonStyle Name.Module , + Name.Module .value_required:n = true , + Name.Class .tl_set:c = pitonStyle Name.Class , + Name.Class .value_required:n = true , + Name.Builtin .tl_set:c = pitonStyle Name.Builtin , + Name.Builtin .value_required:n = true , + TypeParameter .tl_set:c = pitonStyle TypeParameter , + TypeParameter .value_required:n = true , + Name.Type .tl_set:c = pitonStyle Name.Type , + Name.Type .value_required:n = true , + Operator .tl_set:c = pitonStyle Operator , + Operator .value_required:n = true , + Operator.Word .tl_set:c = pitonStyle Operator.Word , + Operator.Word .value_required:n = true , + Exception .tl_set:c = pitonStyle Exception , + Exception .value_required:n = true , + Comment.LaTeX .tl_set:c = pitonStyle Comment.LaTeX , + Comment.LaTeX .value_required:n = true , + Identifier .tl_set:c = pitonStyle Identifier , + Comment.LaTeX .value_required:n = true , + ParseAgain.noCR .tl_set:c = pitonStyle ParseAgain.noCR , + ParseAgain.noCR .value_required:n = true , + ParseAgain .tl_set:c = pitonStyle ParseAgain , + ParseAgain .value_required:n = true , + Prompt .tl_set:c = pitonStyle Prompt , + Prompt .value_required:n = true , + unknown .code:n = + \msg_error:nn { piton } { Unknown~key~for~SetPitonStyle } + } +% \end{macrocode} +% +% +% \bigskip +% \begin{macrocode} +\msg_new:nnn { piton } { Unknown~key~for~SetPitonStyle } + { + The~style~'\l_keys_key_str'~is~unknown.\\ + This~key~will~be~ignored.\\ + The~available~styles~are~(in~alphabetic~order):~ + Comment,~ + Comment.LaTeX,~ + Dict.Value,~ + Exception,~ + Identifier,~ + InitialValues,~ + Keyword,~ + Keyword.Constant,~ + Name.Builtin,~ + Name.Class,~ + Name.Constructor,~ + Name.Decorator,~ + Name.Field,~ + Name.Function,~ + Name.Module,~ + Name.Namespace,~ + UserFunction,~ + Number,~ + Operator,~ + Operator.Word,~ + Prompt,~ + String,~ + String.Doc,~ + String.Long,~ + String.Short,~and~ + String.Interpol. + } +% \end{macrocode} +% +% \bigskip +% \subsubsection{The initial styles} +% +% The initial styles are inspired by the style ``manni'' of Pygments. +% +% \medskip +% \begin{macrocode} +\SetPitonStyle + { + Comment = \color[HTML]{0099FF} \itshape , + Exception = \color[HTML]{CC0000} , + Keyword = \color[HTML]{006699} \bfseries , + Keyword.Constant = \color[HTML]{006699} \bfseries , + Name.Builtin = \color[HTML]{336666} , + Name.Decorator = \color[HTML]{9999FF}, + Name.Class = \color[HTML]{00AA88} \bfseries , + Name.Function = \color[HTML]{CC00FF} , + Name.Namespace = \color[HTML]{00CCFF} , + Name.Constructor = \color[HTML]{006000} \bfseries , + Name.Field = \color[HTML]{AA6600} , + Name.Module = \color[HTML]{0060A0} \bfseries , + Number = \color[HTML]{FF6600} , + Operator = \color[HTML]{555555} , + Operator.Word = \bfseries , + String = \color[HTML]{CC3300} , + String.Doc = \color[HTML]{CC3300} \itshape , + String.Interpol = \color[HTML]{AA0000} , + Comment.LaTeX = \normalfont \color[rgb]{.468,.532,.6} , + Name.Type = \color[HTML]{336666} , + InitialValues = \@@_piton:n , + Dict.Value = \@@_piton:n , + Interpol.Inside = \color{black}\@@_piton:n , + TypeParameter = \color[HTML]{336666} \itshape , + Identifier = \@@_identifier:n , + UserFunction = , + Prompt = , + ParseAgain.noCR = \@@_piton_no_cr:n , + ParseAgain = \@@_piton:n , + } +% \end{macrocode} +% The last styles |ParseAgain.noCR| and |ParseAgain| should be considered as +% ``internal style'' (not available for the final user). However, maybe we will +% change that and document these styles for the final user (why not?). +% +% \medskip +% If the key |math-comments| has been used at load-time, we change the style +% |Comment.Math| which should be considered only at an ``internal style''. +% However, maybe we will document in a future version the possibility to write +% change the style \emph{locally} in a document)]. +% \begin{macrocode} +\bool_if:NT \c_@@_math_comments_bool { \SetPitonStyle { Comment.Math } } +% \end{macrocode} +% +% \bigskip +% +% \bigskip +% \subsubsection{Highlighting some identifiers} +% +% \begin{macrocode} +\cs_new_protected:Npn \@@_identifier:n #1 + { \cs_if_exist_use:c { PitonIdentifier _ \l_@@_language_str _ #1 } { #1 } } +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\keys_define:nn { PitonOptions } + { identifiers .code:n = \@@_set_identifiers:n { #1 } } +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\keys_define:nn { Piton / identifiers } + { + names .clist_set:N = \l_@@_identifiers_names_tl , + style .tl_set:N = \l_@@_style_tl , + } +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\cs_new_protected:Npn \@@_set_identifiers:n #1 + { + \clist_clear_new:N \l_@@_identifiers_names_tl + \tl_clear_new:N \l_@@_style_tl + \keys_set:nn { Piton / identifiers } { #1 } + \clist_map_inline:Nn \l_@@_identifiers_names_tl + { + \tl_set_eq:cN + { PitonIdentifier _ \l_@@_language_str _ ##1 } + \l_@@_style_tl + } + } +% \end{macrocode} +% +% +% \bigskip +% In particular, we have an highlighting of the indentifiers which are the +% names of Python functions previously defined by the user. Indeed, when a +% Python function is defined, the style |Name.Function.Internal| is applied to +% that name. We define now that style (you define it directly and you short-cut +% the function |\SetPitonStyle|). +% \begin{macrocode} +\cs_new_protected:cpn { pitonStyle Name.Function.Internal } #1 + { +% \end{macrocode} +% First, the element is composed in the TeX flow with the style |Name.Function| +% which is provided to the final user. +% \begin{macrocode} + { \PitonStyle { Name.Function } { #1 } } +% \end{macrocode} +% Now, we specify that the name of the new Python function is a known identifier +% that will be formated with the Piton style |UserFunction|. Of course, +% here the affectation is global because we have to exit many groups and even +% the environments |{Piton}|). +% \begin{macrocode} + \cs_gset_protected:cpn { PitonIdentifier _ \l_@@_language_str _ #1 } + { \PitonStyle { UserFunction } } +% \end{macrocode} +% Now, we put the name of that new user function in the dedicated sequence +% (specific of the current language). {\bfseries That sequence will be used only +% by |\PitonClearUserFunctions|}. +% \begin{macrocode} + \seq_if_exist:cF { g_@@_functions _ \l_@@_language_str _ seq } + { \seq_new:c { g_@@_functions _ \l_@@_language_str _ seq } } + \seq_gput_right:cn { g_@@_functions _ \l_@@_language_str _ seq } { #1 } + } +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\NewDocumentCommand \PitonClearUserFunctions { ! O { \l_@@_language_str } } + { + \seq_if_exist:cT { g_@@_functions _ #1 _ seq } + { + \seq_map_inline:cn { g_@@_functions _ #1 _ seq } + { \cs_undefine:c { PitonIdentifier _ #1 _ ##1} } + \seq_gclear:c { g_@@_functions _ #1 _ seq } + } + } +% \end{macrocode} +% +% \bigskip +% \subsubsection{Security} +% +% \begin{macrocode} +\AddToHook { env / piton / begin } + { \msg_fatal:nn { piton } { No~environment~piton } } + +\msg_new:nnn { piton } { No~environment~piton } + { + There~is~no~environment~piton!\\ + There~is~an~environment~{Piton}~and~a~command~ + \token_to_str:N \piton\ but~there~is~no~environment~ + {piton}.~This~error~is~fatal. + } +% \end{macrocode} +% +% \bigskip +% \subsubsection{The error messages of the package} +% +% \begin{macrocode} +\msg_new:nnn { piton } { unknown~file } + { + Unknown~file. \\ + The~file~'#1'~is~unknown.\\ + Your~command~\token_to_str:N \PitonInputFile\ will~be~discarded. + } +% \end{macrocode} +% +% \begin{macrocode} +\msg_new:nnnn { piton } { Unknown~key~for~PitonOptions } + { + Unknown~key. \\ + The~key~'\l_keys_key_str'~is~unknown~for~\token_to_str:N \PitonOptions.~ + It~will~be~ignored.\\ + For~a~list~of~the~available~keys,~type~H~<return>. + } + { + The~available~keys~are~(in~alphabetic~order):~ + all-line-numbers,~ + auto-gobble,~ + background-color,~ + break-lines,~ + break-lines-in-piton,~ + break-lines-in-Piton,~ + continuation-symbol,~ + continuation-symbol-on-indentation,~ + end-of-broken-line,~ + env-gobble,~ + gobble,~ + identifiers,~ + indent-broken-lines,~ + language,~ + left-margin,~ + line-numbers,~ + prompt-background-color,~ + resume,~ + show-spaces,~ + show-spaces-in-strings,~ + splittable,~ + tabs-auto-gobble,~ + tab-size~and~width. + } +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\msg_new:nnn { piton } { label~with~lines~numbers } + { + You~can't~use~the~command~\token_to_str:N \label\ + because~the~key~'line-numbers'~(or~'all-line-numbers')~ + is~not~active.\\ + If~you~go~on,~that~command~will~ignored. + } +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\msg_new:nnn { piton } { cr~not~allowed } + { + You~can't~put~any~carriage~return~in~the~argument~ + of~a~command~\c_backslash_str + \l_@@_beamer_command_str\ within~an~ + environment~of~'piton'.~You~should~consider~using~the~ + corresponding~environment.\\ + That~error~is~fatal. + } +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\msg_new:nnn { piton } { overlay~without~beamer } + { + You~can't~use~an~argument~<...>~for~your~command~ + \token_to_str:N \PitonInputFile\ because~you~are~not~ + in~Beamer.\\ + If~you~go~on,~that~argument~will~be~ignored. + } +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\msg_new:nnn { Piton } { Python~error } + { A~Python~error~has~been~detected. } +% \end{macrocode} +% +% \bigskip +% \subsection{The Lua part of the implementation} +% +% \bigskip +% \begin{macrocode} +\ExplSyntaxOff +\RequirePackage{luacode} +% \end{macrocode} +% +% +% \bigskip +% The Lua code will be loaded via a |{luacode*}| environment. The environment +% is by itself a Lua block and the local declarations will be local to that +% block. All the global functions (used by the L3 parts of the implementation) +% will be put in a Lua table |piton|. +% +% \medskip +% \begin{macrocode} +\begin{luacode*} +piton = piton or { } +% \end{macrocode} +% +% \begin{macrocode} +if piton.comment_latex == nil then piton.comment_latex = ">" end +piton.comment_latex = "#" .. piton.comment_latex +% \end{macrocode} +% +% +% \bigskip +% The following functions are an easy way to safely insert braces (|{| and |}|) +% in the TeX flow. +% \begin{macrocode} +function piton.open_brace () + tex.sprint("{") +end +function piton.close_brace () + tex.sprint("}") +end +% \end{macrocode} +% +% \bigskip +% \subsubsection{Special functions dealing with LPEG} +% +% \medskip +% We will use the Lua library \pkg{lpeg} which is built in LuaTeX. That's why we +% define first aliases for several functions of that library. +% \begin{macrocode} +local P, S, V, C, Ct, Cc = lpeg.P, lpeg.S, lpeg.V, lpeg.C, lpeg.Ct, lpeg.Cc +local Cf, Cs , Cg , Cmt , Cb = lpeg.Cf, lpeg.Cs, lpeg.Cg , lpeg.Cmt , lpeg.Cb +local R = lpeg.R +% \end{macrocode} +% +% +% +% \bigskip +% The function |Q| takes in as argument a pattern and returns a \textsc{lpeg} +% \emph{which does a capture} of the pattern. That capture will be sent to LaTeX +% with the catcode ``other'' for all the characters: it's suitable for elements +% of the Python listings that \pkg{piton} will typeset verbatim (thanks to the +% catcode ``other''). +% \begin{macrocode} +local function Q(pattern) + return Ct ( Cc ( luatexbase.catcodetables.CatcodeTableOther ) * C ( pattern ) ) +end +% \end{macrocode} +% +% +% \bigskip +% The function |L| takes in as argument a pattern and returns a \textsc{lpeg} +% \emph{which does a capture} of the pattern. That capture will be sent to LaTeX +% with standard LaTeX catcodes for all the characters: the elements captured +% will be formatted as normal LaTeX codes. It's suitable for the ``LaTeX +% comments'' in the environments |{Piton}| and the elements beetween +% ``|escape-inside|''. That function won't be much used. +% \begin{macrocode} +local function L(pattern) + return Ct ( C ( pattern ) ) +end +% \end{macrocode} +% +% \bigskip +% The function |Lc| (the c is for \emph{constant}) takes in as argument a string +% and returns a \textsc{lpeg} \emph{with does a constant capture} which returns +% that string. The elements captured will be formatted as L3 code. It will be +% used to send to LaTeX all the formatting LaTeX instructions we have to insert +% in order to do the syntactic highlighting (that's the main job of +% \pkg{piton}). That function will be widely used. +% \begin{macrocode} +local function Lc(string) + return Cc ( { luatexbase.catcodetables.expl , string } ) +end +% \end{macrocode} +% +% \bigskip +% The function |K| creates a \textsc{lpeg} which will return as capture the +% whole LaTeX code corresponding to a Python chunk (that is to say with the +% LaTeX formatting instructions corresponding to the syntactic nature of that +% Python chunk). The first argument is a Lua string corresponding to the name of +% a \pkg{piton} style and the second element is a pattern (that is to say a +% \textsc{lpeg} without capture) +% \begin{macrocode} +local function K(style, pattern) + return + Lc ( "{\\PitonStyle{" .. style .. "}{" ) + * Q ( pattern ) + * Lc ( "}}" ) +end +% \end{macrocode} +% The formatting commands in a given \pkg{piton} style (eg. the style |Keyword|) +% may be semi-global declarations (such as |\bfseries| or |\slshape|) or LaTeX +% macros with an argument (such as |\fbox| or |\colorbox{yellow}|). In order to +% deal with both syntaxes, we have used two pairs of braces: +% |{\PitonStyle{Keyword}{|\texttt{\slshape text to format}|}}|. +% +% +% \bigskip +% \begin{macrocode} +local function WithStyle(style,pattern) + return + Ct ( Cc "Open" * Cc ( "{\\PitonStyle{" .. style .. "}{" ) * Cc "}}" ) + * pattern + * Ct ( Cc "Close" ) +end +% \end{macrocode} +% +% \bigskip +% The following \textsc{lpeg} catches the Python chunks which are in LaTeX +% escapes (and that chunks will be considered as normal LaTeX constructions). We +% recall that |piton.begin_espace| and |piton_end_escape| are Lua strings +% corresponding to the key |escape-inside|\footnote{The \pkg{piton} key +% |escape-inside| is available at load-time only.}. Since the elements that will +% be catched must be sent to LaTeX with standard LaTeX catcodes, we put the +% capture (done by the function |C|) in a table (by using |Ct|, which is an +% alias for |lpeg.Ct|) without number of catcode table at the first component of +% the table. +% \begin{macrocode} +local Escape = + P(piton_begin_escape) + * L ( ( 1 - P(piton_end_escape) ) ^ 1 ) + * P(piton_end_escape) +% \end{macrocode} +% +% \vspace{1cm} +% The following line is mandatory. +% \begin{macrocode} +lpeg.locale(lpeg) +% \end{macrocode} +% +% \bigskip +% \paragraph{The basic syntactic LPEG} +% +% \begin{macrocode} +local alpha, digit = lpeg.alpha, lpeg.digit +local space = P " " +% \end{macrocode} +% +% Remember that, for \textsc{lpeg}, the Unicode characters such as |à|, |â|, +% |ç|, etc. are in fact strings of length 2 (2 bytes) because \pkg{lpeg} is not +% Unicode-aware. +% \begin{macrocode} +local letter = alpha + P "_" + + P "â" + P "à" + P "ç" + P "é" + P "è" + P "ê" + P "ë" + P "ï" + P "î" + + P "ô" + P "û" + P "ü" + P "Â" + P "À" + P "Ç" + P "É" + P "È" + P "Ê" + + P "Ë" + P "Ï" + P "Î" + P "Ô" + P "Û" + P "Ü" + +local alphanum = letter + digit +% \end{macrocode} +% +% \bigskip +% The following \textsc{lpeg} |identifier| is a mere pattern (that is to say +% more or less a regular expression) which matches the Python identifiers (hence +% the name). +% \begin{macrocode} +local identifier = letter * alphanum ^ 0 +% \end{macrocode} +% +% \medskip +% On the other hand, the \textsc{lpeg} |Identifier| (with a capital) also returns +% a \emph{capture}. +% \begin{macrocode} +local Identifier = K ( 'Identifier' , identifier) +% \end{macrocode} +% +% \bigskip +% By convention, we will use names with an initial capital for \textsc{lpeg} +% which return captures. +% +% +% \bigskip +% Here is the first use of our function~|K|. That function will be used to +% construct \textsc{lpeg} which capture Python chunks for which we have a +% dedicated \pkg{piton} style. For example, for the numbers, \pkg{piton} +% provides a style which is called |Number|. The name of the style is provided +% as a Lua string in the second argument of the function~|K|. By convention, we +% use single quotes for delimiting the Lua strings which are names of +% \pkg{piton} styles (but this is only a convention). +% \begin{macrocode} +local Number = + K ( 'Number' , + ( digit^1 * P "." * digit^0 + digit^0 * P "." * digit^1 + digit^1 ) + * ( S "eE" * S "+-" ^ -1 * digit^1 ) ^ -1 + + digit^1 + ) +% \end{macrocode} +% +% \bigskip +% We recall that |piton.begin_espace| and |piton_end_escape| are Lua strings +% corresponding to the key |escape-inside|\footnote{The \pkg{piton} key +% |escape-inside| is available at load-time only.}. Of course, if the final user +% has not used the key |escape-inside|, these strings are empty. +% \begin{macrocode} +local Word +if piton_begin_escape ~= '' +then Word = Q ( ( ( 1 - space - P(piton_begin_escape) - P(piton_end_escape) ) + - S "'\"\r[()]" - digit ) ^ 1 ) +else Word = Q ( ( ( 1 - space ) - S "'\"\r[()]" - digit ) ^ 1 ) +end +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +local Space = ( Q " " ) ^ 1 + +local SkipSpace = ( Q " " ) ^ 0 + +local Punct = Q ( S ".,:;!" ) + +local Tab = P "\t" * Lc ( '\\l_@@_tab_tl' ) +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +local SpaceIndentation = Lc ( '\\@@_an_indentation_space:' ) * ( Q " " ) +% \end{macrocode} +% +% +% \bigskip +% \begin{macrocode} +local Delim = Q ( S "[()]" ) +% \end{macrocode} +% +% \bigskip +% The following \textsc{lpeg} catches a space (U+0020) and replace it by +% |\l_@@_space_tl|. It will be used in the strings. Usually, +% |\l_@@_space_tl| will contain a space and therefore there won't be difference. +% However, when the key |show-spaces-in-strings| is in force, |\\l_@@_space_tl| will +% contain ␣ (U+2423) in order to visualize the spaces. +% \begin{macrocode} +local VisualSpace = space * Lc "\\l_@@_space_tl" +% \end{macrocode} +% +% +% \bigskip +% \subsubsection{The LPEG python} +% +% \bigskip +% Some strings of length 2 are explicit because we want the corresponding +% ligatures available in some fonts such as \emph{Fira Code} to be active. +% \begin{macrocode} +local Operator = + K ( 'Operator' , + P "!=" + P "<>" + P "==" + P "<<" + P ">>" + P "<=" + P ">=" + P ":=" + + P "//" + P "**" + S "-~+/*%=<>&.@|" + ) + +local OperatorWord = + K ( 'Operator.Word' , P "in" + P "is" + P "and" + P "or" + P "not" ) + +local Keyword = + K ( 'Keyword' , + P "as" + P "assert" + P "break" + P "case" + P "class" + P "continue" + + P "def" + P "del" + P "elif" + P "else" + P "except" + P "exec" + + P "finally" + P "for" + P "from" + P "global" + P "if" + P "import" + + P "lambda" + P "non local" + P "pass" + P "return" + P "try" + + P "while" + P "with" + P "yield" + P "yield from" ) + + K ( 'Keyword.Constant' ,P "True" + P "False" + P "None" ) + +local Builtin = + K ( 'Name.Builtin' , + P "__import__" + P "abs" + P "all" + P "any" + P "bin" + P "bool" + + P "bytearray" + P "bytes" + P "chr" + P "classmethod" + P "compile" + + P "complex" + P "delattr" + P "dict" + P "dir" + P "divmod" + + P "enumerate" + P "eval" + P "filter" + P "float" + P "format" + + P "frozenset" + P "getattr" + P "globals" + P "hasattr" + P "hash" + + P "hex" + P "id" + P "input" + P "int" + P "isinstance" + P "issubclass" + + P "iter" + P "len" + P "list" + P "locals" + P "map" + P "max" + + P "memoryview" + P "min" + P "next" + P "object" + P "oct" + P "open" + + P "ord" + P "pow" + P "print" + P "property" + P "range" + P "repr" + + P "reversed" + P "round" + P "set" + P "setattr" + P "slice" + P "sorted" + + P "staticmethod" + P "str" + P "sum" + P "super" + P "tuple" + P "type" + + P "vars" + P "zip" ) + + +local Exception = + K ( 'Exception' , + P "ArithmeticError" + P "AssertionError" + P "AttributeError" + + P "BaseException" + P "BufferError" + P "BytesWarning" + P "DeprecationWarning" + + P "EOFError" + P "EnvironmentError" + P "Exception" + P "FloatingPointError" + + P "FutureWarning" + P "GeneratorExit" + P "IOError" + P "ImportError" + + P "ImportWarning" + P "IndentationError" + P "IndexError" + P "KeyError" + + P "KeyboardInterrupt" + P "LookupError" + P "MemoryError" + P "NameError" + + P "NotImplementedError" + P "OSError" + P "OverflowError" + + P "PendingDeprecationWarning" + P "ReferenceError" + P "ResourceWarning" + + P "RuntimeError" + P "RuntimeWarning" + P "StopIteration" + + P "SyntaxError" + P "SyntaxWarning" + P "SystemError" + P "SystemExit" + + P "TabError" + P "TypeError" + P "UnboundLocalError" + P "UnicodeDecodeError" + + P "UnicodeEncodeError" + P "UnicodeError" + P "UnicodeTranslateError" + + P "UnicodeWarning" + P "UserWarning" + P "ValueError" + P "VMSError" + + P "Warning" + P "WindowsError" + P "ZeroDivisionError" + + P "BlockingIOError" + P "ChildProcessError" + P "ConnectionError" + + P "BrokenPipeError" + P "ConnectionAbortedError" + P "ConnectionRefusedError" + + P "ConnectionResetError" + P "FileExistsError" + P "FileNotFoundError" + + P "InterruptedError" + P "IsADirectoryError" + P "NotADirectoryError" + + P "PermissionError" + P "ProcessLookupError" + P "TimeoutError" + + P "StopAsyncIteration" + P "ModuleNotFoundError" + P "RecursionError" ) + + +local RaiseException = K ( 'Keyword' , P "raise" ) * SkipSpace * Exception * Q ( P "(" ) + +% \end{macrocode} +% +% \bigskip +% In Python, a ``decorator'' is a statement whose begins by |@| which patches +% the function defined in the following statement. +% \begin{macrocode} +local Decorator = K ( 'Name.Decorator' , P "@" * letter^1 ) +% \end{macrocode} +% +% \bigskip +% The following \textsc{lpeg} |DefClass| will be used to detect the definition of a +% new class (the name of that new class will be formatted with the \pkg{piton} +% style |Name.Class|). +% +% \smallskip +% Example:\enskip \piton{class myclass:} +% \begin{macrocode} +local DefClass = + K ( 'Keyword' , P "class" ) * Space * K ( 'Name.Class' , identifier ) +% \end{macrocode} +% +% If the word |class| is not followed by a identifier, it will be catched as +% keyword by the \textsc{lpeg} |Keyword| (useful if we want to type a +% list of keywords). +% +% +% \bigskip +% The following \textsc{lpeg} |ImportAs| is used for the lines beginning by |import|. +% % We have to detect the potential keyword |as| because both the name of the +% module and its alias must be formatted with the \pkg{piton} style |Name.Namespace|. +% +% \smallskip +% Example:\enskip \piton{import numpy as np} +% +% \smallskip +% Moreover, after the keyword |import|, it's possible to have a comma-separated +% list of modules (if the keyword |as| is not used). +% +% \smallskip +% Example:\enskip \piton{import math, numpy} +% \begin{macrocode} +local ImportAs = + K ( 'Keyword' , P "import" ) + * Space + * K ( 'Name.Namespace' , + identifier * ( P "." * identifier ) ^ 0 ) + * ( + ( Space * K ( 'Keyword' , P "as" ) * Space + * K ( 'Name.Namespace' , identifier ) ) + + + ( SkipSpace * Q ( P "," ) * SkipSpace + * K ( 'Name.Namespace' , identifier ) ) ^ 0 + ) +% \end{macrocode} +% Be careful: there is no commutativity of |+| in the previous expression. +% +% \bigskip +% The \textsc{lpeg} |FromImport| is used for the lines beginning by |from|. We +% need a special treatment because the identifier following the keyword |from| +% must be formatted with the \pkg{piton} style |Name.Namespace| and the +% following keyword |import| must be formatted with the \pkg{piton} style +% |Keyword| and must \emph{not} be catched by the \textsc{lpeg} |ImportAs|. +% +% \smallskip +% Example:\enskip \piton{from math import pi} +% +% \smallskip +% \begin{macrocode} +local FromImport = + K ( 'Keyword' , P "from" ) + * Space * K ( 'Name.Namespace' , identifier ) + * Space * K ( 'Keyword' , P "import" ) +% \end{macrocode} +% +% \bigskip +% \paragraph{The strings of Python} +% +% For the strings in Python, there are four categories of delimiters (without +% counting the prefixes for f-strings and raw strings). We will use, in the +% names of our \textsc{lpeg}, prefixes to distinguish the \textsc{lpeg} dealing +% with that categories of strings, as presented in the following tabular. +% \begin{center} +% \begin{tabular}{ccc} +% \toprule +% & |Single| & |Double| \\ +% \midrule +% |Short| & |'text'| & |"text"| \\ +% |Long| & |'''test'''| & |"""text"""| \\ +% \bottomrule +% \end{tabular} +% \end{center} +% +% +% \bigskip +% We have also to deal with the interpolations in the f-strings. Here +% is an example of a f-string with an interpolation and a format +% instruction\footnote{There is no special \pkg{piton} style for the formatting +% instruction (after the colon): the style which will be applied will be the +% style of the encompassing string, that is to say |String.Short| or +% |String.Long|.} in that interpolation: +% +% \piton{f'Total price: {total+1:.2f} €'} +% +% +% \bigskip +% The interpolations beginning by |%| (even though there is more modern +% technics now in Python). +% \begin{macrocode} +local PercentInterpol = + K ( 'String.Interpol' , + P "%" + * ( P "(" * alphanum ^ 1 * P ")" ) ^ -1 + * ( S "-#0 +" ) ^ 0 + * ( digit ^ 1 + P "*" ) ^ -1 + * ( P "." * ( digit ^ 1 + P "*" ) ) ^ -1 + * ( S "HlL" ) ^ -1 + * S "sdfFeExXorgiGauc%" + ) +% \end{macrocode} +% +% \bigskip +% We can now define the \textsc{lpeg} for the four kinds of strings. It's not +% possible to use our function~|K| because of the interpolations which must be +% formatted with another \pkg{piton} style that the rest of the +% string.\footnote{The interpolations are formatted with the \pkg{piton} style +% |Interpol.Inside|. The initial value of that style is \texttt{\textbackslash +% @@\_piton:n} wich means that the interpolations are parsed once again by \pkg{piton}.} +% \begin{macrocode} +local SingleShortString = + WithStyle ( 'String.Short' , +% \end{macrocode} +% First, we deal with the f-strings of Python, which are prefixed by |f| or |F|. +% \begin{macrocode} + Q ( P "f'" + P "F'" ) + * ( + K ( 'String.Interpol' , P "{" ) + * K ( 'Interpol.Inside' , ( 1 - S "}':" ) ^ 0 ) + * Q ( P ":" * (1 - S "}:'") ^ 0 ) ^ -1 + * K ( 'String.Interpol' , P "}" ) + + + VisualSpace + + + Q ( ( P "\\'" + P "{{" + P "}}" + 1 - S " {}'" ) ^ 1 ) + ) ^ 0 + * Q ( P "'" ) + + +% \end{macrocode} +% Now, we deal with the standard strings of Python, but also the ``raw strings''. +% \begin{macrocode} + Q ( P "'" + P "r'" + P "R'" ) + * ( Q ( ( P "\\'" + 1 - S " '\r%" ) ^ 1 ) + + VisualSpace + + PercentInterpol + + Q ( P "%" ) + ) ^ 0 + * Q ( P "'" ) ) + + +local DoubleShortString = + WithStyle ( 'String.Short' , + Q ( P "f\"" + P "F\"" ) + * ( + K ( 'String.Interpol' , P "{" ) + * Q ( ( 1 - S "}\":" ) ^ 0 , 'Interpol.Inside' ) + * ( K ( 'String.Interpol' , P ":" ) * Q ( (1 - S "}:\"") ^ 0 ) ) ^ -1 + * K ( 'String.Interpol' , P "}" ) + + + VisualSpace + + + Q ( ( P "\\\"" + P "{{" + P "}}" + 1 - S " {}\"" ) ^ 1 ) + ) ^ 0 + * Q ( P "\"" ) + + + Q ( P "\"" + P "r\"" + P "R\"" ) + * ( Q ( ( P "\\\"" + 1 - S " \"\r%" ) ^ 1 ) + + VisualSpace + + PercentInterpol + + Q ( P "%" ) + ) ^ 0 + * Q ( P "\"" ) ) + +local ShortString = SingleShortString + DoubleShortString +% \end{macrocode} +% +% \bigskip +% \paragraph{Beamer} +% +% The following \textsc{lpeg} |balanced_braces| will be used for the (mandatory) +% argument of the commands |\only| and \emph{al.} of Beamer. It's necessary to +% use a \emph{grammar} because that pattern mainly checks the correct nesting of +% the delimiters (and it's known in the theory of formal languages that this +% can't be done with regular expressions \emph{stricto sensu} only). +% \begin{macrocode} +local balanced_braces = + P { "E" , + E = + ( + P "{" * V "E" * P "}" + + + ShortString + + + ( 1 - S "{}" ) + ) ^ 0 + } +% \end{macrocode} +% +% +% \bigskip +% If Beamer is used (or if the key |beamer| is used at load-time), the following +% LPEG will be redefined. +% \begin{macrocode} +local Beamer = P ( false ) +local BeamerBeginEnvironments = P ( true ) +local BeamerEndEnvironments = P ( true ) +local BeamerNamesEnvironments = + P "uncoverenv" + P "onlyenv" + P "visibleenv" + P "invisibleenv" + + P "alertenv" + P "actionenv" +% \end{macrocode} +% +% +% \bigskip +% The following function will return a \textsc{lpeg} which will catch an +% environment of Beamer (supported by \pkg{piton}), that is to say |{uncover}|, +% |{only}|, etc. +% \begin{macrocode} +function OneBeamerEnvironment(name) + return + Ct ( Cc "Open" + * C ( + P ( "\\begin{" .. name .. "}" ) + * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1 + ) + * Cc ( "\\end{" .. name .. "}" ) + ) + * ( + C ( ( 1 - P ( "\\end{" .. name .. "}" ) ) ^ 0 ) + / ( function (s) return MainLoopPython:match(s) end ) + ) + * P ( "\\end{" .. name .. "}" ) * Ct ( Cc "Close" ) +end +% \end{macrocode} +% +% +% \bigskip +% \begin{macrocode} +if piton_beamer +then + Beamer = + L ( P "\\pause" * ( P "[" * ( 1 - P "]" ) ^ 0 * P "]" ) ^ -1 ) + + + Ct ( Cc "Open" + * C ( + ( + P "\\uncover" + P "\\only" + P "\\alert" + P "\\visible" + + P "\\invisible" + P "\\action" + ) + * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1 + * P "{" + ) + * Cc "}" + ) + * ( C ( balanced_braces ) / (function (s) return MainLoopPython:match(s) end ) ) + * P "}" * Ct ( Cc "Close" ) + + OneBeamerEnvironment "uncoverenv" + + OneBeamerEnvironment "onlyenv" + + OneBeamerEnvironment "visibleenv" + + OneBeamerEnvironment "invisibleenv" + + OneBeamerEnvironment "alertenv" + + OneBeamerEnvironment "actionenv" + + + L ( +% \end{macrocode} +% For |\\alt|, the specification of the overlays (between angular brackets) is mandatory. +% \begin{macrocode} + ( P "\\alt" ) + * P "<" * (1 - P ">") ^ 0 * P ">" + * P "{" + ) + * K ( 'ParseAgain.noCR' , balanced_braces ) + * L ( P "}{" ) + * K ( 'ParseAgain.noCR' , balanced_braces ) + * L ( P "}" ) + + + L ( +% \end{macrocode} +% For |\\alt|, the specification of the overlays (between angular brackets) is mandatory. +% \begin{macrocode} + ( P "\\temporal" ) + * P "<" * (1 - P ">") ^ 0 * P ">" + * P "{" + ) + * K ( 'ParseAgain.noCR' , balanced_braces ) + * L ( P "}{" ) + * K ( 'ParseAgain.noCR' , balanced_braces ) + * L ( P "}{" ) + * K ( 'ParseAgain.noCR' , balanced_braces ) + * L ( P "}" ) +% \end{macrocode} +% Now for the environemnts. +% \begin{macrocode} + BeamerBeginEnvironments = + ( space ^ 0 * + L + ( + P "\\begin{" * BeamerNamesEnvironments * "}" + * ( P "<" * ( 1 - P ">") ^ 0 * P ">" ) ^ -1 + ) + * P "\r" + ) ^ 0 + BeamerEndEnvironments = + ( space ^ 0 * + L ( P "\\end{" * BeamerNamesEnvironments * P "}" ) + * P "\r" + ) ^ 0 +end +% \end{macrocode} +% +% \bigskip +% \paragraph{EOL} +% +% \bigskip +% The following LPEG will detect the Python prompts when the user is typesetting +% an interactive session of Python (directly or through |{pyconsole}| of +% \pkg{pyluatex}). We have to detect that prompt twice. The first detection +% (called \emph{hasty detection}) will be before the |\@@_begin_line:| because +% you want to trigger a special background color for that row (and, after the +% |\@@_begin_line:|, it's too late to change de background). +% \begin{macrocode} +local PromptHastyDetection = ( # ( P ">>>" + P "..." ) * Lc ( '\\@@_prompt:' ) ) ^ -1 +% \end{macrocode} +% We remind that the marker |#| of \textsc{lpeg} specifies that the pattern will be +% detected but won't consume any character. +% +% \medskip +% With the following \textsc{lpeg}, a style will actually be applied to the +% prompt (for instance, it's possible to decide to discard these prompts). +% \begin{macrocode} +local Prompt = K ( 'Prompt' , ( ( P ">>>" + P "..." ) * P " " ^ -1 ) ^ -1 ) +% \end{macrocode} +% +% +% +% \bigskip +% The following \textsc{lpeg} |EOL| is for the end of lines. +% \begin{macrocode} +local EOL = + P "\r" + * + ( + ( space^0 * -1 ) + + +% \end{macrocode} +% We recall that each line in the Python code we have to parse will be sent +% back to LaTeX between a pair |\@@_begin_line:| -- +% |\@@_end_line:|\footnote{Remember that the \texttt{\textbackslash +% @@\_end\_line:} must be explicit because it will be used as marker in order to +% delimit the argument of the command \texttt{\textbackslash @@\_begin\_line:}}. +% \begin{macrocode} + Ct ( + Cc "EOL" + * + Ct ( + Lc "\\@@_end_line:" + * BeamerEndEnvironments + * BeamerBeginEnvironments + * PromptHastyDetection + * Lc "\\@@_newline: \\@@_begin_line:" + * Prompt + ) + ) + ) + * + SpaceIndentation ^ 0 +% \end{macrocode} +% +% +% \bigskip +% \paragraph{The long strings} +% +% +% \begin{macrocode} +local SingleLongString = + WithStyle ( 'String.Long' , + ( Q ( S "fF" * P "'''" ) + * ( + K ( 'String.Interpol' , P "{" ) + * K ( 'Interpol.Inside' , ( 1 - S "}:\r" - P "'''" ) ^ 0 ) + * Q ( P ":" * (1 - S "}:\r" - P "'''" ) ^ 0 ) ^ -1 + * K ( 'String.Interpol' , P "}" ) + + + Q ( ( 1 - P "'''" - S "{}'\r" ) ^ 1 ) + + + EOL + ) ^ 0 + + + Q ( ( S "rR" ) ^ -1 * P "'''" ) + * ( + Q ( ( 1 - P "'''" - S "\r%" ) ^ 1 ) + + + PercentInterpol + + + P "%" + + + EOL + ) ^ 0 + ) + * Q ( P "'''" ) ) + + +local DoubleLongString = + WithStyle ( 'String.Long' , + ( + Q ( S "fF" * P "\"\"\"" ) + * ( + K ( 'String.Interpol', P "{" ) + * K ( 'Interpol.Inside' , ( 1 - S "}:\r" - P "\"\"\"" ) ^ 0 ) + * Q ( P ":" * (1 - S "}:\r" - P "\"\"\"" ) ^ 0 ) ^ -1 + * K ( 'String.Interpol' , P "}" ) + + + Q ( ( 1 - P "\"\"\"" - S "{}\"\r" ) ^ 1 ) + + + EOL + ) ^ 0 + + + Q ( ( S "rR" ) ^ -1 * P "\"\"\"" ) + * ( + Q ( ( 1 - P "\"\"\"" - S "%\r" ) ^ 1 ) + + + PercentInterpol + + + P "%" + + + EOL + ) ^ 0 + ) + * Q ( P "\"\"\"" ) + ) +% \end{macrocode} +% +% \begin{macrocode} +local LongString = SingleLongString + DoubleLongString +% \end{macrocode} +% +% \bigskip +% We have a \textsc{lpeg} for the Python docstrings. That \textsc{lpeg} will +% be used in the \textsc{lpeg} |DefFunction| which deals with the whole preamble +% of a function definition (which begins with |def|). +% \begin{macrocode} +local StringDoc = + K ( 'String.Doc' , P "\"\"\"" ) + * ( K ( 'String.Doc' , (1 - P "\"\"\"" - P "\r" ) ^ 0 ) * EOL + * Tab ^ 0 + ) ^ 0 + * K ( 'String.Doc' , ( 1 - P "\"\"\"" - P "\r" ) ^ 0 * P "\"\"\"" ) +% \end{macrocode} +% +% \bigskip +% \paragraph{The comments in the Python listings} +% +% We define different \textsc{lpeg} dealing with comments in the Python +% listings. +% \begin{macrocode} +local CommentMath = + P "$" * K ( 'Comment.Math' , ( 1 - S "$\r" ) ^ 1 ) * P "$" + +local Comment = + WithStyle ( 'Comment' , + Q ( P "#" ) + * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0 ) + * ( EOL + -1 ) +% \end{macrocode} +% +% +% +% \bigskip +% The following \textsc{lpeg} |CommentLaTeX| is for what is called in that +% document the ``LaTeX comments''. Since the elements that will be catched must +% be sent to LaTeX with standard LaTeX catcodes, we put the capture (done by +% the function~|C|) in a table (by using~|Ct|, which is an alias for |lpeg.Ct|). +% \begin{macrocode} +local CommentLaTeX = + P(piton.comment_latex) + * Lc "{\\PitonStyle{Comment.LaTeX}{\\ignorespaces" + * L ( ( 1 - P "\r" ) ^ 0 ) + * Lc "}}" + * ( EOL + -1 ) +% \end{macrocode} +% +% \bigskip +% \paragraph{DefFunction} +% +% The following \textsc{lpeg} |expression| will be used for the parameters in +% the \emph{argspec} of a Python function. It's necessary to use a \emph{grammar} +% because that pattern mainly checks the correct nesting of the delimiters +% (and it's known in the theory of formal languages that this can't be done with +% regular expressions \emph{stricto sensu} only). +% \begin{macrocode} +local expression = + P { "E" , + E = ( P "'" * ( P "\\'" + 1 - S "'\r" ) ^ 0 * P "'" + + P "\"" * (P "\\\"" + 1 - S "\"\r" ) ^ 0 * P "\"" + + P "{" * V "F" * P "}" + + P "(" * V "F" * P ")" + + P "[" * V "F" * P "]" + + ( 1 - S "{}()[]\r," ) ) ^ 0 , + F = ( P "{" * V "F" * P "}" + + P "(" * V "F" * P ")" + + P "[" * V "F" * P "]" + + ( 1 - S "{}()[]\r\"'" ) ) ^ 0 + } +% \end{macrocode} +% +% \bigskip +% We will now define a \textsc{lpeg} |Params| that will catch the list of +% parameters (that is to say the \emph{argspec}) in the definition of a Python +% function. For example, in the line of code +% \begin{center} +% \piton{def MyFunction(a,b,x=10,n:int): return n} +% \end{center} +% the \textsc{lpeg} |Params| will be used to catch the chunk\enskip |a,b,x=10,n:int|. +% +% Or course, a |Params| is simply a comma-separated list of |Param|, and that's +% why we define first the \textsc{lpeg} |Param|. +% +% \medskip +% \begin{macrocode} +local Param = + SkipSpace * Identifier * SkipSpace + * ( + K ( 'InitialValues' , P "=" * expression ) + + Q ( P ":" ) * SkipSpace * K ( 'Name.Type' , letter ^ 1 ) + ) ^ -1 +% \end{macrocode} +% +% \medskip +% \begin{macrocode} +local Params = ( Param * ( Q "," * Param ) ^ 0 ) ^ -1 +% \end{macrocode} +% +% \bigskip +% The following \textsc{lpeg} |DefFunction| catches a keyword |def| and the +% following name of function \emph{but also everything else until a potential +% docstring}. That's why this definition of \textsc{lpeg} must occur (in the file +% |piton.sty|) after the definition of several other \textsc{lpeg} such as +% |Comment|, |CommentLaTeX|, |Params|, |StringDoc|... +% \begin{macrocode} +local DefFunction = + K ( 'Keyword' , P "def" ) + * Space + * K ( 'Name.Function.Internal' , identifier ) + * SkipSpace + * Q ( P "(" ) * Params * Q ( P ")" ) + * SkipSpace + * ( Q ( P "->" ) * SkipSpace * K ( 'Name.Type' , identifier ) ) ^ -1 +% \end{macrocode} +% Here, we need a \pkg{piton} style |ParseAgain| which will be linked to +% |\@@_piton:n| (that means that the capture will be parsed once again by +% \pkg{piton}). We could avoid that kind of trick by using a non-terminal of a +% grammar but we have probably here a better legibility. +% \begin{macrocode} + * K ( 'ParseAgain' , ( 1 - S ":\r" )^0 ) + * Q ( P ":" ) + * ( SkipSpace + * ( EOL + CommentLaTeX + Comment ) -- in all cases, that contains an EOL + * Tab ^ 0 + * SkipSpace + * StringDoc ^ 0 -- there may be additionnal docstrings + ) ^ -1 +% \end{macrocode} +% Remark that, in the previous code, |CommentLaTeX| \emph{must} appear +% before |Comment|: there is no commutativity of the addition for the +% \emph{parsing expression grammars} (\textsc{peg}). +% +% \smallskip +% If the word |def| is not followed by an identifier and parenthesis, it will be +% catched as keyword by the \textsc{lpeg} |Keyword| (useful if, for example, the +% final user wants to speak of the keyword \piton{def}). +% +% \bigskip +% \paragraph{The dictionaries of Python} +% +% We have \textsc{lpeg} dealing with dictionaries of Python because, in +% typesettings of explicit Python dictionaries, one may prefer to have all the +% values formatted in black (in order to see more clearly the keys which are +% usually Python strings). That's why we have a \pkg{piton} style |Dict.Value|. +% +% The initial value of that \pkg{piton} style is |\@@_piton:n|, which means that +% the value of the entry of the dictionary is parsed once again by \pkg{piton} +% (and nothing special is done for the dictionary). In the following example, we +% have set the \pkg{piton} style |Dict.Value| to |\color{black}|: +% +% \medskip +% \begingroup +% \SetPitonStyle{Dict.Value = \color{black}} +% \piton{mydict = { 'name' : 'Paul', 'sex' : 'male', 'age' : 31 } } +% \endgroup +% +% \medskip +% At this time, this mechanism works only for explicit dictionaries on a single line! +% +% \begin{macrocode} +local ItemDict = + ShortString * SkipSpace * Q ( P ":" ) * K ( 'Dict.Value' , expression ) + +local ItemOfSet = SkipSpace * ( ItemDict + ShortString ) * SkipSpace + +local Set = + Q ( P "{" ) + * ItemOfSet * ( Q ( P "," ) * ItemOfSet ) ^ 0 + * Q ( P "}" ) +% \end{macrocode} +% +% \paragraph{Miscellaneous} +% +% \begin{macrocode} +local ExceptionInConsole = Exception * Q ( ( 1 - P "\r" ) ^ 0 ) * EOL +% \end{macrocode} +% +% +% \bigskip +% \paragraph{The main LPEG} +% +% First, the main loop : +% \begin{macrocode} +local MainPython = + EOL + + Space + + Tab + + Escape + + CommentLaTeX + + Beamer + + LongString + + Comment + + ExceptionInConsole + + Set + + Delim + + Operator + + OperatorWord * ( Space + Punct + Delim + EOL + -1 ) + + ShortString + + Punct + + FromImport + + RaiseException + + DefFunction + + DefClass + + Keyword * ( Space + Punct + Delim + EOL + -1 ) + + Decorator + + Builtin * ( Space + Punct + Delim + EOL + -1 ) + + Identifier + + Number + + Word +% \end{macrocode} +% +% Ici, il ne faut pas mettre |local| ! +% \begin{macrocode} +MainLoopPython = + ( ( space^1 * -1 ) + + MainPython + ) ^ 0 +% \end{macrocode} +% +% \bigskip +% We recall that each line in the Python code to parse will be sent back to +% LaTeX between a pair |\@@_begin_line:| -- |\@@_end_line:|\footnote{Remember +% that the \texttt{\textbackslash @@\_end\_line:} must be explicit because it +% will be used as marker in order to delimit the argument of the command +% \texttt{\textbackslash @@\_begin\_line:}}. +% \begin{macrocode} +local python = P ( true ) + +python = + Ct ( + ( ( space - P "\r" ) ^0 * P "\r" ) ^ -1 + * BeamerBeginEnvironments + * PromptHastyDetection + * Lc '\\@@_begin_line:' + * Prompt + * SpaceIndentation ^ 0 + * MainLoopPython + * -1 + * Lc '\\@@_end_line:' + ) +% \end{macrocode} +% +% \begin{macrocode} +local languages = { } +languages['python'] = python +% \end{macrocode} +% +% % \bigskip +% \subsubsection{The LPEG ocaml} +% +% \begin{macrocode} +local Delim = Q ( P "[|" + P "|]" + S "[()]" ) +% \end{macrocode} +% +% \begin{macrocode} +local Punct = Q ( S ",:;!" ) +% \end{macrocode} +% +% The identifiers catched by |cap_identifier| begin with a cap. In OCaml, it's +% used for the constructors of types and for the modules. +% \begin{macrocode} +local cap_identifier = R "AZ" * ( R "az" + R "AZ" + S "_'" + digit ) ^ 0 +% \end{macrocode} +% +% \begin{macrocode} +local Constructor = K ( 'Name.Constructor' , cap_identifier ) +local ModuleType = K ( 'Name.Type' , cap_identifier ) +% \end{macrocode} +% +% The identifiers which begin with a lower case letter of an underscore are used +% elsewhere in OCaml. +% \begin{macrocode} +local identifier = + ( R "az" + P "_") * ( R "az" + R "AZ" + S "_'" + digit ) ^ 0 +local Identifier = K ( 'Identifier' , identifier ) +% \end{macrocode} +% +% +% Now, we deal with the records because we want to catch the names of the fields +% of those records in all circunstancies. +% \begin{macrocode} +local expression_for_fields = + P { "E" , + E = ( P "{" * V "F" * P "}" + + P "(" * V "F" * P ")" + + P "[" * V "F" * P "]" + + P "\"" * (P "\\\"" + 1 - S "\"\r" )^0 * P "\"" + + P "'" * ( P "\\'" + 1 - S "'\r" )^0 * P "'" + + ( 1 - S "{}()[]\r;" ) ) ^ 0 , + F = ( P "{" * V "F" * P "}" + + P "(" * V "F" * P ")" + + P "[" * V "F" * P "]" + + ( 1 - S "{}()[]\r\"'" ) ) ^ 0 + } +% \end{macrocode} +% +% \begin{macrocode} +local OneFieldDefinition = + ( K ( 'KeyWord' , P "mutable" ) * SkipSpace ) ^ -1 + * K ( 'Name.Field' , identifier ) * SkipSpace + * Q ":" * SkipSpace + * K ( 'Name.Type' , expression_for_fields ) + * SkipSpace + +local OneField = + K ( 'Name.Field' , identifier ) * SkipSpace + * Q "=" * SkipSpace + * ( C ( expression_for_fields ) / ( function (s) return LoopOCaml:match(s) end ) ) + * SkipSpace + +local Record = + Q "{" * SkipSpace + * + ( + OneFieldDefinition * ( Q ";" * SkipSpace * OneFieldDefinition ) ^ 0 + + + OneField * ( Q ";" * SkipSpace * OneField ) ^ 0 + ) + * + Q "}" +% \end{macrocode} +% +% \bigskip +% Now, we deal with the notations with points (eg: |List.length|). In OCaml, +% such notation is used for the fields of the records and for the modules. +% \begin{macrocode} +local DotNotation = + ( + K ( 'Name.Module' , cap_identifier ) + * Q "." + * ( Identifier + Constructor + Q "(" + Q "[" + Q "{" ) + + + + Identifier + * Q "." + * K ( 'Name.Field' , identifier ) + ) + * ( Q "." * K ( 'Name.Field' , identifier ) ) ^ 0 +% \end{macrocode} +% +% \begin{macrocode} +local Operator = + K ( 'Operator' , + P "!=" + P "<>" + P "==" + P "<<" + P ">>" + P "<=" + P ">=" + P ":=" + + P "||" + P "&&" + P "//" + P "**" + P ";;" + P "::" + P "->" + + P "+." + P "-." + P "*." + P "/." + + S "-~+/*%=<>&@|" + ) + +local OperatorWord = + K ( 'Operator.Word' , + P "and" + P "asr" + P "land" + P "lor" + P "lsl" + P "lxor" + + P "mod" + P "or" ) + +local Keyword = + K ( 'Keyword' , + P "assert" + P "as" + P "begin" + P "class" + P "constraint" + P "done" + + P "downto" + P "do" + P "else" + P "end" + P "exception" + P "external" + + P "false" + P "for" + P "function" + P "functor" + P "fun" + P "if" + + P "include" + P "inherit" + P "initializer" + P "in" + P "lazy" + P "let" + + P "match" + P "method" + P "module" + P "mutable" + P "new" + P "object" + + P "of" + P "open" + P "private" + P "raise" + P "rec" + P "sig" + + P "struct" + P "then" + P "to" + P "true" + P "try" + P "type" + + P "value" + P "val" + P "virtual" + P "when" + P "while" + P "with" ) + + K ( 'Keyword.Constant' , P "true" + P "false" ) + + +local Builtin = + K ( 'Name.Builtin' , P "not" + P "incr" + P "decr" + P "fst" + P "snd" ) +% \end{macrocode} +% +% \bigskip +% The following exceptions are exceptions in the standard library of OCaml (Stdlib). +% \begin{macrocode} +local Exception = + K ( 'Exception' , + P "Division_by_zero" + P "End_of_File" + P "Failure" + + P "Invalid_argument" + P "Match_failure" + P "Not_found" + + P "Out_of_memory" + P "Stack_overflow" + P "Sys_blocked_io" + + P "Sys_error" + P "Undefined_recursive_module" ) +% \end{macrocode} +% +% \bigskip +% \paragraph{The characters in OCaml} +% +% \begin{macrocode} +local Char = + K ( 'String.Short' , P "'" * ( ( 1 - P "'" ) ^ 0 + P "\\'" ) * P "'" ) +% \end{macrocode} +% +% +% \bigskip +% \paragraph{Beamer} +% +% \begin{macrocode} +local balanced_braces = + P { "E" , + E = + ( + P "{" * V "E" * P "}" + + + P "\"" * ( 1 - S "\"" ) ^ 0 * P "\"" -- OCaml strings + + + ( 1 - S "{}" ) + ) ^ 0 + } +% \end{macrocode} +% +% +% \begin{macrocode} +if piton_beamer +then + Beamer = + L ( P "\\pause" * ( P "[" * (1 - P "]") ^ 0 * P "]" ) ^ -1 ) + + + ( P "\\uncover" * Lc ( '\\@@_beamer_command:n{uncover}' ) + + P "\\only" * Lc ( '\\@@_beamer_command:n{only}' ) + + P "\\alert" * Lc ( '\\@@_beamer_command:n{alert}' ) + + P "\\visible" * Lc ( '\\@@_beamer_command:n{visible}' ) + + P "\\invisible" * Lc ( '\\@@_beamer_command:n{invisible}' ) + + P "\\action" * Lc ( '\\@@_beamer_command:n{action}' ) + ) + * + L ( ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1 * P "{" ) + * K ( 'ParseAgain.noCR' , balanced_braces ) + * L ( P "}" ) + + + L ( + ( P "\\alt" ) + * P "<" * (1 - P ">") ^ 0 * P ">" + * P "{" + ) + * K ( 'ParseAgain.noCR' , balanced_braces ) + * L ( P "}{" ) + * K ( 'ParseAgain.noCR' , balanced_braces ) + * L ( P "}" ) + + + L ( + ( P "\\temporal" ) + * P "<" * (1 - P ">") ^ 0 * P ">" + * P "{" + ) + * K ( 'ParseAgain.noCR' , balanced_braces ) + * L ( P "}{" ) + * K ( 'ParseAgain.noCR' , balanced_braces ) + * L ( P "}{" ) + * K ( 'ParseAgain.noCR' , balanced_braces ) + * L ( P "}" ) + BeamerBeginEnvironments = + ( space ^ 0 * + L + ( + P "\\begin{" * BeamerNamesEnvironments * "}" + * ( P "<" * ( 1 - P ">") ^ 0 * P ">" ) ^ -1 + ) + * P "\r" + ) ^ 0 + BeamerEndEnvironments = + ( space ^ 0 * + L ( P "\\end{" * BeamerNamesEnvironments * P "}" ) + * P "\r" + ) ^ 0 +end +% \end{macrocode} +% +% \bigskip +% \paragraph{EOL} +% \begin{macrocode} +local EOL = + P "\r" + * + ( + ( space^0 * -1 ) + + + Ct ( + Cc "EOL" + * + Ct ( + Lc "\\@@_end_line:" + * BeamerEndEnvironments + * BeamerBeginEnvironments + * PromptHastyDetection + * Lc "\\@@_newline: \\@@_begin_line:" + * Prompt + ) + ) + ) + * + SpaceIndentation ^ 0 +% \end{macrocode} +% +% +% \begin{macrocode} +% +% \paragraph{The strings} +% +% We need a pattern |string| without captures because it will be used within the +% comments of OCaml. +% \begin{macrocode} +local ocaml_string = + Q ( P "\"" ) + * ( + VisualSpace + + + Q ( ( 1 - S " \"\r" ) ^ 1 ) + + + EOL + ) ^ 0 + * Q ( P "\"" ) +% \end{macrocode} +% +% \begin{macrocode} +local String = WithStyle ( 'String.Long' , ocaml_string ) +% \end{macrocode} +% +% +% \bigskip +% Now, the ``quoted strings'' of OCaml (for example \verb+{ext|Essai|ext}+). +% +% For those strings, we will do two consecutive analysis. First an analysis to +% determine the whole string and, then, an analysis for the potential visual +% spaces and the EOL in the string. +% +% The first analysis require a match-time capture. For explanations about that +% programmation, see the paragraphe \emph{Lua's long % strings} in +% |www.inf.puc-rio.br/~roberto/lpeg|. +% \begin{macrocode} +local ext = ( R "az" + P "_" ) ^ 0 +local open = "{" * Cg(ext, 'init') * "|" +local close = "|" * C(ext) * "}" +local closeeq = + Cmt ( close * Cb('init'), + function (s, i, a, b) return a==b end ) +% \end{macrocode} +% +% \medskip +% The \textsc{lpeg} |QuotedStringBis| will do the second analysis. +% \begin{macrocode} +local QuotedStringBis = + WithStyle ( 'String.Long' , + ( + VisualSpace + + + Q ( ( 1 - S " \r" ) ^ 1 ) + + + EOL + ) ^ 0 ) + +% \end{macrocode} +% +% \medskip +% We use a ``function capture'' (as called in the official documentation of the +% \textsc{lpeg}) in order to do the second analysis on the result of the first one. +% \begin{macrocode} +local QuotedString = + C ( open * ( 1 - closeeq ) ^ 0 * close ) / + ( function (s) return QuotedStringBis : match(s) end ) +% \end{macrocode} +% +% +% \bigskip +% \paragraph{The comments in the OCaml listings} +% +% In OCaml, the delimiters for the comments are |(*| and |*)|. There are +% unsymmetrical and, therefore, the comments may be nested. That's why we need a +% grammar. +% +% In these comments, we embed the math comments (between |$| and |$|) and we +% embed also a treatment for the end of lines (since the comments may be multi-lines). +% +% \begin{macrocode} +local Comment = + WithStyle ( 'Comment' , + P { + "A" , + A = Q "(*" + * ( V "A" + + Q ( ( 1 - P "(*" - P "*)" - S "\r$\"" ) ^ 1 ) -- $ + + ocaml_string + + P "$" * K ( 'Comment.Math' , ( 1 - S "$\r" ) ^ 1 ) * P "$" -- $ + + EOL + ) ^ 0 + * Q "*)" + } ) +% \end{macrocode} +% +% \bigskip +% \paragraph{The DefFunction} +% +% \begin{macrocode} +local balanced_parens = + P { "E" , + E = + ( + P "(" * V "E" * P ")" + + + ( 1 - S "()" ) + ) ^ 0 + } +% \end{macrocode} +% +% \begin{macrocode} +local Argument = + K ( 'Identifier' , identifier ) + + Q "(" * SkipSpace + * K ( 'Identifier' , identifier ) * SkipSpace + * Q ":" * SkipSpace + * K ( 'Name.Type' , balanced_parens ) * SkipSpace + * Q ")" +% \end{macrocode} +% +% Despite its name, then \textsc{lpeg} |DefFunction| deals also with |let open| +% which opens locally a module. +% \begin{macrocode} +local DefFunction = + K ( 'Keyword' , P "let open" ) + * Space + * K ( 'Name.Module' , cap_identifier ) + + + K ( 'Keyword' , P "let rec" + P "let" + P "and" ) + * Space + * K ( 'Name.Function.Internal' , identifier ) + * Space + * ( + Q "=" * SkipSpace * K ( 'Keyword' , P "function" ) + + + Argument + * ( SkipSpace * Argument ) ^ 0 + * ( + SkipSpace + * Q ":" + * K ( 'Name.Type' , ( 1 - P "=" ) ^ 0 ) + ) ^ -1 + ) +% \end{macrocode} +% +% +% \bigskip +% \paragraph{The DefModule} +% +% The following LPEG will be used in the definitions of modules but also in the +% definitions of \emph{types} of modules. +% \begin{macrocode} +local DefModule = + K ( 'Keyword' , P "module" ) * Space + * + ( + K ( 'Keyword' , P "type" ) * Space + * K ( 'Name.Type' , cap_identifier ) + + + K ( 'Name.Module' , cap_identifier ) * SkipSpace + * + ( + Q "(" * SkipSpace + * K ( 'Name.Module' , cap_identifier ) * SkipSpace + * Q ":" * SkipSpace + * K ( 'Name.Type' , cap_identifier ) * SkipSpace + * + ( + Q "," * SkipSpace + * K ( 'Name.Module' , cap_identifier ) * SkipSpace + * Q ":" * SkipSpace + * K ( 'Name.Type' , cap_identifier ) * SkipSpace + ) ^ 0 + * Q ")" + ) ^ -1 + * + ( + Q "=" * SkipSpace + * K ( 'Name.Module' , cap_identifier ) * SkipSpace + * Q "(" + * K ( 'Name.Module' , cap_identifier ) * SkipSpace + * + ( + Q "," + * + K ( 'Name.Module' , cap_identifier ) * SkipSpace + ) ^ 0 + * Q ")" + ) ^ -1 + ) + + + K ( 'Keyword' , P "include" + P "open" ) + * Space * K ( 'Name.Module' , cap_identifier ) +% \end{macrocode} +% +% \bigskip +% \paragraph{The parameters of the types} +% +% \begin{macrocode} +local TypeParameter = K ( 'TypeParameter' , P "'" * alpha * # ( 1 - P "'" ) ) +% \end{macrocode} +% +% \bigskip +% \paragraph{The main LPEG} +% +% First, the main loop : +% \begin{macrocode} +MainOCaml = + EOL + + Space + + Tab + + Escape + + Beamer + + TypeParameter + + String + QuotedString + Char + + Comment + + Delim + + Operator + + Punct + + FromImport + + Exception + + DefFunction + + DefModule + + Record + + Keyword * ( Space + Punct + Delim + EOL + -1 ) + + OperatorWord * ( Space + Punct + Delim + EOL + -1 ) + + Builtin * ( Space + Punct + Delim + EOL + -1 ) + + DotNotation + + Constructor + + Identifier + + Number + + Word + +LoopOCaml = MainOCaml ^ 0 + +MainLoopOCaml = + ( ( space^1 * -1 ) + + MainOCaml + ) ^ 0 +% \end{macrocode} +% +% \bigskip +% We recall that each line in the Python code to parse will be sent back to +% LaTeX between a pair |\@@_begin_line:| -- |\@@_end_line:|\footnote{Remember +% that the \texttt{\textbackslash @@\_end\_line:} must be explicit because it +% will be used as marker in order to delimit the argument of the command +% \texttt{\textbackslash @@\_begin\_line:}}. +% \begin{macrocode} +local ocaml = P ( true ) + +ocaml = + Ct ( + ( ( space - P "\r" ) ^0 * P "\r" ) ^ -1 + * BeamerBeginEnvironments + * Lc ( '\\@@_begin_line:' ) + * SpaceIndentation ^ 0 + * MainLoopOCaml + * -1 + * Lc ( '\\@@_end_line:' ) + ) +% \end{macrocode} +% +% \begin{macrocode} +languages['ocaml'] = ocaml +% \end{macrocode} +% +% \bigskip +% \subsubsection{The function Parse} +% +% +% The function |Parse| is the main function of the package \pkg{piton}. +% It parses its argument and sends back to LaTeX the code with interlaced +% formatting LaTeX instructions. In fact, everything is done by the +% \textsc{lpeg} |python| which returns as capture a Lua table containing +% data to send to LaTeX. +% +% \bigskip +% \begin{macrocode} +function piton.Parse(language,code) + local t = languages[language] : match ( code ) + local left_stack = {} + local right_stack = {} + for _ , one_item in ipairs(t) + do + if one_item[1] == "EOL" + then + for _ , s in ipairs(right_stack) + do tex.sprint(s) + end + for _ , s in ipairs(one_item[2]) + do tex.tprint(s) + end + for _ , s in ipairs(left_stack) + do tex.sprint(s) + end + else +% \end{macrocode} +% +% Here is an example of an item beginning with |"Open"|. +% +% |{ "Open" , "\begin{uncover}<2>" , "\end{cover}" }| +% +% In order to deal with the ends of lines, we have to close the environment +% (|{cover}| in this example) at the end of each line and reopen it at the +% beginning of the new line. That's why we use two Lua stacks, called +% |left_stack| and |right_stack|. |left_stack| will be for the elements like +% |\begin{uncover}<2>| and |right_stack| will be for the elements like +% |\end{cover}|. +% \begin{macrocode} + if one_item[1] == "Open" + then + tex.sprint( one_item[2] ) + table.insert(left_stack,one_item[2]) + table.insert(right_stack,one_item[3]) + else + if one_item[1] == "Close" + then + tex.sprint( right_stack[#right_stack] ) + left_stack[#left_stack] = nil + right_stack[#right_stack] = nil + else + tex.tprint(one_item) + end + end + end + end +end +% \end{macrocode} +% +% +% +% \bigskip +% The function |ParseFile| will be used by the LaTeX command |\PitonInputFile|. +% That function merely reads the whole file (that is to say all its lines) and +% then apply the function~|Parse| to the resulting Lua string. +% \begin{macrocode} +function piton.ParseFile(language,name,first_line,last_line) + local s = '' + local i = 0 + for line in io.lines(name) + do i = i + 1 + if i >= first_line + then s = s .. '\r' .. line + end + if i >= last_line then break end + end +% \end{macrocode} +% We extract the BOM of utf-8, if present. +% \begin{macrocode} + if string.byte(s,1) == 13 + then if string.byte(s,2) == 239 + then if string.byte(s,3) == 187 + then if string.byte(s,4) == 191 + then s = string.sub(s,5,-1) + end + end + end + end + piton.Parse(language,s) +end +% \end{macrocode} +% +% \bigskip +% \subsubsection{Two variants of the function Parse with integrated preprocessors} +% +% The following command will be used by the user command |\piton|. +% For that command, we have to undo the duplication of the symbols |#|. +% \begin{macrocode} +function piton.ParseBis(language,code) + local s = ( Cs ( ( P '##' / '#' + 1 ) ^ 0 ) ) : match ( code ) + return piton.Parse(language,s) +end +% \end{macrocode} +% +% \bigskip +% The following command will be used when we have to parse some small chunks of +% code that have yet been parsed. They are re-scanned by LaTeX because it has +% been required by |\@@_piton:n| in the \pkg{piton} style of the syntaxic +% element. In that case, you have to remove the potential |\@@_breakable_space:| +% that have been inserted when the key |break-lines| is in force. +% \begin{macrocode} +function piton.ParseTer(language,code) + local s = ( Cs ( ( P '\\@@_breakable_space:' / ' ' + 1 ) ^ 0 ) ) + : match ( code ) + return piton.Parse(language,s) +end +% \end{macrocode} +% +% +% \bigskip +% \subsubsection{Preprocessors of the function Parse for gobble} +% +% We deal now with preprocessors of the function |Parse| which are needed when +% the ``gobble mechanism'' is used. +% +% +% \bigskip +% The function |gobble| gobbles $n$ characters on the left of the code. It uses +% a \textsc{lpeg} that we have to compute dynamically because if depends on the +% value of~$n$. +% \begin{macrocode} +local function gobble(n,code) + function concat(acc,new_value) + return acc .. new_value + end + if n==0 + then return code + else + return Cf ( + Cc ( "" ) * + ( 1 - P "\r" ) ^ (-n) * C ( ( 1 - P "\r" ) ^ 0 ) + * ( C ( P "\r" ) + * ( 1 - P "\r" ) ^ (-n) + * C ( ( 1 - P "\r" ) ^ 0 ) + ) ^ 0 , + concat + ) : match ( code ) + end +end +% \end{macrocode} +% +% +% +% \bigskip +% The following function |add| will be used in the following \textsc{lpeg} +% |AutoGobbleLPEG|, |TabsAutoGobbleLPEG| and |EnvGobbleLPEG|. +% \begin{macrocode} +local function add(acc,new_value) + return acc + new_value +end +% \end{macrocode} +% +% \bigskip +% The following \textsc{lpeg} returns as capture the minimal number of spaces at +% the beginning of the lines of code. The main work is done by two \emph{fold +% captures} (|lpeg.Cf|), one using |add| and the other (encompassing the +% previous one) using |math.min| as folding operator. +% \begin{macrocode} +local AutoGobbleLPEG = + ( space ^ 0 * P "\r" ) ^ -1 + * Cf ( + ( +% \end{macrocode} +% We don't take into account the empty lines (with only spaces). +% \begin{macrocode} + ( P " " ) ^ 0 * P "\r" + + + Cf ( Cc(0) * ( P " " * Cc(1) ) ^ 0 , add ) + * ( 1 - P " " ) * ( 1 - P "\r" ) ^ 0 * P "\r" + ) ^ 0 +% \end{macrocode} +% Now for the last line of the Python code... +% \begin{macrocode} + * + ( Cf ( Cc(0) * ( P " " * Cc(1) ) ^ 0 , add ) + * ( 1 - P " " ) * ( 1 - P "\r" ) ^ 0 ) ^ -1 , + math.min + ) +% \end{macrocode} +% +% \bigskip +% The following \textsc{lpeg} is similar but works with the indentations. +% \begin{macrocode} +local TabsAutoGobbleLPEG = + ( space ^ 0 * P "\r" ) ^ -1 + * Cf ( + ( + ( P "\t" ) ^ 0 * P "\r" + + + Cf ( Cc(0) * ( P "\t" * Cc(1) ) ^ 0 , add ) + * ( 1 - P "\t" ) * ( 1 - P "\r" ) ^ 0 * P "\r" + ) ^ 0 + * + ( Cf ( Cc(0) * ( P "\t" * Cc(1) ) ^ 0 , add ) + * ( 1 - P "\t" ) * ( 1 - P "\r" ) ^ 0 ) ^ -1 , + math.min + ) +% \end{macrocode} +% +% +% +% \bigskip +% The following \textsc{lpeg} returns as capture the number of spaces at the +% last line, that is to say before the |\end{Piton}| (and usually it's also the +% number of spaces before the corresponding |\begin{Piton}| because that's the +% traditionnal way to indent in LaTeX). The main work is done by a \emph{fold +% capture} (|lpeg.Cf|) using the function |add| as folding operator. +% \begin{macrocode} +local EnvGobbleLPEG = + ( ( 1 - P "\r" ) ^ 0 * P "\r" ) ^ 0 + * Cf ( Cc(0) * ( P " " * Cc(1) ) ^ 0 , add ) * -1 +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +function piton.GobbleParse(language,n,code) + if n==-1 + then n = AutoGobbleLPEG : match(code) + else if n==-2 + then n = EnvGobbleLPEG : match(code) + else if n==-3 + then n = TabsAutoGobbleLPEG : match(code) + end + end + end + piton.Parse(language,gobble(n,code)) +end +% \end{macrocode} +% +% \bigskip +% \subsubsection{To count the number of lines} +% +% \medskip +% \begin{macrocode} +function piton.CountLines(code) + local count = 0 + for i in code : gmatch ( "\r" ) do count = count + 1 end + tex.sprint( + luatexbase.catcodetables.expl , + '\\int_set:Nn \\l_@@_nb_lines_int {' .. count .. '}' ) +end +% \end{macrocode} +% +% \begin{macrocode} +function piton.CountNonEmptyLines(code) + local count = 0 + count = + ( Cf ( Cc(0) * + ( + ( P " " ) ^ 0 * P "\r" + + ( 1 - P "\r" ) ^ 0 * P "\r" * Cc(1) + ) ^ 0 + * (1 - P "\r" ) ^ 0 , + add + ) * -1 ) : match (code) + tex.sprint( + luatexbase.catcodetables.expl , + '\\int_set:Nn \\l_@@_nb_non_empty_lines_int {' .. count .. '}' ) +end +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +function piton.CountLinesFile(name) + local count = 0 + for line in io.lines(name) do count = count + 1 end + tex.sprint( + luatexbase.catcodetables.expl , + '\\int_set:Nn \\l_@@_nb_lines_int {' .. count .. '}' ) +end +% \end{macrocode} +% +% +% \bigskip +% \begin{macrocode} +function piton.CountNonEmptyLinesFile(name) + local count = 0 + for line in io.lines(name) + do if not ( ( ( P " " ) ^ 0 * -1 ) : match ( line ) ) + then count = count + 1 + end + end + tex.sprint( + luatexbase.catcodetables.expl , + '\\int_set:Nn \\l_@@_nb_non_empty_lines_int {' .. count .. '}' ) +end +% \end{macrocode} +% +% \begin{macrocode} +\end{luacode*} +% \end{macrocode} +% +% +% \vspace{1cm} +% \section{History} +% +% The successive versions of the file |piton.sty| provided by TeXLive are available on the +% \textsc{svn} server of TeXLive:\par\nobreak +% +% \smallskip +% { +% \small +% \nolinkurl{https://tug.org/svn/texlive/trunk/Master/texmf-dist/tex/lualatex/piton/piton.sty} +% } +% +% \medskip +% The development of the extension \pkg{piton} is done on the following GitHub +% repository: +% +% \verb|https://github.com/fpantigny/piton| +% +% \subsection*{Changes between versions 1.5 and 1.6} +% +% New key |width| (for the total width of the listing). +% +% New style |UserFunction| to format the names of the Python functions +% previously defined by the user. Command |\PitonClearUserFunctions| to clear +% the list of such functions names. +% +% \subsection*{Changes between versions 1.4 and 1.5} +% +% New key |numbers-sep|. +% +% +% \subsection*{Changes between versions 1.3 and 1.4} +% +% New key |identifiers| in |\PitonOptions|. +% +% New command |\PitonStyle|. +% +% |background-color| now accepts as value a \emph{list} of colors. +% +% \subsection*{Changes between versions 1.2 and 1.3} +% +% When the class Beamer is used, the environment |{Piton}| and the command +% |\PitonInputFile| are ``overlay-aware'' (that is to say, they accept a +% specification of overlays between angular brackets). +% +% New key |prompt-background-color| +% +% It's now possible to use the command |\label| to reference a line of code in +% an environment |{Piton}|. +% +% A new command |\|␣ is available in the argument of the command |\piton{...}| to +% insert a space (otherwise, several spaces are replaced by a single space). +% +% \subsection*{Changes between versions 1.1 and 1.2} +% +% New keys |break-lines-in-piton| and |break-lines-in-Piton|. +% +% New key |show-spaces-in-string| and modification of the key |show-spaces|. +% +% When the class \cls{beamer} is used, the environements |{uncoverenv}|, +% |{onlyenv}|, |{visibleenv}| and |{invisibleenv}| +% +% +% \subsection*{Changes between versions 1.0 and 1.1} +% +% The extension \pkg{piton} detects the class \cls{beamer} and activates the +% commands |\action|, |\alert|, |\invisible|, |\only|, |\uncover| and |\visible| +% in the environments |{Piton}| when the class \cls{beamer} is used. +% +% \subsection*{Changes between versions 0.99 and 1.0} +% +% New key |tabs-auto-gobble|. +% +% \subsection*{Changes between versions 0.95 and 0.99} +% +% New key |break-lines| to allow breaks of the lines of code (and other keys to +% customize the appearance). +% +% \subsection*{Changes between versions 0.9 and 0.95} +% +% New key |show-spaces|. +% +% The key |left-margin| now accepts the special value |auto|. +% +% New key |latex-comment| at load-time and replacement of |##| by |#>| +% +% New key |math-comments| at load-time. +% +% New keys |first-line| and |last-line| for the command |\InputPitonFile|. +% +% \subsection*{Changes between versions 0.8 and 0.9} +% +% New key |tab-size|. +% +% Integer value for the key |splittable|. +% +% \subsection*{Changes between versions 0.7 and 0.8} +% +% New keys |footnote| and |footnotehyper| at load-time. +% +% New key |left-margin|. +% +% \subsection*{Changes between versions 0.6 and 0.7} +% +% New keys |resume|, |splittable| and |background-color| in |\PitonOptions|. +% +% The file |piton.lua| has been embedded in the file |piton.sty|. That means +% that the extension \pkg{piton} is now entirely contained in the file |piton.sty|. +% +% +% +% \tableofcontents +% +% \end{document} +% +% +% Local Variables: +% TeX-fold-mode: t +% TeX-fold-preserve-comments: nil +% flyspell-mode: nil +% fill-column: 80 +% End: + + + + + + |