texlive[70205] branches/branch2023.final/Master/texmf-dist: piton

commits+karl at tug.org commits+karl at tug.org
Tue Feb 27 21:48:14 CET 2024


Revision: 70205
          https://tug.org/svn/texlive?view=revision&revision=70205
Author:   karl
Date:     2024-02-27 21:48:14 +0100 (Tue, 27 Feb 2024)
Log Message:
-----------
piton (branch) (27feb24)

Modified Paths:
--------------
    branches/branch2023.final/Master/texmf-dist/doc/lualatex/piton/piton-french.pdf
    branches/branch2023.final/Master/texmf-dist/doc/lualatex/piton/piton-french.tex
    branches/branch2023.final/Master/texmf-dist/doc/lualatex/piton/piton.pdf
    branches/branch2023.final/Master/texmf-dist/source/lualatex/piton/piton.dtx
    branches/branch2023.final/Master/texmf-dist/tex/lualatex/piton/piton.lua
    branches/branch2023.final/Master/texmf-dist/tex/lualatex/piton/piton.sty

Modified: branches/branch2023.final/Master/texmf-dist/doc/lualatex/piton/piton-french.pdf
===================================================================
(Binary files differ)

Modified: branches/branch2023.final/Master/texmf-dist/doc/lualatex/piton/piton-french.tex
===================================================================
--- branches/branch2023.final/Master/texmf-dist/doc/lualatex/piton/piton-french.tex	2024-02-27 20:48:03 UTC (rev 70204)
+++ branches/branch2023.final/Master/texmf-dist/doc/lualatex/piton/piton-french.tex	2024-02-27 20:48:14 UTC (rev 70205)
@@ -159,7 +159,7 @@
 \subsection{Choix du langage}
 
 L'extension \pkg{piton} prend en charge quatre langages informatiques : Python, OCaml, SQL et C, ou plutôt \CC. Il
-prend aussi en charge un langage minimal appelé «|minimal|» : cf.~\pageref{minimal}.
+prend aussi en charge un langage minimal appelé «|minimal|» : cf.~p.~\pageref{minimal}.
 
 \smallskip
 Par défaut, le langage est Python.
@@ -172,8 +172,8 @@
 |\PitonOptions{language = C}|
 
 \smallskip
-\colorbox{yellow!50}{\textbf{Nouveau 2.4}}\enskip La variable L3 contenant le nom du langage courant est :
-|\l_piton_language_str|.
+Pour les développeurs, précisons que le nom du langage courant est stocké (en minuscules) dans la variable publique
+L3 nommée |\l_piton_language_str|. 
 
 \smallskip
 Dans la suite de ce document, on parlera de Python mais les fonctionnalités s'appliquent aussi aux autres langages.
@@ -336,9 +336,9 @@
 \item \index{path} La clé \Definition{path} indique un chemin où seront cherchés les fichiers inclus par
 |\PitonInputFile|. 
 
-\item \index{gobble} La clé \Definition{gobble} prend comme valeur un entier positif $n$ : les $n$ premiers caractères de chaque
-ligne sont alors retirés (avant formatage du code) dans les environnements |{Piton}|. Ces $n$ caractères ne sont
-pas nécessairement des espaces.
+\item \index{gobble}\label{gobble} La clé \Definition{gobble} prend comme valeur un entier positif $n$ : les $n$
+premiers caractères de chaque ligne sont alors retirés (avant formatage du code) dans les environnements |{Piton}|.
+Ces $n$ caractères ne sont pas nécessairement des espaces.
 
 \item \index{auto-gobble}\index{gobble!auto-gobble} Quand la clé \Definition{auto-gobble} est activée, l'extension \pkg{piton} détermine la valeur minimale $n$
 du nombre d'espaces successifs débutant chaque ligne (non vide) de l'environnement |{Piton}| et applique |gobble|
@@ -351,9 +351,11 @@
 valeur de~$n$. Le nom de cette clé vient de \emph{environment gobble}: le nombre d'espaces à retirer ne dépend que
 de la position des délimiteurs |\begin{Piton}| et |\end{Piton}| de l'environnement.
 
-\item \index{write} \colorbox{yellow!50}{\bfseries Nouveau 2.3}\enskip La clé \Definition{write} prend en argument un nom de
-fichier (avec l'extension) et écrit le contenu de l'environnement courant dans ce fichier. À la première
-utilisation du fichier par \pkg{piton}, celui-ci est effacé.
+\item \index{write} La clé \Definition{write} prend en argument un nom de fichier (avec l'extension) et écrit le
+contenu\footnote{En fait, il ne s'agit pas exactement du contenu de l'environnement mais de la valeur renvoyée par
+  l'instruction Lua 
+  |piton.get_last_code()| qui en est une version dans les surcharges de formatage LaTeX (voir la partie \ref{API}, p.~\pageref{API}).} de l'environnement courant dans ce fichier. À la première utilisation du fichier par \pkg{piton}, celui-ci
+est effacé.
 
 \item \index{path-write} \colorbox{yellow!50}{\bfseries Nouveau 2.5}\enskip La clé \Definition{path-write} indique
 un chemin où seront écrits les fichiers écrits par l'emploi de la clé |write| précédente.
@@ -673,7 +675,8 @@
 LaTeX3). 
 
 C'est pourquoi \pkg{piton} propose une commande |\NewPitonEnvironment|. Cette commande a la même syntaxe que la
-commande classique |\NewDocumentEnvironment|.
+commande classique |\NewDocumentEnvironment|.\footnote{Néanmoins, le spécificateur d'argument~|b|, qui sert à
+  capter le corps de l'environnement comme un argument LaTeX, n'est pas autorisé.}
 
 \bigskip
 Par exemple, avec l'instruction suivante, un nouvel environnement |{Python}| sera défini avec le même comportement
@@ -1055,7 +1058,7 @@
 \item Il est possible de demander à \pkg{piton} de détecter directement certaines commandes LaTeX avec leur argument.
 \item Il est possible d'insérer du code LaTeX à n'importe quel endroit d'un listing Python.
 \end{itemize}
-Ces mécanismes vont être détaillés dans les sous-parties de cette partie.
+Ces mécanismes vont être détaillés dans les sous-parties suivantes.
 
 \smallskip
 À remarquer également que, dans le cas où \pkg{piton} est utilisée dans la classe \cls{beamer}, \pkg{piton} détecte
@@ -1145,10 +1148,8 @@
 \subsubsection{La clé «detected-commands»}
 
 \index{detected-commands (key)}
+\label{detected-commands}
 
-\colorbox{yellow!50}{\bfseries Nouveau 2.4}\par\nobreak
-
-\smallskip
 La clé |detected-commands| de |\PitonOptions| permet de spécifier une liste de noms de commandes LaTeX qui seront
 directement détectées par \pkg{piton}.
 
@@ -1159,12 +1160,12 @@
 (ex. : |detected-commands = { emph , textbf }|). 
 
 \item Ces commandes doivent être des commandes LaTeX à un seul argument obligatoire entre accolades (et ces
-accolages doivent être explicites).
+accolades doivent être explicites).
 \end{itemize}
 
 \medskip
 Dans l'exemple suivant, qui est une programmation récursive de la factorielle, on décide de surligner en jaune
-l'appel récursif. La commande |\highLight| de \pkg{lua-el} (cette extension requiert elle-même l'extension
+l'appel récursif. La commande |\highLight| de \pkg{lua-ul} (cette extension requiert elle-même l'extension
 \pkg{luacolor}) permet de le faire avec la syntaxe |\hightLight{...}|.
 
 \smallskip
@@ -1197,6 +1198,7 @@
 
 \index{begin-escape}
 \index{end-escape}
+\label{escape}
 
 Il est aussi possible de surcharger les listings Python pour y insérer du code LaTeX à peu près n'importe où (mais
 entre deux lexèmes, bien entendu). Cette fonctionnalité n'est pas activée par défaut par \pkg{piton}. Pour
@@ -1530,9 +1532,44 @@
 caractères U+0009 par des espaces, bien entendu). Cette clé est donc similaire à la clé |auto-gobble| mais agit sur
 des caractères U+0009 au lieu de caractères U+0020 (espaces).
 
+
+\section{API pour les développeurs}
+
+
+\index{piton.last@\texttt{piton.get\_last\_code} (fonction Lua)}
+\label{API}
+
+La variable L3 |\l_piton_language_str| contient le nom du langage courant (en minuscules).
+
+\bigskip
+
+\colorbox{yellow!50}{\textbf{Nouveau 2.6}}\par\nobreak
+
+L'extension \pkg{piton} fournit une function Lua |piton.get_last_code| sans argument permettant de récupérer le
+code contenu dans le dernier environnement de \pkg{piton}. 
+\begin{itemize}
+\item Les retours à la ligne (présents dans l'environnement de départ) apparaissent comme des caractères |\r|
+(c'est-à-dire des caractères U+000D).
+
+\item Le code fourni par |piton.get_last_code()| tient compte de l'éventuelle application d'une clé |gobble| (cf.
+p.~\pageref{gobble}). 
+
+\item Les surcharges du code (qui entraînent des échappements vers LaTeX) ont été retirées du code fourni par
+|piton.get_last_code()|. Cela s'applique aux commandes LaTeX déclarées par la clé |detected-commands| (cf.
+partie~\ref{detected-commands}) et aux éléments insérés avec le mécanisme «|escape|» (cf. partie~\ref{escape}).
+
+\item |piton.get_last_code| est une fonction Lua et non une chaîne de caracètres : les traitements présentés
+précédemment son exécutés lorsque la fonction est appelée. De ce fait, il peut être judicieux de sotcker la valeur
+renvoyée par |piton.get_last_code()| dans une variable Lua si on doit l'utiliser plusieurs fois.
+\end{itemize}
+
+\medskip
+Pour un exemple d'utilisation, voir la partie concernant l'utilisation (standard) de \pkg{pyluatex},
+partie~\ref{pyluatex}, p.~\pageref{pyluatex}.
+
+
 \section{Exemples}
 
-
 \subsection{Numérotation des lignes}
 
 \label{example-numbering}
@@ -1846,6 +1883,7 @@
 
 \subsection{Utilisation standard de pyluatex}
 
+\label{pyluatex}
 \index{pyluatex@{\pkg{pyluatex}} (extension)}
 
 L'extension \pkg{pyluatex} est une extension qui permet l'exécution de code Python à partir de |lualatex| (pourvu
@@ -1856,62 +1894,35 @@
 
 
 \begin{Verbatim}
-\ExplSyntaxOn
-\NewDocumentEnvironment { ~emphase#PitonExecute@ } { ! O { } }  % le ! est obligatoire 
-  { 
-    \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
+\NewPitonEnvironment{~emphase#PitonExecute@}{O{}}
+  {\PitonOptions{~#1}}
+  {\begin{center}
+   \directlua{pyluatex.execute(piton.get_last_code(), false, true, false, true)}%
+   \end{center}
+   \ignorespacesafterend}
 \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
+\NewPitonEnvironment{PitonExecute}{O{}}
+  {\PitonOptions{#1}}
+  {\begin{center}
+   \directlua{pyluatex.execute(piton.get_last_code(), false, true, false, true)}%
+   \end{center}
+   \ignorespacesafterend}
 
+
+On a utilisé la fonction Lua |piton.get_last_code| fournie dans l'API de \pkg{piton} : cf.~partie~\ref{API},
+p.~\pageref{API}. 
+
+\bigskip
 Cet environnement |{PitonExecute}| prend en argument optionnel (entre crochets) les options proposées par la
 commande |\PitonOptions|.
 
-\bigskip
-Voici un exemple d'utilisation de cet environnement |{PitonExecute}| :
-
 \begin{Verbatim}
 \begin{~emphase#PitonExecute@}[background-color=gray!15]
-def square(x):
+def carré(x):
+    """Calcule le carré de l'argument"""
     return x*x
-print(f'Le carré de 12 est {square(12)}.')
+print(f'Le carré de 12 est {carré(12)}.')
 \end{~emphase#PitonExecute@}
 \end{Verbatim}
 
@@ -1918,9 +1929,10 @@
 
 \medskip
 \begin{PitonExecute}[background-color=gray!15]
-def square(x):
+def carré(x):
+    """Calcule le carré de l'argument"""
     return x*x
-print(f'Le carré de 12 est {square(12)}.')
+print(f'Le carré de 12 est {carré(12)}.')
 \end{PitonExecute}
 
 \bigskip
@@ -1944,9 +1956,13 @@
 
 \medskip
 Voici la programmation d'un environnement |{PitonREPL}| qui effectue ce travail (pour des raisons techniques, le
-|!| est ici obligatoire dans la signature de l'environnement).
+|!| est ici obligatoire dans la signature de l'environnement). On en peut pas procéder comme précédemment (dans
+l'utilisation «standard» de \pkg{pyluatex}) car, bien sûr, c'est le retour fait par |{pythonrepl}| qui doit être
+traité par \pkg{piton}. De ce fait, il ne sera pas possible de mettre des surcharges (avec |detected-commands| ou
+le mécanisme |escape|) dans le code.
 
 \begin{Verbatim}
+\ExplSyntaxOn
 \NewDocumentEnvironment { PitonREPL } { ! O { } } % le ! est obligatoire
  { 
    \PitonOptions
@@ -1960,15 +1976,16 @@
  }
  {
    \end{pythonrepl}
-   \directlua
+   \lua_now:n
      {
        tex.print("\\begin{Piton}")
        tex.print(pyluatex.get_last_output())
        tex.print("\\end{Piton}")
        tex.print("") 
-     }% 
+     } 
    \ignorespacesafterend
  }
+\ExplSyntaxOff
 \end{Verbatim}
 
 \medskip
@@ -1992,7 +2009,7 @@
 
 \bigskip
 
-
+\ExplSyntaxOn
 \NewDocumentEnvironment { PitonREPL } { }
  { 
    \PitonOptions{background-color=white,prompt-background-color = gray!10}
@@ -2001,17 +2018,17 @@
  }
  {
    \end{pythonrepl}
-   \directlua
+   \lua_now:n
      {
        tex.print("\\begin{Piton}")
        tex.print(pyluatex.get_last_output())
        tex.print("\\end{Piton}")
        tex.print("") 
-     }%
+     }
    \ignorespacesafterend
  }
-
-
+\ExplSyntaxOff
+ 
 \begin{PitonREPL}
     def valeur_absolue(x):
         "Renvoie la valeur absolue de x"
@@ -2083,9 +2100,8 @@
     valeur_absolue(5)
 \end{PitonREPL}
 
+\clearpage
 
-\newpage
-
 \section{Les styles pour les différents langages informatiques}
 
 \label{Semantic}
@@ -2336,9 +2352,6 @@
 \label{minimal}
 \index{minimal (langage «minimal»)}
 
-\colorbox{yellow!50}{\bfseries Nouveau 2.4}\par\nobreak
-
-\bigskip
 On peut basculer vers le langage «|minimal|» avec |\PitonOptions{language = minimal}|
 
 \bigskip

Modified: branches/branch2023.final/Master/texmf-dist/doc/lualatex/piton/piton.pdf
===================================================================
(Binary files differ)

Modified: branches/branch2023.final/Master/texmf-dist/source/lualatex/piton/piton.dtx
===================================================================
--- branches/branch2023.final/Master/texmf-dist/source/lualatex/piton/piton.dtx	2024-02-27 20:48:03 UTC (rev 70204)
+++ branches/branch2023.final/Master/texmf-dist/source/lualatex/piton/piton.dtx	2024-02-27 20:48:14 UTC (rev 70205)
@@ -72,12 +72,12 @@
 % \iffalse
 %<*STY>
 % \fi
-\def\PitonFileVersion{2.5}
-\def\PitonFileDate{2024/02/20}
+\def\PitonFileVersion{2.6}
+\def\PitonFileDate{2024/02/27}
 % \iffalse
 %</STY>
 %<*LUA>
--- Version 2.5 of 2024/02/20
+-- Version 2.6 of 2024/02/27
 %</LUA>
 %\fi
 %
@@ -166,7 +166,7 @@
 %
 % In current version, the package \pkg{piton} supports four computer languages:
 % Python, OCaml, SQL and C (in fact \CC). It supports also a special language
-% called ``|minimal|'': cf. \pageref{minimal}.
+% called ``|minimal|'': cf. p.~\pageref{minimal}.
 %
 % \smallskip
 % By default, the language used is Python.
@@ -177,8 +177,8 @@
 % and its key |language|: |\PitonOptions{language = C}|.
 %
 % \smallskip
-% \colorbox{yellow!50}{\textbf{New 2.4}}\enskip The name of the L3 variable
-% corresponding to that key is |\l_piton_language_str|.
+% For the developpers, let's say that the name of the current language is stored
+% (in lower case) in the L3 public variable |\l_piton_language_str|.
 %
 % \smallskip
 % In what follows, we will speak of Python, but the features described also
@@ -333,9 +333,9 @@
 % \item \index{path} The key \Definition{path} specifies a path where the files
 % included by |\PitonInputFile| will be searched.
 % 
-% \item  \index{gobble} 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
+% \item \index{gobble}\label{gobble} 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 \index{auto-gobble}\index{gobble!auto-gobble} When the key
@@ -354,10 +354,12 @@
 % gobble is set by the position of the commands |\begin{Piton}| and
 % |\end{Piton}| which delimit the current environment.
 %
-% \item \index{write} \colorbox{yellow!50}{\bfseries New 2.3}\enskip The key
-% \Definition{write} takes in as argument a name of file (with its extension)
-% and write the content of the current environment in that file. At the first
-% use of a file by \pkg{piton}, it is erased.
+% \item \index{write} The key \Definition{write} takes in as argument a name of
+% file (with its extension) and write the content\footnote{In fact, it's not
+% exactly the body of the environment but the value of |piton.get_last_code()|
+% which is the body without the overwritten LaTeX formatting instructions (cf.
+% the part~\ref{API}, p.~\pageref{API}).} of the current environment in
+% that file. At the first use of a file by \pkg{piton}, it is erased.
 %
 % \item \index{path-write}\colorbox{yellow!50}{\bfseries New 2.5}\enskip The key
 % \Definition{path-write} specifies a path where the files written by the key
@@ -384,7 +386,8 @@
 % \emph{absolute} (that is to say: they are the numbers of the lines in the
 % file). That key may be useful when |\PitonInputFile| is used to insert only a
 % part of the file (cf. part~\ref{part-of-a-file}, p.~\pageref{part-of-a-file}).
-% The key |/absolute| is no-op in the environments |{Piton}|.
+% The key |/absolute| is no-op in the environments |{Piton}| and those created
+% by |\NewPitonEnvironment|.
 % \item The key \Definition{line-numbers/start} requires that the line numbering
 % begins to the value of the key. 
 % \item With the key \Definition{line-numbers/resume}, the counter of lines is
@@ -714,7 +717,10 @@
 % command takes in three mandatory arguments. 
 
 % That command has the same syntax as the classical environment
-% |\NewDocumentEnvironment|.
+% |\NewDocumentEnvironment|.\footnote{However, the specifier of argument |b|
+% (used to catch the body of the environment as a LaTeX argument) is
+% not allowed.}
+%
 % 
 % \bigskip
 % With the following instruction, a new environment |{Python}| will be
@@ -1207,10 +1213,8 @@
 % \subsubsection{The key ``detected-commands''}
 %
 % \index{detected-commands (key)}
+% \label{detected-commands}
 %
-% \colorbox{yellow!50}{\bfseries New 2.4}\par\nobreak
-%
-% \smallskip
 % The key |detected-commands| of |\PitonOptions| allow to specify a
 % (comma-separated) list of names of LaTeX commands that will be detected 
 % directly by \pkg{piton}.
@@ -1253,9 +1257,7 @@
 % 
 % \subsubsection{The mechanism ``escape''}
 %
-% \index{escape-math}
-% \index{begin-escape-math}
-% \index{end-escape-math}
+% \label{escape}
 %
 % It's also possible to overwrite the Python listings to insert LaTeX code
 % almost everywhere (but between lexical units, of course). By default,
@@ -1269,7 +1271,7 @@
 % \medskip
 % We consider once again the previous example of a recursive programmation of
 % the factorial. We want to highlight in pink the instruction containing the
-% recursive call. With the package \pkg{lua-el}, we can use the syntax
+% recursive call. With the package \pkg{lua-ul}, we can use the syntax
 % |\highLight[LightPink]{...}|. Because of the optional argument between square
 % brackets, it's not possible to use the key |detected-commands| but it's
 % possible to acheive our goal with the more general mechanism ``escape''.
@@ -1604,6 +1606,45 @@
 % is similar to the key |auto-gobble| but acts on U+0009 instead of U+0020
 % (spaces).
 %
+%
+% \bigskip
+% \section{API for the developpers}
+%
+% \label{API}
+% 
+% The L3 variable |\l_piton_language_str| contains the name of the current
+% language of \pkg{piton} (in lower case).
+%
+% \bigskip
+% \colorbox{yellow!50}{\textbf{New 2.6}}\par\nobreak
+%
+% The extension \pkg{piton} provides a Lua function |piton.get_last_code|
+% without argument which returns the code in the latest environment of
+% \pkg{piton}.
+% \begin{itemize}
+% \item The carriage returns (which are present in the initial environment)
+% appears as characters |\r| (i.e. U+000D).
+%
+% \item The code returned by |piton.get_last_code()| takes into account the
+% potential application of a key |gobble|, |auto-gobble| or |env-gobble|
+% (cf.~p.~\pageref{gobble}). 
+%
+% \item The extra formatting elements added in the code are deleted in the code
+% returned by |piton.get_last_code()|. That concerns the LaTeX commands declared
+% by the key |detected-commands| (cf. part~\ref{detected-commands}) and the
+% elements inserted by the mechanism ``|escape|'' (cf. part~\ref{escape}).
+%
+% \item |piton.get_last_code| is a Lua function and not a Lua string: the
+% treatments outlined above are executed when the function is called. Therefore,
+% it might be judicious to store the value returned by |piton.get_last_code()|
+% in a variable of Lua if it will be used serveral times.
+% \end{itemize}
+% 
+% \medskip
+% For an example of use, see the part concerning |pyluatex|, part~\ref{pyluatex},
+% p.~\pageref{pyluatex}. 
+%
+%
 % \section{Examples}
 %
 % \subsection{Line numbering}
@@ -1931,6 +1972,7 @@
 % \subsection{Use with pyluatex}
 %
 % \index{pyluatex@{\pkg{pyluatex}} (extension)}
+% \label{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
@@ -1937,62 +1979,29 @@
 % 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).
-%
-%
+% listing (with \pkg{piton}) but also displays the output of the execution of the
+% code with Python.
+% 
+% \medskip
 % \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
+% \NewPitonEnvironment{~emphase#PitonExecute@}{!O{}}
+%   {\PitonOptions{~#1}}
+%   {\begin{center}
+%    \directlua{pyluatex.execute(piton.get_last_code(), false, true, false, true)}%
+%    \end{center}
+%    \ignorespacesafterend}
 % \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
+% \medskip
+% We have used the Lua function |piton.get_last_code| provided in the API of
+% \pkg{piton} : cf.~part~\ref{API}, p.~\pageref{API}.
 %
+% \medskip
 % This environment |{PitonExecute}| takes in as optional argument (between
 % square brackets) the options of the command |\PitonOptions|.
 %
 %
-% \bigskip
+%
 % \clearpage
 % \section{The styles for the different computer languages}
 %
@@ -2247,9 +2256,6 @@
 %
 % \subsection{The language ``minimal''}
 %
-% \colorbox{yellow!50}{\bfseries New 2.4}\par\nobreak
-%
-% \bigskip
 % It's possible to switch to the language ``|minimal|'' with |\PitonOptions{language = minimal}|.
 %
 % \bigskip
@@ -2434,7 +2440,7 @@
   {piton}
   {\PitonFileDate}
   {\PitonFileVersion}
-  {Highlight Python codes with LPEG on LuaLaTeX}
+  {Highlight informatic listings with LPEG on LuaLaTeX}
 %    \end{macrocode}
 %
 % \bigskip
@@ -2472,6 +2478,7 @@
 % \bigskip
 %    \begin{macrocode}
 \RequirePackage { luatexbase } 
+\RequirePackage { luacode }
 %    \end{macrocode}
 % 
 % \bigskip
@@ -2669,6 +2676,8 @@
   { 
     piton = piton~or { } 
     piton.ListCommands = lpeg.P ( false ) 
+    piton.last_code = ''
+    piton.last_language = ''
   }
 %    \end{macrocode}
 % 
@@ -2684,6 +2693,13 @@
 %    \end{macrocode}
 % 
 % \medskip
+% Each time the command |\PitonInputFile| or an environment of \pkg{piton} is
+% used, the code of that environment will be stored in the following global string.
+%    \begin{macrocode}
+\tl_new:N \g_piton_last_code_tl
+%    \end{macrocode}
+%
+% \medskip
 % The following parameter corresponds to the key |path| (which is the path used
 % to include files by |\PitonInputFile|).
 %    \begin{macrocode}
@@ -3015,8 +3031,8 @@
 % 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() } }
+\cs_new_protected:Npn \@@_open_brace: { \lua_now:n { piton.open_brace() } }
+\cs_new_protected:Npn \@@_close_brace: { \lua_now:n { piton.close_brace() } }
 %    \end{macrocode}
 % 
 % \bigskip
@@ -3037,7 +3053,7 @@
   { 
     \tl_gset:Nn \g_@@_begin_line_hook_tl
       { 
-        \tl_if_empty:NF \l_@@_prompt_bg_color_tl % added 2023-04-24
+        \tl_if_empty:NF \l_@@_prompt_bg_color_tl 
           { \clist_set:NV \l_@@_bg_color_clist \l_@@_prompt_bg_color_tl }
       } 
   }
@@ -3400,11 +3416,15 @@
 %    \begin{macrocode}
 \keys_define:nn { PitonOptions }
   {
-    detected-commands .code:n =  \@@_detected_commands:n { #1 } , 
+    detected-commands .code:n =  
+       \lua_now:n { piton.addListCommands('#1') } ,
     detected-commands .value_required:n = true , 
     detected-commands .usage:n = preamble , 
 %    \end{macrocode}
 % First, we put keys that should be avalaible only in the preamble.
+%
+% Remark that the command |\lua_escape:n| is fully expandable. That's why we use
+% |\lua_now:e|.
 %    \begin{macrocode}
     begin-escape .code:n = 
       \lua_now:e { piton.begin_escape = "\lua_escape:n{#1}" } ,
@@ -3977,7 +3997,7 @@
               { \lua_now:e { piton.write = "\l_@@_write_str" } }
               { 
                 \lua_now:e 
-                 { piton.write = "\l_@@_path_write_str / \l_@@_write_str" } 
+                  { piton.write = "\l_@@_path_write_str / \l_@@_write_str" } 
               } 
             \str_if_empty:NF \l_@@_write_str
               { 
@@ -4243,11 +4263,11 @@
 %    \begin{macrocode}
 \NewDocumentCommand { \SetPitonStyle } { O { } m } 
   { 
+    \str_clear_new:N \l_@@_SetPitonStyle_option_str
     \str_set:Nx \l_@@_SetPitonStyle_option_str { \str_lowercase:n { #1 } }
     \str_if_eq:onT \l_@@_SetPitonStyle_option_str { current-language }
       { \str_set_eq:NN \l_@@_SetPitonStyle_option_str \l_piton_language_str }
     \keys_set:nn { piton / Styles } { #2 } 
-    \str_clear:N \l_@@_SetPitonStyle_option_str 
   } 
 %    \end{macrocode}
 % 
@@ -4259,8 +4279,8 @@
 % 
 % \medskip
 %    \begin{macrocode}
-\clist_new:N \g_@@_style_clist
-\clist_set:Nn \g_@@_styles_clist 
+\clist_new:N \g_@@_styles_clist
+\clist_gset:Nn \g_@@_styles_clist 
   {
     Comment ,
     Comment.LaTeX ,
@@ -4798,30 +4818,27 @@
 % \bigskip
 % \subsubsection{Detected commands}
 %
-%    \begin{macrocode}
-\cs_new_protected:Npn \@@_detected_commands:n #1
-  { \lua_now:n { piton.addListCommands('#1') } }
-%    \end{macrocode}
 % 
 %    \begin{macrocode}
 \ExplSyntaxOff
-\directlua 
-  {
+\begin{luacode*}
     lpeg.locale(lpeg)
-    local P , alpha , C , Cf, space 
-      = lpeg.P , lpeg.alpha , lpeg.C , lpeg.Cf , lpeg.space 
-    local S = lpeg.S 
-    local One_P 
-      = space ^ 0 
-        * C ( alpha ^ 1 ) / ( function (s) return P ( string.char(92) .. s ) end ) 
-        * space ^ 0 
+    local P , alpha , C , space , S , V
+      = lpeg.P , lpeg.alpha , lpeg.C , lpeg.space , lpeg.S , lpeg.V
+    local function add(...)
+          local s = P ( false ) 
+          for _ , x in ipairs({...}) do s = s + x end  
+          return s 
+          end
+    local my_lpeg = 
+      P {  "E" ,
+           E = ( V "F" * ( P "," * V "F" ) ^ 0 ) / add ,
+           F = space ^ 0 * ( alpha ^ 1 ) / "\\%0" * space ^ 0 
+        }
     function piton.addListCommands( key_value )
-       piton.ListCommands =  
-         piton.ListCommands + 
-           Cf ( One_P * ( P "," * One_P ) ^ 0  ,
-                ( function (s,t) return s + t end ) ) : match ( key_value ) 
+      piton.ListCommands = piton.ListCommands + my_lpeg : match ( key_value ) 
     end
-  }
+\end{luacode*}
 %</STY>
 %    \end{macrocode}
 % 
@@ -4863,7 +4880,7 @@
 % 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 Cs , Cg , Cmt , Cb = lpeg.Cs, lpeg.Cg , lpeg.Cmt , lpeg.Cb
 local R = lpeg.R
 %    \end{macrocode}
 %
@@ -4945,12 +4962,9 @@
 % \bigskip
 % The following \textsc{lpeg} catches the Python chunks which are in LaTeX
 % escapes (and that chunks will be considered as normal LaTeX constructions).
-% 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}
 Escape = P ( false ) 
+EscapeClean = P ( false ) 
 if piton.begin_escape ~= nil
 then 
   Escape = 
@@ -4957,6 +4971,14 @@
     P(piton.begin_escape)
     * L ( ( 1 - P(piton.end_escape) ) ^ 1 ) 
     * P(piton.end_escape)
+%    \end{macrocode}
+% The LPEG |EscapeClean| will be used in the LPEG Clean (and that LPEG is used
+% to ``clean'' the code by removing the formatting elements).
+%    \begin{macrocode}
+  EscapeClean = 
+    P(piton.begin_escape)
+    * ( 1 - P(piton.end_escape) ) ^ 1 
+    * P(piton.end_escape)
 end
 %    \end{macrocode}
 % 
@@ -5125,13 +5147,13 @@
         Ct ( Cc "Open" 
               * C ( 
                     P ( "\\begin{" .. name ..   "}" )
-                    * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1 
+                    * ( P "<" * ( 1 - P ">") ^ 0 * P ">" ) ^ -1 
                   ) 
              * Cc ( "\\end{" .. name ..  "}" )
             ) 
        * ( 
-           C ( ( 1 - P ( "\\end{" .. name .. "}" ) ) ^ 0 ) 
-           / ( function (s) return lpeg : match(s) end ) 
+           ( ( 1 - P ( "\\end{" .. name .. "}" ) ) ^ 0 ) 
+              / ( function (s) return lpeg : match(s) end ) 
          )
        * P ( "\\end{" .. name ..  "}" ) * Ct ( Cc "Close" ) 
   end 
@@ -5143,6 +5165,7 @@
 % \bigskip
 %    \begin{macrocode}
 local languages = { }
+local CleanLPEGs = { }
 %    \end{macrocode}
 % 
 % \bigskip
@@ -5375,7 +5398,7 @@
          Q ( P "f\"" + P "F\"" ) 
          * ( 
              K ( 'String.Interpol' , P "{" )
-               * Q ( ( 1 - S "}\":" ) ^ 0 , 'Interpol.Inside' )
+               * K ( 'Interpol.Inside' , ( 1 - S "}\":" ) ^ 0 )
                * ( K ( 'String.Interpol' , P ":" ) * Q ( (1 - S "}:\"") ^ 0 ) ) ^ -1
                * K ( 'String.Interpol' , P "}" )
              + 
@@ -5436,7 +5459,7 @@
                 ) 
             * Cc "}" 
          ) 
-       * ( C ( balanced_braces ) / (function (s) return MainLoopPython:match(s) end ) )
+       * ( balanced_braces / (function (s) return MainLoopPython:match(s) end ) )
        * P "}" * Ct ( Cc "Close" ) 
     + OneBeamerEnvironment ( "uncoverenv" , MainLoopPython ) 
     + OneBeamerEnvironment ( "onlyenv" , MainLoopPython ) 
@@ -5481,17 +5504,29 @@
 %    \begin{macrocode}
 DetectedCommands = 
       Ct ( Cc "Open" 
-            * C ( 
-                  piton.ListCommands
-                  * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1 
-                  * P "{" 
-                ) 
+            * C ( piton.ListCommands * P "{" ) 
             * Cc "}" 
          ) 
-       * ( C ( balanced_braces ) / (function (s) return MainLoopPython:match(s) end ) )
+       * ( balanced_braces / (function (s) return MainLoopPython:match(s) end ) )
        * P "}" * Ct ( Cc "Close" ) 
 %    \end{macrocode}
+%
+% \bigskip
+%
+% \paragraph{The LPEG Clean}
+%
+%    \begin{macrocode}
+CleanLPEGs['python']
+      = Ct ( ( piton.ListCommands * P "{" 
+                * (  balanced_braces 
+                    / ( function (s) return CleanLPEGs['python']:match(s) end ) )
+                * P "}" 
+               + EscapeClean
+               +  C ( P ( 1 ) )
+              ) ^ 0 ) / table.concat 
+%    \end{macrocode}
 % 
+% 
 % \bigskip
 % \paragraph{EOL}
 %
@@ -5624,7 +5659,7 @@
 % of a function definition (which begins with |def|).
 %    \begin{macrocode}
 local StringDoc = 
-    K ( 'String.Doc' , P "\"\"\"" )
+    K ( 'String.Doc' , P "r" ^ -1 * P "\"\"\"" )
       * ( K ( 'String.Doc' , (1 - P "\"\"\"" - P "\r" ) ^ 0  ) * EOL
           * Tab ^ 0 
         ) ^ 0
@@ -5702,7 +5737,7 @@
 % \medskip
 %    \begin{macrocode}
 local Param = 
-  SkipSpace * Identifier * SkipSpace
+  SkipSpace * ( Identifier + Q "*args" + Q "**kwargs" ) * SkipSpace
    * ( 
          K ( 'InitialValues' , P "=" * expression )
        + Q ( P ":" ) * SkipSpace * K ( 'Name.Type' , letter ^ 1  ) 
@@ -5868,8 +5903,8 @@
        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 "'"
+             + 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 ")"
@@ -5889,7 +5924,7 @@
 local OneField = 
     K ( 'Name.Field' , identifier ) * SkipSpace
   * Q "=" * SkipSpace
-  * ( C ( expression_for_fields ) / ( function (s) return LoopOCaml:match(s) end ) )
+  * ( expression_for_fields / ( function (s) return LoopOCaml:match(s) end ) )
   * SkipSpace
 
 local Record = 
@@ -5940,7 +5975,7 @@
   K ( 'Keyword' ,
       P "assert" + P "and" + P "as" + P "begin" + P "class" + P "constraint" + P "done" 
   + P "downto" + P "do" + P "else" + P "end" + P "exception" + P "external" 
-  + P "for" + P "function" + P "functor" + P "fun"  + P "if" 
+  + 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" 
@@ -6009,7 +6044,7 @@
                 ) 
             * Cc "}" 
          ) 
-       * ( C ( balanced_braces ) / (function (s) return MainLoopOCaml:match(s) end ) )
+       * ( balanced_braces / (function (s) return MainLoopOCaml:match(s) end ) )
        * P "}" * Ct ( Cc "Close" ) 
     + OneBeamerEnvironment ( "uncoverenv" , MainLoopOCaml ) 
     + OneBeamerEnvironment ( "onlyenv" , MainLoopOCaml ) 
@@ -6051,17 +6086,26 @@
 %    \begin{macrocode}
 DetectedCommands = 
       Ct ( Cc "Open" 
-            * C ( 
-                  piton.ListCommands
-                  * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1 
-                  * P "{" 
-                ) 
-            * Cc "}" 
+            * C ( piton.ListCommands * P "{" ) * Cc "}" 
          ) 
-       * ( C ( balanced_braces ) / (function (s) return MainLoopOCaml:match(s) end ) )
+       * ( balanced_braces / (function (s) return MainLoopOCaml:match(s) end ) )
        * P "}" * Ct ( Cc "Close" ) 
 %    \end{macrocode}
+%
+% \bigskip
+%    \begin{macrocode}
+CleanLPEGs['ocaml']
+      = Ct ( ( piton.ListCommands * P "{" 
+                * ( balanced_braces 
+                    / ( function (s) return CleanLPEGs['ocaml']:match(s) end ) )
+                * P "}" 
+               + EscapeClean
+               +  C ( P ( 1 ) )
+              ) ^ 0 ) / table.concat 
+%    \end{macrocode}
 % 
+
+% 
 %
 % \bigskip
 % \paragraph{EOL}
@@ -6128,7 +6172,7 @@
 local close = "|" * C(ext) * "}"
 local closeeq = 
   Cmt ( close * Cb('init'), 
-        function (s, i, a, b) return a==b end ) 
+        function (s, i, a, b) return a == b end ) 
 %    \end{macrocode}
 %
 % \medskip
@@ -6490,7 +6534,7 @@
                 ) 
             * Cc "}" 
          ) 
-       * ( C ( balanced_braces ) / (function (s) return MainLoopC:match(s) end ) )
+       * ( balanced_braces / (function (s) return MainLoopC:match(s) end ) )
        * P "}" * Ct ( Cc "Close" ) 
     + OneBeamerEnvironment ( "uncoverenv" , MainLoopC ) 
     + OneBeamerEnvironment ( "onlyenv" , MainLoopC ) 
@@ -6532,16 +6576,23 @@
 %    \begin{macrocode}
 DetectedCommands = 
       Ct ( Cc "Open" 
-            * C ( 
-                  piton.ListCommands
-                  * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1 
-                  * P "{" 
-                ) 
-            * Cc "}" 
+            * C ( piton.ListCommands * P "{" ) * Cc "}" 
          ) 
-       * ( C ( balanced_braces ) / (function (s) return MainLoopC:match(s) end ) )
+       * ( balanced_braces / (function (s) return MainLoopC:match(s) end ) )
        * P "}" * Ct ( Cc "Close" ) 
 %    \end{macrocode}
+%
+% \bigskip
+%    \begin{macrocode}
+CleanLPEGs['c']
+      = Ct ( ( piton.ListCommands * P "{" 
+                * ( balanced_braces 
+                    / ( function (s) return CleanLPEGs['c']:match(s) end ) )
+                * P "}" 
+               + EscapeClean
+               +  C ( P ( 1 ) )
+              ) ^ 0 ) / table.concat 
+%    \end{macrocode}
 % 
 % \bigskip
 % \paragraph{EOL}
@@ -6813,7 +6864,7 @@
                 ) 
             * Cc "}" 
          ) 
-       * ( C ( balanced_braces ) / (function (s) return MainLoopSQL:match(s) end ) )
+       * ( balanced_braces / (function (s) return MainLoopSQL:match(s) end ) )
        * P "}" * Ct ( Cc "Close" ) 
     + OneBeamerEnvironment ( "uncoverenv" , MainLoopSQL ) 
     + OneBeamerEnvironment ( "onlyenv" , MainLoopSQL ) 
@@ -6855,18 +6906,25 @@
 %    \begin{macrocode}
 DetectedCommands = 
       Ct ( Cc "Open" 
-            * C ( 
-                  piton.ListCommands
-                  * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1 
-                  * P "{" 
-                ) 
-            * Cc "}" 
+            * C ( piton.ListCommands * P "{" ) * Cc "}" 
          ) 
-       * ( C ( balanced_braces ) / (function (s) return MainLoopSQL:match(s) end ) )
+       * ( balanced_braces / (function (s) return MainLoopSQL:match(s) end ) )
        * P "}" * Ct ( Cc "Close" ) 
 %    \end{macrocode}
 %
 % \bigskip
+%    \begin{macrocode}
+CleanLPEGs['sql']
+      = Ct ( ( piton.ListCommands * P "{" 
+                * ( balanced_braces 
+                    / ( function (s) return CleanLPEGs['sql']:match(s) end ) )
+                * P "}" 
+               + EscapeClean
+               +  C ( P ( 1 ) )
+              ) ^ 0 ) / table.concat 
+%    \end{macrocode}
+%
+% \bigskip
 % \paragraph{EOL}
 %
 % \bigskip
@@ -7106,7 +7164,7 @@
                 ) 
             * Cc "}" 
          ) 
-       * ( C ( balanced_braces ) / (function (s) return MainLoopMinimal:match(s) end ) )
+       * ( balanced_braces / (function (s) return MainLoopMinimal:match(s) end ) )
        * P "}" * Ct ( Cc "Close" ) 
     + OneBeamerEnvironment ( "uncoverenv" , MainLoopMinimal ) 
     + OneBeamerEnvironment ( "onlyenv" , MainLoopMinimal ) 
@@ -7140,16 +7198,23 @@
 
 DetectedCommands = 
       Ct ( Cc "Open" 
-            * C ( 
-                  piton.ListCommands
-                  * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1 
-                  * P "{" 
-                ) 
-            * Cc "}" 
+            * C ( piton.ListCommands * P "{" ) * Cc "}" 
          ) 
-       * ( C ( balanced_braces ) / (function (s) return MainLoopMinimal:match(s) end ) )
+       * ( balanced_braces / (function (s) return MainLoopMinimal:match(s) end ) )
        * P "}" * Ct ( Cc "Close" ) 
 
+
+CleanLPEGs['minimal']
+      = Ct ( ( piton.ListCommands * P "{" 
+                * ( balanced_braces 
+                    / ( function (s) return CleanLPEGs['minimal']:match(s) end ) )
+                * P "}" 
+               + EscapeClean
+               +  C ( P ( 1 ) )
+              ) ^ 0 ) / table.concat 
+
+
+
 local EOL = 
   P "\r" 
   *
@@ -7222,7 +7287,7 @@
 % \bigskip
 % \subsubsection{The function Parse}
 %
-%
+% \medskip
 % 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
@@ -7360,21 +7425,16 @@
 % 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 ) 
+       return ( Ct ( 
+                     ( 1 - P "\r" ) ^ (-n)  * C ( ( 1 - P "\r" ) ^ 0 ) 
+                       * ( C ( P "\r" )
+                       * ( 1 - P "\r" ) ^ (-n)
+                       * C ( ( 1 - P "\r" ) ^ 0 )
+                      ) ^ 0 
+                   ) / table.concat ) : match ( code ) 
   end
 end
 %    \end{macrocode}
@@ -7382,40 +7442,40 @@
 % 
 % 
 % \bigskip
-% The following function |add| will be used in the following \textsc{lpeg}
-% |AutoGobbleLPEG|, |TabsAutoGobbleLPEG| and |EnvGobbleLPEG|.
+% The following function |sum| will be used in the following \textsc{lpeg}
+% |AutoGobbleLPEG|, |TabsAutoGobbleLPEG| and |EnvGobbleLPEG|. It computes the
+% sum of all its arguments.
 %    \begin{macrocode}
-local function add(acc,new_value)
-  return acc + new_value
-end 
+local function count_captures(...)
+    local acc = 0
+    for _ in ipairs({...}) do
+        acc = acc + 1
+    end
+    return acc
+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.
+% the beginning of the lines of code. 
+%    begin{macrocode}
 %    \begin{macrocode}
 local AutoGobbleLPEG = 
-    ( space ^ 0 * P "\r" ) ^ -1 
-    * Cf (
-           (
+  (
+    (
 %    \end{macrocode}
-% We don't take into account the empty lines (with only spaces).
+% We don't take into account the empty lines (those containing 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
+      P " " ^ 0 * P "\r"
+      + 
+      C ( P " " ) ^ 0 / count_captures * ( 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
-         )
+    *
+    ( C ( P " " ) ^ 0 / count_captures * ( 1 - P " " ) * ( 1 - P "\r" ) ^ 0 ) ^ -1 
+  ) / math.min
 %    \end{macrocode}
 %
 % \bigskip
@@ -7422,19 +7482,15 @@
 % 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
-         )
+  (
+    (
+      P "\t" ^ 0 * P "\r"
+      + 
+      C ( P " " ) ^ 0 / count_captures * ( 1 - P "\t" ) * ( 1 - P "\r" ) ^ 0 * P "\r"
+    ) ^ 0
+    *
+    ( C ( P " " ) ^ 0 / count_captures * ( 1 - P "\t" ) * ( 1 - P "\r" ) ^ 0 ) ^ -1 
+  ) / math.min
 %    \end{macrocode}
 % 
 %
@@ -7443,17 +7499,28 @@
 % 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.
+% traditionnal way to indent in LaTeX). 
 %    \begin{macrocode}
 local EnvGobbleLPEG =
-  ( ( 1 - P "\r" ) ^ 0 * P "\r" ) ^ 0 
-    * Cf ( Cc(0) * ( P " " * Cc(1) ) ^ 0 , add ) * -1
+  ( ( 1 - P "\r" ) ^ 0 * P "\r" ) ^ 0 * ( C ( P " " )  ^ 0 / count_captures ) * -1
 %    \end{macrocode}
 % 
 % \bigskip
 %    \begin{macrocode}
+local function remove_before_cr(input_string)
+    local match_result = P("\r") : match(input_string)
+    if match_result then
+        return string.sub(input_string, match_result ) 
+    else
+        return input_string 
+    end
+end
+%    \end{macrocode}
+%
+% \bigskip
+%    \begin{macrocode}
 function piton.GobbleParse(language,n,code)
+  code = remove_before_cr(code)
   if n==-1 
   then n = AutoGobbleLPEG : match(code)
   else if n==-2 
@@ -7463,10 +7530,16 @@
             end
        end
   end
-  piton.Parse(language,gobble(n,code))
+  piton.last_code = gobble(n,code)
+  piton.Parse(language,piton.last_code)
+  piton.last_language = language
+%    \end{macrocode}
+% Now, if the final user has used the key |write| to write the code of the
+% environment on an external file.
+%    \begin{macrocode}
   if piton.write ~= ''
   then local file = assert(io.open(piton.write,piton.write_mode))
-       file:write(code)
+       file:write(piton.get_last_code()) 
        file:close()
   end
 end 
@@ -7473,6 +7546,15 @@
 %    \end{macrocode}
 %
 % \bigskip
+% The following Lua function is provided to the developper. 
+%    \begin{macrocode}
+function piton.get_last_code ( ) 
+  return CleanLPEGs[piton.last_language] : match(piton.last_code) 
+end
+%    \end{macrocode}
+% 
+% 
+% \bigskip
 % \subsubsection{To count the number of lines}
 %
 % \medskip
@@ -7490,14 +7572,12 @@
 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) 
+              + ( 1 - P "\r" ) ^ 0 * C ( P "\r" ) 
+            ) ^ 0 
+          * (1 - P "\r" ) ^ 0 
+       ) / count_captures ) * -1 ) : match (code) 
   tex.sprint( 
       luatexbase.catcodetables.expl , 
       '\\int_set:Nn \\l_@@_nb_non_empty_lines_int {' .. count .. '}' )
@@ -7508,7 +7588,7 @@
 %    \begin{macrocode}
 function piton.CountLinesFile(name)
   local count = 0 
-  io.open(name) -- added
+  io.open(name) 
   for line in io.lines(name) do count = count + 1 end
   tex.sprint( 
       luatexbase.catcodetables.expl , 
@@ -7590,6 +7670,10 @@
 %
 % \verb|https://github.com/fpantigny/piton|
 %
+% \subsection*{Changes between versions 2.5 and 2.6}
+%
+% API: |piton.last_code| and |\g_piton_last_code_tl| are provided.
+%
 % \subsection*{Changes between versions 2.4 and 2.5}
 %
 % New key |path-write|
@@ -7610,8 +7694,6 @@
 % The variable |\l_piton_language_str| is now public.
 % 
 %
-% \subsection*{Changes between versions 2.2 and 2.3}
-%
 % New key |write|.
 % 
 % \subsection*{Changes between versions 2.1 and 2.2}

Modified: branches/branch2023.final/Master/texmf-dist/tex/lualatex/piton/piton.lua
===================================================================
--- branches/branch2023.final/Master/texmf-dist/tex/lualatex/piton/piton.lua	2024-02-27 20:48:03 UTC (rev 70204)
+++ branches/branch2023.final/Master/texmf-dist/tex/lualatex/piton/piton.lua	2024-02-27 20:48:14 UTC (rev 70205)
@@ -20,7 +20,7 @@
 -- -------------------------------------------
 -- 
 -- This file is part of the LuaLaTeX package 'piton'.
--- Version 2.5 of 2024/02/20
+-- Version 2.6 of 2024/02/27
 
 
 if piton.comment_latex == nil then piton.comment_latex = ">" end
@@ -32,7 +32,7 @@
    tex.sprint("}")
 end
 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 Cs , Cg , Cmt , Cb = lpeg.Cs, lpeg.Cg , lpeg.Cmt , lpeg.Cb
 local R = lpeg.R
 local function Q(pattern)
   return Ct ( Cc ( luatexbase.catcodetables.CatcodeTableOther ) * C ( pattern ) )
@@ -56,6 +56,7 @@
      * Ct ( Cc "Close" )
 end
 Escape = P ( false )
+EscapeClean = P ( false )
 if piton.begin_escape ~= nil
 then
   Escape =
@@ -62,6 +63,10 @@
     P(piton.begin_escape)
     * L ( ( 1 - P(piton.end_escape) ) ^ 1 )
     * P(piton.end_escape)
+  EscapeClean =
+    P(piton.begin_escape)
+    * ( 1 - P(piton.end_escape) ) ^ 1
+    * P(piton.end_escape)
 end
 EscapeMath = P ( false )
 if piton.begin_escape_math ~= nil
@@ -133,18 +138,19 @@
         Ct ( Cc "Open"
               * C (
                     P ( "\\begin{" .. name ..   "}" )
-                    * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1
+                    * ( P "<" * ( 1 - P ">") ^ 0 * P ">" ) ^ -1
                   )
              * Cc ( "\\end{" .. name ..  "}" )
             )
        * (
-           C ( ( 1 - P ( "\\end{" .. name .. "}" ) ) ^ 0 )
-           / ( function (s) return lpeg : match(s) end )
+           ( ( 1 - P ( "\\end{" .. name .. "}" ) ) ^ 0 )
+              / ( function (s) return lpeg : match(s) end )
          )
        * P ( "\\end{" .. name ..  "}" ) * Ct ( Cc "Close" )
   end
 end
 local languages = { }
+local CleanLPEGs = { }
 local Operator =
   K ( 'Operator' ,
       P "!=" + P "<>" + P "==" + P "<<" + P ">>" + P "<=" + P ">=" + P ":="
@@ -260,7 +266,7 @@
          Q ( P "f\"" + P "F\"" )
          * (
              K ( 'String.Interpol' , P "{" )
-               * Q ( ( 1 - S "}\":" ) ^ 0 , 'Interpol.Inside' )
+               * K ( 'Interpol.Inside' , ( 1 - S "}\":" ) ^ 0 )
                * ( K ( 'String.Interpol' , P ":" ) * Q ( (1 - S "}:\"") ^ 0 ) ) ^ -1
                * K ( 'String.Interpol' , P "}" )
              +
@@ -306,7 +312,7 @@
                 )
             * Cc "}"
          )
-       * ( C ( balanced_braces ) / (function (s) return MainLoopPython:match(s) end ) )
+       * ( balanced_braces / (function (s) return MainLoopPython:match(s) end ) )
        * P "}" * Ct ( Cc "Close" )
     + OneBeamerEnvironment ( "uncoverenv" , MainLoopPython )
     + OneBeamerEnvironment ( "onlyenv" , MainLoopPython )
@@ -339,15 +345,19 @@
 end
 DetectedCommands =
       Ct ( Cc "Open"
-            * C (
-                  piton.ListCommands
-                  * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1
-                  * P "{"
-                )
+            * C ( piton.ListCommands * P "{" )
             * Cc "}"
          )
-       * ( C ( balanced_braces ) / (function (s) return MainLoopPython:match(s) end ) )
+       * ( balanced_braces / (function (s) return MainLoopPython:match(s) end ) )
        * P "}" * Ct ( Cc "Close" )
+CleanLPEGs['python']
+      = Ct ( ( piton.ListCommands * P "{"
+                * (  balanced_braces
+                    / ( function (s) return CleanLPEGs['python']:match(s) end ) )
+                * P "}"
+               + EscapeClean
+               +  C ( P ( 1 ) )
+              ) ^ 0 ) / table.concat
 local PromptHastyDetection = ( # ( P ">>>" + P "..." ) * Lc ( '\\__piton_prompt:' ) ) ^ -1
 local Prompt = K ( 'Prompt' , ( ( P ">>>" + P "..." ) * P " " ^ -1 ) ^ -1  )
 local EOL =
@@ -428,7 +438,7 @@
   )
 local LongString = SingleLongString + DoubleLongString
 local StringDoc =
-    K ( 'String.Doc' , P "\"\"\"" )
+    K ( 'String.Doc' , P "r" ^ -1 * P "\"\"\"" )
       * ( K ( 'String.Doc' , (1 - P "\"\"\"" - P "\r" ) ^ 0  ) * EOL
           * Tab ^ 0
         ) ^ 0
@@ -461,7 +471,7 @@
              + ( 1 - S "{}()[]\r\"'" ) ) ^ 0
     }
 local Param =
-  SkipSpace * Identifier * SkipSpace
+  SkipSpace * ( Identifier + Q "*args" + Q "**kwargs" ) * SkipSpace
    * (
          K ( 'InitialValues' , P "=" * expression )
        + Q ( P ":" ) * SkipSpace * K ( 'Name.Type' , letter ^ 1  )
@@ -542,8 +552,8 @@
        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 "'"
+             + 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 ")"
@@ -560,7 +570,7 @@
 local OneField =
     K ( 'Name.Field' , identifier ) * SkipSpace
   * Q "=" * SkipSpace
-  * ( C ( expression_for_fields ) / ( function (s) return LoopOCaml:match(s) end ) )
+  * ( expression_for_fields / ( function (s) return LoopOCaml:match(s) end ) )
   * SkipSpace
 
 local Record =
@@ -602,7 +612,7 @@
   K ( 'Keyword' ,
       P "assert" + P "and" + P "as" + P "begin" + P "class" + P "constraint" + P "done"
   + P "downto" + P "do" + P "else" + P "end" + P "exception" + P "external"
-  + P "for" + P "function" + P "functor" + P "fun"  + P "if"
+  + 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"
@@ -647,7 +657,7 @@
                 )
             * Cc "}"
          )
-       * ( C ( balanced_braces ) / (function (s) return MainLoopOCaml:match(s) end ) )
+       * ( balanced_braces / (function (s) return MainLoopOCaml:match(s) end ) )
        * P "}" * Ct ( Cc "Close" )
     + OneBeamerEnvironment ( "uncoverenv" , MainLoopOCaml )
     + OneBeamerEnvironment ( "onlyenv" , MainLoopOCaml )
@@ -680,15 +690,19 @@
 end
 DetectedCommands =
       Ct ( Cc "Open"
-            * C (
-                  piton.ListCommands
-                  * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1
-                  * P "{"
-                )
-            * Cc "}"
+            * C ( piton.ListCommands * P "{" ) * Cc "}"
          )
-       * ( C ( balanced_braces ) / (function (s) return MainLoopOCaml:match(s) end ) )
+       * ( balanced_braces / (function (s) return MainLoopOCaml:match(s) end ) )
        * P "}" * Ct ( Cc "Close" )
+CleanLPEGs['ocaml']
+      = Ct ( ( piton.ListCommands * P "{"
+                * ( balanced_braces
+                    / ( function (s) return CleanLPEGs['ocaml']:match(s) end ) )
+                * P "}"
+               + EscapeClean
+               +  C ( P ( 1 ) )
+              ) ^ 0 ) / table.concat
+
 local EOL =
   P "\r"
   *
@@ -726,7 +740,7 @@
 local close = "|" * C(ext) * "}"
 local closeeq =
   Cmt ( close * Cb('init'),
-        function (s, i, a, b) return a==b end )
+        function (s, i, a, b) return a == b end )
 local QuotedStringBis =
   WithStyle ( 'String.Long' ,
       (
@@ -962,7 +976,7 @@
                 )
             * Cc "}"
          )
-       * ( C ( balanced_braces ) / (function (s) return MainLoopC:match(s) end ) )
+       * ( balanced_braces / (function (s) return MainLoopC:match(s) end ) )
        * P "}" * Ct ( Cc "Close" )
     + OneBeamerEnvironment ( "uncoverenv" , MainLoopC )
     + OneBeamerEnvironment ( "onlyenv" , MainLoopC )
@@ -995,15 +1009,18 @@
 end
 DetectedCommands =
       Ct ( Cc "Open"
-            * C (
-                  piton.ListCommands
-                  * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1
-                  * P "{"
-                )
-            * Cc "}"
+            * C ( piton.ListCommands * P "{" ) * Cc "}"
          )
-       * ( C ( balanced_braces ) / (function (s) return MainLoopC:match(s) end ) )
+       * ( balanced_braces / (function (s) return MainLoopC:match(s) end ) )
        * P "}" * Ct ( Cc "Close" )
+CleanLPEGs['c']
+      = Ct ( ( piton.ListCommands * P "{"
+                * ( balanced_braces
+                    / ( function (s) return CleanLPEGs['c']:match(s) end ) )
+                * P "}"
+               + EscapeClean
+               +  C ( P ( 1 ) )
+              ) ^ 0 ) / table.concat
 local EOL =
   P "\r"
   *
@@ -1163,7 +1180,7 @@
                 )
             * Cc "}"
          )
-       * ( C ( balanced_braces ) / (function (s) return MainLoopSQL:match(s) end ) )
+       * ( balanced_braces / (function (s) return MainLoopSQL:match(s) end ) )
        * P "}" * Ct ( Cc "Close" )
     + OneBeamerEnvironment ( "uncoverenv" , MainLoopSQL )
     + OneBeamerEnvironment ( "onlyenv" , MainLoopSQL )
@@ -1196,15 +1213,18 @@
 end
 DetectedCommands =
       Ct ( Cc "Open"
-            * C (
-                  piton.ListCommands
-                  * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1
-                  * P "{"
-                )
-            * Cc "}"
+            * C ( piton.ListCommands * P "{" ) * Cc "}"
          )
-       * ( C ( balanced_braces ) / (function (s) return MainLoopSQL:match(s) end ) )
+       * ( balanced_braces / (function (s) return MainLoopSQL:match(s) end ) )
        * P "}" * Ct ( Cc "Close" )
+CleanLPEGs['sql']
+      = Ct ( ( piton.ListCommands * P "{"
+                * ( balanced_braces
+                    / ( function (s) return CleanLPEGs['sql']:match(s) end ) )
+                * P "}"
+               + EscapeClean
+               +  C ( P ( 1 ) )
+              ) ^ 0 ) / table.concat
 local EOL =
   P "\r"
   *
@@ -1373,7 +1393,7 @@
                 )
             * Cc "}"
          )
-       * ( C ( balanced_braces ) / (function (s) return MainLoopMinimal:match(s) end ) )
+       * ( balanced_braces / (function (s) return MainLoopMinimal:match(s) end ) )
        * P "}" * Ct ( Cc "Close" )
     + OneBeamerEnvironment ( "uncoverenv" , MainLoopMinimal )
     + OneBeamerEnvironment ( "onlyenv" , MainLoopMinimal )
@@ -1407,16 +1427,20 @@
 
 DetectedCommands =
       Ct ( Cc "Open"
-            * C (
-                  piton.ListCommands
-                  * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1
-                  * P "{"
-                )
-            * Cc "}"
+            * C ( piton.ListCommands * P "{" ) * Cc "}"
          )
-       * ( C ( balanced_braces ) / (function (s) return MainLoopMinimal:match(s) end ) )
+       * ( balanced_braces / (function (s) return MainLoopMinimal:match(s) end ) )
        * P "}" * Ct ( Cc "Close" )
 
+CleanLPEGs['minimal']
+      = Ct ( ( piton.ListCommands * P "{"
+                * ( balanced_braces
+                    / ( function (s) return CleanLPEGs['minimal']:match(s) end ) )
+                * P "}"
+               + EscapeClean
+               +  C ( P ( 1 ) )
+              ) ^ 0 ) / table.concat
+
 local EOL =
   P "\r"
   *
@@ -1558,58 +1582,57 @@
   return piton.Parse(language,s)
 end
 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 )
+       return ( Ct (
+                     ( 1 - P "\r" ) ^ (-n)  * C ( ( 1 - P "\r" ) ^ 0 )
+                       * ( C ( P "\r" )
+                       * ( 1 - P "\r" ) ^ (-n)
+                       * C ( ( 1 - P "\r" ) ^ 0 )
+                      ) ^ 0
+                   ) / table.concat ) : match ( code )
   end
 end
-local function add(acc,new_value)
-  return acc + new_value
+local function count_captures(...)
+    local acc = 0
+    for _ in ipairs({...}) do
+        acc = acc + 1
+    end
+    return acc
 end
 local AutoGobbleLPEG =
-    ( space ^ 0 * P "\r" ) ^ -1
-    * Cf (
-           (
-             ( P " " ) ^ 0 * P "\r"
-             +
-             Cf ( Cc(0) * ( P " " * Cc(1) ) ^ 0 , add )
-             * ( 1 - P " " ) * ( 1 - P "\r" ) ^ 0 * P "\r"
-           ) ^ 0
-           *
-           ( Cf ( Cc(0) * ( P " " * Cc(1) ) ^ 0 , add )
-           * ( 1 - P " " ) * ( 1 - P "\r" ) ^ 0 ) ^ -1 ,
-           math.min
-         )
+  (
+    (
+      P " " ^ 0 * P "\r"
+      +
+      C ( P " " ) ^ 0 / count_captures * ( 1 - P " " ) * ( 1 - P "\r" ) ^ 0 * P "\r"
+    ) ^ 0
+    *
+    ( C ( P " " ) ^ 0 / count_captures * ( 1 - P " " ) * ( 1 - P "\r" ) ^ 0 ) ^ -1
+  ) / math.min
 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
-         )
+  (
+    (
+      P "\t" ^ 0 * P "\r"
+      +
+      C ( P " " ) ^ 0 / count_captures * ( 1 - P "\t" ) * ( 1 - P "\r" ) ^ 0 * P "\r"
+    ) ^ 0
+    *
+    ( C ( P " " ) ^ 0 / count_captures * ( 1 - P "\t" ) * ( 1 - P "\r" ) ^ 0 ) ^ -1
+  ) / math.min
 local EnvGobbleLPEG =
-  ( ( 1 - P "\r" ) ^ 0 * P "\r" ) ^ 0
-    * Cf ( Cc(0) * ( P " " * Cc(1) ) ^ 0 , add ) * -1
+  ( ( 1 - P "\r" ) ^ 0 * P "\r" ) ^ 0 * ( C ( P " " )  ^ 0 / count_captures ) * -1
+local function remove_before_cr(input_string)
+    local match_result = P("\r") : match(input_string)
+    if match_result then
+        return string.sub(input_string, match_result )
+    else
+        return input_string
+    end
+end
 function piton.GobbleParse(language,n,code)
+  code = remove_before_cr(code)
   if n==-1
   then n = AutoGobbleLPEG : match(code)
   else if n==-2
@@ -1619,13 +1642,18 @@
             end
        end
   end
-  piton.Parse(language,gobble(n,code))
+  piton.last_code = gobble(n,code)
+  piton.Parse(language,piton.last_code)
+  piton.last_language = language
   if piton.write ~= ''
   then local file = assert(io.open(piton.write,piton.write_mode))
-       file:write(code)
+       file:write(piton.get_last_code())
        file:close()
   end
 end
+function piton.get_last_code ( )
+  return CleanLPEGs[piton.last_language] : match(piton.last_code)
+end
 function piton.CountLines(code)
   local count = 0
   for i in code : gmatch ( "\r" ) do count = count + 1 end
@@ -1636,14 +1664,12 @@
 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)
+              + ( 1 - P "\r" ) ^ 0 * C ( P "\r" )
+            ) ^ 0
+          * (1 - P "\r" ) ^ 0
+       ) / count_captures ) * -1 ) : match (code)
   tex.sprint(
       luatexbase.catcodetables.expl ,
       '\\int_set:Nn \\l__piton_nb_non_empty_lines_int {' .. count .. '}' )
@@ -1650,7 +1676,7 @@
 end
 function piton.CountLinesFile(name)
   local count = 0
-  io.open(name) -- added
+  io.open(name)
   for line in io.lines(name) do count = count + 1 end
   tex.sprint(
       luatexbase.catcodetables.expl ,

Modified: branches/branch2023.final/Master/texmf-dist/tex/lualatex/piton/piton.sty
===================================================================
--- branches/branch2023.final/Master/texmf-dist/tex/lualatex/piton/piton.sty	2024-02-27 20:48:03 UTC (rev 70204)
+++ branches/branch2023.final/Master/texmf-dist/tex/lualatex/piton/piton.sty	2024-02-27 20:48:14 UTC (rev 70205)
@@ -19,8 +19,8 @@
 %% LaTeX version 2005/12/01 or later.
 %% -------------------------------------------
 %% 
-\def\PitonFileVersion{2.5}
-\def\PitonFileDate{2024/02/20}
+\def\PitonFileVersion{2.6}
+\def\PitonFileDate{2024/02/27}
 
 
 \NeedsTeXFormat{LaTeX2e}
@@ -29,7 +29,7 @@
   {piton}
   {\PitonFileDate}
   {\PitonFileVersion}
-  {Highlight Python codes with LPEG on LuaLaTeX}
+  {Highlight informatic listings with LPEG on LuaLaTeX}
 \cs_new_protected:Npn \__piton_error:n { \msg_error:nn { piton } }
 \cs_new_protected:Npn \__piton_warning:n { \msg_warning:nn { piton } }
 \cs_new_protected:Npn \__piton_error:nn { \msg_error:nnn { piton } }
@@ -55,6 +55,7 @@
   }
 \sys_if_engine_luatex:F { \msg_critical:nn { piton } { LuaLaTeX~mandatory } }
 \RequirePackage { luatexbase }
+\RequirePackage { luacode }
 \__piton_msg_new:nnn { piton.lua~not~found }
   {
     The~file~'piton.lua'~can't~be~found.\\
@@ -161,9 +162,12 @@
   {
     piton = piton~or { }
     piton.ListCommands = lpeg.P ( false )
+    piton.last_code = ''
+    piton.last_language = ''
   }
 \str_new:N \l_piton_language_str
 \str_set:Nn \l_piton_language_str { python }
+\tl_new:N \g_piton_last_code_tl
 \str_new:N \l__piton_path_str
 \str_new:N \l__piton_path_write_str
 \bool_new:N \l__piton_in_PitonOptions_bool
@@ -239,14 +243,14 @@
   }
 \cs_new_protected:Npn \__piton_marker_beginning:n #1 { }
 \cs_new_protected:Npn \__piton_marker_end:n #1 { }
-\cs_new_protected:Npn \__piton_open_brace: { \directlua { piton.open_brace() } }
-\cs_new_protected:Npn \__piton_close_brace: { \directlua { piton.close_brace() } }
+\cs_new_protected:Npn \__piton_open_brace: { \lua_now:n { piton.open_brace() } }
+\cs_new_protected:Npn \__piton_close_brace: { \lua_now:n { piton.close_brace() } }
 \tl_new:N \g__piton_begin_line_hook_tl
 \cs_new_protected:Npn \__piton_prompt:
   {
     \tl_gset:Nn \g__piton_begin_line_hook_tl
       {
-        \tl_if_empty:NF \l__piton_prompt_bg_color_tl % added 2023-04-24
+        \tl_if_empty:NF \l__piton_prompt_bg_color_tl
           { \clist_set:NV \l__piton_bg_color_clist \l__piton_prompt_bg_color_tl }
       }
   }
@@ -485,7 +489,8 @@
   }
 \keys_define:nn { PitonOptions }
   {
-    detected-commands .code:n =  \__piton_detected_commands:n { #1 } ,
+    detected-commands .code:n =
+       \lua_now:n { piton.addListCommands('#1') } ,
     detected-commands .value_required:n = true ,
     detected-commands .usage:n = preamble ,
     begin-escape .code:n =
@@ -881,7 +886,7 @@
               { \lua_now:e { piton.write = "\l__piton_write_str" } }
               {
                 \lua_now:e
-                 { piton.write = "\l__piton_path_write_str / \l__piton_write_str" }
+                  { piton.write = "\l__piton_path_write_str / \l__piton_write_str" }
               }
             \str_if_empty:NF \l__piton_write_str
               {
@@ -1050,16 +1055,16 @@
   }
 \NewDocumentCommand { \SetPitonStyle } { O { } m }
   {
+    \str_clear_new:N \l__piton_SetPitonStyle_option_str
     \str_set:Nx \l__piton_SetPitonStyle_option_str { \str_lowercase:n { #1 } }
     \str_if_eq:onT \l__piton_SetPitonStyle_option_str { current-language }
       { \str_set_eq:NN \l__piton_SetPitonStyle_option_str \l_piton_language_str }
     \keys_set:nn { piton / Styles } { #2 }
-    \str_clear:N \l__piton_SetPitonStyle_option_str
   }
 \cs_new_protected:Npn \__piton_math_scantokens:n #1
   { \normalfont \scantextokens { \begin{math} #1 \end{math} } }
-\clist_new:N \g__piton_style_clist
-\clist_set:Nn \g__piton_styles_clist
+\clist_new:N \g__piton_styles_clist
+\clist_gset:Nn \g__piton_styles_clist
   {
     Comment ,
     Comment.LaTeX ,
@@ -1403,26 +1408,25 @@
   }
 \hook_gput_code:nnn { begindocument } { . }
   { \lua_now:e { require("piton.lua") } }
-\cs_new_protected:Npn \__piton_detected_commands:n #1
-  { \lua_now:n { piton.addListCommands('#1') } }
 \ExplSyntaxOff
-\directlua
-  {
+\begin{luacode*}
     lpeg.locale(lpeg)
-    local P , alpha , C , Cf, space
-      = lpeg.P , lpeg.alpha , lpeg.C , lpeg.Cf , lpeg.space
-    local S = lpeg.S
-    local One_P
-      = space ^ 0
-        * C ( alpha ^ 1 ) / ( function (s) return P ( string.char(92) .. s ) end )
-        * space ^ 0
+    local P , alpha , C , space , S , V
+      = lpeg.P , lpeg.alpha , lpeg.C , lpeg.space , lpeg.S , lpeg.V
+    local function add(...)
+          local s = P ( false )
+          for _ , x in ipairs({...}) do s = s + x end
+          return s
+          end
+    local my_lpeg =
+      P {  "E" ,
+           E = ( V "F" * ( P "," * V "F" ) ^ 0 ) / add ,
+           F = space ^ 0 * ( alpha ^ 1 ) / "\\%0" * space ^ 0
+        }
     function piton.addListCommands( key_value )
-       piton.ListCommands =
-         piton.ListCommands +
-           Cf ( One_P * ( P "," * One_P ) ^ 0  ,
-                ( function (s,t) return s + t end ) ) : match ( key_value )
+      piton.ListCommands = piton.ListCommands + my_lpeg : match ( key_value )
     end
-  }
+\end{luacode*}
 
 \endinput
 %%



More information about the tex-live-commits mailing list.