texlive[72351] Master/texmf-dist: piton (22sep24)

commits+karl at tug.org commits+karl at tug.org
Sun Sep 22 22:22:25 CEST 2024


Revision: 72351
          https://tug.org/svn/texlive?view=revision&revision=72351
Author:   karl
Date:     2024-09-22 22:22:25 +0200 (Sun, 22 Sep 2024)
Log Message:
-----------
piton (22sep24)

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

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

Modified: trunk/Master/texmf-dist/doc/lualatex/piton/piton-french.tex
===================================================================
--- trunk/Master/texmf-dist/doc/lualatex/piton/piton-french.tex	2024-09-22 20:22:16 UTC (rev 72350)
+++ trunk/Master/texmf-dist/doc/lualatex/piton/piton-french.tex	2024-09-22 20:22:25 UTC (rev 72351)
@@ -33,8 +33,6 @@
 \usepackage{booktabs}
 \usepackage{tcolorbox}
 \usepackage{luacolor,lua-ul}
-
-
 \usepackage{caption}
 
 % We use \MakeShortVerb of shortvrb and not \DefineShortVerb of fancyvrb
@@ -73,6 +71,8 @@
 \usepackage{makeidx}
 \makeindex
 
+\usepackage{underscore}
+
 \NewDocumentCommand{\Definition}{m}
   {{\setlength{\fboxsep}{1pt}\colorbox{gray!20}{\ttfamily \vphantom{gl}#1}}}
 
@@ -113,6 +113,9 @@
 \end{abstract}
 
 
+\bigskip
+{\color{red} Dans la version 4.0, la syntaxe des chemins absolus et relatifs utilisés dans
+|\PitonInputFile| a été changée : cf.~partie~\ref{PitonInputFile}, p.~\pageref{PitonInputFile}.}
 
 \section{Présentation}
 
@@ -127,11 +130,11 @@
 la clé |write| est utilisée). La compilation est très rapide puisque tout le travail du
 parseur est fait par la librairie LPEG, écrite en C.
 
-\bigskip
+\medskip
 Voici un exemple de code Python composé avec l'environnement |{Piton}| proposé par \pkg{piton}.
 
 
-\bigskip
+\medskip
 \begin{Piton}
 from math import pi
 
@@ -152,16 +155,17 @@
         return s 
 \end{Piton}
 
-\bigskip
+\medskip
 Les principaux concurrents de l'extension \pkg{piton} sont certainement les extensions
 bien connues \pkg{listings} et \pkg{minted}.
 
-\bigskip
-Le nom de cette extension (\pkg{piton}) a été choisi un peu arbitrairement en référence
-aux pitons d'alpinisme qui servent à gravir les montagnes.
 
+% \medskip
+% Le nom de cette extension (\pkg{piton}) a été choisi un peu arbitrairement en référence
+% aux pitons d'alpinisme qui servent à gravir les montagnes.
 
 
+
 \section{Installation}
 
 L'extension \pkg{piton} est composée de deux fichiers : |piton.sty| et |piton.lua| (le
@@ -197,7 +201,7 @@
 
 \smallskip
 \index{language (clé)}
-On peut changer de langage avec la clé |language| de |\PitonOptions| : 
+On peut changer de langage avec la clé \Definition{language} de |\PitonOptions| : 
 
 \smallskip
 |\PitonOptions{language = OCaml}|
@@ -211,8 +215,8 @@
 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.
+Dans la suite de ce document, on parlera préférentiellement de Python mais les
+fonctionnalités s'appliquent aussi aux autres langages.
 
 
 
@@ -231,7 +235,7 @@
 
 \indexenv{Piton}
 
-L'extension \pkg{piton} fournit plusieurs outils pour composer du code Python: les
+L'extension \pkg{piton} fournit plusieurs outils pour composer du code informatique : les
 commandes |\piton|, l'environnement |{Piton}| et la commande |\PitonInputFile|.
 
 \begin{itemize} \setlength{\fboxsep}{1pt}
@@ -249,24 +253,11 @@
 un mode verbatim, il ne peut pas être utilisé dans l'argument d'une commande LaTeX. Pour
 les besoins de personnalisation, il est possible de définir de nouveaux environnements
 similaires à |{Piton}| en utilisant la commande \DefinitionCommand{NewPitonEnvironment} :
-cf. partie \ref{NewPitonEnvironment} p.~\pageref{NewPitonEnvironment}.
+cf.~partie~\ref{NewPitonEnvironment} p.~\pageref{NewPitonEnvironment}.
 
-\item La commande \colorbox{gray!20}{\ttfamily \textbackslash PitonInputFile} doit être
-utilisée pour insérer et composer un fichier externe.
-
-Il est possible de n'insérer qu'une partie de ce fichier : cf. partie~\ref{part-of-a-file},
-p.~\pageref{part-of-a-file}.
-
-La clé \Definition{path} de la commande |\PitonOptions| permet de spécifier une
-\emph{liste} de chemins où sera recherché le fichier à inclure (dans cette liste, les
-chemins sont séparés par des virgules).
-
-L'extension \pkg{piton} propose aussi des commandes
-\colorbox{gray!20}{\ttfamily\textbackslash PitonInputFileT}, \colorbox{gray!20}{\ttfamily
-  \textbackslash PitonInputFileF} et \colorbox{gray!20}{\ttfamily \textbackslash
-  PitonInputFileTF} avec des arguments correspondant aux lettres |T| et |F|, arguments qui
-seront executés dans le cas où le fichier a été trouvé (lettre |T|) ou pas (lettre |F|).
-
+\item La commande \DefinitionCommand{PitonInputFile} doit être utilisée pour insérer et
+composer un fichier externe : cf.~partie~\ref{PitonInputFile},
+p.~\pageref{PitonInputFile}.
 \end{itemize}
 
 
@@ -285,7 +276,7 @@
 \begin{itemize}
 \item {\color{blue} \textsf{Syntaxe} \verb|\piton{...}|}\par\nobreak
 
-Quand son argument est donné entre accolades, la commande |\piton| ne prend pas son
+Quand son argument est donné entre accolades, la commande |\piton| ne prend \emph{pas} son
 argument en mode verbatim. Les points suivants doivent être remarqués :
 
 \begin{itemize}
@@ -303,9 +294,9 @@
 {\color{cyan} mais les commandes |\{| et |\}| sont aussi fournies pour insérer des
   accolades individuelles} ;
 
-\item les commandes LaTeX\footnote{Cela s'applique aux commandes commençant par une contre-oblique |\| mais
-  également aux caractères actifs, c'est-à-dire ceux de catcode~13.} sont complètement développées sans être
-exécutées
+\item les commandes LaTeX\footnote{Cela s'applique aux commandes commençant par une
+  contre-oblique |\| mais également aux caractères actifs, c'est-à-dire ceux de
+  catcode~13.} sont complètement développées sans être exécutées
 
 {\color{cyan} et on peut donc utiliser |\\| pour insérer une contre-oblique}.
 \end{itemize}
@@ -334,6 +325,10 @@
 arguments des autres commandes LaTeX.\footnote{La commande |\piton| peut par exemple être
   utilisée dans une note de bas de page. Exemple : \piton{s = 'Une chaîne'}.}
 
+En revanche, comme son argument subit un développement (au sens de TeX), il faut prendre 
+soin à ne pas utiliser dans son argument de commandes fragiles (c'est-à-dire des commandes
+qui ne sont ni \emph{protected} ni \emph{fully expandable}).
+
 \bigskip
 \item {\color{blue} \textsf{Syntaxe} \verb!\piton|...|!}\par\nobreak
 
@@ -361,10 +356,6 @@
 
 \section{Personnalisation}
 
-Concernant la fonte de caractères utilisée dans les listings produits par l'extension
-\pkg{piton}, il s'agit simplement de la fonte mono-chasse courante (\pkg{piton} utilise
-simplement en interne la commande LaTeX standard |\ttfamily|). Pour la changer, le mieux
-est d'utiliser |\setmonofont| de \pkg{fontspec}.
 
 \subsection{Les clés de la commande \textbackslash PitonOptions}
 
@@ -386,9 +377,16 @@
 
 La valeur initiale est |Python|.
 
-\item \index{path} La clé \Definition{path} indique un chemin où seront cherchés les fichiers inclus par
-|\PitonInputFile|. 
+\item \index{font-command}
+\colorbox{yellow!50}{\textbf{Nouveau 4.0}}\par\nobreak
 
+La clé \Definition{font-command} contient des instructions de fonte qui seront
+insérées au début de chaque élément formaté par \pkg{piton}, que ce soit avec la commande
+|\piton|, l'environnement |{Piton}| ou bien la commande |\PitonInputFile|.
+
+La valeur initiale de ce paramètre |font-command| est |\ttfamily|, ce qui fait, que, par
+défaut, \pkg{piton} utilise la fonte mono-chasse courante.
+
 \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
@@ -455,10 +453,9 @@
 de lignes (insérés par |line-numbers|) et les lignes du code informatique. La valeur
 initiale est 0.7~em.
 
-\item \colorbox{yellow!50}{\bfseries Nouveau 3.1}\enskip 
-La clé \Definition{line-numbers/format} est une liste de tokens qui est insérée avant le
-numéro de ligne pour le formater. Il est possible de mettre \emph{en dernière position} de
-cette liste une commande LaTeX à un argument comme |\fbox|. 
+\item La clé \Definition{line-numbers/format} est une liste de tokens qui est insérée
+avant le numéro de ligne pour le formater. Il est possible de mettre \emph{en dernière
+  position} de cette liste une commande LaTeX à un argument comme |\fbox|.
 
 La valeur initiale est |\footnotesize \color{gray}|.
 \end{itemize}
@@ -502,11 +499,6 @@
 
 \emph{Exemple} : |\PitonOptions{background-color = {gray!5,white}}|
 
-\smallskip
-Si la clé |split-on-empty-lines| est utilisée (voir la partie «Coupure de pages»,
-p.~\pageref{coupure-de-pages}), les lignes de séparation entre morceaux de code générés
-par cette clé n'ont pas de fond coloré (au moins avec la valeur initiale du paramètre
-|split-separation|).
 
 \item \index{prompt-background-color} Avec la clé \Definition{prompt-background-color},
 \pkg{piton} ajoute un fond coloré aux lignes débutant par le prompt «|>>>|» (et sa
@@ -575,7 +567,7 @@
             if (!swapped) break;
         }
     }   
-\end{Piton}
+~emphase&\end{Piton}@
 \end{Verbatim}
 \endgroup
 
@@ -607,6 +599,7 @@
 particulier la coupure des pages et des lignes p.~\pageref{breakable}).
 
 
+
 \subsection{Les styles}
 
 \label{styles}
@@ -637,17 +630,17 @@
 
 \begin{Verbatim}
 \SetPitonStyle
-  { Name.Function = \bfseries \hightLight[red!50] }
+  { Name.Function = \bfseries \hightLight[red!30] }
 \end{Verbatim}
 
-Ici, |\highLight[red!50]| doit être considéré comme le nom d'une fonction LaTeX qui prend
+Ici, |\highLight[red!30]| doit être considéré comme le nom d'une fonction LaTeX qui prend
 exactement un argument, puisque, habituellement, elle est utilisée avec
-|\highLight[red!50]{|\texttt{\slshape text}|}|.
+|\highLight[red!30]{|\texttt{\slshape text}|}|.
 
 \medskip
 \begingroup
 \SetPitonStyle 
-  { Name.Function = \bfseries \highLight[red!50] }
+  { Name.Function = \bfseries \highLight[red!30] }
 Avec ce réglage, on obtient : \piton{def cube(x) : return x * x * x }
 \endgroup
 
@@ -800,10 +793,10 @@
 environnements directement au-dessus de l'environnement |{Piton}| avec les commandes
 classiques |\newenvironment| (de LaTeX standard) et |\NewDocumentEnvironment| (de LaTeX3).
 
-C'est pourquoi \pkg{piton} propose une commande |\NewPitonEnvironment|. Cette commande a
-la même syntaxe que la 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é.}
+C'est pourquoi \pkg{piton} propose une commande \DefinitionCommand{NewPitonEnvironment}.
+Cette commande a la même syntaxe que la 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
@@ -849,8 +842,6 @@
 \label{NewPitonLanguage}
 \index{listings@\pkg{listings} (extension)}
 
-\colorbox{yellow!50}{\textbf{Nouveau 3.0}}
-
 \medskip
 L'extension \pkg{listings} est une célèbre extension LaTeX pour formater des codes informatiques.  
 
@@ -867,7 +858,7 @@
 
 \medskip
 Précisons tout de suite que l'extension \pkg{piton} n'utilise \emph{pas} cette commande
-pour définir les langages qu'elle propose nativement (Python, C, OCaml, \CC\ et
+pour définir les langages qu'elle propose nativement (Python, C, OCaml, SQL et
 |minimal|), ce qui permet de proposer des parseurs plus puissants.
 
 \medskip
@@ -941,7 +932,7 @@
 \bigskip
 \begingroup
 \small
-\PitonOptions{split-on-empty-lines}
+\PitonOptions{splittable-on-empty-lines}
 \begin{Piton}[language = Java]
 public class Cipher { // cryptage par le chiffre de César
     public static void main(String[] args) {
@@ -991,161 +982,67 @@
 \begin{verbatim}
 \NewPitonLanguage{LaTeX}{keywordsprefix = \ , alsoletter = @_ }
 \end{verbatim}
-} Initialement, les caractères |@| et |_| sont des considérés comme des lettres car de
-nombreux langages de programmation les autorisent dans les mots-clés et les
-identificateurs. Avec \verb|alsoletter = @_|, on les retire de la catégorie des lettres.
+} 
 
+Initialement, les caractères |@| et |_| sont considérés comme des lettres car de nombreux
+langages de programmation les autorisent dans les mots-clés et les identificateurs. Avec
+\verb|alsoletter = @_|, on les retire de la catégorie des lettres.
 
+
 \section{Fonctionnalités avancées}
 
 
-\subsection{Coupure des pages et des lignes}
+\subsection{Insertion d'un fichier}
 
-\label{breakable}
+\label{PitonInputFile}
 
-\subsubsection{Coupure des pages}
+\subsubsection{La commande \textbackslash PitonInputFile}
 
-\label{coupure-de-pages}
+\indexcommand{PitonInputFile}
 
-\index{splittable}
-\index{split-on-empty-lines}
-\index{split-separation}
+La commande \DefinitionCommand{PitonInputFile} permet d'insérer tout ou partie d'un
+fichier extérieur dont le nom est passé en argument. Il existe aussi des commandes
+\DefinitionCommand{PitonInputFileT}, \DefinitionCommand{PitonInputFileF} et
+\DefinitionCommand{PitonInputFileTF} avec des arguments correspondant aux lettres |T| et
+|F|, arguments qui seront exécutés dans le cas où le fichier a été trouvé (lettre |T|) ou
+pas (lettre |F|).
 
-Par défaut, les listings produits par l'environnement |{Piton}| et par la commande
-|\PitonInputFile| sont insécables.
 
+\bigskip
+\colorbox{yellow!50}{\textbf{Modification 4.0}}\par\nobreak
 
-Néanmoins, la commande |\PitonOptions| propose les clés |split-on-empty-lines| et
-|splittable| pour autoriser de telles coupures.
+\smallskip
+\index{old-PitonInputFile}
+La syntaxe pour les chemins absolus et relatifs a été changée pour être conforme aux
+usages traditionnels. Il est toutefois possible d'utiliser la clé
+\Definition{old-PitonInputFile} au chargement de l'extension (c'est-à-dire avec le
+|\usepackage|) pour avoir l'ancien comportement de |\PitonInputFile| (néanmoins, cette clé
+sera supprimée dans une prochaine version de \pkg{piton} !).
 
+\smallskip
+La syntaxe est maintenant la suivante : 
 \begin{itemize}
-\item La clé \Definition{split-on-empty-lines} autorise les coupures sur les lignes
-vides\footnote{Les lignes considérées comme vides sont celles qui ne comportent que des
-  espaces.} du listing. Dans les listings informatiques, les lignes vides séparent le plus
-souvent les définitions des fonctions informatiques et il est donc souvent judicieux de
-pouvoir couper au niveau de ces lignes.
+\item Les chemins commençant par |/| sont des chemins absolus.
 
-Quand la clé |split-on-empty-lines| est activée, le travail effectué va en fait un peu
-plus loin : les lignes vides successives sont supprimées et remplacées par le contenu du
-paramètre correspondant à la clé \Definition{split-separation} 
-\begin{itemize}
-\item Ce paramètre doit contenir du matériel à insérer en \emph{mode vertical} de TeX. On
-peut, par exemple, mettre |\hrule|.
+\emph{Exemple} : |\PitonInputFile{/Users/joe/Documents/programme.py}|
 
-\item La valeur initiale de ce paramètre est |\vspace{\baselineskip}\vspace{-1.25pt}|, ce qui,
-au final, correspond à une ligne vide dans le PDF produit (cet espace vertical est
-supprimé s'il tombe au niveau d'un saut de page). Si la clé |background-color| est
-utilisée, aucun fond n'est affiché au niveau de cette ligne de séparation.
-\end{itemize}
+\item Les chemins ne commençant pas par |/| sont relatifs au répertoire courant.
 
-\medskip
-\item La clé |split-on-empty-lines| peut bien sûr être insuffisante et c'est pourquoi
-\pkg{piton} propose la clé \Definition{splittable}.
-
-Quand la clé |splittable| est utilisée avec la valeur numérique $n$ (qui doit être un
-entier naturel non nul) le listing, ou bien chaque partie de ce listing située entre des
-lignes vides (quand |split-on-empty-lines| est utilisée), pourra être coupé n'importe où
-avec cette exception qu'aucune coupure ne pourra avoir lieu entre les $n$~premières
-lignes, ni entre les $n$~dernières. Par exemple, |splittable = 4| pourrait être un réglage
-raisonnable.
-
-Employée sans argument, la clé |splittable| est équivalente à |splittable = 1|, et les
-listings sont alors sécables n'importe où (ce n'est pas recommandable).
-
-La valeur initiale de la clé |splittable| vaut 100, ce qui fait que listings ne sont pas
-sécables. 
+\emph{Exemple} : |\PitonInputFile{les_listings/programme.py}|
 \end{itemize}
 
-\medskip
-\emph{Remarque}\par\nobreak
 
-Même avec une couleur de fond (fixée avec |background-color|), les sauts de page sont
-possibles, à partir du moment où |split-on-empty-lines| ou |splittable| est
-utilisée.\footnote{Avec la clé |splittable|, un environnement |{Piton}| est sécable même
-  dans un environnement de \pkg{tcolorbox} (à partir du moment où la clé |breakable| de
-  \pkg{tcolorbox} est utilisée). On précise cela parce que, en revanche, un environnement
-  de \pkg{tcolorbox} inclus dans un autre environnement de \pkg{tcolorbox} n'est pas
-  sécable, même quand les deux utilisent la clé |breakable|.}
+\index{path}
+La clé \Definition{path} de la commande |\PitonOptions| permet de spécifier une
+\emph{liste} de chemins où sera recherché le fichier à inclure (dans cette liste, les
+chemins sont séparés par des virgules). Comme précédemment, les chemins absolus doivent
+débuter par une oblique~|/|.
 
 
-\subsubsection{Coupure des lignes}
+\subsubsection{Insertion d'une partie d'un fichier}
 
-\label{line-breaks}
-
-Par défaut, les éléments produits par \pkg{piton} ne peuvent pas être coupés par une fin
-de ligne. Il existe néanmoins des clés pour autoriser de telles coupures (les points de
-coupure possibles sont les espaces, y compris les espaces dans les chaînes Python).
-\begin{itemize}
-\item \index{break-lines!break-lines-in-piton} Avec la clé
-\Definition{break-lines-in-piton}, les coupures de ligne sont autorisées dans la commande
-|\piton{...}| (mais pas dans la commande \verb+\piton|...|+, c'est-à-dire avec la syntaxe
-verbatim).
-
-\item \index{break-lines!break-lines-in-Piton} Avec la clé
-\Definition{break-lines-in-Piton}, les coupures de ligne sont autorisées dans
-l'environnement |{Piton}| (d'où la lettre |P| capitale dans le nom) et les listings
-produits par |\PitonInputFile|.
-
-\item \index{break-lines} La clé \Definition{break-lines} est la conjonction des deux clés
-précédentes.
-\end{itemize}
-
-\medskip
-L'extension \pkg{piton} fournit aussi plusieurs clés pour contrôler l'apparence des
-coupures de ligne autorisées par |break-lines-in-Piton|.
-
-\begin{itemize}
-\item \index{indent-broken-lines} Avec la clé \Definition{indent-broken-lines},
-l'indentation de la ligne coupée est respectée à chaque retour à la ligne.
-
-\item \index{end-of-broken-line} La clé \Definition{end-of-broken-line} correspond au
-symbole placé à la fin d'une ligne coupée. Sa valeur initiale est :
-|\hspace*{0.5em}\textbackslash|.
-
-\item \index{continuation-symbol} La clé \Definition{continuation-symbol} correspond au
-symbole placé à chaque retour de ligne dans la marge gauche. Sa valeur initiale est :
-|+\;| (la commande |\;| insère un petit espace horizontal).
-
-\item \index{continuation-symbol-on-indentation} La clé
-\Definition{continuation-symbol-on-indentation} correspond au symbole placé à chaque
-retour de ligne au niveau de l'indentation (uniquement dans le cas où la clé
-|indent-broken-lines| est active). Sa valeur initiale est : |$\hookrightarrow\;$|.
-\end{itemize}
-
-\bigskip
-Le code suivant a été composé avec le réglage suivant :  
-
-\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_liste(liste):
-    """Convertit une liste de subrs et de descriptions de glyphes en dictionnaire"""
-    dict = {}
-    for liste_lettre in liste:
-        if (liste_lettre[0][0:3] == 'dup'): # si c'est un subr
-            nom = liste_lettre[0][4:-3]
-            print("On traite le subr de numéro " + nom)
-        else:
-            nom = liste_lettre[0][1:-3] # si c'est un glyphe
-            print("On traite le glyphe du caractère " + nom)
-        dict[nom] = [traite_ligne_Postscript(k) for k in liste_lettre[1:-1]]
-    return dict
-\end{Piton}
-\end{center}
-
-
-\bigskip
-\subsection{Insertion d'une partie d'un fichier}
-
 \label{part-of-a-file}
 
-\indexcommand{PitonInputFile}
-
-La commande |\PitonInputFile| permet d'insérer (avec formatage) le contenu d'un fichier.
 En fait, il existe des mécanismes permettant de n'insérer qu'une partie du fichier en
 question.
 \begin{itemize}
@@ -1156,18 +1053,19 @@
 Dans les deux cas, si on souhaite numéroter les lignes avec les numéros des lignes du
 fichier d'origine, il convient d'utiliser la clé |line-numbers/absolute|.
 
-\subsubsection{Avec les numéros de lignes absolus}
+\bigskip
+\textbf{Avec les numéros de lignes absolus}\par\nobreak
 
 La commande |\PitonInputFile| propose les clés \Definition{first-line} et
-\Definition{last-line} pour n'insérer que la partie du fichier comprise entre les lignes
-correspondantes. Ne pas confondre avec la clé |line-numbers/start| qui demande un
-numérotage des lignes commençant à la valeur donnée à cette clé (en un sens
+\Definition{last-line} qui permettent de n'insérer que la partie du fichier comprise entre
+les lignes correspondantes. Ne pas confondre avec la clé |line-numbers/start| qui demande
+un numérotage des lignes commençant à la valeur donnée à cette clé (en un sens
 |line-numbers/start| concerne la sortie alors que |first-line| et |last-line| concernent
 l'entrée).
 
+\bigskip
+\textbf{Avec des marqueurs textuels}\par\nobreak
 
-\subsubsection{Avec des marqueurs textuels}
-
 \index{marker/beginning}
 \index{marker/end}
 
@@ -1278,6 +1176,217 @@
 
 
 
+\subsection{Coupure des pages et des lignes}
+
+\label{breakable}
+
+\subsubsection{Coupure des lignes}
+
+\label{line-breaks}
+
+Par défaut, les éléments produits par \pkg{piton} ne peuvent pas être coupés par une fin
+de ligne. Il existe néanmoins des clés pour autoriser de telles coupures (les points de
+coupure possibles sont les espaces, y compris les espaces dans les chaînes Python).
+\begin{itemize}
+\item \index{break-lines!break-lines-in-piton} Avec la clé
+\Definition{break-lines-in-piton}, les coupures de ligne sont autorisées dans la commande
+|\piton{...}| (mais pas dans la commande \verb+\piton|...|+, c'est-à-dire avec la syntaxe
+verbatim).
+
+\item \index{break-lines!break-lines-in-Piton} Avec la clé
+\Definition{break-lines-in-Piton}, les coupures de ligne sont autorisées dans
+l'environnement |{Piton}| (d'où la lettre |P| capitale dans le nom) et les listings
+produits par |\PitonInputFile|.
+
+\item \index{break-lines} La clé \Definition{break-lines} est la conjonction des deux clés
+précédentes.
+\end{itemize}
+
+\medskip
+L'extension \pkg{piton} fournit aussi plusieurs clés pour contrôler l'apparence des
+coupures de ligne autorisées par |break-lines-in-Piton|.
+
+\begin{itemize}
+\item \index{indent-broken-lines} Avec la clé \Definition{indent-broken-lines},
+l'indentation de la ligne coupée est respectée à chaque retour à la ligne (à condition que
+la fonte utilisée soit une fonte mono-chasse, ce qui est le cas par défaut puisque la
+valeur initiale de |font-command| est |\ttfamily|).
+
+\item \index{end-of-broken-line} La clé \Definition{end-of-broken-line} correspond au
+symbole placé à la fin d'une ligne coupée. Sa valeur initiale est :
+|\hspace*{0.5em}\textbackslash|.
+
+\item \index{continuation-symbol} La clé \Definition{continuation-symbol} correspond au
+symbole placé à chaque retour de ligne dans la marge gauche. Sa valeur initiale est :
+|+\;| (la commande |\;| insère un petit espace horizontal).
+
+\item \index{continuation-symbol-on-indentation} La clé
+\Definition{continuation-symbol-on-indentation} correspond au symbole placé à chaque
+retour de ligne au niveau de l'indentation (uniquement dans le cas où la clé
+|indent-broken-lines| est active). Sa valeur initiale est : |$\hookrightarrow\;$|.
+\end{itemize}
+
+\bigskip
+Le code suivant a été composé avec le réglage suivant :  
+
+\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_liste(liste):
+    """Convertit une liste de subrs et de descriptions de glyphes en dictionnaire"""
+    dict = {}
+    for liste_lettre in liste:
+        if (liste_lettre[0][0:3] == 'dup'): # si c'est un subr
+            nom = liste_lettre[0][4:-3]
+            print("On traite le subr de numéro " + nom)
+        else:
+            nom = liste_lettre[0][1:-3] # si c'est un glyphe
+            print("On traite le glyphe du caractère " + nom)
+        dict[nom] = [traite_ligne_Postscript(k) for k in liste_lettre[1:-1]]
+    return dict
+\end{Piton}
+\end{center}
+
+
+
+\subsubsection{Coupure des pages}
+
+\label{coupure-de-pages}
+\index{splittable}
+\index{splittable-on-empty-lines}
+
+
+Par défaut, les listings produits par l'environnement |{Piton}| et par la commande
+|\PitonInputFile| sont insécables.
+
+
+Néanmoins, \pkg{piton} propose les clés |splittable-on-empty-lines| et |splittable| pour
+autoriser de telles coupures.
+
+\begin{itemize}
+\item La clé \Definition{splittable-on-empty-lines} autorise les coupures sur les lignes
+vides du listing. Les lignes considérées comme vides sont celles qui ne comportent que des
+espaces (et il aurait peut-être été plus habile de parler de lignes blanches). 
+
+\medskip
+\item La clé |splittable-on-empty-lines| peut bien sûr être insuffisante et c'est pourquoi
+\pkg{piton} propose la clé \Definition{splittable}.
+
+Quand la clé |splittable| est utilisée avec la valeur numérique $n$ (qui doit être un
+entier naturel non nul) le listing pourra être coupé n'importe où avec cette exception
+qu'aucune coupure ne pourra avoir lieu entre les $n$~premières lignes, ni entre les
+$n$~dernières.\footnote{Remarquer que l'on parle des lignes du listing d'origine, une
+  telle ligne pouvant être composée sur plusieurs lignes dans le \textsc{pdf} final si la
+  clé |break-lines-in-Piton| est utilisée.}
+
+Par exemple, |splittable = 4| pourrait être un réglage raisonnable.
+
+Employée sans argument, la clé |splittable| est équivalente à |splittable = 1|, et les
+listings sont alors sécables n'importe où (ce n'est pas recommandable).
+
+La valeur initiale de la clé |splittable| vaut 100, ce qui fait que les listings ne sont
+pas sécables. 
+\end{itemize}
+
+\medskip
+\emph{Remarque}\par\nobreak
+
+Même avec une couleur de fond (fixée avec |background-color|), les sauts de page sont
+possibles, à partir du moment où |splittable-on-empty-lines| ou |splittable| est
+utilisée.\footnote{Avec la clé |splittable|, un environnement |{Piton}| est sécable même
+  dans un environnement de \pkg{tcolorbox} (à partir du moment où la clé |breakable| de
+  \pkg{tcolorbox} est utilisée). On précise cela parce que, en revanche, un environnement
+  de \pkg{tcolorbox} inclus dans un autre environnement de \pkg{tcolorbox} n'est pas
+  sécable, même quand les deux utilisent la clé |breakable|.}
+
+\bigskip
+\subsection{Découpe d'un listing en sous-listings}
+
+\index{split-on-empty-lines}
+\label{split-on-empty-lines}
+\index{split-separation}
+\index{env-used-by-split}
+
+L'exension \pkg{piton} fournit la clé \Definition{split-on-empty-lines}, qui ne doit pas
+être confondue avec la clé |splittable-on-empty-lines| définie précédemment. 
+
+\smallskip
+Pour comprendre le fonctionnement de la clé |split-on-empty-lines|, il faut imaginer que
+l'on a à composer un fichier informatique qui contient une succession de définitions de
+fonctions informatiques. Dans la plupart des langages informatiques, ces définitions
+successives sont séparées par des lignes vides (ou plutôt des lignes blanches,
+c'est-à-dire des lignes qui ne contiennent que des espaces). 
+
+\smallskip
+La clé |split-on-empty-lines| coupe le listing au niveau des lignes vides. Les lignes
+vides successives sont supprimées et remplacées par le contenu du paramètre correspondant
+à la clé \Definition{split-separation}.
+\begin{itemize}
+\item Ce paramètre doit contenir du matériel à insérer en \emph{mode vertical} de TeX. On
+peut, par exemple, mettre la primmitive TeX |\hrule|.
+
+\item La valeur initiale de ce paramètre est |\vspace{\baselineskip}\vspace{-1.25pt}|, ce qui,
+au final, correspond à une ligne vide dans le \textsc{pdf} produit (cet espace vertical
+est supprimé s'il tombe au niveau d'un saut de page). 
+\end{itemize}
+
+
+\colorbox{yellow!50}{\textbf{Nouveau 4.0}}\par\nobreak
+
+Chaque morceau du code informatique est formaté (de manière autonome) dans un
+environnement dont le nom est donné par la clé \Definition{env-used-by-split}. La valeur
+initiale de ce paramètre est, sans surprise, |Piton| et les différents morceaux sont donc
+composés dans des environnements |{Piton}|. Si on décide de donner une autre valeur à la
+clé |env-used-by-split|, on doit bien sûr donner le nom d'un environnement créé par
+|\NewPitonEnvironment| (cf.~partie~\ref{NewPitonEnvironment},
+p.~\pageref{NewPitonEnvironment}).
+
+\smallskip
+Chaque morceau du listing de départ étant composé dans son environnement, il dispose de sa
+propre numérotation des lignes (si la clé |line-numbers| est active) et de son propre fond
+coloré (si la clé |background-color| est utilisée), séparé des fonds des autres morceaux.
+Si elle est active, la clé |splittable| s'applique de manière autonome dans chaque
+morceau. Bien sûr, des sauts de page peuvent intervenir entre les différents morceaux du
+code, quelle que soit la valeur de la clé |splittable|.
+
+\bigskip
+\begin{Verbatim}
+\begin{Piton}[~emphase#split-on-empty-lines@,background-color=gray!15,line-numbers]
+def carré(x):
+    """Calcule le carré de x"""
+    return x*x
+
+def cube(x):
+    """Calcule le cube de x"""
+    return x*x*x
+\end{Piton}
+\end{Verbatim}
+
+
+\begin{Piton}[split-on-empty-lines,background-color=gray!15,line-numbers]
+def carré(x):
+    """Calcule le carré de x"""
+    return x*x
+
+def cube(x):
+    """Calcule le cube de x"""
+    return x*x*x
+\end{Piton}
+
+
+\bigskip
+\textbf{Attention} : Comme chaque morceau est traité de manière indépendante, les
+commandes spécifiées par |detected-commands| et les commandes et environnements de Beamer
+automatiquement détectés par \pkg{piton} ne doivent pas enjamber les lignes vides du
+listing de départ. 
+
+
+\bigskip
 \subsection{Mise en évidence d'identificateurs}
 
 \indexcommand{SetPitonIdentifier}
@@ -1509,9 +1618,10 @@
 
 \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-ul} (cette
-extension requiert elle-même l'extension \pkg{luacolor}) permet de le faire avec la
-syntaxe |\hightLight{...}|.
+de surligner en jaune l'appel récursif. La commande |\highLight| de
+\pkg{lua-ul}\footnote{L'extension \pkg{lua-ul} requiert elle-même l'extension
+  \pkg{luacolor}.} permet de le faire facilement avec la
+syntaxe |\highLight{...}|.
 
 \smallskip
 On suppose que l'on a mis dans le préambule du document LaTeX l'instruction suivante :
@@ -1724,9 +1834,9 @@
 |#> \pause|. Ainsi, si le code Python est copié, il est   interprétable par Python.} ;  
 \item un argument obligatoire : |\action|, |\alert|, |\invisible|, |\only|, |\uncover| et
 |\visible| ; \newline 
-\colorbox{yellow!50}{\bfseries Nouveau 3.1} on peut rajouter à cette liste de
-nouveaux noms de commandes avec la clé \Definition{detected-beamer-commands} (les noms de
-commandes ne doivent \emph{pas} être précédés de la contre-oblique) ;
+La clé \Definition{detected-beamer-commands} permet de rajouter à cette liste de nouveaux
+noms de commandes (les noms de commandes ne doivent \emph{pas} être précédés de la
+contre-oblique) ;  
 \item deux arguments obligatoires : |\alt| ;
 \item trois arguments obligatoires : |\temporal|.
 \end{itemize}
@@ -1779,8 +1889,8 @@
 |{visibleenv}|.
 
 \smallskip
-\index{detected-beamer-environments} \colorbox{yellow!50}{\bfseries Nouveau 3.1}\enskip On
-peut ajouter de nouveaux environnements à cette liste d'environnements reconnus avec la
+\index{detected-beamer-environments} 
+On peut ajouter de nouveaux environnements à cette liste d'environnements reconnus avec la
 clé \Definition{detected-beamer-environments}.
 
 \medskip
@@ -1850,11 +1960,7 @@
 |{alertenv}|).
 
 
-
 \bigskip
-
-
-\bigskip
 \subsection{Notes de pied de page dans les environnements de piton}
 
 \index{footnote@\pkg{footnote} (extension)}
@@ -1900,12 +2006,12 @@
 \bigskip
 Par défaut, une commande |\footnote| ne peut apparaître que dans un «commentaire LaTeX».
 Mais on peut aussi ajouter la commande |\footnote| à la liste des
-``\emph{detected-commands}'' (cf.~partie~\ref{detected-commands},
+\emph{detected-commands} (cf.~partie~\ref{detected-commands},
 p.~\pageref{detected-commands}). 
 
 \medskip
 Dans ce document, l'extension \pkg{piton} a été chargée avec l'option |footnotehyper| et
-on rajouté la commande |\footnote| aux ``\emph{detected-commands}'' avec le code suivant
+on rajouté la commande |\footnote| aux \emph{detected-commands} avec le code suivant
 dans la préambule du document LaTeX :
 
 \qquad \verb|\PitonOptions{detected-commands = footnote}|
@@ -1944,7 +2050,7 @@
 
 Si on utilise l'environnement |{Piton}| dans un environnement |{minipage}| de LaTeX, les
 notes sont, bien entendu, composées au bas de l'environnement |{minipage}|. Rappelons
-qu'une telle |{minipage}| ne peut être coupée par un saut de page.
+qu'une telle |{minipage}| ne peut \emph{pas} être coupée par un saut de page.
 
 
 \begingroup
@@ -1988,7 +2094,8 @@
 \index{tab-size}
 
 \smallskip
-Même s'il est recommandé d'indenter les listings Python avec des espaces (cf. PEP~8),
+Même s'il est sans doute recommandable d'indenter les listings informatiques avec des
+espaces et non des tabulations\footnote{Voir, par exemple, pour le langage Piton, la note PEP~8},
 \pkg{piton} accepte les caractères de tabulations (U+0009) en début de ligne. Chaque
 caractère U+0009 est remplacé par $n$ espaces. La valeur initiale de~$n$ est~4 mais on
 peut la changer avec la clé \Definition{tab-size} de |\PitonOptions|.
@@ -2010,14 +2117,13 @@
 \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).
+La variable L3 \DefinitionCommand{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 fonction Lua |piton.get_last_code| sans argument
-permettant de récupérer le code contenu dans le dernier environnement de \pkg{piton}.
+L'extension \pkg{piton} fournit une fonction Lua \Definition{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).
@@ -2040,7 +2146,6 @@
 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}
@@ -2187,10 +2292,7 @@
 Les styles graphiques ont été présentés à la partie \ref{styles}, p.~\pageref{styles}.
 
 \smallskip
-On présente ici un réglage de ces styles adapté pour les documents en noir et blanc. On
-l'utilise avec la fonte \emph{DejaVu Sans Mono}\footnote{Voir:
-  \url{https://dejavu-fonts.github.io}} spécifiée avec la commande |\setmonofont| de
-\pkg{fontspec}.
+On présente ici un réglage de ces styles adapté pour les documents en noir et blanc.
 
 Ce réglage utilise la commande |\highLight| de \pkg{lua-ul} (cette extension nécessite
 elle-même l'extension \pkg{luacolor}).
@@ -2197,8 +2299,6 @@
 
 
 \begin{Verbatim}
-\setmonofont[Scale=0.85]{DejaVu Sans Mono}
-
 \SetPitonStyle
   {
     Number = ,
@@ -2227,9 +2327,6 @@
 
 \begingroup
 
-
-\setmonofont[Scale=0.85]{DejaVu Sans Mono}
-
 \SetPitonStyle
   {
     Number = ,

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

Modified: trunk/Master/texmf-dist/source/lualatex/piton/piton.dtx
===================================================================
--- trunk/Master/texmf-dist/source/lualatex/piton/piton.dtx	2024-09-22 20:22:16 UTC (rev 72350)
+++ trunk/Master/texmf-dist/source/lualatex/piton/piton.dtx	2024-09-22 20:22:25 UTC (rev 72351)
@@ -79,12 +79,12 @@
 % \iffalse
 %<*STY>
 % \fi
-\def\PitonFileVersion{3.1b}
-\def\PitonFileDate{2024/08/29}
+\def\PitonFileVersion{4.0}
+\def\PitonFileDate{2024/09/22}
 % \iffalse
 %</STY>
 %<*LUA>
-piton_version = "3.1b" -- 2024/08/29
+piton_version = "4.0" -- 2024/09/22
 %</LUA>
 %\fi
 %
@@ -101,6 +101,10 @@
 % syntactic highlighting, by using the Lua library LPEG. It requires LuaLaTeX.
 % \end{abstract}
 % 
+% \bigskip
+% {\color{red} In the version 4.0, the syntax of the absolute and relative
+% paths used in |\PitonInputFile| has been changed:
+% cf.~part~\ref{PitonInputFile}, p.~\pageref{PitonInputFile}.} 
 % 
 %
 % \section{Presentation}
@@ -143,11 +147,11 @@
 %    \end{Piton}
 %
 %
-% \bigskip
+% \medskip
 % The main alternatives to the package \pkg{piton} are probably the packages
 % \pkg{listings} and \pkg{minted}.
 % 
-% \bigskip
+% \medskip
 % The name of this extension (\pkg{piton}) has been chosen arbitrarily by
 % reference to the pitons used by the climbers in alpinism.
 % 
@@ -186,8 +190,8 @@
 % |minimal| may be used to format pseudo-codes: cf. p.~\pageref{minimal}};
 % \item the languages defined by the final user by using the built-in command
 % |\NewPitonLanguage| described p.~\pageref{NewPitonLanguage} (the parsers of
-% those languages can't be as precise as those of the native languages supported
-% by \pkg{piton}).
+% those languages can't be as precise as those of the languages supported
+% natively by \pkg{piton}).
 % \end{itemize}
 % 
 %
@@ -197,7 +201,7 @@
 % \smallskip
 % \index{language (key)}
 % It's possible to change the current language with the command |\PitonOptions|
-% and its key |language|: |\PitonOptions{language = OCaml}|.
+% and its key \Definition{language}: |\PitonOptions{language = OCaml}|.
 %
 % \smallskip
 % In fact, for \pkg{piton}, the names of the informatic languages are always
@@ -216,12 +220,12 @@
 %
 % \indexenv{Piton}
 % 
-% The package \pkg{piton} provides several tools to typeset Python codes: the
+% The package \pkg{piton} provides several tools to typeset informatic codes: 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:
+% \item The command \DefinitionCommand{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}
@@ -235,23 +239,11 @@
 % 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 external file.
+% \item The command \DefinitionCommand{PitonInputFile} is used to insert and
+% typeset an external file: cf.~\ref{PitonInputFile}
+% p.~\pageref{PitonInputFile}.
 %
-% It's possible to insert only a part of the file: cf.
-% part~\ref{part-of-a-file}, p.~\pageref{part-of-a-file}. 
 %
-% The key \Definition{path} of the command |\PitonOptions| specifies a
-% \emph{list} of paths where the files included by |\PitonInputFile| will be
-% searched. That list is comma separated.
-%
-% The extension \pkg{piton} also provides the commands
-% \colorbox{gray!20}{\ttfamily \textbackslash PitonInputFileT},
-% \colorbox{gray!20}{\ttfamily \textbackslash PitonInputFileF} and
-% \colorbox{gray!20}{\ttfamily \textbackslash PitonInputFileTF} with
-% supplementary arguments corresponding to the letters~|T| and~|F|. Those
-% arguments will be executed if the file to include has been found (letter~|T|)
-% or not found (letter~|F|).
 % \end{itemize}
 %
 % \subsection{The syntax of the command \textbackslash piton}
@@ -261,8 +253,8 @@
 % 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|...|!).
+% 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
@@ -283,8 +275,7 @@
 % {\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,
+% 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}
@@ -315,6 +306,10 @@
 % \texttt{\textbackslash piton} in a footnote. Example :
 % \piton{s = 'A string'}.}
 %
+% However, since the argument is expanded (in the TeX sens), one should take
+% care not using in its argument \emph{fragile} commands (that is to say
+% commands which are neither \emph{protected} nor \emph{fully expandable}).
+%
 % \bigskip
 % \item {\color{blue} \textsf{Syntax} \verb!\piton|...|!}\par\nobreak
 %
@@ -368,10 +363,16 @@
 % (cf.~part~\ref{NewPitonLanguage}, p.~\pageref{NewPitonLanguage}.  
 %
 % The initial value is |Python|.
+%
+% \item \index{font-command}
+% \colorbox{yellow!50}{\textbf{New 4.0}}\par\nobreak
+%
+% The key \Definition{font-command} contains instructions of font which will be
+% inserted at the beginning of all the elements composed by \pkg{piton}.
+%
+% The initial value is |\ttfamily| and, thus, \pkg{piton} uses by default the
+% current monospaced font.
 % 
-% \item \index{path} The key \Definition{path} specifies a path where the files
-% included by |\PitonInputFile| will be searched.
-% 
 % \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 highlighting of the code) for each line of the environment
@@ -439,8 +440,7 @@
 % \item The key \Definition{line-numbers/sep} is the horizontal distance between
 % the numbers of lines (inserted by |line-numbers|) and the beginning of the
 % lines of code. The initial value is 0.7~em.
-% \item \colorbox{yellow!50}{\bfseries New 3.1}\enskip The key
-% \Definition{line-numbers/format} is a list of tokens which are inserted before
+% \item The key \Definition{line-numbers/format} is a list of tokens which are inserted before
 % the number of line in order to format it. It's possible to put, \emph{at the
 % end} of the list, a LaTeX command with one argument, such as, for example,
 % |\fbox|. 
@@ -489,11 +489,6 @@
 % 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}|.
 %
-% \smallskip
-% When the key |split-on-empty-lines| is in force (see the part ``Page breaks'',
-% p.~\pageref{page breaks}), the empty lines generated by that key don't have
-% any background color (at least with the initial value of the parameter
-% |split-separation|). 
 %
 % \item \index{prompt-background-color} With the key
 % \Definition{prompt-background-color}, \pkg{piton} adds a 
@@ -625,17 +620,17 @@
 % package \pkg{luacolor}).
 %
 % \begin{verbatim}
-% \SetPitonStyle{ Name.Function = \bfseries \highLight[red!50] }
+% \SetPitonStyle{ Name.Function = \bfseries \highLight[red!30] }
 % \end{verbatim}
 %
-% In that example, |\highLight[red!50]| must be considered as the name of a
+% In that example, |\highLight[red!30]| 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]{...}|.
+% with |\highLight[red!30]{...}|.
 %
 % \medskip
 % \begingroup
 % \SetPitonStyle 
-%   { Name.Function = \bfseries \highLight[red!50] }
+%   { Name.Function = \bfseries \highLight[red!30] }
 % With that setting, we will have : \piton{def cube(x) : return x * x * x }
 % \endgroup
 % 
@@ -841,7 +836,6 @@
 % \indexcommand{NewPitonLanguage}
 % \label{NewPitonLanguage}
 % \index{listings@\pkg{listings} (extension)}
-% \colorbox{yellow!50}{\textbf{New 3.0}}
 %
 % \medskip
 % The package \pkg{listings} is a famous LaTeX package to format informatic
@@ -860,7 +854,7 @@
 % syntax of~|\lstdefinelanguage|.
 %
 % Let's precise that \pkg{piton} does \emph{not} use that command to define the
-% languages provided natively (Python, OCaml, \CC, SQL and |minimal|), which
+% languages provided natively (Python, OCaml, C, SQL and |minimal|), which
 % allows more powerful parsers.
 %
 % \medskip
@@ -933,7 +927,7 @@
 % \bigskip
 % \begingroup
 % \small
-% \PitonOptions{split-on-empty-lines}
+% \PitonOptions{splittable-on-empty-lines}
 % \begin{Piton}[language = java]
 % public class Cipher {  // Caesar cipher
 %     public static void main(String[] args) {
@@ -992,146 +986,55 @@
 % category of the letters. 
 % 
 % \section{Advanced features}
+% \subsection{Insertion of a file}
 %
-% \subsection{Page breaks and line breaks}
+% \label{PitonInputFile}
 %
-% \label{breakable}
+% \subsubsection{The command \textbackslash PitonInputFile}
 %
-% \subsubsection{Page breaks}
-% \label{page breaks}
-% \index{splittable}
+% \indexcommand{PitonInputFile}
 %
-% By default, the listings produced by the environment |{Piton}| and the command
-% |\PitonInputFile| are not breakable.
-%
-% However, the command |\PitonOptions| provides the keys |split-on-empty-lines|
-% and |splittable| to allow such breaks.
-%
-% \begin{itemize}
-% \item The key \Definition{split-on-empty-lines} allows breaks on the empty
-% lines\footnote{The ``empty lines'' are the lines which contains only spaes.} in
-% the listing. In the informatic listings, the empty lines usually separate the
-% definitions of the informatic functions and it's pertinent to allow breaks
-% between these functions.
-%
-% In fact, when the key |split-on-empty-lines| is in force, the work goes a
-% little further than merely allowing page breaks: several successive empty lines
-% are deleted and replaced by the content of the parameter corresponding to the
-% key \Definition{split-separation}. 
-% \begin{itemize}
-% \item That parameter must contain elements allowed to be inserted in
-% \emph{vertical mode} of TeX. For example, it's possible to put |\hrule|.
-%
-% \item The initial value of this parameter is
-% |\vspace{\baselineskip}\vspace{-1.25pt}| which corresponds eventually to an 
-% empty line in the final PDF (this vertical space is deleted if it occurs on a
-% page break). If the key |background-color| is in force, no background color is
-% added to that empty line.
-% \end{itemize}
-%
-% \item Of course, the key |split-on-empty-lines| may not be sufficient and
-% that's why \pkg{piton} provides the key \Definition{splittable}.
-%
-% When the key |splittable| is used with the numeric value~$n$ (which must be a
-% positive integer) the listing, or each part of the listing delimited by empty
-% lines (when |split-on-empty-lines| is in force) may be broken anywhere with
-% the restriction that no break will occur within the $n$ first lines of
-% the listing or within the $n$ last lines. For example, a tuning with
-% |splittable = 4| may be a good choice.
-%
-% When used without value, the key |splittable| is equivalent to 
-% |splittable = 1| and the listings may be broken anywhere (it's probably 
-% not recommandable).
-%
-% The initial value of the key |splittable| is equal to 100 (by default, the
-% listings are not breakable at all).
-% \end{itemize} 
+% The command \DefinitionCommand{PitonInputFile} includes the content of the
+% file specified in argument (or only a part of that file: see below). The
+% extension \pkg{piton} also provides the commands
+% \DefinitionCommand{PitonInputFileT}, \DefinitionCommand{PitonInputFileF} and
+% \DefinitionCommand{PitonInputFileTF} with supplementary arguments
+% corresponding to the letters~|T| and~|F|. Those arguments will be executed if
+% the file to include has been found (letter~|T|) or not found (letter~|F|).
 % 
+% \bigskip
+% \colorbox{yellow!50}{\textbf{Modification 4.0}}\par\nobreak
 %
+% \index{old-PitonInputFile}
+% \smallskip
+% The syntax for the absolute and relative paths has been changed in order to
+% be conform to the traditionnal usages. However, it's possible to use the key
+% \Definition{old-PitonInputFile} at load-time (that is to say with the
+% |\usepackage|) in order to have the old behaviour (though, that key will be
+% deleted in a future version of \pkg{piton}!).
 %
-% \medskip
-% Even with a background color (set by the key |background-color|), the pages
-% breaks are allowed, as soon as the key |split-on-empty-lines| or 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).
+% \smallskip
+% Now, the syntax if the following one:
 % \begin{itemize}
-% \item \index{break-lines!break-lines-in-piton} With the key
-% \Definition{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 \index{break-lines!break-lines-in-Piton} With the key
-% \Definition{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 \index{break-lines} The key \Definition{break-lines} is a conjunction 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|.
+% \item The paths beginning by |/| are absolute.
 %
-% \begin{itemize}
-% \item \index{indent-broken-lines} With the key
-% \Definition{indent-broken-lines}, the indentation of a 
-% broken line is respected at carriage return.
+% \emph{Example} : |\PitonInputFile{/Users/joe/Documents/program.py}|
 %
-% \item The key \Definition{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 paths which do not begin with |/| are relative to the current
+% repertory. 
 %
-% \item \index{continuation-symbol} The key \Definition{continuation-symbol}
-% corresponds to the symbol placed at each carriage return. The initial value
-% is: |+\;| (the command |\;| inserts a small horizontal space).
-%
-% \item \index{continuation-symbol-on-indentation} 
-% The key \Definition{continuation-symbol-on-indentation} corresponds 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\;$|.
+% \emph{Example} : |\PitonInputFile{my_listings/program.py}|
 % \end{itemize}
 %
+% \index{path}
+% The key \Definition{path} of the command |\PitonOptions| specifies a
+% \emph{list} of paths where the files included by |\PitonInputFile| will be
+% searched. That list is comma separated.
 %
-% \bigskip
-% The following code has been composed with the following tuning:
+% As previously, the absolute paths must begin with |/|.
 %
-% \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}
-%
-%
 % \bigskip
-% \subsection{Insertion of a part of a file}
+% \subsubsection{Insertion of a part of a file}
 %
 % \label{part-of-a-file}
 % \indexcommand{PitonInputFile}
@@ -1147,7 +1050,8 @@
 % In both cases, if we want to number the lines with the numbers of the
 % lines in the file, we have to use the key |line-numbers/absolute|.
 %
-% \subsubsection{With line numbers}
+% \bigskip
+% \textbf{With line numbers}\par\nobreak
 %
 % The command |\PitonInputFile| supports the keys \Definition{first-line} and
 % \Definition{last-line} in order to insert only the part of file between the
@@ -1156,7 +1060,8 @@
 % |line-numbers/start| deals with the output whereas |first-line| and
 % |last-line| deal with the input.
 %
-% \subsubsection{With textual markers}
+% \bigskip
+% \textbf{With textual markers}\par\nobreak
 %
 % \index{marker/beginning}
 % \index{marker/end}
@@ -1272,6 +1177,209 @@
 %
 %
 %
+% \bigskip
+% \subsection{Page breaks and line breaks}
+%
+% \label{breakable}
+% 
+% \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 \index{break-lines!break-lines-in-piton} With the key
+% \Definition{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 \index{break-lines!break-lines-in-Piton} With the key
+% \Definition{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 \index{break-lines} The key \Definition{break-lines} is a conjunction 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 \index{indent-broken-lines} With the key
+% \Definition{indent-broken-lines}, the indentation of a 
+% broken line is respected at carriage return (on the condition that the used
+% font is a monospaced font and this is the case by default since the initial
+% value of |font-command| is |\ttfamily|).
+%
+% \item The key \Definition{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 \index{continuation-symbol} The key \Definition{continuation-symbol}
+% corresponds to the symbol placed at each carriage return. The initial value
+% is: |+\;| (the command |\;| inserts a small horizontal space).
+%
+% \item \index{continuation-symbol-on-indentation} 
+% The key \Definition{continuation-symbol-on-indentation} corresponds 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}
+%
+% \subsubsection{Page breaks}
+% \label{page breaks}
+% \index{splittable}
+% \index{splittable-on-empty-lines}
+%
+% By default, the listings produced by the environment |{Piton}| and the command
+% |\PitonInputFile| are not breakable.
+%
+% However, \pkg{piton} provides the keys |splittable-on-empty-lines| and
+% |splittable| to allow such breaks.
+%
+% \begin{itemize}
+% \item The key \Definition{splittable-on-empty-lines} allows breaks on the empty
+% lines. The ``empty lines'' are in fact the lines which contains only spaces.
+%
+% \item Of course, the key |splittable-on-empty-lines| may not be sufficient and
+% that's why \pkg{piton} provides the key \Definition{splittable}.
+%
+% When the key |splittable| is used with the numeric value~$n$ (which must be a
+% positive integer) the listing, or each part of the listing delimited by empty
+% lines (when |split-on-empty-lines| is in force) may be broken anywhere with
+% the restriction that no break will occur within the $n$ first lines of
+% the listing or within the $n$ last lines.\footnote{Remark that we speak of the
+% lines of the original informatic listing and such line may be composed on
+% several lines in the final \textsc{pdf} when the key |break-lines-in-Piton| is
+% in force.} 
+%
+% For example, a tuning with |splittable = 4| may be a good choice.
+%
+% When used without value, the key |splittable| is equivalent to 
+% |splittable = 1| and the listings may be broken anywhere (it's probably 
+% not recommandable).
+%
+% The initial value of the key |splittable| is equal to 100 (by default, the
+% listings are not breakable at all).
+% \end{itemize} 
+%
+% \medskip
+% Even with a background color (set by the key |background-color|), the pages
+% breaks are allowed, as soon as the key |split-on-empty-lines| or 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}.}
+%
+% \subsection{Splitting of a listing in sub-listings}
+%
+% \index{split-on-empty-lines}
+% \label{split-on-empty-lines}
+% \index{split-separation}
+%
+% The extension \pkg{piton} provides the key \Definition{split-on-empty-lines},
+% which should not be confused with the key |splittable-on-empty-lines|
+% previously defined.
+%
+% \smallskip
+% In order to understand the behaviour of the key |split-on-empty-lines|, one
+% should imagine that he has to compose an informatic listing which contains
+% several definitions of informatic functions. Usually, in the informatic
+% languages, those definitions of functions are separated by empty lines.
+%
+% \smallskip
+% The key |split-on-empty-lines| splits the listings on the empty lines. Several
+% empty lines are deleted and replaced by the content of the parameter
+% corresponding to the key \Definition{split-separation}.
+% \begin{itemize}
+% \item That parameter must contain elements allowed to be inserted in
+% \emph{vertical mode} of TeX. For example, it's possible to put the TeX
+% primitive |\hrule|.
+%
+% \item The initial value of this parameter is
+% |\vspace{\baselineskip}\vspace{-1.25pt}| which corresponds eventually to an 
+% empty line in the final \textsc{pdf} (this vertical space is deleted if it
+% occurs on a page break). If the key |background-color| is in force, no
+% background color is added to that empty line.
+% \end{itemize}
+%
+%
+% \colorbox{yellow!50}{\textbf{New 4.0}}\par\nobreak
+% Each chunk of the informatic listing is composed in an environment whose name
+% is given by the key \Definition{env-used-by-split}. The initial value of that
+% parameter is, not surprisingly, |Piton| and, hence, the different chunks are
+% composed in several environments |{Piton}|. If one decides to change the value
+% of |env-used-by-split|, he should use the name of an environment created by
+% |\NewPitonEnvironment| (cf.~part~\ref{NewPitonEnvironment},
+% p.~\pageref{NewPitonEnvironment}).
+%
+% Each chunk of the informatic listing is formated in its own environment.
+% Therefore, it has its own line numbering (if the key
+% |line-numbers| is in force) and its own colored background (when the key
+% |background-color| is in force), separated from the background color of the
+% other chunks. When used, the key |splittable| applies in each chunk
+% (independently of the other chunks). Of course, a page break may occur between
+% the chunks of code, regardless of the value of |splittable|.
+%
+% \bigskip
+% \begin{Verbatim}
+% \begin{Piton}[~emphase#split-on-empty-lines@,background-color=gray!15,line-numbers]
+% def square(x):
+%     """Computes the square of x"""
+%     return x*x
+%
+% def cube(x):
+%     """Calcule the cube of x"""
+%     return x*x*x
+% \end{Piton}
+% \end{Verbatim}
+%
+%
+% \begin{Piton}[split-on-empty-lines,background-color=gray!15,line-numbers]
+% def square(x):
+%     """Computes the square of x"""
+%     return x*x
+%
+% def cube(x):
+%     """Calcule the cube of x"""
+%     return x*x*x
+% \end{Piton}
+%
+% \bigskip
+% \textbf{Caution}: Since each chunk is treated independently of the others, the
+% commands specified by |detected-commands| and the commands and environments
+% of Beamer automatically detected by \pkg{piton} must not cross the enmpty
+% lines of the original listing.
+%
 % \subsection{Highlighting some identifiers}
 %
 % \label{SetPitonIdentifier}
@@ -1293,7 +1401,7 @@
 % identifiers.
 %
 % \item The second mandatory argument is a list of LaTeX instructions of the
-% same type as \pkg{piton} ``styles'' previously presented (cf~\ref{styles}
+% same type as \pkg{piton} ``styles'' previously presented (cf.~\ref{styles}
 % p.~\pageref{styles}). 
 % \end{itemize}
 % 
@@ -1491,8 +1599,14 @@
 % between braces (and these braces must appear explicitly in the informatic listing). 
 % \end{itemize}
 %
-% \medskip
-% We assume that the preamble of the LaTeX document contains the following line.
+% \bigskip
+% In the following example, which is a recursive programmation of the factorial
+% function, we decide to highlight the recursive call. The command |\highLight|
+% of \pkg{lua-ul}\footnote{The package \pkg{lua-ul} requires itself the package
+% \pkg{luacolor}.} directly does the job with the easy syntax |\highLight{...}|.
+%
+% \medskip 
+% We assume that the preamble of the LaTeX document contains the following line:
 % \begin{Verbatim}
 % \PitonOptions{~emphase#detected-commands@ = highLight}
 % \end{Verbatim}
@@ -1700,8 +1814,7 @@
 % 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| ; \newline
-% \colorbox{yellow!50}{\bfseries New 3.1}\newline
-% It's possible to add new commands to that list with the key
+% % It's possible to add new commands to that list with the key
 % \Definition{detected-beamer-commands} (the names of the commands must
 % \emph{not} be preceded by a backslash). 
 % \item two mandatory arguments : |\alt| ; 
@@ -1756,8 +1869,6 @@
 %
 % \smallskip
 % \index{detected-beamer-environments}
-% \colorbox{yellow!50}{\bfseries New 3.1} 
-% 
 % It's possible to add new environments to that list with the key
 % \Definition{detected-beamer-environments}. 
 %
@@ -1960,8 +2071,9 @@
 % \index{tab-size}
 %
 % \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
+% Even though it's probably recommended to indent the informatics listings with
+% spaces and not tabulations\footnote{For the language Python, see the note %
+% 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 \Definition{tab-size} of |\PitonOptions|.
@@ -1982,15 +2094,14 @@
 %
 % \label{API}
 % 
-% The L3 variable |\l_piton_language_str| contains the name of the current
-% language of \pkg{piton} (in lower case).
+% The L3 variable \DefinitionCommand{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}.
+% The extension \pkg{piton} provides a Lua function
+% \Definition{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).
@@ -2168,16 +2279,12 @@
 %
 % \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}. 
+% in black and white.
 %
 % 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 = ,
@@ -2204,9 +2311,6 @@
 % \pkg{piton} is \emph{not} empty.
 %
 % \begingroup
-%
-% \setmonofont[Scale=0.85]{DejaVu Sans Mono}
-%
 %  \PitonOptions{splittable}
 %
 % \SetPitonStyle
@@ -2881,7 +2985,8 @@
 %    \end{macrocode}
 %
 % \medskip
-% The following boolean corresponds to the key |math-comments| (available only at load-time).
+% The following boolean corresponds to the key |math-comments| (available only
+% in the preamble of the LaTeX document). 
 %    \begin{macrocode}
 \bool_new:N \g_@@_math_comments_bool
 %    \end{macrocode}
@@ -2891,6 +2996,16 @@
 \bool_new:N \g_@@_beamer_bool
 \tl_new:N \g_@@_escape_inside_tl 
 %    \end{macrocode}
+%
+% \medskip
+% In version 4.0 of \pkg{piton}, we changed the mechanism used by \pkg{piton}
+% to search the file to load with |\PitonInputFile|. With the key
+% |old-PitonInputFile|, it's possible to keep the old behaviour but it's only
+% for backward compatibility and it will be deleted in a future version.
+%    \begin{macrocode}
+\bool_new:N \l_@@_old_PitonInputFile_bool 
+%    \end{macrocode}
+%
 % 
 % \bigskip
 % We define a set of keys for the options at load-time.
@@ -2899,9 +3014,22 @@
   { 
     footnote .bool_gset:N = \g_@@_footnote_bool ,
     footnotehyper .bool_gset:N = \g_@@_footnotehyper_bool ,
+    footnote .usage:n = load , 
+    footnotehyper .usage:n = load ,
 
     beamer .bool_gset:N = \g_@@_beamer_bool ,
     beamer .default:n = true , 
+    beamer .usage:n = load ,
+%    \end{macrocode}
+% \medskip
+% In version 4.0 of \pkg{piton}, we changed the mechanism used by \pkg{piton}
+% to search the file to load with |\PitonInputFile|. With the key
+% |old-PitonInputFile|, it's possible to keep the old behaviour but it's only
+% for backward compatibility and it will be deleted in a future version.
+%    \begin{macrocode}
+    old-PitonInputFile .bool_set:N = \l_@@_old_PitonInputFile_bool ,
+    old-PitonInputFile .default:n = true , 
+    old-PitonInputFile .usage:n = load ,
 
     unknown .code:n = \@@_error:n { Unknown~key~for~package }
   }
@@ -2914,8 +3042,8 @@
   {
     Unknown~key.\\
     You~have~used~the~key~'\l_keys_key_str'~but~the~only~keys~available~here~
-    are~'beamer',~'footnote',~'footnotehyper'.~Other~keys~are~available~in~
-    \token_to_str:N \PitonOptions.\\ 
+    are~'beamer',~'footnote',~'footnotehyper'~and~'old-PitonInputFile'.~
+    Other~keys~are~available~in~\token_to_str:N \PitonOptions.\\ 
     That~key~will~be~ignored.
   }
 %    \end{macrocode}
@@ -3011,8 +3139,8 @@
 %    \begin{macrocode}
 \lua_now:n 
   { 
-    piton.BeamerCommands = lpeg.P ( "\\uncover" ) 
-          + "\\only" + "\\visible" + "\\invisible" + "\\alert" + "\\action" 
+    piton.BeamerCommands = lpeg.P ( [[\uncover]] ) 
+       + [[\only]] + [[\visible]] + [[\invisible]] + [[\alert]] + [[\action]] 
     piton.beamer_environments = { "uncoverenv" , "onlyenv" , "visibleenv" , 
                "invisibleenv" ,  "alertenv" ,  "actionenv" }
     piton.DetectedCommands = lpeg.P ( false ) 
@@ -3062,6 +3190,12 @@
 \bool_new:N \l_@@_in_PitonInputFile_bool 
 %    \end{macrocode}
 %
+% \medskip
+% The following parameter corresponds to the key |font-command|.
+%    \begin{macrocode}
+\tl_new:N \l_@@_font_command_tl
+\tl_set:Nn \l_@@_font_command_tl { \ttfamily }
+%    \end{macrocode}
 % 
 % \medskip
 % We will compute (with Lua) the numbers of lines of the listings (or
@@ -3075,7 +3209,9 @@
 %    \begin{macrocode}
 \int_new:N \l_@@_nb_non_empty_lines_int
 %    \end{macrocode}
+%
 % 
+% \medskip 
 % The following counter will be used to count the lines during the composition.
 % It will take into account all the lines, empty or not empty. It won't be used
 % to print the numbers of the lines but will be used to allow or disallow line
@@ -3120,7 +3256,6 @@
 %    \end{macrocode}
 % That parameter must contain elements to be inserted in \emph{vertical} mode by
 % TeX. 
-% 
 %
 % 
 % \medskip
@@ -3337,8 +3472,10 @@
 %    \end{macrocode}
 % 
 % \medskip
+% Be careful: when executed, the following command does \emph{not} create a
+% space (only an incrementation of the counter).
 %    \begin{macrocode}
-\cs_new_protected:Npn \@@_an_indentation_space:
+\cs_new_protected:Npn \@@_leading_space:
   { \int_gincr:N \g_@@_indentation_int }
 %    \end{macrocode}
 %
@@ -3365,8 +3502,8 @@
             } 
           } 
         \@esphack
-     }
-     { \@@_error:n { label~with~lines~numbers } }
+      }
+      { \@@_error:n { label~with~lines~numbers } }
   }
 %    \end{macrocode}
 %
@@ -3383,13 +3520,6 @@
 %    \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: { \lua_now:n { piton.open_brace() } }
-\cs_new_protected:Npn \@@_close_brace: { \lua_now:n { piton.close_brace() } }
-%    \end{macrocode}
 % 
 % \bigskip
 % The following token list will be evaluated at the beginning of
@@ -3410,7 +3540,7 @@
     \tl_gset:Nn \g_@@_begin_line_hook_tl
       { 
         \tl_if_empty:NF \l_@@_prompt_bg_color_tl 
-          { \clist_set:NV \l_@@_bg_color_clist \l_@@_prompt_bg_color_tl }
+          { \clist_set:No \l_@@_bg_color_clist \l_@@_prompt_bg_color_tl }
       } 
   }
 %    \end{macrocode}
@@ -3434,8 +3564,8 @@
     \tl_set:Nn \l_tmpa_tl { #1 } 
     \bool_if:NTF \l_@@_show_spaces_bool
       { 
-        \tl_set:Nn \l_@@_space_tl { ␣ }
-        \regex_replace_all:nnN { \x20 } { ␣ } \l_tmpa_tl % U+2423
+        \tl_set:Nn \l_@@_space_tl { ␣ } % U+2423
+        \regex_replace_all:nnN { \x20 } { ␣ } \l_tmpa_tl 
       } 
       {
 %    \end{macrocode}
@@ -3451,6 +3581,10 @@
               { \x20 } 
               { \c { @@_breakable_space: } }
               \l_tmpa_tl 
+            \regex_replace_all:nnN 
+              { \c { l_@@_space_tl } } 
+              { \c { @@_breakable_space: } }
+              \l_tmpa_tl 
           } 
       }
     \l_tmpa_tl 
@@ -3459,11 +3593,22 @@
 % 
 % \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.
+% surrounded by |\@@_begin_line:| and |\@@_end_line:|. 
+
+% |\@@_begin_line:| is a
+% TeX command with a delimited argument (|\@@_end_line:| is the marker for the
+% end of the argument).
 %
+% However, we define also |\@@_end_line:| as no-op, because, when the last line
+% of the listing is the end of an environment of Beamer (eg |\end{uncoverenv}|),
+% we will have a token |\@@_end_line:| added at the end without any
+% corresponding |\@@_begin_line:|).
 %    \begin{macrocode}
+\cs_set_protected:Npn \@@_end_line: { }
+%    \end{macrocode}
+% 
+% \bigskip
+%    \begin{macrocode}
 \cs_set_protected:Npn \@@_begin_line: #1 \@@_end_line:
   { 
     \group_begin:
@@ -3496,16 +3641,30 @@
         \skip_horizontal:N \l_@@_left_margin_dim
         \bool_if:NT \l_@@_line_numbers_bool
           {
-            \bool_if:nF
-              { 
-                \str_if_eq_p:nn { #1 } { \PitonStyle { Prompt } { } } 
-                && 
-                \l_@@_skip_empty_lines_bool 
+%    \end{macrocode}
+% |\l_tmpa_int| will be true equal to $1$ when the current line is not empty.
+%    \begin{macrocode}
+            \int_set:Nn \l_tmpa_int 
+              {
+                \lua_now:e 
+                  { 
+                    tex.sprint
+                      ( 
+                        luatexbase.catcodetables.expl ,
+                        tostring 
+                          ( piton.empty_lines
+                              [ \int_eval:n { \g_@@_line_int + 1 } ] 
+                          ) 
+                      ) 
+                  } 
               }
+            \bool_lazy_or:nnT
+              { \int_compare_p:nNn \l_tmpa_int = \c_one_int }
+              { ! \l_@@_skip_empty_lines_bool }
               { \int_gincr:N \g_@@_visual_line_int }
             \bool_if:nT
               { 
-                ! \str_if_eq_p:nn { #1 } { \PitonStyle { Prompt } { } } 
+                \int_compare_p:nNn \l_tmpa_int = \c_one_int
                 ||
                 ( ! \l_@@_skip_empty_lines_bool && \l_@@_label_empty_lines_bool ) 
               }
@@ -3521,12 +3680,17 @@
 % ... 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 } }
+              { \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 } 
+%    \end{macrocode}
+% We have to explicitely begin a paragraph because we will insert a TeX box (and
+% we don't want that box to be inserted in the vertical list).
+%    \begin{macrocode}
+    \mode_leave_vertical:
     \clist_if_empty:NTF \l_@@_bg_color_clist
       { \box_use_drop:N \l_tmpa_box }
       {
@@ -3539,11 +3703,10 @@
                        depth \box_dp:N \l_tmpa_box 
                        width \l_@@_width_dim
               } 
-            \skip_vertical:n { - \box_ht_plus_dp:N \l_tmpa_box }
+            \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
   }
@@ -3606,7 +3769,7 @@
   {
     \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_set:Ne \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
@@ -3613,7 +3776,7 @@
 % 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 }
+      { \exp_args:No \@@_color_i:n \l_tmpa_tl }
   }
 %    \end{macrocode}
 %
@@ -3639,57 +3802,64 @@
 % \item In fact, it will be inserted between two commands
 % |\@@_begin_line:|...|\@@_end_of_line:|. 
 % \item When the key |break-lines-in-Piton| is in force, a line of the
-% informatic code (the \emph{input}) may result in several lines in the PDF (the
-% \emph{output}). 
-% \item |\@@_newline:| has a rather complex behaviour because it may close and
-% open |\vtop|s and finish and start paragraphs.
+% informatic code (the \emph{input}) may result in several lines in the
+% \textsc{pdf} (the \emph{output}). 
+% \item Remind that |\@@_newline:| has a rather complex behaviour because it will
+% finish and start paragraphs.
 % \end{itemize}
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_newline: 
   { 
+    \bool_if:NT \g_@@_footnote_bool \endsavenotes 
 %    \end{macrocode}
 % We recall that |\g_@@_line_int| is \emph{not} used for the number of line
-% printed in the PDF (when |line-numbers| is in force)...
+% printed in the \textsc{pdf} (when |line-numbers| is in force)...
 %    \begin{macrocode}
     \int_gincr:N \g_@@_line_int
 %    \end{macrocode}
-% ... it will be used to allow or disallow page breaks (the final user controls
-% that behaviour with the key |splittable|).
+% ... it will be used to allow or disallow page breaks.
+%
+%
+% Each line in the listing is composed in a box of TeX (which may contain
+% several lines when the key |break-lines-in-Piton| is in force) put in a
+% paragraph. 
 %    \begin{macrocode}
-    \int_compare:nNnT \g_@@_line_int > { \l_@@_splittable_int - 1 }
-      {
-        \int_compare:nNnT 
-          { \l_@@_nb_lines_int - \g_@@_line_int + 1 } > \l_@@_splittable_int 
+    \par 
 %    \end{macrocode}
-% Now, we allow a page break after the current line of code.
+% We now add a |\kern| because each line of code is overlapping vertically by a
+% quantity of 2.5~pt in order to have a good background (when |background-color|
+% is in force). We need to use a |\kern| (in fact |\par\kern...|) and not a
+% |\vskip| because page breaks should \emph{not} be allowed on that kern.
 %    \begin{macrocode}
-          {
-            \egroup
-            \bool_if:NT \g_@@_footnote_bool \endsavenotes 
-            \par 
+    \kern -2.5 pt 
 %    \end{macrocode}
-% Each non-splittable block of lines is composed in a |\vtop| of
-% TeX inserted in a paragraph of TeX. 
-% \begin{itemize}
-% \item In the previous lines, we have closed a |\vtop| (with |\egroup|) and a
-% paragraph (with |\par|).
-% \item Now, we start a new paragraph (with |\mode_leave_vertical:|) and open a
-% |\vtop| (with |\vtop \bgroup|).
-% \end{itemize}
+% Now, we control page breaks after the paragraph. We use the Lua table
+% |piton.lines_status| which has been written by |piton.ComputeLinesStatus| for
+% this aim. Each line has a ``status`` (equal to 0, 1 or 2) and that status
+% directly says whether a break is allowed.
 %    \begin{macrocode}
-            \mode_leave_vertical: 
-            \bool_if:NT \g_@@_footnote_bool \savenotes 
-            \vtop \bgroup
+    \int_case:nn
+      { 
+        \lua_now:e 
+          { 
+            tex.sprint
+              ( 
+                luatexbase.catcodetables.expl ,
+                tostring ( piton.lines_status [ \int_use:N \g_@@_line_int ] ) 
+              ) 
+          } 
+      }
+      { 1 { \penalty 100 } 2 \nobreak }
 %    \end{macrocode}
-% And, in that |\vtop|, of course, we will put a box for each line of the
-% informatic listing (but a line of the informatic listing may be formatted as a
-% box of several lines when |break-lines-in-Piton| is in force).
+% 
+%     \begin{macrocode}
+   \bool_if:NT \g_@@_footnote_bool \savenotes 
+%    \end{macrocode}
+%
 %    \begin{macrocode}
-          }
-     }
   } 
 %    \end{macrocode}
-% After the command |\@@_newline:|, we will have a command |\@@_begin_line:|.
+% After the command |\@@_newline:|, we will usually have a command |\@@_begin_line:|.
 %
 % \bigskip
 %    \begin{macrocode}
@@ -3724,6 +3894,8 @@
 % \bigskip
 % \subsubsection{PitonOptions}
 %
+%
+%
 % \medskip
 %    \begin{macrocode}
 \bool_new:N \l_@@_line_numbers_bool 
@@ -3737,6 +3909,7 @@
 \int_new:N \l_@@_number_lines_start_int
 \bool_new:N \l_@@_resume_bool 
 \bool_new:N \l_@@_split_on_empty_lines_bool
+\bool_new:N \l_@@_splittable_on_empty_lines_bool
 %    \end{macrocode}
 % 
 %
@@ -3820,19 +3993,20 @@
 % First, we put keys that should be available only in the preamble.
 %    \begin{macrocode}
     detected-commands .code:n =  
-       \lua_now:n { piton.addDetectedCommands('#1') } ,
+      \lua_now:n { piton.addDetectedCommands('#1') } ,
     detected-commands .value_required:n = true , 
     detected-commands .usage:n = preamble , 
     detected-beamer-commands .code:n =  
-       \lua_now:n { piton.addBeamerCommands('#1') } ,
+      \lua_now:n { piton.addBeamerCommands('#1') } ,
     detected-beamer-commands .value_required:n = true , 
     detected-beamer-commands .usage:n = preamble , 
     detected-beamer-environments .code:n =  
-       \lua_now:n { piton.addBeamerEnvironments('#1') } ,
+      \lua_now:n { piton.addBeamerEnvironments('#1') } ,
     detected-beamer-environments .value_required:n = true , 
     detected-beamer-environments .usage:n = preamble , 
 %    \end{macrocode}
 %
+% 
 % Remark that the command |\lua_escape:n| is fully expandable. That's why we use
 % |\lua_now:e|.
 %    \begin{macrocode}
@@ -3869,7 +4043,7 @@
 % Now, general keys.
 %    \begin{macrocode}
     language         .code:n = 
-      \str_set:Nx \l_piton_language_str { \str_lowercase:n { #1 } } , 
+      \str_set:Ne \l_piton_language_str { \str_lowercase:n { #1 } } , 
     language         .value_required:n  = true ,
     path .code:n = 
       \seq_clear:N \l_@@_path_seq
@@ -3886,6 +4060,8 @@
     path             .initial:n         = . ,
     path-write       .str_set:N         = \l_@@_path_write_str ,
     path-write       .value_required:n  = true , 
+    font-command     .tl_set:N          = \l_@@_font_command_tl ,
+    font-command     .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 } , 
@@ -3895,6 +4071,9 @@
     tabs-auto-gobble .code:n            = \int_set:Nn \l_@@_gobble_int { -3 } , 
     tabs-auto-gobble .value_forbidden:n = true ,
 
+    splittable-on-empty-lines .bool_set:N = \l_@@_splittable_on_empty_lines_bool ,
+    splittable-on-empty-lines .default:n  = true ,
+
     split-on-empty-lines .bool_set:N = \l_@@_split_on_empty_lines_bool ,
     split-on-empty-lines .default:n = true ,
 
@@ -3991,6 +4170,10 @@
       } ,
     range .value_required:n = true ,
 
+    env-used-by-split .code:n = 
+      \lua_now:n { piton.env_used_by_split = '#1'} , 
+    env-used-by-split .initial:n = Piton ,
+
     resume .meta:n = line-numbers/resume , 
 
     unknown .code:n = \@@_error:n { Unknown~key~for~PitonOptions } ,
@@ -4000,10 +4183,6 @@
       \bool_set_true:N \l_@@_line_numbers_bool 
       \bool_set_false:N \l_@@_skip_empty_lines_bool ,
     all-line-numbers .value_forbidden:n = true ,
-
-    % deprecated
-    numbers-sep .dim_set:N = \l_@@_numbers_sep_dim ,
-    numbers-sep .value_required:n = true 
   }
 %    \end{macrocode}
 %
@@ -4095,7 +4274,7 @@
     \tl_if_empty:NF \g_@@_aux_tl 
       {
         \iow_now:Nn \@mainaux { \ExplSyntaxOn }
-        \iow_now:Nx \@mainaux 
+        \iow_now:Ne \@mainaux 
           {
             \tl_gset:cn { c_@@_ \int_use:N \g_@@_env_int _ tl } 
               { \exp_not:o \g_@@_aux_tl } 
@@ -4112,7 +4291,7 @@
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_width_to_aux:
   {
-    \tl_gput_right:Nx \g_@@_aux_tl
+    \tl_gput_right:Ne \g_@@_aux_tl
       { 
         \dim_set:Nn \l_@@_line_width_dim 
           { \dim_eval:n { \g_@@_tmp_width_dim } }
@@ -4180,7 +4359,7 @@
 % that is to say, for example : |[AspectJ]{Java}|. We use |\tl_if_blank:nF|
 % because the final user may have written |\NewPitonLanguage[ ]{Java}{...}|.
 %    \begin{macrocode}
-    \tl_set:Nx \l_tmpa_tl 
+    \tl_set:Ne \l_tmpa_tl 
       { 
         \tl_if_blank:nF { #1 } { [ \str_lowercase:n { #1 } ] } 
         \str_lowercase:n { #2 } 
@@ -4201,7 +4380,7 @@
 % |\AtBeginDocument|. Hence, we will put also in a |\AtBeginDocument| the
 % utilisation of the Lua function |piton.new_language| (which does the main job).
 %    \begin{macrocode}
-    \exp_args:NV \@@_NewPitonLanguage:nn \l_tmpa_tl { #3 }
+    \exp_args:No \@@_NewPitonLanguage:nn \l_tmpa_tl { #3 }
   }
 %    \end{macrocode}
 % 
@@ -4223,7 +4402,7 @@
 % is to say, for example : |[AspectJ]{Java}|. We use |\tl_if_blank:nF| because
 % the final user may have used |\NewPitonLanguage[Handel]{C}[ ]{C}{...}|
 %    \begin{macrocode}
-    \tl_set:Nx \l_tmpa_tl 
+    \tl_set:Ne \l_tmpa_tl 
       { 
          \tl_if_blank:nF { #3 } { [ \str_lowercase:n { #3 } ] } 
          \str_lowercase:n { #4 }
@@ -4234,12 +4413,12 @@
 % languages provided by \pkg{piton} but only those defined by using
 % |\NewPitonLanguage|. 
 %    \begin{macrocode}
-     \prop_get:NoNTF \g_@@_languages_prop \l_tmpa_tl \l_tmpb_tl 
+    \prop_get:NoNTF \g_@@_languages_prop \l_tmpa_tl \l_tmpb_tl 
 %    \end{macrocode}
 % We can now define the new language by using the previous function.
 %    \begin{macrocode}
-       { \@@_NewPitonLanguage:nnno { #1 } { #2 } { #5 } \l_tmpb_tl }
-       { \@@_error:n { Language~not~defined } }
+      { \@@_NewPitonLanguage:nnno { #1 } { #2 } { #5 } \l_tmpb_tl }
+      { \@@_error:n { Language~not~defined } }
   }
 %    \end{macrocode}
 %
@@ -4272,7 +4451,7 @@
     \automatichyphenmode = 1
 %    \end{macrocode}
 % Remark that the argument of |\piton| (with the normal syntax) is expanded in
-% the TeX sens, (see the |\tl_set:Nx| below) and that's why we can provide the
+% the TeX sens, (see the |\tl_set:Ne| below) and that's why we can provide the
 % following escapes to the final user:
 %    \begin{macrocode}
     \cs_set_eq:NN \\ \c_backslash_str
@@ -4288,9 +4467,8 @@
 %    \end{macrocode}
 %
 %    \begin{macrocode}
-    \cs_set_protected:Npn \@@_begin_line: { }
-    \cs_set_protected:Npn \@@_end_line: { }
-    \tl_set:Nx \l_tmpa_tl 
+    \cs_set_eq:NN \@@_begin_line: \prg_do_nothing:
+    \tl_set:Ne \l_tmpa_tl 
       { 
         \lua_now:e 
           { piton.ParseBis('\l_piton_language_str',token.scan_string()) }
@@ -4312,9 +4490,9 @@
 % The command |\text| is provided by the package \pkg{amstext} (loaded by \pkg{piton}).
 %    \begin{macrocode}
     \if_mode_math:
-       \text { \ttfamily \l_tmpa_tl }
+       \text { \l_@@_font_command_tl \l_tmpa_tl }
     \else:
-       \ttfamily \l_tmpa_tl
+       \l_@@_font_command_tl \l_tmpa_tl
     \fi: 
     \group_end:
   }
@@ -4325,11 +4503,10 @@
 \NewDocumentCommand { \@@_piton_verbatim } { v }
   {
     \group_begin:
-    \ttfamily
+    \l_@@_font_command_tl
     \automatichyphenmode = 1
-    \cs_set_protected:Npn \@@_begin_line: { }
-    \cs_set_protected:Npn \@@_end_line: { }
-    \tl_set:Nx \l_tmpa_tl 
+    \cs_set_eq:NN \@@_begin_line: \prg_do_nothing:
+    \tl_set:Ne \l_tmpa_tl 
       { 
         \lua_now:e 
           { piton.Parse('\l_piton_language_str',token.scan_string()) } 
@@ -4353,32 +4530,21 @@
 % arguments of a Python function).
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_piton:n #1
+  { \tl_if_blank:nF { #1 } { \@@_piton_i:n { #1 } } }
+
+\cs_new_protected:Npn \@@_piton_i:n #1
   { 
     \group_begin:
-    \cs_set_protected:Npn \@@_begin_line: { }
-    \cs_set_protected:Npn \@@_end_line: { }
+    \cs_set_eq:NN \@@_begin_line: \prg_do_nothing:
     \cs_set:cpn { pitonStyle _ \l_piton_language_str  _ Prompt } { }
     \cs_set:cpn { pitonStyle _ Prompt } { }
     \cs_set_eq:NN \@@_trailing_space: \space
-    \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_piton_language_str',token.scan_string()) } 
-              { #1 } 
-          }
+    \tl_set:Ne \l_tmpa_tl 
+      { 
+        \lua_now:e 
+          { piton.ParseTer('\l_piton_language_str',token.scan_string()) } 
+          { #1 } 
       }
-      {
-        \tl_set:Nx \l_tmpa_tl 
-          { 
-            \lua_now:e 
-              { piton.Parse('\l_piton_language_str',token.scan_string()) }
-              { #1 } 
-          }
-      }
     \bool_if:NT \l_@@_show_spaces_bool
       { \regex_replace_all:nnN { \x20 } { ␣ } \l_tmpa_tl } % U+2423
     \exp_args:No \@@_replace_spaces:n \l_tmpa_tl 
@@ -4437,7 +4603,7 @@
                   { #2 }
                 \int_to_arabic:n 
                   { \g_@@_visual_line_int + \l_@@_nb_non_empty_lines_int }   
-               }
+              }
               {
                 \int_to_arabic:n 
                   { \g_@@_visual_line_int + \l_@@_nb_lines_int }  
@@ -4528,18 +4694,24 @@
           ####1 
           \c_backslash_str end \c_left_brace_str #1 \c_right_brace_str
       }
-         { 
+          { 
             \group_end:
             \mode_if_vertical:TF { \noindent \mode_leave_vertical: } \newline 
 %    \end{macrocode}
+% The following line is only to compute |\l_@@_lines_int| which will be used
+% only when both |left-margin=auto| and |skip-empty-lines = false| are in force.
+% You should change that.
+%    \begin{macrocode}
+            \lua_now:e { piton.CountLines ( '\lua_escape:n{##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
+            \l_@@_font_command_tl
             \dim_zero:N \parskip
-            \noindent % added 2024/08/07 
+            \noindent
 %    \end{macrocode}
 % 
 % Now, the key |write|.
@@ -4553,11 +4725,11 @@
             \str_if_empty:NTF \l_@@_write_str
               { \lua_now:n { piton.write = '' } }
               { 
-                \seq_if_in:NVTF \g_@@_write_seq \l_@@_write_str 
+                \seq_if_in:NoTF \g_@@_write_seq \l_@@_write_str 
                   { \lua_now:n { piton.write_mode = "a" } }
                   { 
                     \lua_now:n { piton.write_mode = "w" } 
-                    \seq_gput_left:NV \g_@@_write_seq \l_@@_write_str
+                    \seq_gput_left:No \g_@@_write_seq \l_@@_write_str
                   }
               }  
 %    \end{macrocode}
@@ -4565,8 +4737,8 @@
 % Now, the main job.
 %    \begin{macrocode}
             \bool_if:NTF \l_@@_split_on_empty_lines_bool
-              \@@_gobble_split_parse:n 
-              \@@_gobble_parse:n 
+              \@@_retrieve_gobble_split_parse:n 
+              \@@_retrieve_gobble_parse:n 
               { ##1 }
 %    \end{macrocode}
 %
@@ -4620,17 +4792,21 @@
 %
 % \bigskip
 % The following function will be used when the key |split-on-empty-lines| is not
-% in force. It will gobble the spaces at the beginning of the lines and parse
-% the code. The argument is provided by curryfication.
+% in force. It will retrieve the first empty line, gobble the spaces at the
+% beginning of the lines and parse the code. The argument is provided by
+% curryfication. 
 %    \begin{macrocode}
-\cs_new_protected:Npn \@@_gobble_parse:n 
+\cs_new_protected:Npn \@@_retrieve_gobble_parse:n 
   {
     \lua_now:e 
       { 
-        piton.GobbleParse
+        piton.RetrieveGobbleParse
           ( 
             '\l_piton_language_str' , 
             \int_use:N \l_@@_gobble_int ,
+            \bool_if:NTF \l_@@_splittable_on_empty_lines_bool
+              { \int_eval:n { - \l_@@_splittable_int } } 
+              { \int_use:N \l_@@_splittable_int } ,
             token.scan_argument ( )
           ) 
       } 
@@ -4643,14 +4819,15 @@
 % |gobble| is in force), then split the code at the empty lines and, eventually,
 % parse the code. The argument is provided by curryfication.
 %    \begin{macrocode}
-\cs_new_protected:Npn \@@_gobble_split_parse:n 
+\cs_new_protected:Npn \@@_retrieve_gobble_split_parse:n 
   {
     \lua_now:e 
       { 
-        piton.GobbleSplitParse
+        piton.RetrieveGobbleSplitParse
           ( 
             '\l_piton_language_str' , 
             \int_use:N \l_@@_gobble_int ,
+            \int_use:N \l_@@_splittable_int , 
             token.scan_argument ( )
           ) 
       } 
@@ -4690,21 +4867,38 @@
   {
     \group_begin:
 %    \end{macrocode}
-% The boolean |\l_tmap_bool| will be raised if the file is found somewhere in
-% the path (specified by the key |path|).
+% In version 4.0 of \pkg{piton}, we changed the mechanism used by \pkg{piton}
+% to search the file to load with |\PitonInputFile|. With the key
+% |old-PitonInputFile|, it's possible to keep the old behaviour but it's only
+% for backward compatibility and it will be deleted in a future version.
 %    \begin{macrocode}
-    \bool_set_false:N \l_tmpa_bool
-    \seq_map_inline:Nn \l_@@_path_seq 
+    \bool_if:NTF \l_@@_old_PitonInputFile_bool
       {
-        \str_set:Nn \l_@@_file_name_str { ##1 / #3 }
-        \file_if_exist:nT { \l_@@_file_name_str }
-          { 
-            \@@_input_file:nn { #1 } { #2 } 
-            \bool_set_true:N \l_tmpa_bool
-            \seq_map_break:
+        \bool_set_false:N \l_tmpa_bool
+        \seq_map_inline:Nn \l__piton_path_seq
+          {
+            \str_set:Nn \l__piton_file_name_str { ##1 / #3 }
+            \file_if_exist:nT { \l__piton_file_name_str }
+              {
+                \__piton_input_file:nn { #1 } { #2 }
+                \bool_set_true:N \l_tmpa_bool
+                \seq_map_break:
+              }
           }
+        \bool_if:NTF \l_tmpa_bool { #4 } { #5 }
       }
-    \bool_if:NTF \l_tmpa_bool { #4 } { #5 }
+      {
+        \seq_concat:NNN 
+          \l_file_search_path_seq 
+          \l_@@_path_seq
+          \l_file_search_path_seq  
+        \file_get_full_name:nNTF { #3 } \l_@@_file_name_str
+          {  
+            \@@_input_file:nn { #1 } { #2 }
+            #4
+          }
+          { #5 }
+      }
     \group_end:
   }
 %    \end{macrocode}
@@ -4791,8 +4985,7 @@
       \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.
+% stored by Lua in |\l_@@_nb_lines_int|. 
 %    \begin{macrocode}
       \lua_now:e { piton.CountLinesFile ( '\l_@@_file_name_str' ) } 
 %    \end{macrocode}
@@ -4801,7 +4994,7 @@
 %    \begin{macrocode}
       \@@_compute_left_margin:no { CountNonEmptyLinesFile } \l_@@_file_name_str
       \@@_compute_width:
-      \ttfamily
+      \l_@@_font_command_tl
       \lua_now:e
         { 
           piton.ParseFile(
@@ -4809,6 +5002,9 @@
            '\l_@@_file_name_str' ,
            \int_use:N \l_@@_first_line_int , 
            \int_use:N \l_@@_last_line_int ,
+           \bool_if:NTF \l_@@_splittable_on_empty_lines_bool
+             { \int_eval:n { - \l_@@_splittable_int } } 
+             { \int_use:N \l_@@_splittable_int } ,
            \bool_if:NTF \l_@@_split_on_empty_lines_bool { 1 } { 0 } ) 
         } 
       \bool_if:NT \l_@@_width_min_bool \@@_width_to_aux:
@@ -4820,7 +5016,7 @@
 % file (read by |\PitonInputFile|) is loaded during the compilation of the LaTeX
 % document. 
 %    \begin{macrocode}
-    \exp_args:Nx \iow_log:n {(\l_@@_file_name_str)}
+    \iow_log:e {(\l_@@_file_name_str)}
 %    \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}|
@@ -4843,15 +5039,15 @@
 % We store the markers in L3 strings (|str|) in order to do safely the following
 % replacement of |\#|.
 %    \begin{macrocode}
-    \str_set:Nx \l_tmpa_str { \@@_marker_beginning:n \l_@@_begin_range_str }
-    \str_set:Nx \l_tmpb_str { \@@_marker_end:n \l_@@_end_range_str }
+    \str_set:Ne \l_tmpa_str { \@@_marker_beginning:n \l_@@_begin_range_str }
+    \str_set:Ne \l_tmpb_str { \@@_marker_end:n \l_@@_end_range_str }
 %    \end{macrocode}
 % We replace the sequences |\#| which may be present in the prefixes (and, more
 % unlikely, suffixes) added to the markers by the functions
 % |\@@_marker_beginning:n| and |\@@_marker_end:n|
 %    \begin{macrocode}
-    \exp_args:NnV \regex_replace_all:nnN { \\\# } \c_hash_str \l_tmpa_str
-    \exp_args:NnV \regex_replace_all:nnN { \\\# } \c_hash_str \l_tmpb_str
+    \exp_args:Nno \regex_replace_all:nnN { \\\# } \c_hash_str \l_tmpa_str
+    \exp_args:Nno \regex_replace_all:nnN { \\\# } \c_hash_str \l_tmpb_str
     \lua_now:e
       { 
         piton.ComputeRange
@@ -4878,7 +5074,7 @@
 \NewDocumentCommand { \SetPitonStyle } { O { } m } 
   { 
     \str_clear_new:N \l_@@_SetPitonStyle_option_str
-    \str_set:Nx \l_@@_SetPitonStyle_option_str { \str_lowercase:n { #1 } }
+    \str_set:Ne \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 } 
@@ -4982,7 +5178,7 @@
 \SetPitonStyle[OCaml]
   {
     TypeExpression = 
-      \SetPitonStyle { Identifier = \PitonStyle { Name.Type } } \@@_piton:n 
+      \SetPitonStyle { Identifier = \PitonStyle { Name.Type } } \@@_piton:n ,
   }
 %    \end{macrocode}
 % 
@@ -5060,16 +5256,16 @@
 % ``internal style'' (not available for the final user). However, maybe we will
 % change that and document that style for the final user.
 %
-% \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)].
+% \medskip 
+% If the key |math-comments| has been used in the preamble of the LaTeX
+% document, 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}
-\AtBeginDocument 
+\hook_gput_code:nnn { begindocument } { . } 
   { 
     \bool_if:NT \g_@@_math_comments_bool 
-       { \SetPitonStyle { Comment.Math = \@@_math_scantokens:n } } 
+      { \SetPitonStyle { Comment.Math = \@@_math_scantokens:n } } 
   }
 %    \end{macrocode}
 % 
@@ -5090,7 +5286,7 @@
           { \cs_set:cpn { PitonIdentifier _ ##1 } { #3 } }
       }
       {
-        \str_set:Nx \l_tmpa_str { \str_lowercase:n { #1 } }
+        \str_set:Ne \l_tmpa_str { \str_lowercase:n { #1 } }
         \str_if_eq:onT \l_tmpa_str { current-language }
           { \str_set_eq:NN \l_tmpa_str \l_piton_language_str }
         \clist_map_inline:Nn \l_tmpa_clist 
@@ -5146,8 +5342,8 @@
 % We update |\g_@@_languages_seq| which is used only by the command
 % |\PitonClearUserFunctions| when it's used without its optional argument.
 %    \begin{macrocode}
-    \seq_if_in:NVF \g_@@_languages_seq \l_piton_language_str 
-      { \seq_gput_left:NV \g_@@_languages_seq \l_piton_language_str }
+    \seq_if_in:NoF \g_@@_languages_seq \l_piton_language_str 
+      { \seq_gput_left:No \g_@@_languages_seq \l_piton_language_str }
   }
 %    \end{macrocode}
 %
@@ -5327,7 +5523,7 @@
 \@@_msg_new:nn { SyntaxError }
   {
     Syntax~Error.\\
-    Your~code~of~the~language~"\l_piton_language_str"~is~not~
+    Your~code~of~the~language~'\l_piton_language_str'~is~not~
     syntactically~correct.\\  
     It~won't~be~printed~in~the~PDF~file.
   }
@@ -5399,6 +5595,8 @@
     end-of-broken-line,~
     end-range,~
     env-gobble,~
+    env-used-by-split,~
+    font-command,~
     gobble,~
     indent-broken-lines,~
     language,~
@@ -5413,6 +5611,7 @@
     show-spaces,~
     show-spaces-in-strings,~
     splittable,~
+    splittable-on-empty-lines,~
     split-on-empty-lines,~
     split-separation,~
     tabs-auto-gobble,~
@@ -5555,7 +5754,7 @@
 %    \begin{macrocode}
 local P, S, V, C, Ct, Cc = lpeg.P, lpeg.S, lpeg.V, lpeg.C, lpeg.Ct, lpeg.Cc
 local Cs , Cg , Cmt , Cb = lpeg.Cs, lpeg.Cg , lpeg.Cmt , lpeg.Cb 
-local R = lpeg.R
+local B , R = lpeg.B , lpeg.R
 %    \end{macrocode}
 %
 % 
@@ -5769,8 +5968,10 @@
 %    \end{macrocode}
 % 
 % \bigskip
+% Remember that |\@@_leading_space:| does \emph{not} create a space, only an
+% incrementation of the coutnter |\g_@@_indentation_int|.
 %    \begin{macrocode}
-local SpaceIndentation = Lc [[\@@_an_indentation_space:]] * Q " "
+local SpaceIndentation = Lc [[\@@_leading_space:]] * Q " "
 %    \end{macrocode}
 %
 % \bigskip
@@ -5836,11 +6037,11 @@
 %         
 % \bigskip
 % The following Lua function will compute the \text{lpeg} |DetectedCommands|
-% which is a \textsc{lpeg} with captures).
+% which is a \textsc{lpeg} with captures.
 %    \begin{macrocode}
 local function Compute_DetectedCommands ( lang , braces ) return 
   Ct ( Cc "Open" 
-        * C ( piton.DetectedCommands * P "{" ) 
+        * C ( piton.DetectedCommands * space ^ 0 * P "{" ) 
         * Cc "}" 
      ) 
    * ( braces 
@@ -5902,7 +6103,7 @@
 BeamerEndEnvironments = 
     ( space ^ 0 * 
       L ( P "\\end{" * piton.BeamerEnvironments * "}" ) 
-      * "\r" 
+      * "\r"
     ) ^ 0 
 %    \end{macrocode}
 %
@@ -5915,10 +6116,10 @@
 local function Compute_Beamer ( lang , braces ) 
 %    \end{macrocode}
 %
-% \bigskip
+% \smallskip
 % We will compute in |lpeg| the \textsc{lpeg} that we will return.
 %    \begin{macrocode}
-  local lpeg = L ( P "\\pause" * ( "[" * ( 1 - P "]" ) ^ 0 * "]" ) ^ -1 ) 
+  local lpeg = L ( P [[\pause]] * ( "[" * ( 1 - P "]" ) ^ 0 * "]" ) ^ -1 ) 
   lpeg = lpeg + 
       Ct ( Cc "Open" 
             * C ( piton.BeamerCommands
@@ -5939,7 +6140,7 @@
 % brackets) is mandatory. 
 %    \begin{macrocode}
   lpeg = lpeg +
-    L ( P "\\alt" * "<" * ( 1 - P ">" ) ^ 0 * ">" * "{" )
+    L ( P [[\alt]] * "<" * ( 1 - P ">" ) ^ 0 * ">" * "{" )
      * ( braces / 
          ( function ( s ) if s ~= '' then return LPEG1[lang] : match ( s ) end end ) )
      * L ( P "}{" )
@@ -5953,7 +6154,7 @@
 % is mandatory. 
 %    \begin{macrocode}
   lpeg = lpeg +
-      L ( ( P "\\temporal" ) * "<" * ( 1 - P ">" ) ^ 0 * ">" * "{" )
+      L ( ( P [[\temporal]] ) * "<" * ( 1 - P ">" ) ^ 0 * ">" * "{" )
       * ( braces 
           / ( function ( s ) 
               if s ~= '' then return LPEG1[lang] : match ( s ) end end ) )
@@ -6022,7 +6223,7 @@
 % |\@@_begin_line:|, it's too late to change de background).
 %    \begin{macrocode}
 local PromptHastyDetection = 
-  ( # ( P ">>>" + "..." ) * Lc '\\@@_prompt:' ) ^ -1 
+  ( # ( 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.
@@ -6039,11 +6240,11 @@
 % \bigskip
 % The following \textsc{lpeg} |EOL| is for the end of lines.
 %    \begin{macrocode}
-local EOL_without_space_indentation = 
+local EOL = 
   P "\r" 
   *
   (
-    ( space ^ 0 * -1 )
+    space ^ 0 * -1 
     + 
 %    \end{macrocode}
 % We recall that each line of the informatic code we have to parse will be sent
@@ -6055,22 +6256,30 @@
     Ct ( 
          Cc "EOL"
          * 
-         Ct (
-              Lc [[\@@_end_line:]]
+         Ct ( Lc [[\@@_end_line:]]
               * BeamerEndEnvironments 
-              * BeamerBeginEnvironments 
-              * PromptHastyDetection
-              * Lc [[\@@_newline:\@@_begin_line:]]
-              * Prompt
+              *
+                (
+%    \end{macrocode}
+% If the last line of the listing is the end of an environment of Beamer (eg.
+% |\end{uncoverenv}|), then, we don't open a new line. A token |\@@_end_line:|
+% will be added at the end of the environment but it will be no-op since we have
+% defined the macro |\@@_end_line:| to be no-op (even though it is also used as
+% a marker for the TeX delimited macro |\@@_begin_line:|).
+%    \begin{macrocode}
+                    -1 
+                  + 
+                    BeamerBeginEnvironments 
+                  * PromptHastyDetection
+                  * Lc [[\@@_newline:\@@_begin_line:]]
+                  * Prompt
+                )
             )
        )
   ) 
+  * ( SpaceIndentation ^ 0 * # ( 1 - S " \r" ) ) ^ -1
 %    \end{macrocode}
 %
-%    \begin{macrocode}
-local EOL = EOL_without_space_indentation  
-  * ( SpaceIndentation ^ 0 * # ( 1 - S " \r" ) ) ^ -1
-%    \end{macrocode}
 % 
 % \bigskip
 % The following \textsc{lpeg} |CommentLaTeX| is for what is called in that
@@ -6079,10 +6288,10 @@
 % 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" 
+  P ( piton.comment_latex ) 
+  * Lc [[{\PitonStyle{Comment.LaTeX}{\ignorespaces]]
   * L ( ( 1 - P "\r" ) ^ 0 ) 
-  * Lc "}}" 
+  * Lc [[}}]]
   * ( EOL + -1 )  
 %    \end{macrocode}
 % 
@@ -6091,77 +6300,81 @@
 % \bigskip
 % \subsubsection{The language Python}
 % 
+% We open a Lua local scope for the language Python (of course, there will be
+% also global definitions).
+%    \begin{macrocode}
+do 
+%    \end{macrocode}
+%
 % \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 "!=" + "<>" + "==" + "<<" + ">>" + "<=" + ">=" + ":=" + "//" + "**" 
-      + S "-~+/*%=<>&.@|" )
+  local Operator = 
+    K ( 'Operator' ,
+        P "!=" + "<>" + "==" + "<<" + ">>" + "<=" + ">=" + ":=" + "//" + "**" 
+        + S "-~+/*%=<>&.@|" )
 
-local OperatorWord = 
-  K ( 'Operator.Word' , P "in" + "is" + "and" + "or" + "not" )
+  local OperatorWord = 
+    K ( 'Operator.Word' , P "in" + "is" + "and" + "or" + "not" )
 %    \end{macrocode}
 %
 % \smallskip
 % The keyword |in| in a construction such as ``|for i in range(n)|'' must be
-% formatted as a keyword and not as an |Operator.Word|.
+% formatted as a keyword and not as an |Operator.Word| and that's why we write
+% the following LPEG |For|.
 %    \begin{macrocode}
-local For = K ( 'Keyword' , P "for" ) 
-            * Space
-            * Identifier
-            * Space 
-            * K ( 'Keyword' , P "in" ) 
+  local For = K ( 'Keyword' , P "for" ) 
+              * Space
+              * Identifier
+              * Space 
+              * K ( 'Keyword' , P "in" ) 
 
-local Keyword = 
-  K ( 'Keyword' ,
-      P "as" + "assert" + "break" + "case" + "class" + "continue" + "def" +
-      "del" + "elif" + "else" + "except" + "exec" + "finally" + "for" + "from" +
-      "global" + "if" + "import" + "lambda" + "non local" + "pass" + "return" +
-      "try" + "while" + "with" + "yield" + "yield from" )
-  + K ( 'Keyword.Constant' , P "True" + "False" + "None" ) 
+  local Keyword = 
+    K ( 'Keyword' ,
+        P "as" + "assert" + "break" + "case" + "class" + "continue" + "def" +
+        "del" + "elif" + "else" + "except" + "exec" + "finally" + "for" + "from" +
+        "global" + "if" + "import" + "lambda" + "non local" + "pass" + "return" +
+        "try" + "while" + "with" + "yield" + "yield from" )
+    + K ( 'Keyword.Constant' , P "True" + "False" + "None" ) 
 
-local Builtin = 
-  K ( 'Name.Builtin' ,
-      P "__import__" + "abs" + "all" + "any" + "bin" + "bool" + "bytearray" +
-      "bytes" + "chr" + "classmethod" + "compile" + "complex" + "delattr" +
-      "dict" + "dir" + "divmod" + "enumerate" + "eval" + "filter" + "float" +
-      "format" + "frozenset" + "getattr" + "globals" + "hasattr" + "hash" +
-      "hex" + "id" + "input" + "int" + "isinstance" + "issubclass" + "iter" +
-      "len" + "list" + "locals" + "map" + "max" + "memoryview" + "min" + "next"
-      + "object" + "oct" + "open" + "ord" + "pow" + "print" + "property" +
-      "range" + "repr" + "reversed" + "round" + "set" + "setattr" + "slice" +
-      "sorted" + "staticmethod" + "str" + "sum" + "super" + "tuple" + "type" +
-      "vars" + "zip" ) 
+  local Builtin = 
+    K ( 'Name.Builtin' ,
+        P "__import__" + "abs" + "all" + "any" + "bin" + "bool" + "bytearray" +
+        "bytes" + "chr" + "classmethod" + "compile" + "complex" + "delattr" +
+        "dict" + "dir" + "divmod" + "enumerate" + "eval" + "filter" + "float" +
+        "format" + "frozenset" + "getattr" + "globals" + "hasattr" + "hash" +
+        "hex" + "id" + "input" + "int" + "isinstance" + "issubclass" + "iter" +
+        "len" + "list" + "locals" + "map" + "max" + "memoryview" + "min" + "next"
+        + "object" + "oct" + "open" + "ord" + "pow" + "print" + "property" +
+        "range" + "repr" + "reversed" + "round" + "set" + "setattr" + "slice" +
+        "sorted" + "staticmethod" + "str" + "sum" + "super" + "tuple" + "type" +
+        "vars" + "zip" ) 
 
+  local Exception =
+    K ( 'Exception' ,
+        P "ArithmeticError" + "AssertionError" + "AttributeError" +
+        "BaseException" + "BufferError" + "BytesWarning" + "DeprecationWarning" +
+        "EOFError" + "EnvironmentError" + "Exception" + "FloatingPointError" +
+        "FutureWarning" + "GeneratorExit" + "IOError" + "ImportError" +
+        "ImportWarning" + "IndentationError" + "IndexError" + "KeyError" +
+        "KeyboardInterrupt" + "LookupError" + "MemoryError" + "NameError" +
+        "NotImplementedError" + "OSError" + "OverflowError" +
+        "PendingDeprecationWarning" + "ReferenceError" + "ResourceWarning" +
+        "RuntimeError" + "RuntimeWarning" + "StopIteration" + "SyntaxError" +
+        "SyntaxWarning" + "SystemError" + "SystemExit" + "TabError" + "TypeError"
+        + "UnboundLocalError" + "UnicodeDecodeError" + "UnicodeEncodeError" +
+        "UnicodeError" + "UnicodeTranslateError" + "UnicodeWarning" +
+        "UserWarning" + "ValueError" + "VMSError" + "Warning" + "WindowsError" +
+        "ZeroDivisionError" + "BlockingIOError" + "ChildProcessError" +
+        "ConnectionError" + "BrokenPipeError" + "ConnectionAbortedError" +
+        "ConnectionRefusedError" + "ConnectionResetError" + "FileExistsError" +
+        "FileNotFoundError" + "InterruptedError" + "IsADirectoryError" +
+        "NotADirectoryError" + "PermissionError" + "ProcessLookupError" +
+        "TimeoutError" + "StopAsyncIteration" + "ModuleNotFoundError" +
+        "RecursionError" ) 
 
-local Exception =
-  K ( 'Exception' ,
-      P "ArithmeticError" + "AssertionError" + "AttributeError" +
-      "BaseException" + "BufferError" + "BytesWarning" + "DeprecationWarning" +
-      "EOFError" + "EnvironmentError" + "Exception" + "FloatingPointError" +
-      "FutureWarning" + "GeneratorExit" + "IOError" + "ImportError" +
-      "ImportWarning" + "IndentationError" + "IndexError" + "KeyError" +
-      "KeyboardInterrupt" + "LookupError" + "MemoryError" + "NameError" +
-      "NotImplementedError" + "OSError" + "OverflowError" +
-      "PendingDeprecationWarning" + "ReferenceError" + "ResourceWarning" +
-      "RuntimeError" + "RuntimeWarning" + "StopIteration" + "SyntaxError" +
-      "SyntaxWarning" + "SystemError" + "SystemExit" + "TabError" + "TypeError"
-      + "UnboundLocalError" + "UnicodeDecodeError" + "UnicodeEncodeError" +
-      "UnicodeError" + "UnicodeTranslateError" + "UnicodeWarning" +
-      "UserWarning" + "ValueError" + "VMSError" + "Warning" + "WindowsError" +
-      "ZeroDivisionError" + "BlockingIOError" + "ChildProcessError" +
-      "ConnectionError" + "BrokenPipeError" + "ConnectionAbortedError" +
-      "ConnectionRefusedError" + "ConnectionResetError" + "FileExistsError" +
-      "FileNotFoundError" + "InterruptedError" + "IsADirectoryError" +
-      "NotADirectoryError" + "PermissionError" + "ProcessLookupError" +
-      "TimeoutError" + "StopAsyncIteration" + "ModuleNotFoundError" +
-      "RecursionError" ) 
-
-
-local RaiseException = K ( 'Keyword' , P "raise" ) * SkipSpace * Exception * Q "("  
-
+  local RaiseException = K ( 'Keyword' , P "raise" ) * SkipSpace * Exception * Q "("  
 %    \end{macrocode}
 %
 % \bigskip
@@ -6168,7 +6381,7 @@
 % 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  ) 
+  local Decorator = K ( 'Name.Decorator' , P "@" * letter ^ 1  ) 
 %    \end{macrocode}
 % 
 % \bigskip
@@ -6179,8 +6392,8 @@
 % \smallskip
 % Example:\enskip \piton{class myclass:}
 %    \begin{macrocode}
-local DefClass = 
-  K ( 'Keyword' , "class" ) * Space * K ( 'Name.Class' , identifier ) 
+  local DefClass = 
+    K ( 'Keyword' , "class" ) * Space * K ( 'Name.Class' , identifier ) 
 %    \end{macrocode}
 % 
 % If the word |class| is not followed by a identifier, it will be caught as
@@ -6187,7 +6400,6 @@
 % 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
@@ -6203,17 +6415,17 @@
 % \smallskip
 % Example:\enskip \piton{import math, numpy}
 %    \begin{macrocode}
-local ImportAs = 
-  K ( 'Keyword' , "import" )
-   * Space 
-   * K ( 'Name.Namespace' , identifier * ( "." * identifier ) ^ 0 )
-   * ( 
-       ( Space * K ( 'Keyword' , "as" ) * Space 
-          * K ( 'Name.Namespace' , identifier ) )
-       + 
-       ( SkipSpace * Q "," * SkipSpace 
-          * K ( 'Name.Namespace' , identifier ) ) ^ 0 
-     ) 
+  local ImportAs = 
+    K ( 'Keyword' , "import" )
+     * Space 
+     * K ( 'Name.Namespace' , identifier * ( "." * identifier ) ^ 0 )
+     * ( 
+         ( Space * K ( 'Keyword' , "as" ) * Space 
+            * K ( 'Name.Namespace' , identifier ) )
+         + 
+         ( SkipSpace * Q "," * SkipSpace 
+            * K ( 'Name.Namespace' , identifier ) ) ^ 0 
+       ) 
 %    \end{macrocode}
 % Be careful: there is no commutativity of |+| in the previous expression.
 %
@@ -6229,10 +6441,10 @@
 %
 % \smallskip
 %    \begin{macrocode}
-local FromImport =
-  K ( 'Keyword' , "from" ) 
-    * Space * K ( 'Name.Namespace' , identifier )
-    * Space * K ( 'Keyword' , "import" ) 
+  local FromImport =
+    K ( 'Keyword' , "from" ) 
+      * Space * K ( 'Name.Namespace' , identifier )
+      * Space * K ( 'Keyword' , "import" ) 
 %    \end{macrocode}
 %
 % \bigskip
@@ -6269,16 +6481,16 @@
 % The interpolations beginning by |%| (even though there is more modern
 % techniques now in Python).
 %    \begin{macrocode}
-local PercentInterpol =  
-  K ( 'String.Interpol' , 
-      P "%" 
-      * ( "(" * alphanum ^ 1 * ")" ) ^ -1 
-      * ( S "-#0 +" ) ^ 0 
-      * ( digit ^ 1 + "*" ) ^ -1 
-      * ( "." * ( digit ^ 1 + "*" ) ) ^ -1 
-      * ( S "HlL" ) ^ -1
-      * S "sdfFeExXorgiGauc%" 
-    ) 
+  local PercentInterpol =  
+    K ( 'String.Interpol' , 
+        P "%" 
+        * ( "(" * alphanum ^ 1 * ")" ) ^ -1 
+        * ( S "-#0 +" ) ^ 0 
+        * ( digit ^ 1 + "*" ) ^ -1 
+        * ( "." * ( digit ^ 1 + "*" ) ) ^ -1 
+        * ( S "HlL" ) ^ -1
+        * S "sdfFeExXorgiGauc%" 
+      ) 
 %    \end{macrocode}
 % 
 % \bigskip
@@ -6289,61 +6501,61 @@
 % |Interpol.Inside|. The initial value of that style is \texttt{\textbackslash
 % @@\_piton:n} which means that the interpolations are parsed once again by \pkg{piton}.}
 %    \begin{macrocode}
-local SingleShortString =
-  WithStyle ( 'String.Short' ,
+  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'" + "F'" ) 
-         * ( 
-             K ( 'String.Interpol' , "{" )
-              * K ( 'Interpol.Inside' , ( 1 - S "}':" ) ^ 0  )
-              * Q ( P ":" * ( 1 - S "}:'" ) ^ 0 ) ^ -1
-              * K ( 'String.Interpol' , "}" )
-             + 
-             VisualSpace 
-             + 
-             Q ( ( P "\\'" + "{{" + "}}" + 1 - S " {}'" ) ^ 1 )
-           ) ^ 0 
-         * Q "'" 
-       + 
+           Q ( P "f'" + "F'" ) 
+           * ( 
+               K ( 'String.Interpol' , "{" )
+                * K ( 'Interpol.Inside' , ( 1 - S "}':" ) ^ 0  )
+                * Q ( P ":" * ( 1 - S "}:'" ) ^ 0 ) ^ -1
+                * K ( 'String.Interpol' , "}" )
+               + 
+               VisualSpace 
+               + 
+               Q ( ( P "\\'" + "\\\\" + "{{" + "}}" + 1 - S " {}'" ) ^ 1 )
+             ) ^ 0 
+           * Q "'" 
+         + 
 %    \end{macrocode}
 % Now, we deal with the standard strings of Python, but also the ``raw strings''.
 %    \begin{macrocode}
-         Q ( P "'" + "r'" + "R'" ) 
-         * ( Q ( ( P "\\'" + 1 - S " '\r%" ) ^ 1 ) 
-             + VisualSpace 
-             + PercentInterpol 
-             + Q "%" 
-           ) ^ 0 
-         * Q "'" )
+           Q ( P "'" + "r'" + "R'" ) 
+           * ( Q ( ( P "\\'" + "\\\\" + 1 - S " '\r%" ) ^ 1 ) 
+               + VisualSpace 
+               + PercentInterpol 
+               + Q "%" 
+             ) ^ 0 
+           * Q "'" )
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+  local DoubleShortString =
+    WithStyle ( 'String.Short' , 
+           Q ( P "f\"" + "F\"" ) 
+           * ( 
+               K ( 'String.Interpol' , "{" )
+                 * K ( 'Interpol.Inside' , ( 1 - S "}\":" ) ^ 0 )
+                 * ( K ( 'String.Interpol' , ":" ) * Q ( (1 - S "}:\"") ^ 0 ) ) ^ -1
+                 * K ( 'String.Interpol' , "}" )
+               + 
+               VisualSpace 
+               + 
+               Q ( ( P "\\\"" + "\\\\" + "{{" + "}}" + 1 - S " {}\"" ) ^ 1 ) 
+              ) ^ 0
+           * Q "\"" 
+         +
+           Q ( P "\"" + "r\"" + "R\"" ) 
+           * ( Q ( ( P "\\\"" + "\\\\" + 1 - S " \"\r%" ) ^ 1 ) 
+               + VisualSpace 
+               + PercentInterpol 
+               + Q "%"
+             ) ^ 0 
+           * Q "\""  )
 
-
-
-local DoubleShortString =
-  WithStyle ( 'String.Short' , 
-         Q ( P "f\"" + "F\"" ) 
-         * ( 
-             K ( 'String.Interpol' , "{" )
-               * K ( 'Interpol.Inside' , ( 1 - S "}\":" ) ^ 0 )
-               * ( K ( 'String.Interpol' , ":" ) * Q ( (1 - S "}:\"") ^ 0 ) ) ^ -1
-               * K ( 'String.Interpol' , "}" )
-             + 
-             VisualSpace 
-             + 
-             Q ( ( P "\\\"" + "{{" + "}}" + 1 - S " {}\"" ) ^ 1 ) 
-            ) ^ 0
-         * Q "\"" 
-       +
-         Q ( P "\"" + "r\"" + "R\"" ) 
-         * ( Q ( ( P "\\\"" + 1 - S " \"\r%" ) ^ 1 ) 
-             + VisualSpace 
-             + PercentInterpol 
-             + Q "%"
-           ) ^ 0 
-         * Q "\""  )
-
-local ShortString = SingleShortString + DoubleShortString
+  local ShortString = SingleShortString + DoubleShortString
 %    \end{macrocode}
 %
 % \bigskip
@@ -6353,16 +6565,16 @@
 % catching} corresponding to the strings of the language.
 %
 %    \begin{macrocode}
-local braces = 
-  Compute_braces 
-   (
-       ( P "\"" + "r\"" + "R\"" + "f\"" + "F\"" ) 
-           * ( P "\\\"" + 1 - S "\"" ) ^ 0 * "\""  
-     + 
-       ( P '\'' + 'r\'' + 'R\'' + 'f\'' + 'F\'' ) 
-           * ( P '\\\'' + 1 - S '\'' ) ^ 0 * '\''  
-   )
-if piton.beamer then Beamer = Compute_Beamer ( 'python' , braces ) end
+  local braces = 
+    Compute_braces 
+     (
+         ( P "\"" + "r\"" + "R\"" + "f\"" + "F\"" ) 
+             * ( P "\\\"" + 1 - S "\"" ) ^ 0 * "\""  
+       + 
+         ( P '\'' + 'r\'' + 'R\'' + 'f\'' + 'F\'' ) 
+             * ( P '\\\'' + 1 - S '\'' ) ^ 0 * '\''  
+     )
+  if piton.beamer then Beamer = Compute_Beamer ( 'python' , braces ) end
 %    \end{macrocode}
 %
 % \bigskip
@@ -6369,7 +6581,7 @@
 % \paragraph{Detected commands}
 %
 %    \begin{macrocode}
-DetectedCommands = Compute_DetectedCommands ( 'python' , braces ) 
+  DetectedCommands = Compute_DetectedCommands ( 'python' , braces ) 
 %    \end{macrocode}
 %
 % \bigskip
@@ -6377,7 +6589,7 @@
 % \paragraph{LPEG_cleaner}
 %
 %    \begin{macrocode}
-LPEG_cleaner['python'] = Compute_LPEG_cleaner ( 'python' , braces ) 
+  LPEG_cleaner['python'] = Compute_LPEG_cleaner ( 'python' , braces ) 
 %    \end{macrocode}
 % 
 % \bigskip
@@ -6385,66 +6597,67 @@
 % 
 % 
 %    \begin{macrocode}
-local SingleLongString =
-  WithStyle ( 'String.Long' , 
-     ( Q ( S "fF" * P "'''" )
-         * (
-             K ( 'String.Interpol' , "{" )
-               * K ( 'Interpol.Inside' , ( 1 - S "}:\r" - "'''" ) ^ 0  )
-               * Q ( P ":" * (1 - S "}:\r" - "'''" ) ^ 0 ) ^ -1
-               * K ( 'String.Interpol' , "}"  )
-             + 
-             Q ( ( 1 - P "'''" - S "{}'\r" ) ^ 1 )
-             + 
-             EOL
-           ) ^ 0 
-       +
-         Q ( ( S "rR" ) ^ -1  * "'''" )
-         * (
-             Q ( ( 1 - P "'''" - S "\r%" ) ^ 1 )  
-             + 
-             PercentInterpol
-             +
-             P "%"
-             +
-             EOL
-           ) ^ 0 
-      )
-      * Q "'''"  ) 
-
-
-local DoubleLongString =
-  WithStyle ( 'String.Long' ,
-     (
-        Q ( S "fF" * "\"\"\"" )
-        * (
-            K ( 'String.Interpol', "{"  )
-              * K ( 'Interpol.Inside' , ( 1 - S "}:\r" - "\"\"\"" ) ^ 0 )
-              * Q ( ":" * (1 - S "}:\r" - "\"\"\"" ) ^ 0 ) ^ -1
-              * K ( 'String.Interpol' , "}"  )
-            + 
-            Q ( ( 1 - S "{}\"\r" - "\"\"\"" ) ^ 1 ) 
-            + 
-            EOL
-          ) ^ 0 
-      +
-        Q ( S "rR" ^ -1  * "\"\"\"" )
-        * (
-            Q ( ( 1 - P "\"\"\"" - S "%\r" ) ^ 1 )  
-            + 
-            PercentInterpol 
-            + 
-            P "%"
-            + 
-            EOL
-          ) ^ 0 
-     )
-     * Q "\"\"\"" 
-  ) 
+  local SingleLongString =
+    WithStyle ( 'String.Long' , 
+       ( Q ( S "fF" * P "'''" )
+           * (
+               K ( 'String.Interpol' , "{" )
+                 * K ( 'Interpol.Inside' , ( 1 - S "}:\r" - "'''" ) ^ 0  )
+                 * Q ( P ":" * (1 - S "}:\r" - "'''" ) ^ 0 ) ^ -1
+                 * K ( 'String.Interpol' , "}"  )
+               + 
+               Q ( ( 1 - P "'''" - S "{}'\r" ) ^ 1 )
+               + 
+               EOL
+             ) ^ 0 
+         +
+           Q ( ( S "rR" ) ^ -1  * "'''" )
+           * (
+               Q ( ( 1 - P "'''" - S "\r%" ) ^ 1 )  
+               + 
+               PercentInterpol
+               +
+               P "%"
+               +
+               EOL
+             ) ^ 0 
+        )
+        * Q "'''"  ) 
 %    \end{macrocode}
+%   
+%    \begin{macrocode}
+  local DoubleLongString =
+    WithStyle ( 'String.Long' ,
+       (
+          Q ( S "fF" * "\"\"\"" )
+          * (
+              K ( 'String.Interpol', "{"  )
+                * K ( 'Interpol.Inside' , ( 1 - S "}:\r" - "\"\"\"" ) ^ 0 )
+                * Q ( ":" * (1 - S "}:\r" - "\"\"\"" ) ^ 0 ) ^ -1
+                * K ( 'String.Interpol' , "}"  )
+              + 
+              Q ( ( 1 - S "{}\"\r" - "\"\"\"" ) ^ 1 ) 
+              + 
+              EOL
+            ) ^ 0 
+        +
+          Q ( S "rR" ^ -1  * "\"\"\"" )
+          * (
+              Q ( ( 1 - P "\"\"\"" - S "%\r" ) ^ 1 )  
+              + 
+              PercentInterpol 
+              + 
+              P "%"
+              + 
+              EOL
+            ) ^ 0 
+       )
+       * Q "\"\"\"" 
+    ) 
+%    \end{macrocode}
 %
 %    \begin{macrocode}
-local LongString = SingleLongString + DoubleLongString
+  local LongString = SingleLongString + DoubleLongString
 %    \end{macrocode}
 %
 % \bigskip
@@ -6452,12 +6665,12 @@
 % 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 "r" ^ -1 * "\"\"\"" )
-      * ( K ( 'String.Doc' , (1 - P "\"\"\"" - "\r" ) ^ 0  ) * EOL
-          * Tab ^ 0 
-        ) ^ 0
-      * K ( 'String.Doc' , ( 1 - P "\"\"\"" - "\r" ) ^ 0 * "\"\"\"" )
+  local StringDoc = 
+      K ( 'String.Doc' , P "r" ^ -1 * "\"\"\"" )
+        * ( K ( 'String.Doc' , (1 - P "\"\"\"" - "\r" ) ^ 0  ) * EOL
+            * Tab ^ 0 
+          ) ^ 0
+        * K ( 'String.Doc' , ( 1 - P "\"\"\"" - "\r" ) ^ 0 * "\"\"\"" )
 %    \end{macrocode}
 %
 % \bigskip
@@ -6466,10 +6679,12 @@
 % We define different \textsc{lpeg} dealing with comments in the Python
 % listings.
 %    \begin{macrocode}
-local Comment = 
-  WithStyle ( 'Comment' ,
-     Q "#" * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0 ) -- $
-           * ( EOL + -1 )
+  local Comment = 
+    WithStyle 
+     ( 'Comment' ,
+       Q "#" * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0  -- $
+     ) 
+    * ( EOL + -1 )
 %    \end{macrocode}
 % 
 % 
@@ -6482,19 +6697,19 @@
 % (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 "\\'" + 1 - S "'\r" ) ^ 0 * "'" 
-             + "\"" * ( P "\\\"" + 1 - S "\"\r" ) ^ 0 * "\""
-             + "{" * V "F" * "}"
-             + "(" * V "F" * ")"
-             + "[" * V "F" * "]" 
-             + ( 1 - S "{}()[]\r," ) ) ^ 0 ,
-       F = (   "{" * V "F" * "}"
-             + "(" * V "F" * ")"
-             + "[" * V "F" * "]"
-             + ( 1 - S "{}()[]\r\"'" ) ) ^ 0
-    }
+  local expression =
+    P { "E" ,
+         E = ( "'" * ( P "\\'" + 1 - S "'\r" ) ^ 0 * "'" 
+               + "\"" * ( P "\\\"" + 1 - S "\"\r" ) ^ 0 * "\""
+               + "{" * V "F" * "}"
+               + "(" * V "F" * ")"
+               + "[" * V "F" * "]" 
+               + ( 1 - S "{}()[]\r," ) ) ^ 0 ,
+         F = (   "{" * V "F" * "}"
+               + "(" * V "F" * ")"
+               + "[" * V "F" * "]"
+               + ( 1 - S "{}()[]\r\"'" ) ) ^ 0
+      }
 %    \end{macrocode}
 %
 % \bigskip 
@@ -6508,15 +6723,15 @@
 %
 % \medskip
 %    \begin{macrocode}
-local Params = 
-  P { "E" , 
-       E = ( V "F" * ( Q "," * V "F" ) ^ 0 ) ^ -1 ,
-       F = SkipSpace * ( Identifier + Q "*args" + Q "**kwargs" ) * SkipSpace
-           * ( 
-                 K ( 'InitialValues' , "=" * expression )
-               + Q ":" * SkipSpace * K ( 'Name.Type' , identifier ) 
-             ) ^ -1
-    }
+  local Params = 
+    P { "E" , 
+         E = ( V "F" * ( Q "," * V "F" ) ^ 0 ) ^ -1 ,
+         F = SkipSpace * ( Identifier + Q "*args" + Q "**kwargs" ) * SkipSpace
+             * ( 
+                   K ( 'InitialValues' , "=" * expression )
+                 + Q ":" * SkipSpace * K ( 'Name.Type' , identifier ) 
+               ) ^ -1
+      }
 %    \end{macrocode}
 % 
 % 
@@ -6527,14 +6742,14 @@
 % |piton.sty|) after the definition of several other \textsc{lpeg} such as
 % |Comment|, |CommentLaTeX|, |Params|, |StringDoc|...
 %    \begin{macrocode}
-local DefFunction =
-  K ( 'Keyword' , "def" )
-  * Space
-  * K ( 'Name.Function.Internal' , identifier ) 
-  * SkipSpace 
-  * Q "("  * Params * Q ")" 
-  * SkipSpace
-  * ( Q "->" * SkipSpace * K ( 'Name.Type' , identifier ) ) ^ -1
+  local DefFunction =
+    K ( 'Keyword' , "def" )
+    * Space
+    * K ( 'Name.Function.Internal' , identifier ) 
+    * SkipSpace 
+    * Q "("  * Params * Q ")" 
+    * SkipSpace
+    * ( Q "->" * SkipSpace * K ( 'Name.Type' , identifier ) ) ^ -1
 %    \end{macrocode}
 % Here, we need a \pkg{piton} style |ParseAgain.noCR| which will be linked to
 % |\@@_piton_no_cr:n| (that means that the capture will be parsed once again by
@@ -6541,14 +6756,14 @@
 % \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.noCR' , ( 1 - S ":\r" ) ^ 0 ) 
-  * Q ":" 
-  * ( SkipSpace
-      * ( EOL + CommentLaTeX + Comment ) -- in all cases, that contains an EOL
-      * Tab ^ 0 
-      * SkipSpace
-      * StringDoc ^ 0 -- there may be additional docstrings 
-    ) ^ -1
+    * K ( 'ParseAgain.noCR' , ( 1 - S ":\r" ) ^ 0 ) 
+    * Q ":" 
+    * ( SkipSpace
+        * ( EOL + CommentLaTeX + Comment ) -- in all cases, that contains an EOL
+        * Tab ^ 0 
+        * SkipSpace
+        * StringDoc ^ 0 -- there may be additional 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
@@ -6563,7 +6778,7 @@
 % \paragraph{Miscellaneous}
 % 
 %    \begin{macrocode}
-local ExceptionInConsole = Exception *  Q ( ( 1 - P "\r" ) ^ 0 ) * EOL 
+  local ExceptionInConsole = Exception *  Q ( ( 1 - P "\r" ) ^ 0 ) * EOL 
 %    \end{macrocode}
 % 
 % 
@@ -6571,44 +6786,44 @@
 % \paragraph{The main LPEG for the language Python}
 %
 %    \begin{macrocode}
-local EndKeyword = Space + Punct + Delim + EOL + Beamer + DetectedCommands + -1 
+  local EndKeyword = Space + Punct + Delim + EOL + Beamer + DetectedCommands + -1 
 %    \end{macrocode}
 %
 % First, the main loop :
 %    \begin{macrocode}
-local Main = 
-     --   space ^ 1 * -1
-     -- + space ^ 0 * EOL 
-     Space 
-     + Tab
-     + Escape + EscapeMath
-     + CommentLaTeX
-     + Beamer
-     + DetectedCommands 
-     + LongString 
-     + Comment
-     + ExceptionInConsole
-     + Delim
-     + Operator
-     + OperatorWord * EndKeyword
-     + ShortString
-     + Punct
-     + FromImport
-     + RaiseException 
-     + DefFunction
-     + DefClass 
-     + For
-     + Keyword * EndKeyword
-     + Decorator
-     + Builtin * EndKeyword
-     + Identifier 
-     + Number
-     + Word
+  local Main = 
+       space ^ 0 * EOL -- faut-il le mettre en commentaire ?
+       + Space 
+       + Tab
+       + Escape + EscapeMath
+       + CommentLaTeX
+       + Beamer
+       + DetectedCommands 
+       + LongString 
+       + Comment
+       + ExceptionInConsole
+       + Delim
+       + Operator
+       + OperatorWord * EndKeyword
+       + ShortString
+       + Punct
+       + FromImport
+       + RaiseException 
+       + DefFunction
+       + DefClass 
+       + For
+       + Keyword * EndKeyword
+       + Decorator
+       + Builtin * EndKeyword
+       + Identifier 
+       + Number
+       + Word
 %    \end{macrocode}
 %
+% \bigskip
 % Here, we must not put |local|!
 %    \begin{macrocode}
-LPEG1['python'] = Main ^ 0 
+  LPEG1['python'] = Main ^ 0 
 %    \end{macrocode}
 %
 % \bigskip
@@ -6618,547 +6833,654 @@
 % will be used as marker in order to delimit the argument of the command
 % \texttt{\textbackslash @@\_begin\_line:}}.
 %    \begin{macrocode}
-LPEG2['python'] = 
-  Ct (
-       ( space ^ 0 * "\r" ) ^ -1 
-       * BeamerBeginEnvironments 
-       * PromptHastyDetection
-       * Lc [[\@@_begin_line:]]
-       * Prompt 
-       * SpaceIndentation ^ 0 
-       * ( space ^ 1 * -1 + space ^ 0 * EOL + Main ) ^ 0 
-       * -1 
-       * Lc [[\@@_end_line:]] 
-     )
+  LPEG2['python'] = 
+    Ct (
+         ( space ^ 0 * "\r" ) ^ -1 
+         * BeamerBeginEnvironments 
+         * PromptHastyDetection
+         * Lc [[\@@_begin_line:]]
+         * Prompt 
+         * SpaceIndentation ^ 0 
+         * ( space ^ 1 * -1 + space ^ 0 * EOL + Main ) ^ 0 
+         * -1 
+         * Lc [[\@@_end_line:]] 
+       )
 %    \end{macrocode}
 %
+% \bigskip
+% End of the Lua scope for the language Python.
+%    \begin{macrocode}
+end
+%    \end{macrocode}
 %
 % \bigskip
 % \subsubsection{The language Ocaml}
 %
+% We open a Lua local scope for the language OCaml (of course, there will be also
+% global definitions).
+%    \begin{macrocode}
+do 
+%    \end{macrocode}
+%
+% \bigskip
+%    \begin{macrocode}
+  local SkipSpace = ( Q " " + EOL ) ^ 0
+  local Space = ( Q " " + EOL ) ^ 1
+%    \end{macrocode}
+%
+% \bigskip
+%    \begin{macrocode}
+  local braces = Compute_braces ( "\"" * ( 1 - S "\"" ) ^ 0 * "\"" )
+%    \end{macrocode}
+%
+% \bigskip
+%    \begin{macrocode}
+  if piton.beamer then
+    Beamer = Compute_Beamer ( 'ocaml' , braces )
+  end
+  DetectedCommands = Compute_DetectedCommands ( 'ocaml' , braces )
+  local function Q ( pattern )
+    return Ct ( Cc ( luatexbase.catcodetables.CatcodeTableOther ) 
+                * C ( pattern ) ) 
+           + Beamer + DetectedCommands + EscapeMath + Escape
+  end
+%    \end{macrocode}
+%
+% \bigskip
+%    \begin{macrocode}
+  local function K ( style , pattern )
+  return
+     Lc ( "{\\PitonStyle{" .. style .. "}{" )
+     * Q ( pattern )
+     * Lc "}}"
+  end
+%    \end{macrocode}
+%
+% \bigskip
+%    \begin{macrocode}
+  local function WithStyle ( style , pattern )
+  return
+       Ct ( Cc "Open" * Cc ( "{\\PitonStyle{" .. style .. "}{" ) * Cc "}}" )
+     * ( pattern + Beamer + DetectedCommands + EscapeMath + Escape )
+     * Ct ( Cc "Close" )
+  end
+%    \end{macrocode}
+% 
+% \bigskip
 % The following LPEG corresponds to the balanced expressions (balanced according
 % to the parenthesis). Of course, we must write |(1 - S "()")| with outer parenthesis.
 %    \begin{macrocode}
-local balanced_parens =
-  P { "E" , E = ( "(" * V "E" * ")" + ( 1 - S "()" ) ) ^ 0 }
+  local balanced_parens =
+    P { "E" , E = ( "(" * V "E" * ")" + ( 1 - S "()" ) ) ^ 0 }
 %    \end{macrocode}
+%
+% \paragraph{The strings of OCaml}
+%    \begin{macrocode}
+  local ocaml_string =
+    Q "\""
+  * (
+      VisualSpace
+      +
+      Q ( ( 1 - S " \"\r" ) ^ 1 )
+      +
+      EOL
+    ) ^ 0
+  * Q "\""
+%    \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 Delim = Q ( P "[|" + "|]" + S "[()]" )
+  local ext = ( R "az" + "_" ) ^ 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 Punct = Q ( S ",:;!" )
+  local QuotedStringBis =
+    WithStyle ( 'String.Long' ,
+        (
+          Space
+          +
+          Q ( ( 1 - S " \r" ) ^ 1 )
+          +
+          EOL
+        ) ^ 0  )
 %    \end{macrocode}
 % 
-% The identifiers caught by |cap_identifier| begin with a cap. In OCaml, it's
-% used for the constructors of types and for the modules.
+% \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 cap_identifier = R "AZ" * ( R "az" + R "AZ" + S "_'" + digit ) ^ 0 
+  local QuotedString =
+    C ( open * ( 1 - closeeq ) ^ 0  * close ) /
+    ( function ( s ) return QuotedStringBis : match ( s ) end )
 %    \end{macrocode}
 %
+% \bigskip
+% In OCaml, the delimiters for the comments are |(*| and |*)|. There are
+% unsymmetrical and OCaml allows those comments to 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 Constructor = K ( 'Name.Constructor' , cap_identifier )
-local ModuleType = K ( 'Name.Type' , cap_identifier ) 
+  local Comment =
+    WithStyle ( 'Comment' ,
+      P {
+          "A" ,
+          A = Q "(*"
+              * ( V "A"
+                  + Q ( ( 1 - S "\r$\"" - "(*" - "*)" ) ^ 1 ) -- $
+                  + ocaml_string
+                  + "$" * K ( 'Comment.Math' , ( 1 - S "$\r" ) ^ 1 ) * "$" -- $
+                  + EOL
+                ) ^ 0
+              * Q "*)"
+        }   )
 %    \end{macrocode}
 %
-% The identifiers which begin with a lower case letter or an underscore are used 
-% elsewhere in OCaml.
+% 
+% \paragraph{Some standard LPEG}
+%
 %    \begin{macrocode}
-local identifier = ( R "az" + "_" ) * ( R "az" + R "AZ" + S "_'" + digit ) ^ 0 
-local Identifier = K ( 'Identifier.Internal' , identifier )
+  local Delim = Q ( P "[|" + "|]" + S "[()]" )
+  local Punct = Q ( S ",:;!" )
 %    \end{macrocode}
 %
+% \bigskip
+% The identifiers caught by |cap_identifier| begin with a capital. In OCaml,
+% it's used for the constructors of types and for the names of the modules.
 %
-% 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 = (   "{" * V "F" * "}"
-             + "(" * V "F" * ")"
-             + "[" * V "F" * "]" 
-             + "\"" * ( P "\\\"" + 1 - S "\"\r" ) ^ 0 * "\""
-             + "'" * ( P "\\'" + 1 - S "'\r" ) ^ 0 * "'"
-             + ( 1 - S "{}()[]\r;" ) ) ^ 0 ,
-       F = (   "{" * V "F" * "}"
-             + "(" * V "F" * ")"
-             + "[" * V "F" * "]"
-             + ( 1 - S "{}()[]\r\"'" ) ) ^ 0
-    }
+  local cap_identifier = R "AZ" * ( R "az" + R "AZ" + S "_'" + digit ) ^ 0
 %    \end{macrocode}
-% 
+%
+% \bigskip
 %    \begin{macrocode}
-local OneFieldDefinition = 
-    ( K ( 'Keyword' , "mutable" ) * SkipSpace ) ^ -1
-  * K ( 'Name.Field' , identifier ) * SkipSpace
-  * Q ":" * SkipSpace
-  * K ( 'TypeExpression' , expression_for_fields ) 
-  * SkipSpace
-
-local OneField = 
-    K ( 'Name.Field' , identifier ) * SkipSpace
-  * Q "=" * SkipSpace
-  * ( expression_for_fields 
-      / ( function ( s ) return LPEG1['ocaml'] : match ( s ) end ) 
-    )
-  * SkipSpace
-
-local Record = 
-  Q "{" * SkipSpace
-  * 
-    (
-      OneFieldDefinition * ( Q ";" * SkipSpace * OneFieldDefinition ) ^ 0 
-      + 
-      OneField * ( Q ";" * SkipSpace * OneField ) ^ 0 
-    )
-  *
-  Q "}"
+  local Constructor = 
+    K ( 'Name.Constructor' , 
+        Q "`" ^ -1 * cap_identifier 
 %    \end{macrocode}
+% We consider |::|  and |[]| as constructors (of the lists) as does the Tuareg
+% mode of Emacs.
+%    \begin{macrocode}
+        + Q "::" 
+        + Q "[" * SkipSpace * 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 "{" ) ^ ( -1 ) 
-      + 
-      Identifier 
-        * Q "."
-        * K ( 'Name.Field' , identifier ) 
-  )
-  * ( Q "." * K ( 'Name.Field' , identifier ) ) ^ 0 
+  local ModuleType = K ( 'Name.Type' , cap_identifier )
 %    \end{macrocode}
 %
+% \bigskip
 %    \begin{macrocode}
-local Operator = 
-  K ( 'Operator' ,
-      P "!=" + "<>" + "==" + "<<" + ">>" + "<=" + ">=" + ":=" + "||" + "&&" +
-      "//" + "**" + ";;" + "::" + "->" + "+." + "-." + "*." + "/." 
-      + S "-~+/*%=<>&@|" )
-
-local OperatorWord = 
-  K ( 'Operator.Word' ,
-      P "asr" + "land" + "lor" + "lsl" + "lxor" + "mod" + "or" )
-
-
-local governing_keyword = P "and" + "begin" + "class" + "constraint" +
-      "end" + "external" + "functor" + "include" + "inherit" + "initializer" +
-      "in" + "let" + "method" + "module" + "object" + "open" + "rec" + "sig" +
-      "struct" + "type" + "val"
-
-local Keyword =
-  K ( 'Keyword' ,
-      P "assert" + "as" + "done" + "downto" + "do" + "else" + "exception" 
-      + "for" + "function"  + "fun" + "if" + "lazy" + "match" + "mutable" 
-      + "new" + "of" + "private" + "raise" + "then" + "to" + "try"  
-      + "virtual" + "when" + "while" + "with" )
-  + K ( 'Keyword.Constant' , P "true" + "false" )
-  + K ('Keyword.Governing', governing_keyword )
-
-local Builtin = 
-  K ( 'Name.Builtin' , P "not" + "incr" + "decr" + "fst" + "snd" + "ref" )
+  local OperatorWord =
+    K ( 'Operator.Word' ,
+        P "asr" + "land" + "lor" + "lsl" + "lxor" + "mod" + "or" )
 %    \end{macrocode}
 % 
 % \bigskip
-% The following exceptions are exceptions in the standard library of OCaml (Stdlib).
+% In OCaml, some keywords are considered as \emph{governing keywords} with some
+% special syntactic characteristics.
 %    \begin{macrocode}
-local Exception =
-  K (   'Exception' ,
-       P "Division_by_zero" + "End_of_File" + "Failure" + "Invalid_argument" +
-       "Match_failure" + "Not_found" + "Out_of_memory" + "Stack_overflow" +
-       "Sys_blocked_io" + "Sys_error" + "Undefined_recursive_module" )
+  local governing_keyword = P "and" + "begin" + "class" + "constraint" +
+        "end" + "external" + "functor" + "include" + "inherit" + "initializer" +
+        "in" + "let" + "method" + "module" + "object" + "open" + "rec" + "sig" +
+        "struct" + "type" + "val"
 %    \end{macrocode}
+%   
+% \bigskip
+%    \begin{macrocode}
+  local Keyword =
+    K ( 'Keyword' ,
+        P "assert" + "as" + "done" + "downto" + "do" + "else" + "exception"
+        + "for" + "function"  + "fun" + "if" + "lazy" + "match" + "mutable"
+        + "new" + "of" + "private" + "raise" + "then" + "to" + "try"
+        + "virtual" + "when" + "while" + "with" )
+    + K ( 'Keyword.Constant' , P "true" + "false" )
+    + K ( 'Keyword.Governing', governing_keyword )
+%    \end{macrocode}
 %
 % \bigskip
-% \paragraph{The characters in OCaml}
+%    \begin{macrocode}
+  local EndKeyword 
+   = Space + Punct + Delim + EOL + Beamer + DetectedCommands + -1
+%    \end{macrocode}
 %
+% \bigskip
+% Now, the identifier. Recall that we have also a LPEG |cap_identifier| for the
+% indentifiers beginning with a capital letter.
 %    \begin{macrocode}
-local Char =
-  K ( 'String.Short',
-    P "'" *
-    (
-      ( 1 - S "'\\" ) 
-      + "\\" 
-        * ( S "\\'ntbr \"" 
-            + digit * digit * digit 
-            + P "x" * ( digit + R "af" + R "AF" ) 
-                    * ( digit + R "af" + R "AF" ) 
-                    * ( digit + R "af" + R "AF" )
-            + P "o" * R "03" * R "07" * R "07" ) 
-    )
-    * "'" )
+  local identifier = ( R "az" + "_" ) * ( R "az" + R "AZ" + S "_'" + digit ) ^ 0 
+                     - ( OperatorWord + Keyword ) * EndKeyword
 %    \end{macrocode}
-% 
 %
 % \bigskip
-% \paragraph{Beamer}
+% We have the internal style |Identifier.Internal| in order to be able to
+% implement the mechanism |\SetPitonIdentifier|. The final user has access to a
+% style called |Identifier|.
+%    \begin{macrocode}
+  local Identifier = K ( 'Identifier.Internal' , identifier )
+%    \end{macrocode}
 %
 % \bigskip
-% The argument of |Compute_braces| must be a pattern \emph{which does no
-% catching} corresponding to the strings of the language.
+% In OCmal, \emph{character} is a type different of the type |string|.
+%    \begin{macrocode}
+  local Char =
+    K ( 'String.Short',
+      P "'" *
+      (
+        ( 1 - S "'\\" )
+        + "\\"
+          * ( S "\\'ntbr \""
+              + digit * digit * digit
+              + P "x" * ( digit + R "af" + R "AF" )
+                      * ( digit + R "af" + R "AF" )
+                      * ( digit + R "af" + R "AF" )
+              + P "o" * R "03" * R "07" * R "07" )
+      )
+      * "'" )
+%    \end{macrocode}
 %
+% \bigskip
+% For the parameter of the types (for example : |`\a| as in |`a list|).
 %    \begin{macrocode}
-local braces = Compute_braces ( "\"" * ( 1 - S "\"" ) ^ 0 * "\"" ) 
-if piton.beamer then 
-  Beamer = Compute_Beamer ( 'ocaml' , braces ) -- modified 2024/07/24
-end
+  local TypeParameter =
+    K ( 'TypeParameter' , 
+        "'" * Q"_" ^ -1 * alpha ^ 1 * ( # ( 1 - P "'" ) + -1 ) )
 %    \end{macrocode}
-% 
+%
+% \paragraph{The records}
+%
 %    \begin{macrocode}
-DetectedCommands = Compute_DetectedCommands ( 'ocaml' , braces ) 
+  local expression_for_fields_type =
+    P { "E" ,
+        E =  (   "{" * V "F" * "}"
+              + "(" * V "F" * ")"
+              + TypeParameter
+              + ( 1 - S "{}()[]\r;" ) ) ^ 0 ,
+        F = (    "{" * V "F" * "}"
+              + "(" * V "F" * ")"
+              + ( 1 - S "{}()[]\r\"'" ) + TypeParameter ) ^ 0
+      }
 %    \end{macrocode}
 %
 % \bigskip
 %    \begin{macrocode}
-LPEG_cleaner['ocaml'] = Compute_LPEG_cleaner ( 'ocaml' , braces ) 
+  local expression_for_fields_value =
+    P { "E" ,
+        E =  (   "{" * V "F" * "}"
+              + "(" * V "F" * ")"
+              + "[" * V "F" * "]"
+              + String + QuotedString + Char
+              + ( 1 - S "{}()[]\r;" ) ) ^ 0 ,
+        F = (    "{" * V "F" * "}"
+              + "(" * V "F" * ")"
+              + "[" * V "F" * "]"
+              + ( 1 - S "{}()[]\r\"'" )) ^ 0
+      }
 %    \end{macrocode}
 %
 % \bigskip
-%
-% 
-% \paragraph{The strings en OCaml}
-% 
-% We need a pattern |ocaml_string| without captures because it will be used
-% within the comments of OCaml.
 %    \begin{macrocode}
-local ocaml_string =
-       Q "\"" 
-     * ( 
-         VisualSpace
-         + 
-         Q ( ( 1 - S " \"\r" ) ^ 1 ) 
-         +  
-         EOL
-       ) ^ 0 
-     * Q "\"" 
+  local OneFieldDefinition =
+      ( K ( 'Keyword' , "mutable" ) * SkipSpace ) ^ -1
+    * K ( 'Name.Field' , identifier ) * SkipSpace
+    * Q ":" * SkipSpace
+    * K ( 'TypeExpression' , expression_for_fields_type )
+    * SkipSpace
 %    \end{macrocode}
-% 
+%
+% \bigskip
 %    \begin{macrocode}
-local String = WithStyle ( 'String.Long' , ocaml_string ) 
+  local OneField =
+      K ( 'Name.Field' , identifier ) * SkipSpace
+    * Q "=" * SkipSpace
+    * ( expression_for_fields_value
+        / ( function ( s ) return LPEG1['ocaml'] : match ( s ) end )
+      )
+    * SkipSpace
 %    \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|. 
+% The \emph{records} may occur in the definitions of type (beginning by |type|)
+% but also when used as values.
 %    \begin{macrocode}
-local ext = ( R "az" + "_" ) ^ 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 ) 
+  local Record =
+    Q "{" * SkipSpace
+    *
+      (
+        OneFieldDefinition 
+        * ( Q ";" * SkipSpace * ( Comment * SkipSpace ) ^ 0 * OneFieldDefinition ) ^ 0
+        +
+        OneField * ( Q ";" * SkipSpace * ( Comment * SkipSpace ) ^ 0 * OneField ) ^ 0
+      )
+    * SkipSpace
+    * Q ";" ^ -1
+    * SkipSpace
+    * Comment ^ -1
+    * SkipSpace
+    * Q "}"
 %    \end{macrocode}
 %
-% \medskip
-% The \textsc{lpeg} |QuotedStringBis| will do the second analysis. 
+% \paragraph{DotNotation}
+%
+% 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 QuotedStringBis = 
-  WithStyle ( 'String.Long' ,
-      (  
-        Space
+  local DotNotation =
+    (
+        K ( 'Name.Module' , cap_identifier )
+          * Q "."
+          * ( Identifier + Constructor + Q "(" + Q "[" + Q "{" ) ^ -1 
         +
-        Q ( ( 1 - S " \r" ) ^ 1 ) 
-        +  
-        EOL
-      ) ^ 0  ) 
+         Identifier
+          * Q "."
+          * K ( 'Name.Field' , identifier )
+    )
+    * ( Q "." * K ( 'Name.Field' , identifier ) ) ^ 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.
+%
+% \bigskip
 %    \begin{macrocode}
-local QuotedString = 
-   C ( open * ( 1 - closeeq ) ^ 0  * close ) /
-  ( function ( s ) return QuotedStringBis : match ( s ) end ) 
+  local Operator =
+    K ( 'Operator' ,
+        P "!=" + "<>" + "==" + "<<" + ">>" + "<=" + ">=" + ":=" + "||" + "&&" +
+        "//" + "**" + ";;" + "->" + "+." + "-." + "*." + "/."
+        + S "-~+/*%=<>&@|" )
 %    \end{macrocode}
-% 
 %
 % \bigskip
-% \paragraph{The comments in the OCaml listings}
+%    \begin{macrocode}
+  local Builtin =
+    K ( 'Name.Builtin' , P "not" + "incr" + "decr" + "fst" + "snd" + "ref" )
+%    \end{macrocode}
 %
-% In OCaml, the delimiters for the comments are |(*| and |*)|. There are
-% unsymmetrical and OCaml allows those comments to 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).
-% 
+% \bigskip
 %    \begin{macrocode}
-local Comment =
-  WithStyle ( 'Comment' ,
-     P {
-         "A" ,
-         A = Q "(*"
-             * ( V "A" 
-                 + Q ( ( 1 - S "\r$\"" - "(*" - "*)" ) ^ 1 ) -- $
-                 + ocaml_string 
-                 + "$" * K ( 'Comment.Math' , ( 1 - S "$\r" ) ^ 1 ) * "$" -- $
-                 + EOL
-               ) ^ 0 
-             * Q "*)" 
-       }   )
+  local Exception =
+    K (   'Exception' ,
+        P "Division_by_zero" + "End_of_File" + "Failure" + "Invalid_argument" +
+        "Match_failure" + "Not_found" + "Out_of_memory" + "Stack_overflow" +
+        "Sys_blocked_io" + "Sys_error" + "Undefined_recursive_module" )
 %    \end{macrocode}
-% 
+%
 % \bigskip
-% \paragraph{The DefFunction}
+%    \begin{macrocode}
+  LPEG_cleaner['ocaml'] = Compute_LPEG_cleaner ( 'ocaml' , braces )
+%    \end{macrocode}
 %
+% \bigskip
 %    \begin{macrocode}
-local Argument = 
+  local Argument =
 %    \end{macrocode}
 % For the labels of the labeled arguments. Maybe you will, in the future, create
 % a style for those elements.
 %    \begin{macrocode}
-  (  Q "~" * Identifier * Q ":" * SkipSpace ) ^ -1 
-  *  
-  ( K ( 'Identifier.Internal' , identifier ) 
-    + Q "(" * SkipSpace 
-      * K ( 'Identifier.Internal' , identifier ) * SkipSpace 
-      * Q ":" * SkipSpace  
-      * K ( 'TypeExpression' , balanced_parens ) * SkipSpace
-      * Q ")"
-  )
+    (  Q "~" * Identifier * Q ":" * SkipSpace ) ^ -1
+    *
+    ( K ( 'Identifier.Internal' , identifier )
+      + Q "(" * SkipSpace
+        * K ( 'Identifier.Internal' , identifier ) * SkipSpace
+        * Q ":" * SkipSpace
+        * K ( 'TypeExpression' , balanced_parens ) * SkipSpace
+        * Q ")"
+    )
 %    \end{macrocode}
 %
+% \bigskip
 % Despite its name, then \textsc{lpeg} |DefFunction| deals also with |let open|
 % which opens locally a module.
 %    \begin{macrocode}
-local DefFunction = 
-  K ( 'Keyword.Governing' , "let open" ) 
-   * Space
-   * K ( 'Name.Module' , cap_identifier ) 
-  + 
-  K ( 'Keyword.Governing' , P "let rec" + "let" + "and" ) 
+  local DefFunction =
+    K ( 'Keyword.Governing' , "let open" )
     * Space
-    * K ( 'Name.Function.Internal' , identifier ) 
-    * Space 
-    * (
-        Q "=" * SkipSpace * K ( 'Keyword' , "function" ) 
-        + 
-        Argument 
-         * ( SkipSpace * Argument ) ^ 0 
-         * ( 
-             SkipSpace 
-             * Q ":" 
-             * K ( 'TypeExpression' , ( 1 - P "=" ) ^ 0 ) 
-           ) ^ -1 
-      ) 
+    * K ( 'Name.Module' , cap_identifier )
+    +
+    K ( 'Keyword.Governing' , P "let rec" + "let" + "and" )
+      * Space
+      * K ( 'Name.Function.Internal' , identifier )
+      * Space
+      * (
+          Q "=" * SkipSpace * K ( 'Keyword' , "function" )
+          +
+          Argument
+          * ( SkipSpace * Argument ) ^ 0
+          * (
+              SkipSpace
+              * Q ":"
+              * K ( 'TypeExpression' , ( 1 - P "=" ) ^ 0 )
+            ) ^ -1
+        )
 %    \end{macrocode}
 %
-% 
-% \bigskip
-% \paragraph{The DefModule}\par
+% \paragraph{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.Governing' , "module" ) * Space
-  *
-    (
-          K ( 'Keyword.Governing' , "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 
-              *
+  local DefModule =
+    K ( 'Keyword.Governing' , "module" ) * Space
+    *
+      (
+            K ( 'Keyword.Governing' , "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 "," * SkipSpace 
-                    * K ( 'Name.Module' , cap_identifier ) * SkipSpace 
-                    * Q ":" * SkipSpace 
-                    * K ( 'Name.Type' , cap_identifier ) * SkipSpace 
-                ) ^ 0 
+                  Q ","
+                  *
+                  K ( 'Name.Module' , 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.Governing' , P "include" + "open" )
-  * Space * K ( 'Name.Module' , cap_identifier ) 
+            ) ^ -1
+      )
+    +
+    K ( 'Keyword.Governing' , P "include" + "open" )
+    * Space 
+    * K ( 'Name.Module' , cap_identifier )
 %    \end{macrocode}
 %
-% 
-% \bigskip
-% \paragraph{The DefType}\par
+% \paragraph{DefType}
 %
 %    \begin{macrocode}
-local TypeParameter = 
-  K ( 'TypeParameter' , "'" * alpha * ( # ( 1 - P "'" ) + -1 ) ) 
+  local DefType =
+    K ( 'Keyword.Governing' , "type" )
+    * Space
+    * K ( 'TypeExpression' , Q ( 1 - P "=" ) ^ 1 )
+    * SkipSpace 
+    * ( Q "+=" + Q "=" ) 
+    * SkipSpace
+    * ( 
+        Record 
+        +
+        WithStyle
+         ( 
+           'TypeExpression' , 
+           ( 
+             ( EOL + Q ( 1 - P ";;" - governing_keyword ) ) ^ 0 
+             * ( # ( governing_keyword ) + Q ";;" ) 
+           )
+         )
+      )
 %    \end{macrocode}
 %
-%
 % \bigskip
-% The following LPEG is for the instructions of definitions of types (which
-% begin with |type|).
-%    \begin{macrocode}
-local DefType = 
-  K ( 'Keyword.Governing' , "type" ) 
-  * Space 
-  * WithStyle 
-      ( 
-        'TypeExpression' , 
-        ( Q ( 1 - P ";;" - P "\r" ) + EOL_without_space_indentation ) ^ 0 
-      )
-  * ( # governing_keyword + Q ";;" + -1 )
-%    \end{macrocode}
-% 
-% \bigskip
 % \paragraph{The main LPEG for the language OCaml}
 %
 %    \begin{macrocode}
-local EndKeyword = Space + Punct + Delim + EOL + Beamer + DetectedCommands + -1 
+  local Main =
+      space ^ 0 * EOL
+      + Space
+      + Tab
+      + Escape + EscapeMath
+      + Beamer
+      + DetectedCommands
+      + TypeParameter
+      + String + QuotedString + Char
+      + Comment
+      + Operator
 %    \end{macrocode}
-% 
-% First, the main loop :
+% For the labels (maybe we will write in the future a dedicated LPEG pour those tokens).
 %    \begin{macrocode}
-local Main = 
-     Space 
-     + Tab
-     + Escape + EscapeMath
-     + Beamer 
-     + DetectedCommands
-     + TypeParameter
-     + String + QuotedString + Char
-     + Comment
-     + Delim
-     + Operator
+      + Q ( "~" ) * Identifier * ( Q ":" ) ^ -1
+      + Q ":" * # (1 - P ":") * SkipSpace
+          * K ( 'TypeExpression' , balanced_parens ) * SkipSpace * Q ")"
+      + Exception
+      + DefType
+      + DefFunction
+      + DefModule
+      + Record
+      + Keyword * EndKeyword
+      + OperatorWord * EndKeyword
+      + Builtin * EndKeyword
+      + DotNotation
+      + Constructor
+      + Identifier
+      + Punct
+      + Delim
+      + Number
+      + Word
 %    \end{macrocode}
-% For the labels of the labeled arguments. Maybe you will, in the future, create
-% a style for those elements.
+%
+% \bigskip
+% % Here, we must not put |local|!
 %    \begin{macrocode}
-     + Q ( "~" ) * Identifier * ( Q ":" ) ^ -1
-     + Q ":" * # (1 - P":") * SkipSpace 
-          * K ( 'TypeExpression' , balanced_parens ) * SkipSpace * Q ")"
-     + Punct
-     + Exception 
-     + DefFunction
-     + DefModule
-     + DefType
-     + Record 
-     + Keyword * EndKeyword
-     + OperatorWord * EndKeyword
-     + Builtin * EndKeyword 
-     + DotNotation
-     + Constructor
-     + Identifier 
-     + Number
-     + Word
-
-LPEG1['ocaml'] = Main ^ 0 
+  LPEG1['ocaml'] = Main ^ 0
 %    \end{macrocode}
 %
 % \bigskip
-% We recall that each line in the 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}
-LPEG2['ocaml'] = 
-  Ct (  
+  LPEG2['ocaml'] =
+    Ct (
 %    \end{macrocode}
 % The following lines are in order to allow, in |\piton| (and not in |{Piton}|),
-% judments of type (such as |f : my_type -> 'a list|) or single expressions of
+% judgments of type (such as |f : my_type -> 'a list|) or single expressions of
 % type such as |my_type -> 'a list| (in that case, the argument of |\piton|
 % \emph{must} begin by a colon).
 %    \begin{macrocode}
-       ( P ":" + Identifier * SkipSpace * Q ":" ) 
-         * SkipSpace 
-         * K ( 'TypeExpression' , ( 1 - P "\r" ) ^ 0 ) 
-       + 
+        ( P ":" + Identifier * SkipSpace * Q ":" )
+          * SkipSpace
+          * K ( 'TypeExpression' , ( 1 - P "\r" ) ^ 0 )
+        +
+        ( space ^ 0 * "\r" ) ^ -1
+        * BeamerBeginEnvironments
+        * Lc [[\@@_begin_line:]]
+        * SpaceIndentation ^ 0
+        * ( ( space * Lc [[\@@_trailing_space:]] ) ^ 1 * -1 
+              + space ^ 0 * EOL 
+              + Main 
+          ) ^ 0
+        * -1
+        * Lc [[\@@_end_line:]]
+      )
 %    \end{macrocode}
-% Now, the main part.
+% 
+% \bigskip
+% End of the Lua scope for the language OCaml.
 %    \begin{macrocode}
-       ( space ^ 0 * "\r" ) ^ -1 
-       * BeamerBeginEnvironments 
-       * Lc [[\@@_begin_line:]] 
-       * SpaceIndentation ^ 0 
-       * ( ( space * Lc [[\@@_trailing_space:]] ) ^ 1 * -1 + space ^ 0 * EOL + Main ) ^ 0 
-       * -1 
-       * Lc [[\@@_end_line:]] 
-     )
+end
 %    \end{macrocode}
-%
 % 
+% 
 % \bigskip
 % \subsubsection{The language C}
 % 
+% We open a Lua local scope for the language C (of course, there will be also
+% global definitions).
 %    \begin{macrocode}
-local Delim = Q ( S "{[()]}" )
+do 
 %    \end{macrocode}
 %
+% \bigskip
 %    \begin{macrocode}
-local Punct = Q ( S ",:;!" )
+  local Delim = Q ( S "{[()]}" )
 %    \end{macrocode}
 %
+%    \begin{macrocode}
+  local Punct = Q ( S ",:;!" )
+%    \end{macrocode}
+%
 % \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 identifier = letter * alphanum ^ 0
+  local identifier = letter * alphanum ^ 0
 
-local Operator = 
-  K ( 'Operator' ,
-      P "!=" + "==" + "<<" + ">>" + "<=" + ">=" + "||" + "&&" 
-        + S "-~+/*%=<>&.@|!" )
+  local Operator = 
+    K ( 'Operator' ,
+        P "!=" + "==" + "<<" + ">>" + "<=" + ">=" + "||" + "&&" 
+          + S "-~+/*%=<>&.@|!" )
 
-local Keyword = 
-  K ( 'Keyword' ,
-      P "alignas" + "asm" + "auto" + "break" + "case" + "catch" + "class" +
-      "const" + "constexpr" + "continue" + "decltype" + "do" + "else" + "enum" +
-      "extern" + "for" + "goto" + "if" + "nexcept" + "private" + "public" +
-      "register" + "restricted" + "return" + "static" + "static_assert" +
-      "struct" + "switch" + "thread_local" + "throw" + "try" + "typedef" +
-      "union" + "using" + "virtual" + "volatile" + "while" 
-    )
-  + K ( 'Keyword.Constant' , P "default" + "false" + "NULL" + "nullptr" + "true" ) 
+  local Keyword = 
+    K ( 'Keyword' ,
+        P "alignas" + "asm" + "auto" + "break" + "case" + "catch" + "class" +
+        "const" + "constexpr" + "continue" + "decltype" + "do" + "else" + "enum" +
+        "extern" + "for" + "goto" + "if" + "nexcept" + "private" + "public" +
+        "register" + "restricted" + "return" + "static" + "static_assert" +
+        "struct" + "switch" + "thread_local" + "throw" + "try" + "typedef" +
+        "union" + "using" + "virtual" + "volatile" + "while" 
+      )
+    + K ( 'Keyword.Constant' , P "default" + "false" + "NULL" + "nullptr" + "true" ) 
 
-local Builtin = 
-  K ( 'Name.Builtin' ,
-      P "alignof" + "malloc" + "printf" + "scanf" + "sizeof" )
+  local Builtin = 
+    K ( 'Name.Builtin' ,
+        P "alignof" + "malloc" + "printf" + "scanf" + "sizeof" )
 
-local Type = 
-  K ( 'Name.Type' ,
-      P "bool" + "char" + "char16_t" + "char32_t" + "double" + "float" + "int" +
-      "int8_t" + "int16_t" + "int32_t" + "int64_t" + "long" + "short" + "signed"
-      + "unsigned" + "void" + "wchar_t" ) * Q "*" ^ 0 
+  local Type = 
+    K ( 'Name.Type' ,
+        P "bool" + "char" + "char16_t" + "char32_t" + "double" + "float" + "int" +
+        "int8_t" + "int16_t" + "int32_t" + "int64_t" + "long" + "short" + "signed"
+        + "unsigned" + "void" + "wchar_t" ) * Q "*" ^ 0 
 
-local DefFunction = 
-  Type 
-  * Space 
-  * Q "*" ^ -1
-  * K ( 'Name.Function.Internal' , identifier ) 
-  * SkipSpace 
-  * # P "("
+  local DefFunction = 
+    Type 
+    * Space 
+    * Q "*" ^ -1
+    * K ( 'Name.Function.Internal' , identifier ) 
+    * SkipSpace 
+    * # P "("
 %    \end{macrocode}
 % We remind that the marker |#| of \textsc{lpeg} specifies that the pattern will be
 % detected but won't consume any character.
@@ -7171,8 +7493,8 @@
 % \smallskip
 % Example:\enskip \piton{class myclass:}
 %    \begin{macrocode}
-local DefClass = 
-  K ( 'Keyword' , "class" ) * Space * K ( 'Name.Class' , identifier ) 
+  local DefClass = 
+    K ( 'Keyword' , "class" ) * Space * K ( 'Name.Class' , identifier ) 
 %    \end{macrocode}
 % 
 % If the word |class| is not followed by a identifier, it will be caught as
@@ -7183,17 +7505,17 @@
 % \paragraph{The strings of C}
 %
 %    \begin{macrocode}
-String = 
-  WithStyle ( 'String.Long' ,
-      Q "\"" 
-      * ( VisualSpace 
-          + K ( 'String.Interpol' , 
-                "%" * ( S "difcspxXou" + "ld" + "li" + "hd" + "hi" )
-              ) 
-          + Q ( ( P "\\\"" + 1 - S " \"" ) ^ 1 ) 
-        ) ^ 0 
-      * Q "\""
-    )
+  String = 
+    WithStyle ( 'String.Long' ,
+        Q "\"" 
+        * ( VisualSpace 
+            + K ( 'String.Interpol' , 
+                  "%" * ( S "difcspxXou" + "ld" + "li" + "hd" + "hi" )
+                ) 
+            + Q ( ( P "\\\"" + 1 - S " \"" ) ^ 1 ) 
+          ) ^ 0 
+        * Q "\""
+      )
 %    \end{macrocode}
 % 
 % \bigskip
@@ -7203,16 +7525,16 @@
 % The argument of |Compute_braces| must be a pattern \emph{which does no
 % catching} corresponding to the strings of the language.
 %    \begin{macrocode}
-local braces = Compute_braces ( "\"" * ( 1 - S "\"" ) ^ 0 * "\"" ) 
-if piton.beamer then Beamer = Compute_Beamer ( 'c' , braces ) end
+  local braces = Compute_braces ( "\"" * ( 1 - S "\"" ) ^ 0 * "\"" ) 
+  if piton.beamer then Beamer = Compute_Beamer ( 'c' , braces ) end
 %    \end{macrocode}
 %
 %    \begin{macrocode}
-DetectedCommands = Compute_DetectedCommands ( 'c' , braces ) 
+  DetectedCommands = Compute_DetectedCommands ( 'c' , braces ) 
 %    \end{macrocode}
 %
 %    \begin{macrocode}
-LPEG_cleaner['c'] = Compute_LPEG_cleaner ( 'c' , braces ) 
+  LPEG_cleaner['c'] = Compute_LPEG_cleaner ( 'c' , braces ) 
 %    \end{macrocode}
 % 
 % \bigskip
@@ -7219,7 +7541,7 @@
 % \paragraph{The directives of the preprocessor}
 %
 %    \begin{macrocode}
-local Preproc = K ( 'Preproc' , "#" * ( 1 - P "\r" ) ^ 0  ) * ( EOL + -1 )
+  local Preproc = K ( 'Preproc' , "#" * ( 1 - P "\r" ) ^ 0  ) * ( EOL + -1 )
 %    \end{macrocode}
 % 
 %
@@ -7228,17 +7550,17 @@
 %
 % We define different \textsc{lpeg} dealing with comments in the C listings.
 %    \begin{macrocode}
-local Comment = 
-  WithStyle ( 'Comment' ,
-     Q "//" * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0 ) -- $
-            * ( EOL + -1 )
+  local Comment = 
+    WithStyle ( 'Comment' ,
+       Q "//" * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0 ) -- $
+              * ( EOL + -1 )
 
-local LongComment = 
-  WithStyle ( 'Comment' , 
-               Q "/*" 
-               * ( CommentMath + Q ( ( 1 - P "*/" - S "$\r" ) ^ 1 ) + EOL ) ^ 0 
-               * Q "*/" 
-            ) -- $
+  local LongComment = 
+    WithStyle ( 'Comment' , 
+                 Q "/*" 
+                 * ( CommentMath + Q ( ( 1 - P "*/" - S "$\r" ) ^ 1 ) + EOL ) ^ 0 
+                 * Q "*/" 
+              ) -- $
 %    \end{macrocode}
 %
 %
@@ -7248,37 +7570,39 @@
 % \paragraph{The main LPEG for the language C}
 %
 %    \begin{macrocode}
-local EndKeyword = Space + Punct + Delim + EOL + Beamer + DetectedCommands + -1 
+  local EndKeyword = Space + Punct + Delim + EOL + Beamer + DetectedCommands + -1 
 %    \end{macrocode}
 %
 % First, the main loop :
 %    \begin{macrocode}
-local Main = 
-     Space 
-     + Tab
-     + Escape + EscapeMath 
-     + CommentLaTeX
-     + Beamer
-     + DetectedCommands
-     + Preproc
-     + Comment + LongComment
-     + Delim
-     + Operator
-     + String
-     + Punct
-     + DefFunction
-     + DefClass 
-     + Type * ( Q "*" ^ -1 + EndKeyword ) 
-     + Keyword * EndKeyword
-     + Builtin * EndKeyword
-     + Identifier 
-     + Number
-     + Word
+  local Main = 
+       space ^ 0 * EOL
+       + Space 
+       + Tab
+       + Escape + EscapeMath 
+       + CommentLaTeX
+       + Beamer
+       + DetectedCommands
+       + Preproc
+       + Comment + LongComment
+       + Delim
+       + Operator
+       + String
+       + Punct
+       + DefFunction
+       + DefClass 
+       + Type * ( Q "*" ^ -1 + EndKeyword ) 
+       + Keyword * EndKeyword
+       + Builtin * EndKeyword
+       + Identifier 
+       + Number
+       + Word
 %    \end{macrocode}
 %
+% \bigskip
 % Here, we must not put |local|!
 %    \begin{macrocode}
-LPEG1['c'] = Main ^ 0 
+  LPEG1['c'] = Main ^ 0 
 %    \end{macrocode}
 %
 % \bigskip
@@ -7288,47 +7612,60 @@
 % will be used as marker in order to delimit the argument of the command
 % \texttt{\textbackslash @@\_begin\_line:}}.
 %    \begin{macrocode}
-LPEG2['c'] = 
-  Ct (
-       ( space ^ 0 * P "\r" ) ^ -1 
-       * BeamerBeginEnvironments 
-       * Lc [[\@@_begin_line:]]
-       * SpaceIndentation ^ 0 
-       * ( space ^ 1 * -1 + space ^ 0 * EOL + Main ) ^ 0 
-       * -1 
-       * Lc [[\@@_end_line:]] 
-     )
+  LPEG2['c'] = 
+    Ct (
+         ( space ^ 0 * P "\r" ) ^ -1 
+         * BeamerBeginEnvironments 
+         * Lc [[\@@_begin_line:]]
+         * SpaceIndentation ^ 0 
+         * ( space ^ 1 * -1 + space ^ 0 * EOL + Main ) ^ 0 
+         * -1 
+         * Lc [[\@@_end_line:]] 
+       )
 %    \end{macrocode}
 %
+% \bigskip
+% End of the Lua scope for the language C.
+%    \begin{macrocode}
+end
+%    \end{macrocode}
 %
 % \bigskip
 % \subsubsection{The language SQL}
 % 
+% We open a Lua local scope for the language SQL (of course, there will be also
+% global definitions).
 %    \begin{macrocode}
-local function LuaKeyword ( name ) 
-return 
-   Lc [[{\PitonStyle{Keyword}{]]
-   * Q ( Cmt ( 
-               C ( identifier ) , 
-               function ( s , i , a ) return string.upper ( a ) == name end 
-             ) 
-       ) 
-   * Lc "}}" 
-end 
+do 
 %    \end{macrocode}
 %
 % \bigskip
+%    \begin{macrocode}
+  local function LuaKeyword ( name ) 
+  return 
+     Lc [[{\PitonStyle{Keyword}{]]
+     * Q ( Cmt ( 
+                 C ( identifier ) , 
+                 function ( s , i , a ) return string.upper ( a ) == name end 
+               ) 
+         ) 
+     * Lc "}}" 
+  end 
+%    \end{macrocode}
+%
+% \bigskip
 % In the identifiers, we will be able to catch those contening spaces, that is
 % to say like |"last name"|. 
 %    \begin{macrocode}
-local identifier = 
-  letter * ( alphanum + "-" ) ^ 0 
-  + P '"' * ( ( 1 - P '"' ) ^ 1 ) * '"' 
-
-
-local Operator = 
-  K ( 'Operator' , P "=" + "!=" + "<>" + ">=" + ">" + "<=" + "<"  + S "*+/" )
+  local identifier = 
+    letter * ( alphanum + "-" ) ^ 0 
+    + P '"' * ( ( 1 - P '"' ) ^ 1 ) * '"' 
 %    \end{macrocode}
+% 
+%    \begin{macrocode}
+  local Operator = 
+    K ( 'Operator' , P "=" + "!=" + "<>" + ">=" + ">" + "<=" + "<"  + S "*+/" )
+%    \end{macrocode}
 %
 % In SQL, the keywords are case-insensitive. That's why we have a little
 % complication. We will catch the keywords with the identifiers and, then,
@@ -7335,56 +7672,61 @@
 % distinguish the keywords with a Lua function. However, some keywords will be
 % caught in special LPEG because we want to detect the names of the SQL tables.
 %    \begin{macrocode}
-local function Set ( list )
-  local set = { }
-  for _, l in ipairs ( list ) do set[l] = true end
-  return set
-end
-
-local set_keywords = Set
- { 
-   "ADD" , "AFTER" , "ALL" , "ALTER" , "AND" , "AS" , "ASC" , "BETWEEN" , "BY" ,
-   "CHANGE" , "COLUMN" , "CREATE" , "CROSS JOIN" , "DELETE" , "DESC" , "DISTINCT" , 
-   "DROP" , "FROM" , "GROUP" , "HAVING" , "IN" , "INNER" , "INSERT" , "INTO" , "IS" , 
-   "JOIN" , "LEFT" , "LIKE" , "LIMIT" , "MERGE" , "NOT" , "NULL" , "ON" , "OR" , 
-   "ORDER" , "OVER" , "RIGHT" , "SELECT" , "SET" , "TABLE" , "THEN" , "TRUNCATE" , 
-   "UNION" , "UPDATE" , "VALUES" , "WHEN" , "WHERE" , "WITH"
- }
-
-local set_builtins = Set
- { 
-   "AVG" , "COUNT" , "CHAR_LENGHT" , "CONCAT" , "CURDATE" , "CURRENT_DATE" ,
-   "DATE_FORMAT" , "DAY" , "LOWER" , "LTRIM" , "MAX" , "MIN" , "MONTH" , "NOW" ,
-   "RANK" , "ROUND" , "RTRIM" , "SUBSTRING" , "SUM" , "UPPER" , "YEAR" 
- }
+  local function Set ( list )
+    local set = { }
+    for _, l in ipairs ( list ) do set[l] = true end
+    return set
+  end
 %    \end{macrocode}
+% 
+% \bigskip
+%    \begin{macrocode}
+  local set_keywords = Set
+   { 
+     "ADD" , "AFTER" , "ALL" , "ALTER" , "AND" , "AS" , "ASC" , "BETWEEN" , "BY" ,
+     "CHANGE" , "COLUMN" , "CREATE" , "CROSS JOIN" , "DELETE" , "DESC" , "DISTINCT" , 
+     "DROP" , "FROM" , "GROUP" , "HAVING" , "IN" , "INNER" , "INSERT" , "INTO" , "IS" , 
+     "JOIN" , "LEFT" , "LIKE" , "LIMIT" , "MERGE" , "NOT" , "NULL" , "ON" , "OR" , 
+     "ORDER" , "OVER" , "RIGHT" , "SELECT" , "SET" , "TABLE" , "THEN" , "TRUNCATE" , 
+     "UNION" , "UPDATE" , "VALUES" , "WHEN" , "WHERE" , "WITH"
+   }
+%    \end{macrocode}
+% 
+%    \begin{macrocode}
+  local set_builtins = Set
+   { 
+     "AVG" , "COUNT" , "CHAR_LENGHT" , "CONCAT" , "CURDATE" , "CURRENT_DATE" ,
+     "DATE_FORMAT" , "DAY" , "LOWER" , "LTRIM" , "MAX" , "MIN" , "MONTH" , "NOW" ,
+     "RANK" , "ROUND" , "RTRIM" , "SUBSTRING" , "SUM" , "UPPER" , "YEAR" 
+   }
+%    \end{macrocode}
 %
 % The \textsc{lpeg} |Identifier| will catch the identifiers of the fields  
 % but also the keywords and the built-in functions of SQL. If will \emph{not}
 % catch the names of the SQL tables.
 %    \begin{macrocode}
-local Identifier = 
-  C ( identifier ) /
-  ( 
-    function (s) 
-        if set_keywords[string.upper(s)] -- the keywords are case-insensitive in SQL
+  local Identifier = 
+    C ( identifier ) /
+    ( 
+      function (s) 
+          if set_keywords[string.upper(s)] -- the keywords are case-insensitive in SQL
 %    \end{macrocode}
 % Remind that, in Lua, it's possible to return \emph{several} values. 
 %    \begin{macrocode}
-        then return { "{\\PitonStyle{Keyword}{" } ,
-                    { luatexbase.catcodetables.other , s } ,
-                    { "}}" }
-        else if set_builtins[string.upper(s)]
-             then return { "{\\PitonStyle{Name.Builtin}{" } ,
-                         { luatexbase.catcodetables.other , s } ,
-                         { "}}" }
-             else return { "{\\PitonStyle{Name.Field}{" } ,
-                         { luatexbase.catcodetables.other , s } ,
-                         { "}}" }
-             end
-        end 
-    end
-  ) 
+          then return { "{\\PitonStyle{Keyword}{" } ,
+                      { luatexbase.catcodetables.other , s } ,
+                      { "}}" }
+          else if set_builtins[string.upper(s)]
+               then return { "{\\PitonStyle{Name.Builtin}{" } ,
+                           { luatexbase.catcodetables.other , s } ,
+                           { "}}" }
+               else return { "{\\PitonStyle{Name.Field}{" } ,
+                           { luatexbase.catcodetables.other , s } ,
+                           { "}}" }
+               end
+          end 
+      end
+    ) 
 %    \end{macrocode}
 % 
 % \bigskip
@@ -7391,7 +7733,7 @@
 % \paragraph{The strings of SQL}
 %
 %    \begin{macrocode}
-local String = K ( 'String.Long' , "'" * ( 1 - P "'" ) ^ 1 * "'" ) 
+  local String = K ( 'String.Long' , "'" * ( 1 - P "'" ) ^ 1 * "'" ) 
 %    \end{macrocode}
 % 
 % \bigskip
@@ -7402,16 +7744,16 @@
 % catching} corresponding to the strings of the language.
 %
 %    \begin{macrocode}
-local braces = Compute_braces ( "'" * ( 1 - P "'" ) ^ 1 * "'" ) 
-if piton.beamer then Beamer = Compute_Beamer ( 'sql' , braces ) end
+  local braces = Compute_braces ( "'" * ( 1 - P "'" ) ^ 1 * "'" ) 
+  if piton.beamer then Beamer = Compute_Beamer ( 'sql' , braces ) end
 %    \end{macrocode}
 % 
 %    \begin{macrocode}
-DetectedCommands = Compute_DetectedCommands ( 'sql' , braces ) 
+  DetectedCommands = Compute_DetectedCommands ( 'sql' , braces ) 
 %    \end{macrocode}
 %
 %    \begin{macrocode}
-LPEG_cleaner['sql'] = Compute_LPEG_cleaner ( 'sql' , braces ) 
+  LPEG_cleaner['sql'] = Compute_LPEG_cleaner ( 'sql' , braces ) 
 %    \end{macrocode}
 %
 % 
@@ -7421,18 +7763,18 @@
 %
 % We define different \textsc{lpeg} dealing with comments in the SQL listings.
 %    \begin{macrocode}
-local Comment = 
-  WithStyle ( 'Comment' ,
-     Q "--"   -- syntax of SQL92
-     * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0 ) -- $
-  * ( EOL + -1 )
+  local Comment = 
+    WithStyle ( 'Comment' ,
+       Q "--"   -- syntax of SQL92
+       * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0 ) -- $
+    * ( EOL + -1 )
 
-local LongComment = 
-  WithStyle ( 'Comment' , 
-               Q "/*" 
-               * ( CommentMath + Q ( ( 1 - P "*/" - S "$\r" ) ^ 1 ) + EOL ) ^ 0 
-               * Q "*/" 
-            ) -- $
+  local LongComment = 
+    WithStyle ( 'Comment' , 
+                 Q "/*" 
+                 * ( CommentMath + Q ( ( 1 - P "*/" - S "$\r" ) ^ 1 ) + EOL ) ^ 0 
+                 * Q "*/" 
+              ) -- $
 %    \end{macrocode}
 %
 %
@@ -7441,78 +7783,80 @@
 % \paragraph{The main LPEG for the language SQL}
 %
 %    \begin{macrocode}
-local EndKeyword = Space + Punct + Delim + EOL + Beamer + DetectedCommands + -1 
+  local EndKeyword = Space + Punct + Delim + EOL + Beamer + DetectedCommands + -1 
 %    \end{macrocode}
 %
 %    \begin{macrocode}
-local TableField = 
-       K ( 'Name.Table' , identifier ) 
-     * Q "." 
-     * K ( 'Name.Field' , identifier ) 
+  local TableField = 
+         K ( 'Name.Table' , identifier ) 
+       * Q "." 
+       * K ( 'Name.Field' , identifier ) 
 
-local OneField = 
-  ( 
-    Q ( "(" * ( 1 - P ")" ) ^ 0 * ")" )
-    + 
-        K ( 'Name.Table' , identifier ) 
-      * Q "." 
-      * K ( 'Name.Field' , identifier ) 
-    + 
-    K ( 'Name.Field' , identifier ) 
-  )
-  * ( 
-      Space * LuaKeyword "AS" * Space * K ( 'Name.Field' , identifier ) 
-    ) ^ -1
-  * ( Space * ( LuaKeyword "ASC" + LuaKeyword "DESC" ) ) ^ -1
+  local OneField = 
+    ( 
+      Q ( "(" * ( 1 - P ")" ) ^ 0 * ")" )
+      + 
+          K ( 'Name.Table' , identifier ) 
+        * Q "." 
+        * K ( 'Name.Field' , identifier ) 
+      + 
+      K ( 'Name.Field' , identifier ) 
+    )
+    * ( 
+        Space * LuaKeyword "AS" * Space * K ( 'Name.Field' , identifier ) 
+      ) ^ -1
+    * ( Space * ( LuaKeyword "ASC" + LuaKeyword "DESC" ) ) ^ -1
 
-local OneTable = 
-     K ( 'Name.Table' , identifier ) 
-   * ( 
-       Space 
-       * LuaKeyword "AS"  
-       * Space 
-       * K ( 'Name.Table' , identifier ) 
-     ) ^ -1 
+  local OneTable = 
+       K ( 'Name.Table' , identifier ) 
+     * ( 
+         Space 
+         * LuaKeyword "AS"  
+         * Space 
+         * K ( 'Name.Table' , identifier ) 
+       ) ^ -1 
 
-local WeCatchTableNames = 
-     LuaKeyword "FROM" 
-   * ( Space + EOL ) 
-   * OneTable * ( SkipSpace * Q "," * SkipSpace * OneTable ) ^ 0 
-  + ( 
-      LuaKeyword "JOIN" + LuaKeyword "INTO" + LuaKeyword "UPDATE" 
-      + LuaKeyword "TABLE" 
-    ) 
-    * ( Space + EOL ) * OneTable 
+  local WeCatchTableNames = 
+       LuaKeyword "FROM" 
+     * ( Space + EOL ) 
+     * OneTable * ( SkipSpace * Q "," * SkipSpace * OneTable ) ^ 0 
+    + ( 
+        LuaKeyword "JOIN" + LuaKeyword "INTO" + LuaKeyword "UPDATE" 
+        + LuaKeyword "TABLE" 
+      ) 
+      * ( Space + EOL ) * OneTable 
 %    \end{macrocode}
 % 
 %    \begin{macrocode}
-local EndKeyword = Space + Punct + Delim + EOL + Beamer + DetectedCommands + -1 
+  local EndKeyword = Space + Punct + Delim + EOL + Beamer + DetectedCommands + -1 
 %    \end{macrocode}
 %
 %
 % First, the main loop :
 %    \begin{macrocode}
-local Main = 
-     Space 
-     + Tab
-     + Escape + EscapeMath 
-     + CommentLaTeX
-     + Beamer
-     + DetectedCommands
-     + Comment + LongComment
-     + Delim
-     + Operator
-     + String
-     + Punct
-     + WeCatchTableNames
-     + ( TableField + Identifier ) * ( Space + Operator + Punct + Delim + EOL + -1 )  
-     + Number
-     + Word
+  local Main = 
+       space ^ 0 * EOL
+       + Space 
+       + Tab
+       + Escape + EscapeMath 
+       + CommentLaTeX
+       + Beamer
+       + DetectedCommands
+       + Comment + LongComment
+       + Delim
+       + Operator
+       + String
+       + Punct
+       + WeCatchTableNames
+       + ( TableField + Identifier ) * ( Space + Operator + Punct + Delim + EOL + -1 )  
+       + Number
+       + Word
 %    \end{macrocode}
 %
+% \bigskip
 % Here, we must not put |local|!
 %    \begin{macrocode}
-LPEG1['sql'] = Main ^ 0 
+  LPEG1['sql'] = Main ^ 0 
 %    \end{macrocode}
 %
 % \bigskip
@@ -7522,87 +7866,112 @@
 % will be used as marker in order to delimit the argument of the command
 % \texttt{\textbackslash @@\_begin\_line:}}.
 %    \begin{macrocode}
-LPEG2['sql'] =
-  Ct (
-       ( space ^ 0 * "\r" ) ^ -1 
-       * BeamerBeginEnvironments 
-       * Lc [[\@@_begin_line:]]
-       * SpaceIndentation ^ 0 
-       * ( space ^ 1 * -1 + space ^ 0 * EOL + Main ) ^ 0 
-       * -1 
-       * Lc [[\@@_end_line:]]
-     )
+  LPEG2['sql'] =
+    Ct (
+         ( space ^ 0 * "\r" ) ^ -1 
+         * BeamerBeginEnvironments 
+         * Lc [[\@@_begin_line:]]
+         * SpaceIndentation ^ 0 
+         * ( space ^ 1 * -1 + space ^ 0 * EOL + Main ) ^ 0 
+         * -1 
+         * Lc [[\@@_end_line:]]
+       )
 %    \end{macrocode}
 %
+% \bigskip
+% End of the Lua scope for the language SQL.
+%    \begin{macrocode}
+end
+%    \end{macrocode}
 % 
 % \subsubsection{The language ``Minimal''}
 % 
+% We open a Lua local scope for the language ``|minimal|'' (of course, there
+% will be also global definitions).
 %    \begin{macrocode}
-local Punct = Q ( S ",:;!\\" )
+do 
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+  local Punct = Q ( S ",:;!\\" )
 
-local Comment = 
-  WithStyle ( 'Comment' ,
-              Q "#" 
-              * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0 -- $
-            )
-     * ( EOL + -1 )
+  local Comment = 
+    WithStyle ( 'Comment' ,
+                Q "#" 
+                * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0 -- $
+              )
+       * ( EOL + -1 )
 
-local String = 
-  WithStyle ( 'String.Short' ,
-              Q "\"" 
-              * ( VisualSpace 
-                  + Q ( ( P "\\\"" + 1 - S " \"" ) ^ 1 ) 
-                ) ^ 0 
-              * Q "\""
-            )
-
+  local String = 
+    WithStyle ( 'String.Short' ,
+                Q "\"" 
+                * ( VisualSpace 
+                    + Q ( ( P "\\\"" + 1 - S " \"" ) ^ 1 ) 
+                  ) ^ 0 
+                * Q "\""
+              )
 %    \end{macrocode}
+%
+% \bigskip
 % The argument of |Compute_braces| must be a pattern \emph{which does no
 % catching} corresponding to the strings of the language.
 %    \begin{macrocode}
-local braces = Compute_braces ( P "\"" * ( P "\\\"" + 1 - P "\"" ) ^ 1 * "\"" ) 
+  local braces = Compute_braces ( P "\"" * ( P "\\\"" + 1 - P "\"" ) ^ 1 * "\"" ) 
 
-if piton.beamer then Beamer = Compute_Beamer ( 'minimal' , braces ) end
+  if piton.beamer then Beamer = Compute_Beamer ( 'minimal' , braces ) end
 
-DetectedCommands = Compute_DetectedCommands ( 'minimal' , braces ) 
+  DetectedCommands = Compute_DetectedCommands ( 'minimal' , braces ) 
 
-LPEG_cleaner['minimal'] = Compute_LPEG_cleaner ( 'minimal' , braces ) 
+  LPEG_cleaner['minimal'] = Compute_LPEG_cleaner ( 'minimal' , braces ) 
 
-local identifier = letter * alphanum ^ 0
+  local identifier = letter * alphanum ^ 0
 
-local Identifier = K ( 'Identifier.Internal' , identifier )
+  local Identifier = K ( 'Identifier.Internal' , identifier )
 
-local Delim = Q ( S "{[()]}" )
+  local Delim = Q ( S "{[()]}" )
 
-local Main = 
-     Space 
-     + Tab
-     + Escape + EscapeMath 
-     + CommentLaTeX
-     + Beamer
-     + DetectedCommands
-     + Comment
-     + Delim
-     + String
-     + Punct
-     + Identifier 
-     + Number
-     + Word
+  local Main = 
+       space ^ 0 * EOL
+       + Space 
+       + Tab
+       + Escape + EscapeMath 
+       + CommentLaTeX
+       + Beamer
+       + DetectedCommands
+       + Comment
+       + Delim
+       + String
+       + Punct
+       + Identifier 
+       + Number
+       + Word
+%    \end{macrocode}
+%
+% \bigskip
+% Here, we must not put |local|!
+%    \begin{macrocode}
+  LPEG1['minimal'] = Main ^ 0
 
-LPEG1['minimal'] = Main ^ 0
-
-LPEG2['minimal'] = 
-  Ct (
-       ( space ^ 0 * "\r" ) ^ -1 
-       * BeamerBeginEnvironments 
-       * Lc [[\@@_begin_line:]]
-       * SpaceIndentation ^ 0 
-       * ( space ^ 1 * -1 + space ^ 0 * EOL + Main ) ^ 0 
-       * -1 
-       * Lc [[\@@_end_line:]]
-     )
-
+  LPEG2['minimal'] = 
+    Ct (
+         ( space ^ 0 * "\r" ) ^ -1 
+         * BeamerBeginEnvironments 
+         * Lc [[\@@_begin_line:]]
+         * SpaceIndentation ^ 0 
+         * ( space ^ 1 * -1 + space ^ 0 * EOL + Main ) ^ 0 
+         * -1 
+         * Lc [[\@@_end_line:]]
+       )
+%    \end{macrocode}
+% 
+%
 % \bigskip
+% End of the Lua scope for the language ``|minimal|''.
+%    \begin{macrocode}
+end
+%    \end{macrocode}
+%
+% \bigskip
 % \subsubsection{The function Parse}
 %
 % \medskip
@@ -7673,7 +8042,8 @@
 % That function merely reads the file (between |first_line| and |last_line|) and
 % then apply the function~|Parse| to the resulting Lua string.
 %    \begin{macrocode}
-function piton.ParseFile ( language , name , first_line , last_line , split )
+function piton.ParseFile 
+  ( lang , name , first_line , last_line , splittable , split )
   local s = ''
   local i = 0 
   for line in io.lines ( name ) do 
@@ -7696,15 +8066,21 @@
     end
   end
   if split == 1 then
-    piton.GobbleSplitParse ( language , 0 , s ) 
+    piton.RetrieveGobbleSplitParse ( lang , 0 , splittable , s ) 
   else
-    sprintL3 [[ \bool_if:NT \g_@@_footnote_bool \savenotes \vtop \bgroup ]] 
-    piton.Parse ( language , s )    
-    sprintL3  
-      [[\vspace{2.5pt}\egroup\bool_if:NT\g_@@_footnote_bool\endsavenotes\par]] 
+    piton.RetrieveGobbleParse ( lang , 0 , splittable , s )    
   end
 end
 %    \end{macrocode}
+%
+% \bigskip
+%    \begin{macrocode}
+function piton.RetrieveGobbleParse ( lang , n , splittable , code )
+  local s 
+  s = ( ( P " " ^ 0 * "\r" ) ^ -1 * C ( P ( 1 ) ^ 0 ) * -1 ) : match ( code )  
+  piton.GobbleParse ( lang , n , splittable , s )
+end 
+%    \end{macrocode}
 % 
 % \bigskip
 % \subsubsection{Two variants of  the function Parse with integrated preprocessors}
@@ -7730,8 +8106,16 @@
 % Be careful: we have to write |[[\@@_breakable_space: ]]| with a space after
 % the name of the LaTeX command |\@@_breakable_space:|. 
 %    \begin{macrocode}
-  local s = ( Cs ( ( P [[\@@_breakable_space: ]] / ' ' + 1 ) ^ 0 ) ) 
-            : match ( code )
+  local s
+  s = ( Cs ( ( P [[\@@_breakable_space: ]] / ' ' + 1 ) ^ 0 ) ) 
+      : match ( code )
+%    \end{macrocode}
+% Remember that |\@@_leading_space:| does not create a space, only an
+% incrementation of the counter |\g_@@_indentation_int|. That's why we don't
+% replace it by a space...
+%    \begin{macrocode}
+  s = ( Cs ( ( P [[\@@_leading_space: ]] / '' + 1 ) ^ 0 ) ) 
+      : match ( s )
   return piton.Parse ( lang , s )
 end
 %    \end{macrocode}
@@ -7820,7 +8204,8 @@
     end
 %    \end{macrocode}
 % We have a second test |if n == 0| because the, even if the key like
-% |auto-gobble| is in force, it's possible that, in fact, there is no space to gobble...
+% |auto-gobble| is in force, it's possible that, in fact, there is no space to
+% gobble... 
 %    \begin{macrocode}
     if n == 0 then
       return code
@@ -7846,33 +8231,29 @@
 %
 % \bigskip
 % In the following code, |n| is the value of |\l_@@_gobble_int|.
+%
+% |splittable| is the value of |\l_@@_splittable_int|.
 %    \begin{macrocode}
-function piton.GobbleParse ( lang , n , code )
+function piton.GobbleParse ( lang , n , splittable , code )
+  piton.ComputeLinesStatus ( code , splittable ) 
   piton.last_code = gobble ( n , code )
   piton.last_language = lang
 %    \end{macrocode}
 % We count the number of lines of the informatic code. The result will be stored
-% by Lua in |\l_@@_nb_lines_int|. That information will be used to allow or
-% disallow page breaks (when |splittable| is in force).
+% by Lua in |\l_@@_nb_lines_int|. 
 %    \begin{macrocode}
   piton.CountLines ( piton.last_code ) 
   sprintL3 [[ \bool_if:NT \g_@@_footnote_bool \savenotes ]] 
-%    \end{macrocode}
-% We begin a |\vtop| for an non-splittable block of lines.
-%    \begin{macrocode}
-  sprintL3 [[ \vtop \bgroup ]] 
   piton.Parse ( lang , piton.last_code )
 %    \end{macrocode}
-% We close the latest opened |\vtop| with the following |\egroup|. Be careful:
-% that |\vtop| is \emph{not} necessarily the |\vtop| opened two lines above
-% because the commands |\@@_newline:| inserted by Lua may open and close
-% |\vtop|s and start and finish paragraphs (when |splittable| is in force).
+%
 %    \begin{macrocode}
-  sprintL3 [[ \vspace{2.5pt} \egroup ]]
+  sprintL3 [[ \vspace{2.5pt} ]]
   sprintL3 [[ \bool_if:NT \g_@@_footnote_bool \endsavenotes ]]
 %    \end{macrocode}
-% We finish the paragraph (each block of non-splittable lines of code is
-% composed in a |\vtop| inserted in a paragraph).
+% We finish the paragraph (each line of the listing is composed in a TeX box
+% --- with potentially several lines when |break-lines-in-Piton| is in force ---
+% put alone in a paragraph.
 %    \begin{macrocode}
   sprintL3 [[ \par ]] 
 %    \end{macrocode}
@@ -7900,35 +8281,49 @@
 % argument |n| corresponds to the value of the key |gobble| (number of spaces to
 % gobble). 
 %    \begin{macrocode}
-function piton.GobbleSplitParse ( lang , n , code )
-  P { "E" ,
-      E = ( V "F" 
-           * ( P " " ^ 0 * "\r" 
-               / ( function ( x ) sprintL3 [[ \@@_incr_visual_line: ]] end )
-             ) ^ 1 
-             / ( function ( x ) 
-                 sprintL3 ( piton.string_between_chunks ) 
-                 end ) 
-          ) ^ 0 * V "F" ,
+function piton.GobbleSplitParse ( lang , n , splittable , code )
+  local chunks 
+  chunks =
+     ( 
+       Ct ( 
+            ( 
+              P " " ^ 0 * "\r" 
+              + 
+              C ( ( ( 1 - P "\r" ) ^ 1 * "\r" - ( P " " ^ 0 * "\r" ) ) ^ 1 ) 
+            ) ^ 0 
+          ) 
+     ) : match ( gobble ( n , code ) )
+  sprintL3 ( [[ \begingroup ]] ) 
+  sprintL3 
+    ( 
+      [[ \PitonOptions { split-on-empty-lines=false, gobble = 0, ]]
+      .. "language = " .. lang .. "," 
+      .. "splittable = " .. splittable .. "}"
+    )
+  for k , v in pairs ( chunks ) do 
+    if k > 1 then 
+     sprintL3 ( [[\l_@@_split_separation_tl ]] )
+    end 
+    tex.sprint 
+      ( 
+        [[\begin{]] .. piton.env_used_by_split .. "}\r"
+        .. v 
+        .. [[\end{]] .. piton.env_used_by_split .. "}"
+      )
+  end
+  sprintL3 ( [[ \endgroup ]] ) 
+end 
 %    \end{macrocode}
-% The non-terminal |F| corresponds to a chunk of the informatic code.
+%
+%  \bigskip 
 %    \begin{macrocode}
-      F = C ( V "G" ^ 0 ) 
-%    \end{macrocode}
-% The second argument of |piton.GobbleSplitParse| is the argument |gobble|: we put
-% that argument to~$0$ because we will have gobbled previously the whole argument
-% |code| (see below).
-%    \begin{macrocode}
-          / ( function ( x ) piton.GobbleParse ( lang , 0 , x ) end ) , 
-%    \end{macrocode}
-% The non-terminal |G| corresponds to a non-empty line of code.
-%    \begin{macrocode}
-      G = ( 1 - P "\r" ) ^ 0 * "\r" - ( P " " ^ 0 * "\r" ) 
-          + ( ( 1 - P "\r" ) ^ 1 * -1 - ( P " " ^ 0 * -1 ) )
-    } : match ( gobble ( n , code ) ) 
+function piton.RetrieveGobbleSplitParse ( lang , n , splittable , code )
+  local s 
+  s = ( ( P " " ^ 0 * "\r" ) ^ -1 * C ( P ( 1 ) ^ 0 ) * -1 ) : match ( code )  
+  piton.GobbleSplitParse ( lang , n , splittable , s )
 end 
 %    \end{macrocode}
-%
+% 
 % \bigskip
 % The following Lua string will be inserted between the chunks of code created
 % when the key |split-on-empty-lines| is in force. It's used only once: you have
@@ -7953,18 +8348,19 @@
 % 
 % 
 % \bigskip
+% 
 % \subsubsection{To count the number of lines}
 %
-% \medskip
-% The following function is only used once (in |piton.GobbleParse|). We have
-% written an autonomous function only for legibility. The number of lines of the
-% code will be stored in |\l_@@_nb_lines_int| and will be used to allow or
-% disallow line breaks (when |splittable| is in force).
 %    \begin{macrocode}
 function piton.CountLines ( code )
-  local count = 0 
-  for i in code : gmatch ( "\r" ) do count = count + 1 end 
-  sprintL3 ( string.format ( [[ \int_set:Nn  \l_@@_nb_lines_int { % i } ]] , count ) ) 
+  local count = 0
+  count =
+     ( Ct ( ( ( 1 - P "\r" ) ^ 0 * C "\r" ) ^ 0
+            * ( ( 1 - P "\r" ) ^ 1 * Cc "\r" ) ^ -1
+            * -1
+          ) / table.getn
+     ) : match ( code )
+  sprintL3 ( string.format ( [[ \int_set:Nn  \l_@@_nb_lines_int { %i } ]] , count ) ) 
 end 
 %    \end{macrocode}
 %
@@ -7984,7 +8380,7 @@
           ) / table.getn
      ) : match ( code )
   sprintL3 
-   ( string.format ( [[ \int_set:Nn  \l_@@_nb_non_empty_lines_int { % i } ]] , count ) ) 
+   ( string.format ( [[ \int_set:Nn  \l_@@_nb_non_empty_lines_int { %i } ]] , count ) ) 
 end 
 %    \end{macrocode}
 %
@@ -7994,7 +8390,7 @@
   local count = 0 
   for line in io.lines ( name ) do count = count + 1 end
   sprintL3 
-   ( string.format ( [[ \int_set:Nn \l_@@_nb_lines_int { %i } ]], count))
+   ( string.format ( [[ \int_set:Nn \l_@@_nb_lines_int { %i } ]], count ) )
 end 
 %    \end{macrocode}
 %
@@ -8050,6 +8446,143 @@
 %    \end{macrocode}
 %
 % \bigskip
+% \subsubsection{To determine the empty lines of the listings}
+%
+% Despite its name, the Lua function |ComputeLinesStatus| computes
+% |piton.lines_status| but also |piton.empty_lines|.
+%
+% \medskip
+% In |piton.empty_lines|, a line will have the number 0 if it's a empty line (in
+% fact a blank line, with only spaces) and 1 elsewhere.
+% 
+% \medskip
+% In |piton.lines_status|, each line will have a status with regard the
+% breaking points allowed (for the changes of pages).
+% \begin{itemize}
+% \item 0 if the line is empty and a page break is allowed;
+% \item 1 if the line is not empty but a page break is allowed after that line;
+% \item 2 if a page break is \emph{not} allowed after that line (empty or not empty).
+% \end{itemize}
+%    
+% \medskip
+% |splittable| is the value of |\l_@@_splittable_int|.
+% However, if |splittable-on-empty-lines| is in force, |splittable| is the
+% opposite of |\l_@@_splittable_int|.
+%    \begin{macrocode}
+function piton.ComputeLinesStatus ( code , splittable ) 
+%    \end{macrocode}
+% The lines in the listings which correspond to the beginning or the end of an
+% environment of Beamer (eg. |\begin{uncoverenv}|) must be retrieved (those
+% lines have \emph{no} number and therefore, \emph{no} status).
+%    \begin{macrocode}
+  local lpeg_line_beamer
+  if piton.beamer then
+    lpeg_line_beamer = 
+       space ^ 0 
+        * P "\\begin{" * piton.BeamerEnvironments * "}"
+        * ( "<" * ( 1 - P ">" ) ^ 0 * ">" ) ^ -1 
+       +
+       space ^ 0 
+        * P "\\end{" * piton.BeamerEnvironments * "}" 
+  else 
+    lpeg_line_beamer = P ( false ) 
+  end 
+%    \end{macrocode}
+%    \begin{macrocode}
+  local lpeg_empty_lines =
+    Ct (
+         ( lpeg_line_beamer * "\r" 
+           +
+           P " " ^ 0 * "\r" * Cc ( 0 )
+           + 
+           ( 1 - P "\r" ) ^ 0 * "\r" * Cc ( 1 )  
+         ) ^ 0
+         * 
+         ( lpeg_line_beamer + ( 1 - P "\r" ) ^ 1 * Cc ( 1 ) ) ^ -1
+       )
+    * -1
+%    \end{macrocode}
+%    \begin{macrocode}
+  local lpeg_all_lines =    
+    Ct ( 
+         ( lpeg_line_beamer * "\r" 
+           +
+           ( 1 - P "\r" ) ^ 0 * "\r" * Cc ( 1 ) 
+         ) ^ 0 
+         * 
+         ( lpeg_line_beamer + ( 1 - P "\r" ) ^ 1 * Cc ( 1 ) ) ^ -1
+       )
+    * -1
+%    \end{macrocode}
+% We begin with the computation of |piton.empty_lines|. It will be used in
+% conjonction with |line-numbers|. 
+%    \begin{macrocode}
+  piton.empty_lines = lpeg_empty_lines : match ( code ) 
+%    \end{macrocode}
+% 
+% Now, we compute |piton.lines_status|. It will be used in conjonction with
+% |splittable| and |splittable-on-empty-lines|. 
+%
+% Now, we will take into account the current value of |\l_@@_splittable_int|
+% (provided by the \emph{absolute value} of the argument |splittable|).
+%    \begin{macrocode}
+  local lines_status
+  local s = splittable
+  if splittable < 0 then s = - splittable end 
+%    \end{macrocode}
+% 
+%    \begin{macrocode}
+  if splittable > 0 then  
+    lines_status = lpeg_all_lines : match ( code ) 
+  else
+%    \end{macrocode}
+% Here, we should try to copy |piton.empty_lines| but it's not easy.
+%    \begin{macrocode}
+    lines_status = lpeg_empty_lines : match ( code ) 
+    for i , x in ipairs ( lines_status ) do
+      if x == 0 then
+        for j = 1 , s - 1 do
+          if i + j > #lines_status then break end 
+          if lines_status[i+j] == 0 then break end 
+            lines_status[i+j] = 2 
+        end
+        for j = 1 , s - 1 do
+          if i - j - 1 == 0 then break end 
+          if lines_status[i-j-1] == 0 then break end 
+          lines_status[i-j-1] = 2 
+        end
+      end 
+    end 
+  end 
+%    \end{macrocode}
+% 
+% In all cases (whatever is the value of |splittable-on-empty-lines|) we have to
+% deal with both extremities of the listing to format.
+%
+% First from the beginning of the code.
+%    \begin{macrocode}
+  for j = 1 , s - 1 do
+    if j > #lines_status then break end
+    if lines_status[j] == 0 then break end
+    lines_status[j] = 2
+  end
+%    \end{macrocode}
+% Now, from the end of the code.
+%    \begin{macrocode}
+  for j = 1 , s - 1 do 
+    if #lines_status - j == 0 then break end 
+    if lines_status[#lines_status - j] == 0 then break end
+    lines_status[#lines_status - j] = 2
+  end 
+%    \end{macrocode}
+% 
+% \bigskip
+%    \begin{macrocode}
+  piton.lines_status = lines_status
+end 
+%    \end{macrocode}
+% 
+% \bigskip
 % \subsubsection{To create new languages with the syntax of listings}
 %
 %    \begin{macrocode}
@@ -8353,7 +8886,7 @@
         central_pattern = P ( arg3 .. arg3 ) + central_pattern
       end
       if arg1 == "m" 
-      then prefix = lpeg.B ( 1 - letter - ")" - "]" ) 
+      then prefix = B ( 1 - letter - ")" - "]" ) 
       else prefix = P ( true ) 
       end
 %    \end{macrocode}
@@ -8503,7 +9036,8 @@
 % 
 %    \begin{macrocode}
   local Main = 
-       Space 
+       space ^ 0 * EOL
+       + Space 
        + Tab
        + Escape + EscapeMath 
        + CommentLaTeX
@@ -8526,6 +9060,8 @@
 %
 % The \textsc{lpeg} |LPEG1[lang]| is used to reformat small elements, for
 % example the arguments of the ``detected commands''.
+%
+% Of course, here, we must not put |local|!
 %   \begin{macrocode}
   LPEG1[lang] = Main ^ 0 
 %    \end{macrocode}
@@ -8617,6 +9153,16 @@
 %
 % \verb|https://github.com/fpantigny/piton|
 %
+% \subsection*{Changes between versions 3.1 and 4.0}
+%
+% This version introduces an incompatibility: the syntax for the relative and
+% absolute paths in |\PitonInputFile| and the key |path| has been changed to be
+% conform to usual conventions. An temporary key |old-PitonInputFile|, available
+% at load-time, has been added for backward compatibility.
+%
+% New keys |font-command|, |splittable-on-empty-lines| and |env-used-by-split|.
+%
+%
 % \subsection*{Changes between versions 3.0 and 3.1}
 %
 % Keys |line-numbers/format|, |detected-beamer-commands| and

Modified: trunk/Master/texmf-dist/tex/lualatex/piton/piton.lua
===================================================================
--- trunk/Master/texmf-dist/tex/lualatex/piton/piton.lua	2024-09-22 20:22:16 UTC (rev 72350)
+++ trunk/Master/texmf-dist/tex/lualatex/piton/piton.lua	2024-09-22 20:22:25 UTC (rev 72351)
@@ -20,7 +20,7 @@
 -- -------------------------------------------
 -- 
 -- This file is part of the LuaLaTeX package 'piton'.
-piton_version = "3.1b" -- 2024/08/29
+piton_version = "4.0" -- 2024/09/22
 
 
 
@@ -32,7 +32,7 @@
 end
 local P, S, V, C, Ct, Cc = lpeg.P, lpeg.S, lpeg.V, lpeg.C, lpeg.Ct, lpeg.Cc
 local Cs , Cg , Cmt , Cb = lpeg.Cs, lpeg.Cg , lpeg.Cmt , lpeg.Cb
-local R = lpeg.R
+local B , R = lpeg.B , lpeg.R
 local function Q ( pattern )
   return Ct ( Cc ( luatexbase.catcodetables.CatcodeTableOther ) * C ( pattern ) )
 end
@@ -120,7 +120,7 @@
 local Punct = Q ( S ".,:;!" )
 
 local Tab = "\t" * Lc [[\__piton_tab:]]
-local SpaceIndentation = Lc [[\__piton_an_indentation_space:]] * Q " "
+local SpaceIndentation = Lc [[\__piton_leading_space:]] * Q " "
 local Delim = Q ( S "[({})]" )
 local VisualSpace = space * Lc [[\l__piton_space_tl]]
   local strict_braces  =
@@ -146,7 +146,7 @@
 end
 local function Compute_DetectedCommands ( lang , braces ) return
   Ct ( Cc "Open"
-        * C ( piton.DetectedCommands * P "{" )
+        * C ( piton.DetectedCommands * space ^ 0 * P "{" )
         * Cc "}"
      )
    * ( braces
@@ -186,7 +186,7 @@
       * "\r"
     ) ^ 0
 local function Compute_Beamer ( lang , braces )
-  local lpeg = L ( P "\\pause" * ( "[" * ( 1 - P "]" ) ^ 0 * "]" ) ^ -1 )
+  local lpeg = L ( P [[\pause]] * ( "[" * ( 1 - P "]" ) ^ 0 * "]" ) ^ -1 )
   lpeg = lpeg +
       Ct ( Cc "Open"
             * C ( piton.BeamerCommands
@@ -200,7 +200,7 @@
        * "}"
        * Ct ( Cc "Close" )
   lpeg = lpeg +
-    L ( P "\\alt" * "<" * ( 1 - P ">" ) ^ 0 * ">" * "{" )
+    L ( P [[\alt]] * "<" * ( 1 - P ">" ) ^ 0 * ">" * "{" )
      * ( braces /
          ( function ( s ) if s ~= '' then return LPEG1[lang] : match ( s ) end end ) )
      * L ( P "}{" )
@@ -208,7 +208,7 @@
          ( function ( s ) if s ~= '' then return LPEG1[lang] : match ( s ) end end ) )
      * L ( P "}" )
   lpeg = lpeg +
-      L ( ( P "\\temporal" ) * "<" * ( 1 - P ">" ) ^ 0 * ">" * "{" )
+      L ( ( P [[\temporal]] ) * "<" * ( 1 - P ">" ) ^ 0 * ">" * "{" )
       * ( braces
           / ( function ( s )
               if s ~= '' then return LPEG1[lang] : match ( s ) end end ) )
@@ -246,906 +246,962 @@
 local CommentMath =
   P "$" * K ( 'Comment.Math' , ( 1 - S "$\r" ) ^ 1  ) * P "$" -- $
 local PromptHastyDetection =
-  ( # ( P ">>>" + "..." ) * Lc '\\__piton_prompt:' ) ^ -1
+  ( # ( P ">>>" + "..." ) * Lc [[\__piton_prompt:]] ) ^ -1
 local Prompt = K ( 'Prompt' , ( ( P ">>>" + "..." ) * P " " ^ -1 ) ^ -1  )
-local EOL_without_space_indentation =
+local EOL =
   P "\r"
   *
   (
-    ( space ^ 0 * -1 )
+    space ^ 0 * -1
     +
     Ct (
          Cc "EOL"
          *
-         Ct (
-              Lc [[\__piton_end_line:]]
+         Ct ( Lc [[\__piton_end_line:]]
               * BeamerEndEnvironments
-              * BeamerBeginEnvironments
-              * PromptHastyDetection
-              * Lc [[\__piton_newline:\__piton_begin_line:]]
-              * Prompt
+              *
+                (
+                    -1
+                  +
+                    BeamerBeginEnvironments
+                  * PromptHastyDetection
+                  * Lc [[\__piton_newline:\__piton_begin_line:]]
+                  * Prompt
+                )
             )
        )
   )
-local EOL = EOL_without_space_indentation
   * ( SpaceIndentation ^ 0 * # ( 1 - S " \r" ) ) ^ -1
 local CommentLaTeX =
-  P(piton.comment_latex)
-  * Lc "{\\PitonStyle{Comment.LaTeX}{\\ignorespaces"
+  P ( piton.comment_latex )
+  * Lc [[{\PitonStyle{Comment.LaTeX}{\ignorespaces]]
   * L ( ( 1 - P "\r" ) ^ 0 )
-  * Lc "}}"
+  * Lc [[}}]]
   * ( EOL + -1 )
-local Operator =
-  K ( 'Operator' ,
-      P "!=" + "<>" + "==" + "<<" + ">>" + "<=" + ">=" + ":=" + "//" + "**"
-      + S "-~+/*%=<>&.@|" )
+do
+  local Operator =
+    K ( 'Operator' ,
+        P "!=" + "<>" + "==" + "<<" + ">>" + "<=" + ">=" + ":=" + "//" + "**"
+        + S "-~+/*%=<>&.@|" )
 
-local OperatorWord =
-  K ( 'Operator.Word' , P "in" + "is" + "and" + "or" + "not" )
-local For = K ( 'Keyword' , P "for" )
-            * Space
-            * Identifier
-            * Space
-            * K ( 'Keyword' , P "in" )
+  local OperatorWord =
+    K ( 'Operator.Word' , P "in" + "is" + "and" + "or" + "not" )
+  local For = K ( 'Keyword' , P "for" )
+              * Space
+              * Identifier
+              * Space
+              * K ( 'Keyword' , P "in" )
 
-local Keyword =
-  K ( 'Keyword' ,
-      P "as" + "assert" + "break" + "case" + "class" + "continue" + "def" +
-      "del" + "elif" + "else" + "except" + "exec" + "finally" + "for" + "from" +
-      "global" + "if" + "import" + "lambda" + "non local" + "pass" + "return" +
-      "try" + "while" + "with" + "yield" + "yield from" )
-  + K ( 'Keyword.Constant' , P "True" + "False" + "None" )
+  local Keyword =
+    K ( 'Keyword' ,
+        P "as" + "assert" + "break" + "case" + "class" + "continue" + "def" +
+        "del" + "elif" + "else" + "except" + "exec" + "finally" + "for" + "from" +
+        "global" + "if" + "import" + "lambda" + "non local" + "pass" + "return" +
+        "try" + "while" + "with" + "yield" + "yield from" )
+    + K ( 'Keyword.Constant' , P "True" + "False" + "None" )
 
-local Builtin =
-  K ( 'Name.Builtin' ,
-      P "__import__" + "abs" + "all" + "any" + "bin" + "bool" + "bytearray" +
-      "bytes" + "chr" + "classmethod" + "compile" + "complex" + "delattr" +
-      "dict" + "dir" + "divmod" + "enumerate" + "eval" + "filter" + "float" +
-      "format" + "frozenset" + "getattr" + "globals" + "hasattr" + "hash" +
-      "hex" + "id" + "input" + "int" + "isinstance" + "issubclass" + "iter" +
-      "len" + "list" + "locals" + "map" + "max" + "memoryview" + "min" + "next"
-      + "object" + "oct" + "open" + "ord" + "pow" + "print" + "property" +
-      "range" + "repr" + "reversed" + "round" + "set" + "setattr" + "slice" +
-      "sorted" + "staticmethod" + "str" + "sum" + "super" + "tuple" + "type" +
-      "vars" + "zip" )
+  local Builtin =
+    K ( 'Name.Builtin' ,
+        P "__import__" + "abs" + "all" + "any" + "bin" + "bool" + "bytearray" +
+        "bytes" + "chr" + "classmethod" + "compile" + "complex" + "delattr" +
+        "dict" + "dir" + "divmod" + "enumerate" + "eval" + "filter" + "float" +
+        "format" + "frozenset" + "getattr" + "globals" + "hasattr" + "hash" +
+        "hex" + "id" + "input" + "int" + "isinstance" + "issubclass" + "iter" +
+        "len" + "list" + "locals" + "map" + "max" + "memoryview" + "min" + "next"
+        + "object" + "oct" + "open" + "ord" + "pow" + "print" + "property" +
+        "range" + "repr" + "reversed" + "round" + "set" + "setattr" + "slice" +
+        "sorted" + "staticmethod" + "str" + "sum" + "super" + "tuple" + "type" +
+        "vars" + "zip" )
 
-local Exception =
-  K ( 'Exception' ,
-      P "ArithmeticError" + "AssertionError" + "AttributeError" +
-      "BaseException" + "BufferError" + "BytesWarning" + "DeprecationWarning" +
-      "EOFError" + "EnvironmentError" + "Exception" + "FloatingPointError" +
-      "FutureWarning" + "GeneratorExit" + "IOError" + "ImportError" +
-      "ImportWarning" + "IndentationError" + "IndexError" + "KeyError" +
-      "KeyboardInterrupt" + "LookupError" + "MemoryError" + "NameError" +
-      "NotImplementedError" + "OSError" + "OverflowError" +
-      "PendingDeprecationWarning" + "ReferenceError" + "ResourceWarning" +
-      "RuntimeError" + "RuntimeWarning" + "StopIteration" + "SyntaxError" +
-      "SyntaxWarning" + "SystemError" + "SystemExit" + "TabError" + "TypeError"
-      + "UnboundLocalError" + "UnicodeDecodeError" + "UnicodeEncodeError" +
-      "UnicodeError" + "UnicodeTranslateError" + "UnicodeWarning" +
-      "UserWarning" + "ValueError" + "VMSError" + "Warning" + "WindowsError" +
-      "ZeroDivisionError" + "BlockingIOError" + "ChildProcessError" +
-      "ConnectionError" + "BrokenPipeError" + "ConnectionAbortedError" +
-      "ConnectionRefusedError" + "ConnectionResetError" + "FileExistsError" +
-      "FileNotFoundError" + "InterruptedError" + "IsADirectoryError" +
-      "NotADirectoryError" + "PermissionError" + "ProcessLookupError" +
-      "TimeoutError" + "StopAsyncIteration" + "ModuleNotFoundError" +
-      "RecursionError" )
+  local Exception =
+    K ( 'Exception' ,
+        P "ArithmeticError" + "AssertionError" + "AttributeError" +
+        "BaseException" + "BufferError" + "BytesWarning" + "DeprecationWarning" +
+        "EOFError" + "EnvironmentError" + "Exception" + "FloatingPointError" +
+        "FutureWarning" + "GeneratorExit" + "IOError" + "ImportError" +
+        "ImportWarning" + "IndentationError" + "IndexError" + "KeyError" +
+        "KeyboardInterrupt" + "LookupError" + "MemoryError" + "NameError" +
+        "NotImplementedError" + "OSError" + "OverflowError" +
+        "PendingDeprecationWarning" + "ReferenceError" + "ResourceWarning" +
+        "RuntimeError" + "RuntimeWarning" + "StopIteration" + "SyntaxError" +
+        "SyntaxWarning" + "SystemError" + "SystemExit" + "TabError" + "TypeError"
+        + "UnboundLocalError" + "UnicodeDecodeError" + "UnicodeEncodeError" +
+        "UnicodeError" + "UnicodeTranslateError" + "UnicodeWarning" +
+        "UserWarning" + "ValueError" + "VMSError" + "Warning" + "WindowsError" +
+        "ZeroDivisionError" + "BlockingIOError" + "ChildProcessError" +
+        "ConnectionError" + "BrokenPipeError" + "ConnectionAbortedError" +
+        "ConnectionRefusedError" + "ConnectionResetError" + "FileExistsError" +
+        "FileNotFoundError" + "InterruptedError" + "IsADirectoryError" +
+        "NotADirectoryError" + "PermissionError" + "ProcessLookupError" +
+        "TimeoutError" + "StopAsyncIteration" + "ModuleNotFoundError" +
+        "RecursionError" )
 
-local RaiseException = K ( 'Keyword' , P "raise" ) * SkipSpace * Exception * Q "("
+  local RaiseException = K ( 'Keyword' , P "raise" ) * SkipSpace * Exception * Q "("
+  local Decorator = K ( 'Name.Decorator' , P "@" * letter ^ 1  )
+  local DefClass =
+    K ( 'Keyword' , "class" ) * Space * K ( 'Name.Class' , identifier )
+  local ImportAs =
+    K ( 'Keyword' , "import" )
+     * Space
+     * K ( 'Name.Namespace' , identifier * ( "." * identifier ) ^ 0 )
+     * (
+         ( Space * K ( 'Keyword' , "as" ) * Space
+            * K ( 'Name.Namespace' , identifier ) )
+         +
+         ( SkipSpace * Q "," * SkipSpace
+            * K ( 'Name.Namespace' , identifier ) ) ^ 0
+       )
+  local FromImport =
+    K ( 'Keyword' , "from" )
+      * Space * K ( 'Name.Namespace' , identifier )
+      * Space * K ( 'Keyword' , "import" )
+  local PercentInterpol =
+    K ( 'String.Interpol' ,
+        P "%"
+        * ( "(" * alphanum ^ 1 * ")" ) ^ -1
+        * ( S "-#0 +" ) ^ 0
+        * ( digit ^ 1 + "*" ) ^ -1
+        * ( "." * ( digit ^ 1 + "*" ) ) ^ -1
+        * ( S "HlL" ) ^ -1
+        * S "sdfFeExXorgiGauc%"
+      )
+  local SingleShortString =
+    WithStyle ( 'String.Short' ,
+           Q ( P "f'" + "F'" )
+           * (
+               K ( 'String.Interpol' , "{" )
+                * K ( 'Interpol.Inside' , ( 1 - S "}':" ) ^ 0  )
+                * Q ( P ":" * ( 1 - S "}:'" ) ^ 0 ) ^ -1
+                * K ( 'String.Interpol' , "}" )
+               +
+               VisualSpace
+               +
+               Q ( ( P "\\'" + "\\\\" + "{{" + "}}" + 1 - S " {}'" ) ^ 1 )
+             ) ^ 0
+           * Q "'"
+         +
+           Q ( P "'" + "r'" + "R'" )
+           * ( Q ( ( P "\\'" + "\\\\" + 1 - S " '\r%" ) ^ 1 )
+               + VisualSpace
+               + PercentInterpol
+               + Q "%"
+             ) ^ 0
+           * Q "'" )
+  local DoubleShortString =
+    WithStyle ( 'String.Short' ,
+           Q ( P "f\"" + "F\"" )
+           * (
+               K ( 'String.Interpol' , "{" )
+                 * K ( 'Interpol.Inside' , ( 1 - S "}\":" ) ^ 0 )
+                 * ( K ( 'String.Interpol' , ":" ) * Q ( (1 - S "}:\"") ^ 0 ) ) ^ -1
+                 * K ( 'String.Interpol' , "}" )
+               +
+               VisualSpace
+               +
+               Q ( ( P "\\\"" + "\\\\" + "{{" + "}}" + 1 - S " {}\"" ) ^ 1 )
+              ) ^ 0
+           * Q "\""
+         +
+           Q ( P "\"" + "r\"" + "R\"" )
+           * ( Q ( ( P "\\\"" + "\\\\" + 1 - S " \"\r%" ) ^ 1 )
+               + VisualSpace
+               + PercentInterpol
+               + Q "%"
+             ) ^ 0
+           * Q "\""  )
 
-local Decorator = K ( 'Name.Decorator' , P "@" * letter ^ 1  )
-local DefClass =
-  K ( 'Keyword' , "class" ) * Space * K ( 'Name.Class' , identifier )
-local ImportAs =
-  K ( 'Keyword' , "import" )
-   * Space
-   * K ( 'Name.Namespace' , identifier * ( "." * identifier ) ^ 0 )
-   * (
-       ( Space * K ( 'Keyword' , "as" ) * Space
-          * K ( 'Name.Namespace' , identifier ) )
+  local ShortString = SingleShortString + DoubleShortString
+  local braces =
+    Compute_braces
+     (
+         ( P "\"" + "r\"" + "R\"" + "f\"" + "F\"" )
+             * ( P "\\\"" + 1 - S "\"" ) ^ 0 * "\""
        +
-       ( SkipSpace * Q "," * SkipSpace
-          * K ( 'Name.Namespace' , identifier ) ) ^ 0
+         ( P '\'' + 'r\'' + 'R\'' + 'f\'' + 'F\'' )
+             * ( P '\\\'' + 1 - S '\'' ) ^ 0 * '\''
      )
-local FromImport =
-  K ( 'Keyword' , "from" )
-    * Space * K ( 'Name.Namespace' , identifier )
-    * Space * K ( 'Keyword' , "import" )
-local PercentInterpol =
-  K ( 'String.Interpol' ,
-      P "%"
-      * ( "(" * alphanum ^ 1 * ")" ) ^ -1
-      * ( S "-#0 +" ) ^ 0
-      * ( digit ^ 1 + "*" ) ^ -1
-      * ( "." * ( digit ^ 1 + "*" ) ) ^ -1
-      * ( S "HlL" ) ^ -1
-      * S "sdfFeExXorgiGauc%"
+  if piton.beamer then Beamer = Compute_Beamer ( 'python' , braces ) end
+  DetectedCommands = Compute_DetectedCommands ( 'python' , braces )
+  LPEG_cleaner['python'] = Compute_LPEG_cleaner ( 'python' , braces )
+  local SingleLongString =
+    WithStyle ( 'String.Long' ,
+       ( Q ( S "fF" * P "'''" )
+           * (
+               K ( 'String.Interpol' , "{" )
+                 * K ( 'Interpol.Inside' , ( 1 - S "}:\r" - "'''" ) ^ 0  )
+                 * Q ( P ":" * (1 - S "}:\r" - "'''" ) ^ 0 ) ^ -1
+                 * K ( 'String.Interpol' , "}"  )
+               +
+               Q ( ( 1 - P "'''" - S "{}'\r" ) ^ 1 )
+               +
+               EOL
+             ) ^ 0
+         +
+           Q ( ( S "rR" ) ^ -1  * "'''" )
+           * (
+               Q ( ( 1 - P "'''" - S "\r%" ) ^ 1 )
+               +
+               PercentInterpol
+               +
+               P "%"
+               +
+               EOL
+             ) ^ 0
+        )
+        * Q "'''"  )
+  local DoubleLongString =
+    WithStyle ( 'String.Long' ,
+       (
+          Q ( S "fF" * "\"\"\"" )
+          * (
+              K ( 'String.Interpol', "{"  )
+                * K ( 'Interpol.Inside' , ( 1 - S "}:\r" - "\"\"\"" ) ^ 0 )
+                * Q ( ":" * (1 - S "}:\r" - "\"\"\"" ) ^ 0 ) ^ -1
+                * K ( 'String.Interpol' , "}"  )
+              +
+              Q ( ( 1 - S "{}\"\r" - "\"\"\"" ) ^ 1 )
+              +
+              EOL
+            ) ^ 0
+        +
+          Q ( S "rR" ^ -1  * "\"\"\"" )
+          * (
+              Q ( ( 1 - P "\"\"\"" - S "%\r" ) ^ 1 )
+              +
+              PercentInterpol
+              +
+              P "%"
+              +
+              EOL
+            ) ^ 0
+       )
+       * Q "\"\"\""
     )
-local SingleShortString =
-  WithStyle ( 'String.Short' ,
-         Q ( P "f'" + "F'" )
-         * (
-             K ( 'String.Interpol' , "{" )
-              * K ( 'Interpol.Inside' , ( 1 - S "}':" ) ^ 0  )
-              * Q ( P ":" * ( 1 - S "}:'" ) ^ 0 ) ^ -1
-              * K ( 'String.Interpol' , "}" )
-             +
-             VisualSpace
-             +
-             Q ( ( P "\\'" + "{{" + "}}" + 1 - S " {}'" ) ^ 1 )
-           ) ^ 0
-         * Q "'"
-       +
-         Q ( P "'" + "r'" + "R'" )
-         * ( Q ( ( P "\\'" + 1 - S " '\r%" ) ^ 1 )
-             + VisualSpace
-             + PercentInterpol
-             + Q "%"
-           ) ^ 0
-         * Q "'" )
-
-local DoubleShortString =
-  WithStyle ( 'String.Short' ,
-         Q ( P "f\"" + "F\"" )
-         * (
-             K ( 'String.Interpol' , "{" )
-               * K ( 'Interpol.Inside' , ( 1 - S "}\":" ) ^ 0 )
-               * ( K ( 'String.Interpol' , ":" ) * Q ( (1 - S "}:\"") ^ 0 ) ) ^ -1
-               * K ( 'String.Interpol' , "}" )
-             +
-             VisualSpace
-             +
-             Q ( ( P "\\\"" + "{{" + "}}" + 1 - S " {}\"" ) ^ 1 )
-            ) ^ 0
-         * Q "\""
-       +
-         Q ( P "\"" + "r\"" + "R\"" )
-         * ( Q ( ( P "\\\"" + 1 - S " \"\r%" ) ^ 1 )
-             + VisualSpace
-             + PercentInterpol
-             + Q "%"
-           ) ^ 0
-         * Q "\""  )
-
-local ShortString = SingleShortString + DoubleShortString
-local braces =
-  Compute_braces
-   (
-       ( P "\"" + "r\"" + "R\"" + "f\"" + "F\"" )
-           * ( P "\\\"" + 1 - S "\"" ) ^ 0 * "\""
-     +
-       ( P '\'' + 'r\'' + 'R\'' + 'f\'' + 'F\'' )
-           * ( P '\\\'' + 1 - S '\'' ) ^ 0 * '\''
-   )
-if piton.beamer then Beamer = Compute_Beamer ( 'python' , braces ) end
-DetectedCommands = Compute_DetectedCommands ( 'python' , braces )
-LPEG_cleaner['python'] = Compute_LPEG_cleaner ( 'python' , braces )
-local SingleLongString =
-  WithStyle ( 'String.Long' ,
-     ( Q ( S "fF" * P "'''" )
-         * (
-             K ( 'String.Interpol' , "{" )
-               * K ( 'Interpol.Inside' , ( 1 - S "}:\r" - "'''" ) ^ 0  )
-               * Q ( P ":" * (1 - S "}:\r" - "'''" ) ^ 0 ) ^ -1
-               * K ( 'String.Interpol' , "}"  )
-             +
-             Q ( ( 1 - P "'''" - S "{}'\r" ) ^ 1 )
-             +
-             EOL
-           ) ^ 0
-       +
-         Q ( ( S "rR" ) ^ -1  * "'''" )
-         * (
-             Q ( ( 1 - P "'''" - S "\r%" ) ^ 1 )
-             +
-             PercentInterpol
-             +
-             P "%"
-             +
-             EOL
-           ) ^ 0
-      )
-      * Q "'''"  )
-
-local DoubleLongString =
-  WithStyle ( 'String.Long' ,
-     (
-        Q ( S "fF" * "\"\"\"" )
-        * (
-            K ( 'String.Interpol', "{"  )
-              * K ( 'Interpol.Inside' , ( 1 - S "}:\r" - "\"\"\"" ) ^ 0 )
-              * Q ( ":" * (1 - S "}:\r" - "\"\"\"" ) ^ 0 ) ^ -1
-              * K ( 'String.Interpol' , "}"  )
-            +
-            Q ( ( 1 - S "{}\"\r" - "\"\"\"" ) ^ 1 )
-            +
-            EOL
+  local LongString = SingleLongString + DoubleLongString
+  local StringDoc =
+      K ( 'String.Doc' , P "r" ^ -1 * "\"\"\"" )
+        * ( K ( 'String.Doc' , (1 - P "\"\"\"" - "\r" ) ^ 0  ) * EOL
+            * Tab ^ 0
           ) ^ 0
-      +
-        Q ( S "rR" ^ -1  * "\"\"\"" )
-        * (
-            Q ( ( 1 - P "\"\"\"" - S "%\r" ) ^ 1 )
-            +
-            PercentInterpol
-            +
-            P "%"
-            +
-            EOL
-          ) ^ 0
+        * K ( 'String.Doc' , ( 1 - P "\"\"\"" - "\r" ) ^ 0 * "\"\"\"" )
+  local Comment =
+    WithStyle
+     ( 'Comment' ,
+       Q "#" * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0  -- $
      )
-     * Q "\"\"\""
-  )
-local LongString = SingleLongString + DoubleLongString
-local StringDoc =
-    K ( 'String.Doc' , P "r" ^ -1 * "\"\"\"" )
-      * ( K ( 'String.Doc' , (1 - P "\"\"\"" - "\r" ) ^ 0  ) * EOL
-          * Tab ^ 0
-        ) ^ 0
-      * K ( 'String.Doc' , ( 1 - P "\"\"\"" - "\r" ) ^ 0 * "\"\"\"" )
-local Comment =
-  WithStyle ( 'Comment' ,
-     Q "#" * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0 ) -- $
-           * ( EOL + -1 )
-local expression =
-  P { "E" ,
-       E = ( "'" * ( P "\\'" + 1 - S "'\r" ) ^ 0 * "'"
-             + "\"" * ( P "\\\"" + 1 - S "\"\r" ) ^ 0 * "\""
-             + "{" * V "F" * "}"
-             + "(" * V "F" * ")"
-             + "[" * V "F" * "]"
-             + ( 1 - S "{}()[]\r," ) ) ^ 0 ,
-       F = (   "{" * V "F" * "}"
-             + "(" * V "F" * ")"
-             + "[" * V "F" * "]"
-             + ( 1 - S "{}()[]\r\"'" ) ) ^ 0
-    }
-local Params =
-  P { "E" ,
-       E = ( V "F" * ( Q "," * V "F" ) ^ 0 ) ^ -1 ,
-       F = SkipSpace * ( Identifier + Q "*args" + Q "**kwargs" ) * SkipSpace
-           * (
-                 K ( 'InitialValues' , "=" * expression )
-               + Q ":" * SkipSpace * K ( 'Name.Type' , identifier )
-             ) ^ -1
-    }
-local DefFunction =
-  K ( 'Keyword' , "def" )
-  * Space
-  * K ( 'Name.Function.Internal' , identifier )
-  * SkipSpace
-  * Q "("  * Params * Q ")"
-  * SkipSpace
-  * ( Q "->" * SkipSpace * K ( 'Name.Type' , identifier ) ) ^ -1
-  * K ( 'ParseAgain.noCR' , ( 1 - S ":\r" ) ^ 0 )
-  * Q ":"
-  * ( SkipSpace
-      * ( EOL + CommentLaTeX + Comment ) -- in all cases, that contains an EOL
-      * Tab ^ 0
-      * SkipSpace
-      * StringDoc ^ 0 -- there may be additional docstrings
-    ) ^ -1
-local ExceptionInConsole = Exception *  Q ( ( 1 - P "\r" ) ^ 0 ) * EOL
-local EndKeyword = Space + Punct + Delim + EOL + Beamer + DetectedCommands + -1
-local Main =
-     --   space ^ 1 * -1
-     -- + space ^ 0 * EOL
-     Space
-     + Tab
-     + Escape + EscapeMath
-     + CommentLaTeX
-     + Beamer
-     + DetectedCommands
-     + LongString
-     + Comment
-     + ExceptionInConsole
-     + Delim
-     + Operator
-     + OperatorWord * EndKeyword
-     + ShortString
-     + Punct
-     + FromImport
-     + RaiseException
-     + DefFunction
-     + DefClass
-     + For
-     + Keyword * EndKeyword
-     + Decorator
-     + Builtin * EndKeyword
-     + Identifier
-     + Number
-     + Word
-LPEG1['python'] = Main ^ 0
-LPEG2['python'] =
-  Ct (
-       ( space ^ 0 * "\r" ) ^ -1
-       * BeamerBeginEnvironments
-       * PromptHastyDetection
-       * Lc [[\__piton_begin_line:]]
-       * Prompt
-       * SpaceIndentation ^ 0
-       * ( space ^ 1 * -1 + space ^ 0 * EOL + Main ) ^ 0
-       * -1
-       * Lc [[\__piton_end_line:]]
-     )
-local balanced_parens =
-  P { "E" , E = ( "(" * V "E" * ")" + ( 1 - S "()" ) ) ^ 0 }
-local Delim = Q ( P "[|" + "|]" + S "[()]" )
-local Punct = Q ( S ",:;!" )
-local cap_identifier = R "AZ" * ( R "az" + R "AZ" + S "_'" + digit ) ^ 0
-local Constructor = K ( 'Name.Constructor' , cap_identifier )
-local ModuleType = K ( 'Name.Type' , cap_identifier )
-local identifier = ( R "az" + "_" ) * ( R "az" + R "AZ" + S "_'" + digit ) ^ 0
-local Identifier = K ( 'Identifier.Internal' , identifier )
-local expression_for_fields =
-  P { "E" ,
-       E = (   "{" * V "F" * "}"
-             + "(" * V "F" * ")"
-             + "[" * V "F" * "]"
-             + "\"" * ( P "\\\"" + 1 - S "\"\r" ) ^ 0 * "\""
-             + "'" * ( P "\\'" + 1 - S "'\r" ) ^ 0 * "'"
-             + ( 1 - S "{}()[]\r;" ) ) ^ 0 ,
-       F = (   "{" * V "F" * "}"
-             + "(" * V "F" * ")"
-             + "[" * V "F" * "]"
-             + ( 1 - S "{}()[]\r\"'" ) ) ^ 0
-    }
-local OneFieldDefinition =
-    ( K ( 'Keyword' , "mutable" ) * SkipSpace ) ^ -1
-  * K ( 'Name.Field' , identifier ) * SkipSpace
-  * Q ":" * SkipSpace
-  * K ( 'TypeExpression' , expression_for_fields )
-  * SkipSpace
-
-local OneField =
-    K ( 'Name.Field' , identifier ) * SkipSpace
-  * Q "=" * SkipSpace
-  * ( expression_for_fields
-      / ( function ( s ) return LPEG1['ocaml'] : match ( s ) end )
-    )
-  * SkipSpace
-
-local Record =
-  Q "{" * SkipSpace
-  *
-    (
-      OneFieldDefinition * ( Q ";" * SkipSpace * OneFieldDefinition ) ^ 0
+    * ( EOL + -1 )
+  local expression =
+    P { "E" ,
+         E = ( "'" * ( P "\\'" + 1 - S "'\r" ) ^ 0 * "'"
+               + "\"" * ( P "\\\"" + 1 - S "\"\r" ) ^ 0 * "\""
+               + "{" * V "F" * "}"
+               + "(" * V "F" * ")"
+               + "[" * V "F" * "]"
+               + ( 1 - S "{}()[]\r," ) ) ^ 0 ,
+         F = (   "{" * V "F" * "}"
+               + "(" * V "F" * ")"
+               + "[" * V "F" * "]"
+               + ( 1 - S "{}()[]\r\"'" ) ) ^ 0
+      }
+  local Params =
+    P { "E" ,
+         E = ( V "F" * ( Q "," * V "F" ) ^ 0 ) ^ -1 ,
+         F = SkipSpace * ( Identifier + Q "*args" + Q "**kwargs" ) * SkipSpace
+             * (
+                   K ( 'InitialValues' , "=" * expression )
+                 + Q ":" * SkipSpace * K ( 'Name.Type' , identifier )
+               ) ^ -1
+      }
+  local DefFunction =
+    K ( 'Keyword' , "def" )
+    * Space
+    * K ( 'Name.Function.Internal' , identifier )
+    * SkipSpace
+    * Q "("  * Params * Q ")"
+    * SkipSpace
+    * ( Q "->" * SkipSpace * K ( 'Name.Type' , identifier ) ) ^ -1
+    * K ( 'ParseAgain.noCR' , ( 1 - S ":\r" ) ^ 0 )
+    * Q ":"
+    * ( SkipSpace
+        * ( EOL + CommentLaTeX + Comment ) -- in all cases, that contains an EOL
+        * Tab ^ 0
+        * SkipSpace
+        * StringDoc ^ 0 -- there may be additional docstrings
+      ) ^ -1
+  local ExceptionInConsole = Exception *  Q ( ( 1 - P "\r" ) ^ 0 ) * EOL
+  local EndKeyword = Space + Punct + Delim + EOL + Beamer + DetectedCommands + -1
+  local Main =
+       space ^ 0 * EOL -- faut-il le mettre en commentaire ?
+       + Space
+       + Tab
+       + Escape + EscapeMath
+       + CommentLaTeX
+       + Beamer
+       + DetectedCommands
+       + LongString
+       + Comment
+       + ExceptionInConsole
+       + Delim
+       + Operator
+       + OperatorWord * EndKeyword
+       + ShortString
+       + Punct
+       + FromImport
+       + RaiseException
+       + DefFunction
+       + DefClass
+       + For
+       + Keyword * EndKeyword
+       + Decorator
+       + Builtin * EndKeyword
+       + Identifier
+       + Number
+       + Word
+  LPEG1['python'] = Main ^ 0
+  LPEG2['python'] =
+    Ct (
+         ( space ^ 0 * "\r" ) ^ -1
+         * BeamerBeginEnvironments
+         * PromptHastyDetection
+         * Lc [[\__piton_begin_line:]]
+         * Prompt
+         * SpaceIndentation ^ 0
+         * ( space ^ 1 * -1 + space ^ 0 * EOL + Main ) ^ 0
+         * -1
+         * Lc [[\__piton_end_line:]]
+       )
+end
+do
+  local SkipSpace = ( Q " " + EOL ) ^ 0
+  local Space = ( Q " " + EOL ) ^ 1
+  local braces = Compute_braces ( "\"" * ( 1 - S "\"" ) ^ 0 * "\"" )
+  if piton.beamer then
+    Beamer = Compute_Beamer ( 'ocaml' , braces )
+  end
+  DetectedCommands = Compute_DetectedCommands ( 'ocaml' , braces )
+  local function Q ( pattern )
+    return Ct ( Cc ( luatexbase.catcodetables.CatcodeTableOther )
+                * C ( pattern ) )
+           + Beamer + DetectedCommands + EscapeMath + Escape
+  end
+  local function K ( style , pattern )
+  return
+     Lc ( "{\\PitonStyle{" .. style .. "}{" )
+     * Q ( pattern )
+     * Lc "}}"
+  end
+  local function WithStyle ( style , pattern )
+  return
+       Ct ( Cc "Open" * Cc ( "{\\PitonStyle{" .. style .. "}{" ) * Cc "}}" )
+     * ( pattern + Beamer + DetectedCommands + EscapeMath + Escape )
+     * Ct ( Cc "Close" )
+  end
+  local balanced_parens =
+    P { "E" , E = ( "(" * V "E" * ")" + ( 1 - S "()" ) ) ^ 0 }
+  local ocaml_string =
+    Q "\""
+  * (
+      VisualSpace
       +
-      OneField * ( Q ";" * SkipSpace * OneField ) ^ 0
-    )
-  *
-  Q "}"
-local DotNotation =
-  (
-      K ( 'Name.Module' , cap_identifier )
-        * Q "."
-        * ( Identifier + Constructor + Q "(" + Q "[" + Q "{" ) ^ ( -1 )
+      Q ( ( 1 - S " \"\r" ) ^ 1 )
       +
-      Identifier
-        * Q "."
-        * K ( 'Name.Field' , identifier )
-  )
-  * ( Q "." * K ( 'Name.Field' , identifier ) ) ^ 0
-local Operator =
-  K ( 'Operator' ,
-      P "!=" + "<>" + "==" + "<<" + ">>" + "<=" + ">=" + ":=" + "||" + "&&" +
-      "//" + "**" + ";;" + "::" + "->" + "+." + "-." + "*." + "/."
-      + S "-~+/*%=<>&@|" )
-
-local OperatorWord =
-  K ( 'Operator.Word' ,
-      P "asr" + "land" + "lor" + "lsl" + "lxor" + "mod" + "or" )
-
-local governing_keyword = P "and" + "begin" + "class" + "constraint" +
-      "end" + "external" + "functor" + "include" + "inherit" + "initializer" +
-      "in" + "let" + "method" + "module" + "object" + "open" + "rec" + "sig" +
-      "struct" + "type" + "val"
-
-local Keyword =
-  K ( 'Keyword' ,
-      P "assert" + "as" + "done" + "downto" + "do" + "else" + "exception"
-      + "for" + "function"  + "fun" + "if" + "lazy" + "match" + "mutable"
-      + "new" + "of" + "private" + "raise" + "then" + "to" + "try"
-      + "virtual" + "when" + "while" + "with" )
-  + K ( 'Keyword.Constant' , P "true" + "false" )
-  + K ('Keyword.Governing', governing_keyword )
-
-local Builtin =
-  K ( 'Name.Builtin' , P "not" + "incr" + "decr" + "fst" + "snd" + "ref" )
-local Exception =
-  K (   'Exception' ,
-       P "Division_by_zero" + "End_of_File" + "Failure" + "Invalid_argument" +
-       "Match_failure" + "Not_found" + "Out_of_memory" + "Stack_overflow" +
-       "Sys_blocked_io" + "Sys_error" + "Undefined_recursive_module" )
-local Char =
-  K ( 'String.Short',
-    P "'" *
-    (
-      ( 1 - S "'\\" )
-      + "\\"
-        * ( S "\\'ntbr \""
-            + digit * digit * digit
-            + P "x" * ( digit + R "af" + R "AF" )
-                    * ( digit + R "af" + R "AF" )
-                    * ( digit + R "af" + R "AF" )
-            + P "o" * R "03" * R "07" * R "07" )
-    )
-    * "'" )
-local braces = Compute_braces ( "\"" * ( 1 - S "\"" ) ^ 0 * "\"" )
-if piton.beamer then
-  Beamer = Compute_Beamer ( 'ocaml' , braces ) -- modified 2024/07/24
-end
-DetectedCommands = Compute_DetectedCommands ( 'ocaml' , braces )
-LPEG_cleaner['ocaml'] = Compute_LPEG_cleaner ( 'ocaml' , braces )
-local ocaml_string =
-       Q "\""
-     * (
-         VisualSpace
-         +
-         Q ( ( 1 - S " \"\r" ) ^ 1 )
-         +
-         EOL
-       ) ^ 0
-     * Q "\""
-local String = WithStyle ( 'String.Long' , ocaml_string )
-local ext = ( R "az" + "_" ) ^ 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 )
-local QuotedStringBis =
-  WithStyle ( 'String.Long' ,
+      EOL
+    ) ^ 0
+  * Q "\""
+  local String = WithStyle ( 'String.Long' , ocaml_string )
+  local ext = ( R "az" + "_" ) ^ 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 )
+  local QuotedStringBis =
+    WithStyle ( 'String.Long' ,
+        (
+          Space
+          +
+          Q ( ( 1 - S " \r" ) ^ 1 )
+          +
+          EOL
+        ) ^ 0  )
+  local QuotedString =
+    C ( open * ( 1 - closeeq ) ^ 0  * close ) /
+    ( function ( s ) return QuotedStringBis : match ( s ) end )
+  local Comment =
+    WithStyle ( 'Comment' ,
+      P {
+          "A" ,
+          A = Q "(*"
+              * ( V "A"
+                  + Q ( ( 1 - S "\r$\"" - "(*" - "*)" ) ^ 1 ) -- $
+                  + ocaml_string
+                  + "$" * K ( 'Comment.Math' , ( 1 - S "$\r" ) ^ 1 ) * "$" -- $
+                  + EOL
+                ) ^ 0
+              * Q "*)"
+        }   )
+  local Delim = Q ( P "[|" + "|]" + S "[()]" )
+  local Punct = Q ( S ",:;!" )
+  local cap_identifier = R "AZ" * ( R "az" + R "AZ" + S "_'" + digit ) ^ 0
+  local Constructor =
+    K ( 'Name.Constructor' ,
+        Q "`" ^ -1 * cap_identifier
+        + Q "::"
+        + Q "[" * SkipSpace * Q "]" )
+  local ModuleType = K ( 'Name.Type' , cap_identifier )
+  local OperatorWord =
+    K ( 'Operator.Word' ,
+        P "asr" + "land" + "lor" + "lsl" + "lxor" + "mod" + "or" )
+  local governing_keyword = P "and" + "begin" + "class" + "constraint" +
+        "end" + "external" + "functor" + "include" + "inherit" + "initializer" +
+        "in" + "let" + "method" + "module" + "object" + "open" + "rec" + "sig" +
+        "struct" + "type" + "val"
+  local Keyword =
+    K ( 'Keyword' ,
+        P "assert" + "as" + "done" + "downto" + "do" + "else" + "exception"
+        + "for" + "function"  + "fun" + "if" + "lazy" + "match" + "mutable"
+        + "new" + "of" + "private" + "raise" + "then" + "to" + "try"
+        + "virtual" + "when" + "while" + "with" )
+    + K ( 'Keyword.Constant' , P "true" + "false" )
+    + K ( 'Keyword.Governing', governing_keyword )
+  local EndKeyword
+   = Space + Punct + Delim + EOL + Beamer + DetectedCommands + -1
+  local identifier = ( R "az" + "_" ) * ( R "az" + R "AZ" + S "_'" + digit ) ^ 0
+                     - ( OperatorWord + Keyword ) * EndKeyword
+  local Identifier = K ( 'Identifier.Internal' , identifier )
+  local Char =
+    K ( 'String.Short',
+      P "'" *
       (
-        Space
+        ( 1 - S "'\\" )
+        + "\\"
+          * ( S "\\'ntbr \""
+              + digit * digit * digit
+              + P "x" * ( digit + R "af" + R "AF" )
+                      * ( digit + R "af" + R "AF" )
+                      * ( digit + R "af" + R "AF" )
+              + P "o" * R "03" * R "07" * R "07" )
+      )
+      * "'" )
+  local TypeParameter =
+    K ( 'TypeParameter' ,
+        "'" * Q"_" ^ -1 * alpha ^ 1 * ( # ( 1 - P "'" ) + -1 ) )
+  local expression_for_fields_type =
+    P { "E" ,
+        E =  (   "{" * V "F" * "}"
+              + "(" * V "F" * ")"
+              + TypeParameter
+              + ( 1 - S "{}()[]\r;" ) ) ^ 0 ,
+        F = (    "{" * V "F" * "}"
+              + "(" * V "F" * ")"
+              + ( 1 - S "{}()[]\r\"'" ) + TypeParameter ) ^ 0
+      }
+  local expression_for_fields_value =
+    P { "E" ,
+        E =  (   "{" * V "F" * "}"
+              + "(" * V "F" * ")"
+              + "[" * V "F" * "]"
+              + String + QuotedString + Char
+              + ( 1 - S "{}()[]\r;" ) ) ^ 0 ,
+        F = (    "{" * V "F" * "}"
+              + "(" * V "F" * ")"
+              + "[" * V "F" * "]"
+              + ( 1 - S "{}()[]\r\"'" )) ^ 0
+      }
+  local OneFieldDefinition =
+      ( K ( 'Keyword' , "mutable" ) * SkipSpace ) ^ -1
+    * K ( 'Name.Field' , identifier ) * SkipSpace
+    * Q ":" * SkipSpace
+    * K ( 'TypeExpression' , expression_for_fields_type )
+    * SkipSpace
+  local OneField =
+      K ( 'Name.Field' , identifier ) * SkipSpace
+    * Q "=" * SkipSpace
+    * ( expression_for_fields_value
+        / ( function ( s ) return LPEG1['ocaml'] : match ( s ) end )
+      )
+    * SkipSpace
+  local Record =
+    Q "{" * SkipSpace
+    *
+      (
+        OneFieldDefinition
+        * ( Q ";" * SkipSpace * ( Comment * SkipSpace ) ^ 0 * OneFieldDefinition ) ^ 0
         +
-        Q ( ( 1 - S " \r" ) ^ 1 )
+        OneField * ( Q ";" * SkipSpace * ( Comment * SkipSpace ) ^ 0 * OneField ) ^ 0
+      )
+    * SkipSpace
+    * Q ";" ^ -1
+    * SkipSpace
+    * Comment ^ -1
+    * SkipSpace
+    * Q "}"
+  local DotNotation =
+    (
+        K ( 'Name.Module' , cap_identifier )
+          * Q "."
+          * ( Identifier + Constructor + Q "(" + Q "[" + Q "{" ) ^ -1
         +
-        EOL
-      ) ^ 0  )
-local QuotedString =
-   C ( open * ( 1 - closeeq ) ^ 0  * close ) /
-  ( function ( s ) return QuotedStringBis : match ( s ) end )
-local Comment =
-  WithStyle ( 'Comment' ,
-     P {
-         "A" ,
-         A = Q "(*"
-             * ( V "A"
-                 + Q ( ( 1 - S "\r$\"" - "(*" - "*)" ) ^ 1 ) -- $
-                 + ocaml_string
-                 + "$" * K ( 'Comment.Math' , ( 1 - S "$\r" ) ^ 1 ) * "$" -- $
-                 + EOL
-               ) ^ 0
-             * Q "*)"
-       }   )
-local Argument =
-  (  Q "~" * Identifier * Q ":" * SkipSpace ) ^ -1
-  *
-  ( K ( 'Identifier.Internal' , identifier )
-    + Q "(" * SkipSpace
-      * K ( 'Identifier.Internal' , identifier ) * SkipSpace
-      * Q ":" * SkipSpace
-      * K ( 'TypeExpression' , balanced_parens ) * SkipSpace
-      * Q ")"
-  )
-local DefFunction =
-  K ( 'Keyword.Governing' , "let open" )
-   * Space
-   * K ( 'Name.Module' , cap_identifier )
-  +
-  K ( 'Keyword.Governing' , P "let rec" + "let" + "and" )
+         Identifier
+          * Q "."
+          * K ( 'Name.Field' , identifier )
+    )
+    * ( Q "." * K ( 'Name.Field' , identifier ) ) ^ 0
+  local Operator =
+    K ( 'Operator' ,
+        P "!=" + "<>" + "==" + "<<" + ">>" + "<=" + ">=" + ":=" + "||" + "&&" +
+        "//" + "**" + ";;" + "->" + "+." + "-." + "*." + "/."
+        + S "-~+/*%=<>&@|" )
+  local Builtin =
+    K ( 'Name.Builtin' , P "not" + "incr" + "decr" + "fst" + "snd" + "ref" )
+  local Exception =
+    K (   'Exception' ,
+        P "Division_by_zero" + "End_of_File" + "Failure" + "Invalid_argument" +
+        "Match_failure" + "Not_found" + "Out_of_memory" + "Stack_overflow" +
+        "Sys_blocked_io" + "Sys_error" + "Undefined_recursive_module" )
+  LPEG_cleaner['ocaml'] = Compute_LPEG_cleaner ( 'ocaml' , braces )
+  local Argument =
+    (  Q "~" * Identifier * Q ":" * SkipSpace ) ^ -1
+    *
+    ( K ( 'Identifier.Internal' , identifier )
+      + Q "(" * SkipSpace
+        * K ( 'Identifier.Internal' , identifier ) * SkipSpace
+        * Q ":" * SkipSpace
+        * K ( 'TypeExpression' , balanced_parens ) * SkipSpace
+        * Q ")"
+    )
+  local DefFunction =
+    K ( 'Keyword.Governing' , "let open" )
     * Space
-    * K ( 'Name.Function.Internal' , identifier )
-    * Space
-    * (
-        Q "=" * SkipSpace * K ( 'Keyword' , "function" )
+    * K ( 'Name.Module' , cap_identifier )
+    +
+    K ( 'Keyword.Governing' , P "let rec" + "let" + "and" )
+      * Space
+      * K ( 'Name.Function.Internal' , identifier )
+      * Space
+      * (
+          Q "=" * SkipSpace * K ( 'Keyword' , "function" )
+          +
+          Argument
+          * ( SkipSpace * Argument ) ^ 0
+          * (
+              SkipSpace
+              * Q ":"
+              * K ( 'TypeExpression' , ( 1 - P "=" ) ^ 0 )
+            ) ^ -1
+        )
+  local DefModule =
+    K ( 'Keyword.Governing' , "module" ) * Space
+    *
+      (
+            K ( 'Keyword.Governing' , "type" ) * Space
+          * K ( 'Name.Type' , cap_identifier )
         +
-        Argument
-         * ( SkipSpace * Argument ) ^ 0
-         * (
-             SkipSpace
-             * Q ":"
-             * K ( 'TypeExpression' , ( 1 - P "=" ) ^ 0 )
-           ) ^ -1
-      )
-local DefModule =
-  K ( 'Keyword.Governing' , "module" ) * Space
-  *
-    (
-          K ( 'Keyword.Governing' , "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.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 ":" * SkipSpace
-              * K ( 'Name.Type' , cap_identifier ) * SkipSpace
-              *
+                *
                 (
-                  Q "," * SkipSpace
-                    * K ( 'Name.Module' , cap_identifier ) * SkipSpace
-                    * Q ":" * SkipSpace
-                    * K ( 'Name.Type' , cap_identifier ) * SkipSpace
+                  Q ","
+                  *
+                  K ( 'Name.Module' , 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.Governing' , P "include" + "open" )
-  * Space * K ( 'Name.Module' , cap_identifier )
-local TypeParameter =
-  K ( 'TypeParameter' , "'" * alpha * ( # ( 1 - P "'" ) + -1 ) )
-local DefType =
-  K ( 'Keyword.Governing' , "type" )
-  * Space
-  * WithStyle
-      (
-        'TypeExpression' ,
-        ( Q ( 1 - P ";;" - P "\r" ) + EOL_without_space_indentation ) ^ 0
+            ) ^ -1
       )
-  * ( # governing_keyword + Q ";;" + -1 )
-local EndKeyword = Space + Punct + Delim + EOL + Beamer + DetectedCommands + -1
-local Main =
-     Space
-     + Tab
-     + Escape + EscapeMath
-     + Beamer
-     + DetectedCommands
-     + TypeParameter
-     + String + QuotedString + Char
-     + Comment
-     + Delim
-     + Operator
-     + Q ( "~" ) * Identifier * ( Q ":" ) ^ -1
-     + Q ":" * # (1 - P":") * SkipSpace
+    +
+    K ( 'Keyword.Governing' , P "include" + "open" )
+    * Space
+    * K ( 'Name.Module' , cap_identifier )
+  local DefType =
+    K ( 'Keyword.Governing' , "type" )
+    * Space
+    * K ( 'TypeExpression' , Q ( 1 - P "=" ) ^ 1 )
+    * SkipSpace
+    * ( Q "+=" + Q "=" )
+    * SkipSpace
+    * (
+        Record
+        +
+        WithStyle
+         (
+           'TypeExpression' ,
+           (
+             ( EOL + Q ( 1 - P ";;" - governing_keyword ) ) ^ 0
+             * ( # ( governing_keyword ) + Q ";;" )
+           )
+         )
+      )
+  local Main =
+      space ^ 0 * EOL
+      + Space
+      + Tab
+      + Escape + EscapeMath
+      + Beamer
+      + DetectedCommands
+      + TypeParameter
+      + String + QuotedString + Char
+      + Comment
+      + Operator
+      + Q ( "~" ) * Identifier * ( Q ":" ) ^ -1
+      + Q ":" * # (1 - P ":") * SkipSpace
           * K ( 'TypeExpression' , balanced_parens ) * SkipSpace * Q ")"
-     + Punct
-     + Exception
-     + DefFunction
-     + DefModule
-     + DefType
-     + Record
-     + Keyword * EndKeyword
-     + OperatorWord * EndKeyword
-     + Builtin * EndKeyword
-     + DotNotation
-     + Constructor
-     + Identifier
-     + Number
-     + Word
+      + Exception
+      + DefType
+      + DefFunction
+      + DefModule
+      + Record
+      + Keyword * EndKeyword
+      + OperatorWord * EndKeyword
+      + Builtin * EndKeyword
+      + DotNotation
+      + Constructor
+      + Identifier
+      + Punct
+      + Delim
+      + Number
+      + Word
+  LPEG1['ocaml'] = Main ^ 0
+  LPEG2['ocaml'] =
+    Ct (
+        ( P ":" + Identifier * SkipSpace * Q ":" )
+          * SkipSpace
+          * K ( 'TypeExpression' , ( 1 - P "\r" ) ^ 0 )
+        +
+        ( space ^ 0 * "\r" ) ^ -1
+        * BeamerBeginEnvironments
+        * Lc [[\__piton_begin_line:]]
+        * SpaceIndentation ^ 0
+        * ( ( space * Lc [[\__piton_trailing_space:]] ) ^ 1 * -1
+              + space ^ 0 * EOL
+              + Main
+          ) ^ 0
+        * -1
+        * Lc [[\__piton_end_line:]]
+      )
+end
+do
+  local Delim = Q ( S "{[()]}" )
+  local Punct = Q ( S ",:;!" )
+  local identifier = letter * alphanum ^ 0
 
-LPEG1['ocaml'] = Main ^ 0
-LPEG2['ocaml'] =
-  Ct (
-       ( P ":" + Identifier * SkipSpace * Q ":" )
-         * SkipSpace
-         * K ( 'TypeExpression' , ( 1 - P "\r" ) ^ 0 )
-       +
-       ( space ^ 0 * "\r" ) ^ -1
-       * BeamerBeginEnvironments
-       * Lc [[\__piton_begin_line:]]
-       * SpaceIndentation ^ 0
-       * ( ( space * Lc [[\__piton_trailing_space:]] ) ^ 1 * -1 + space ^ 0 * EOL + Main ) ^ 0
-       * -1
-       * Lc [[\__piton_end_line:]]
-     )
-local Delim = Q ( S "{[()]}" )
-local Punct = Q ( S ",:;!" )
-local identifier = letter * alphanum ^ 0
+  local Operator =
+    K ( 'Operator' ,
+        P "!=" + "==" + "<<" + ">>" + "<=" + ">=" + "||" + "&&"
+          + S "-~+/*%=<>&.@|!" )
 
-local Operator =
-  K ( 'Operator' ,
-      P "!=" + "==" + "<<" + ">>" + "<=" + ">=" + "||" + "&&"
-        + S "-~+/*%=<>&.@|!" )
+  local Keyword =
+    K ( 'Keyword' ,
+        P "alignas" + "asm" + "auto" + "break" + "case" + "catch" + "class" +
+        "const" + "constexpr" + "continue" + "decltype" + "do" + "else" + "enum" +
+        "extern" + "for" + "goto" + "if" + "nexcept" + "private" + "public" +
+        "register" + "restricted" + "return" + "static" + "static_assert" +
+        "struct" + "switch" + "thread_local" + "throw" + "try" + "typedef" +
+        "union" + "using" + "virtual" + "volatile" + "while"
+      )
+    + K ( 'Keyword.Constant' , P "default" + "false" + "NULL" + "nullptr" + "true" )
 
-local Keyword =
-  K ( 'Keyword' ,
-      P "alignas" + "asm" + "auto" + "break" + "case" + "catch" + "class" +
-      "const" + "constexpr" + "continue" + "decltype" + "do" + "else" + "enum" +
-      "extern" + "for" + "goto" + "if" + "nexcept" + "private" + "public" +
-      "register" + "restricted" + "return" + "static" + "static_assert" +
-      "struct" + "switch" + "thread_local" + "throw" + "try" + "typedef" +
-      "union" + "using" + "virtual" + "volatile" + "while"
-    )
-  + K ( 'Keyword.Constant' , P "default" + "false" + "NULL" + "nullptr" + "true" )
+  local Builtin =
+    K ( 'Name.Builtin' ,
+        P "alignof" + "malloc" + "printf" + "scanf" + "sizeof" )
 
-local Builtin =
-  K ( 'Name.Builtin' ,
-      P "alignof" + "malloc" + "printf" + "scanf" + "sizeof" )
+  local Type =
+    K ( 'Name.Type' ,
+        P "bool" + "char" + "char16_t" + "char32_t" + "double" + "float" + "int" +
+        "int8_t" + "int16_t" + "int32_t" + "int64_t" + "long" + "short" + "signed"
+        + "unsigned" + "void" + "wchar_t" ) * Q "*" ^ 0
 
-local Type =
-  K ( 'Name.Type' ,
-      P "bool" + "char" + "char16_t" + "char32_t" + "double" + "float" + "int" +
-      "int8_t" + "int16_t" + "int32_t" + "int64_t" + "long" + "short" + "signed"
-      + "unsigned" + "void" + "wchar_t" ) * Q "*" ^ 0
+  local DefFunction =
+    Type
+    * Space
+    * Q "*" ^ -1
+    * K ( 'Name.Function.Internal' , identifier )
+    * SkipSpace
+    * # P "("
+  local DefClass =
+    K ( 'Keyword' , "class" ) * Space * K ( 'Name.Class' , identifier )
+  String =
+    WithStyle ( 'String.Long' ,
+        Q "\""
+        * ( VisualSpace
+            + K ( 'String.Interpol' ,
+                  "%" * ( S "difcspxXou" + "ld" + "li" + "hd" + "hi" )
+                )
+            + Q ( ( P "\\\"" + 1 - S " \"" ) ^ 1 )
+          ) ^ 0
+        * Q "\""
+      )
+  local braces = Compute_braces ( "\"" * ( 1 - S "\"" ) ^ 0 * "\"" )
+  if piton.beamer then Beamer = Compute_Beamer ( 'c' , braces ) end
+  DetectedCommands = Compute_DetectedCommands ( 'c' , braces )
+  LPEG_cleaner['c'] = Compute_LPEG_cleaner ( 'c' , braces )
+  local Preproc = K ( 'Preproc' , "#" * ( 1 - P "\r" ) ^ 0  ) * ( EOL + -1 )
+  local Comment =
+    WithStyle ( 'Comment' ,
+       Q "//" * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0 ) -- $
+              * ( EOL + -1 )
 
-local DefFunction =
-  Type
-  * Space
-  * Q "*" ^ -1
-  * K ( 'Name.Function.Internal' , identifier )
-  * SkipSpace
-  * # P "("
-local DefClass =
-  K ( 'Keyword' , "class" ) * Space * K ( 'Name.Class' , identifier )
-String =
-  WithStyle ( 'String.Long' ,
-      Q "\""
-      * ( VisualSpace
-          + K ( 'String.Interpol' ,
-                "%" * ( S "difcspxXou" + "ld" + "li" + "hd" + "hi" )
-              )
-          + Q ( ( P "\\\"" + 1 - S " \"" ) ^ 1 )
-        ) ^ 0
-      * Q "\""
-    )
-local braces = Compute_braces ( "\"" * ( 1 - S "\"" ) ^ 0 * "\"" )
-if piton.beamer then Beamer = Compute_Beamer ( 'c' , braces ) end
-DetectedCommands = Compute_DetectedCommands ( 'c' , braces )
-LPEG_cleaner['c'] = Compute_LPEG_cleaner ( 'c' , braces )
-local Preproc = K ( 'Preproc' , "#" * ( 1 - P "\r" ) ^ 0  ) * ( EOL + -1 )
-local Comment =
-  WithStyle ( 'Comment' ,
-     Q "//" * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0 ) -- $
-            * ( EOL + -1 )
-
-local LongComment =
-  WithStyle ( 'Comment' ,
-               Q "/*"
-               * ( CommentMath + Q ( ( 1 - P "*/" - S "$\r" ) ^ 1 ) + EOL ) ^ 0
-               * Q "*/"
-            ) -- $
-local EndKeyword = Space + Punct + Delim + EOL + Beamer + DetectedCommands + -1
-local Main =
-     Space
-     + Tab
-     + Escape + EscapeMath
-     + CommentLaTeX
-     + Beamer
-     + DetectedCommands
-     + Preproc
-     + Comment + LongComment
-     + Delim
-     + Operator
-     + String
-     + Punct
-     + DefFunction
-     + DefClass
-     + Type * ( Q "*" ^ -1 + EndKeyword )
-     + Keyword * EndKeyword
-     + Builtin * EndKeyword
-     + Identifier
-     + Number
-     + Word
-LPEG1['c'] = Main ^ 0
-LPEG2['c'] =
-  Ct (
-       ( space ^ 0 * P "\r" ) ^ -1
-       * BeamerBeginEnvironments
-       * Lc [[\__piton_begin_line:]]
-       * SpaceIndentation ^ 0
-       * ( space ^ 1 * -1 + space ^ 0 * EOL + Main ) ^ 0
-       * -1
-       * Lc [[\__piton_end_line:]]
-     )
-local function LuaKeyword ( name )
-return
-   Lc [[{\PitonStyle{Keyword}{]]
-   * Q ( Cmt (
-               C ( identifier ) ,
-               function ( s , i , a ) return string.upper ( a ) == name end
-             )
+  local LongComment =
+    WithStyle ( 'Comment' ,
+                 Q "/*"
+                 * ( CommentMath + Q ( ( 1 - P "*/" - S "$\r" ) ^ 1 ) + EOL ) ^ 0
+                 * Q "*/"
+              ) -- $
+  local EndKeyword = Space + Punct + Delim + EOL + Beamer + DetectedCommands + -1
+  local Main =
+       space ^ 0 * EOL
+       + Space
+       + Tab
+       + Escape + EscapeMath
+       + CommentLaTeX
+       + Beamer
+       + DetectedCommands
+       + Preproc
+       + Comment + LongComment
+       + Delim
+       + Operator
+       + String
+       + Punct
+       + DefFunction
+       + DefClass
+       + Type * ( Q "*" ^ -1 + EndKeyword )
+       + Keyword * EndKeyword
+       + Builtin * EndKeyword
+       + Identifier
+       + Number
+       + Word
+  LPEG1['c'] = Main ^ 0
+  LPEG2['c'] =
+    Ct (
+         ( space ^ 0 * P "\r" ) ^ -1
+         * BeamerBeginEnvironments
+         * Lc [[\__piton_begin_line:]]
+         * SpaceIndentation ^ 0
+         * ( space ^ 1 * -1 + space ^ 0 * EOL + Main ) ^ 0
+         * -1
+         * Lc [[\__piton_end_line:]]
        )
-   * Lc "}}"
 end
-local identifier =
-  letter * ( alphanum + "-" ) ^ 0
-  + P '"' * ( ( 1 - P '"' ) ^ 1 ) * '"'
+do
+  local function LuaKeyword ( name )
+  return
+     Lc [[{\PitonStyle{Keyword}{]]
+     * Q ( Cmt (
+                 C ( identifier ) ,
+                 function ( s , i , a ) return string.upper ( a ) == name end
+               )
+         )
+     * Lc "}}"
+  end
+  local identifier =
+    letter * ( alphanum + "-" ) ^ 0
+    + P '"' * ( ( 1 - P '"' ) ^ 1 ) * '"'
+  local Operator =
+    K ( 'Operator' , P "=" + "!=" + "<>" + ">=" + ">" + "<=" + "<"  + S "*+/" )
+  local function Set ( list )
+    local set = { }
+    for _, l in ipairs ( list ) do set[l] = true end
+    return set
+  end
+  local set_keywords = Set
+   {
+     "ADD" , "AFTER" , "ALL" , "ALTER" , "AND" , "AS" , "ASC" , "BETWEEN" , "BY" ,
+     "CHANGE" , "COLUMN" , "CREATE" , "CROSS JOIN" , "DELETE" , "DESC" , "DISTINCT" ,
+     "DROP" , "FROM" , "GROUP" , "HAVING" , "IN" , "INNER" , "INSERT" , "INTO" , "IS" ,
+     "JOIN" , "LEFT" , "LIKE" , "LIMIT" , "MERGE" , "NOT" , "NULL" , "ON" , "OR" ,
+     "ORDER" , "OVER" , "RIGHT" , "SELECT" , "SET" , "TABLE" , "THEN" , "TRUNCATE" ,
+     "UNION" , "UPDATE" , "VALUES" , "WHEN" , "WHERE" , "WITH"
+   }
+  local set_builtins = Set
+   {
+     "AVG" , "COUNT" , "CHAR_LENGHT" , "CONCAT" , "CURDATE" , "CURRENT_DATE" ,
+     "DATE_FORMAT" , "DAY" , "LOWER" , "LTRIM" , "MAX" , "MIN" , "MONTH" , "NOW" ,
+     "RANK" , "ROUND" , "RTRIM" , "SUBSTRING" , "SUM" , "UPPER" , "YEAR"
+   }
+  local Identifier =
+    C ( identifier ) /
+    (
+      function (s)
+          if set_keywords[string.upper(s)] -- the keywords are case-insensitive in SQL
+          then return { "{\\PitonStyle{Keyword}{" } ,
+                      { luatexbase.catcodetables.other , s } ,
+                      { "}}" }
+          else if set_builtins[string.upper(s)]
+               then return { "{\\PitonStyle{Name.Builtin}{" } ,
+                           { luatexbase.catcodetables.other , s } ,
+                           { "}}" }
+               else return { "{\\PitonStyle{Name.Field}{" } ,
+                           { luatexbase.catcodetables.other , s } ,
+                           { "}}" }
+               end
+          end
+      end
+    )
+  local String = K ( 'String.Long' , "'" * ( 1 - P "'" ) ^ 1 * "'" )
+  local braces = Compute_braces ( "'" * ( 1 - P "'" ) ^ 1 * "'" )
+  if piton.beamer then Beamer = Compute_Beamer ( 'sql' , braces ) end
+  DetectedCommands = Compute_DetectedCommands ( 'sql' , braces )
+  LPEG_cleaner['sql'] = Compute_LPEG_cleaner ( 'sql' , braces )
+  local Comment =
+    WithStyle ( 'Comment' ,
+       Q "--"   -- syntax of SQL92
+       * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0 ) -- $
+    * ( EOL + -1 )
 
-local Operator =
-  K ( 'Operator' , P "=" + "!=" + "<>" + ">=" + ">" + "<=" + "<"  + S "*+/" )
-local function Set ( list )
-  local set = { }
-  for _, l in ipairs ( list ) do set[l] = true end
-  return set
-end
+  local LongComment =
+    WithStyle ( 'Comment' ,
+                 Q "/*"
+                 * ( CommentMath + Q ( ( 1 - P "*/" - S "$\r" ) ^ 1 ) + EOL ) ^ 0
+                 * Q "*/"
+              ) -- $
+  local EndKeyword = Space + Punct + Delim + EOL + Beamer + DetectedCommands + -1
+  local TableField =
+         K ( 'Name.Table' , identifier )
+       * Q "."
+       * K ( 'Name.Field' , identifier )
 
-local set_keywords = Set
- {
-   "ADD" , "AFTER" , "ALL" , "ALTER" , "AND" , "AS" , "ASC" , "BETWEEN" , "BY" ,
-   "CHANGE" , "COLUMN" , "CREATE" , "CROSS JOIN" , "DELETE" , "DESC" , "DISTINCT" ,
-   "DROP" , "FROM" , "GROUP" , "HAVING" , "IN" , "INNER" , "INSERT" , "INTO" , "IS" ,
-   "JOIN" , "LEFT" , "LIKE" , "LIMIT" , "MERGE" , "NOT" , "NULL" , "ON" , "OR" ,
-   "ORDER" , "OVER" , "RIGHT" , "SELECT" , "SET" , "TABLE" , "THEN" , "TRUNCATE" ,
-   "UNION" , "UPDATE" , "VALUES" , "WHEN" , "WHERE" , "WITH"
- }
+  local OneField =
+    (
+      Q ( "(" * ( 1 - P ")" ) ^ 0 * ")" )
+      +
+          K ( 'Name.Table' , identifier )
+        * Q "."
+        * K ( 'Name.Field' , identifier )
+      +
+      K ( 'Name.Field' , identifier )
+    )
+    * (
+        Space * LuaKeyword "AS" * Space * K ( 'Name.Field' , identifier )
+      ) ^ -1
+    * ( Space * ( LuaKeyword "ASC" + LuaKeyword "DESC" ) ) ^ -1
 
-local set_builtins = Set
- {
-   "AVG" , "COUNT" , "CHAR_LENGHT" , "CONCAT" , "CURDATE" , "CURRENT_DATE" ,
-   "DATE_FORMAT" , "DAY" , "LOWER" , "LTRIM" , "MAX" , "MIN" , "MONTH" , "NOW" ,
-   "RANK" , "ROUND" , "RTRIM" , "SUBSTRING" , "SUM" , "UPPER" , "YEAR"
- }
-local Identifier =
-  C ( identifier ) /
-  (
-    function (s)
-        if set_keywords[string.upper(s)] -- the keywords are case-insensitive in SQL
-        then return { "{\\PitonStyle{Keyword}{" } ,
-                    { luatexbase.catcodetables.other , s } ,
-                    { "}}" }
-        else if set_builtins[string.upper(s)]
-             then return { "{\\PitonStyle{Name.Builtin}{" } ,
-                         { luatexbase.catcodetables.other , s } ,
-                         { "}}" }
-             else return { "{\\PitonStyle{Name.Field}{" } ,
-                         { luatexbase.catcodetables.other , s } ,
-                         { "}}" }
-             end
-        end
-    end
-  )
-local String = K ( 'String.Long' , "'" * ( 1 - P "'" ) ^ 1 * "'" )
-local braces = Compute_braces ( "'" * ( 1 - P "'" ) ^ 1 * "'" )
-if piton.beamer then Beamer = Compute_Beamer ( 'sql' , braces ) end
-DetectedCommands = Compute_DetectedCommands ( 'sql' , braces )
-LPEG_cleaner['sql'] = Compute_LPEG_cleaner ( 'sql' , braces )
-local Comment =
-  WithStyle ( 'Comment' ,
-     Q "--"   -- syntax of SQL92
-     * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0 ) -- $
-  * ( EOL + -1 )
-
-local LongComment =
-  WithStyle ( 'Comment' ,
-               Q "/*"
-               * ( CommentMath + Q ( ( 1 - P "*/" - S "$\r" ) ^ 1 ) + EOL ) ^ 0
-               * Q "*/"
-            ) -- $
-local EndKeyword = Space + Punct + Delim + EOL + Beamer + DetectedCommands + -1
-local TableField =
+  local OneTable =
        K ( 'Name.Table' , identifier )
-     * Q "."
-     * K ( 'Name.Field' , identifier )
+     * (
+         Space
+         * LuaKeyword "AS"
+         * Space
+         * K ( 'Name.Table' , identifier )
+       ) ^ -1
 
-local OneField =
-  (
-    Q ( "(" * ( 1 - P ")" ) ^ 0 * ")" )
-    +
-        K ( 'Name.Table' , identifier )
-      * Q "."
-      * K ( 'Name.Field' , identifier )
-    +
-    K ( 'Name.Field' , identifier )
-  )
-  * (
-      Space * LuaKeyword "AS" * Space * K ( 'Name.Field' , identifier )
-    ) ^ -1
-  * ( Space * ( LuaKeyword "ASC" + LuaKeyword "DESC" ) ) ^ -1
+  local WeCatchTableNames =
+       LuaKeyword "FROM"
+     * ( Space + EOL )
+     * OneTable * ( SkipSpace * Q "," * SkipSpace * OneTable ) ^ 0
+    + (
+        LuaKeyword "JOIN" + LuaKeyword "INTO" + LuaKeyword "UPDATE"
+        + LuaKeyword "TABLE"
+      )
+      * ( Space + EOL ) * OneTable
+  local EndKeyword = Space + Punct + Delim + EOL + Beamer + DetectedCommands + -1
+  local Main =
+       space ^ 0 * EOL
+       + Space
+       + Tab
+       + Escape + EscapeMath
+       + CommentLaTeX
+       + Beamer
+       + DetectedCommands
+       + Comment + LongComment
+       + Delim
+       + Operator
+       + String
+       + Punct
+       + WeCatchTableNames
+       + ( TableField + Identifier ) * ( Space + Operator + Punct + Delim + EOL + -1 )
+       + Number
+       + Word
+  LPEG1['sql'] = Main ^ 0
+  LPEG2['sql'] =
+    Ct (
+         ( space ^ 0 * "\r" ) ^ -1
+         * BeamerBeginEnvironments
+         * Lc [[\__piton_begin_line:]]
+         * SpaceIndentation ^ 0
+         * ( space ^ 1 * -1 + space ^ 0 * EOL + Main ) ^ 0
+         * -1
+         * Lc [[\__piton_end_line:]]
+       )
+end
+do
+  local Punct = Q ( S ",:;!\\" )
 
-local OneTable =
-     K ( 'Name.Table' , identifier )
-   * (
-       Space
-       * LuaKeyword "AS"
-       * Space
-       * K ( 'Name.Table' , identifier )
-     ) ^ -1
+  local Comment =
+    WithStyle ( 'Comment' ,
+                Q "#"
+                * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0 -- $
+              )
+       * ( EOL + -1 )
 
-local WeCatchTableNames =
-     LuaKeyword "FROM"
-   * ( Space + EOL )
-   * OneTable * ( SkipSpace * Q "," * SkipSpace * OneTable ) ^ 0
-  + (
-      LuaKeyword "JOIN" + LuaKeyword "INTO" + LuaKeyword "UPDATE"
-      + LuaKeyword "TABLE"
-    )
-    * ( Space + EOL ) * OneTable
-local EndKeyword = Space + Punct + Delim + EOL + Beamer + DetectedCommands + -1
-local Main =
-     Space
-     + Tab
-     + Escape + EscapeMath
-     + CommentLaTeX
-     + Beamer
-     + DetectedCommands
-     + Comment + LongComment
-     + Delim
-     + Operator
-     + String
-     + Punct
-     + WeCatchTableNames
-     + ( TableField + Identifier ) * ( Space + Operator + Punct + Delim + EOL + -1 )
-     + Number
-     + Word
-LPEG1['sql'] = Main ^ 0
-LPEG2['sql'] =
-  Ct (
-       ( space ^ 0 * "\r" ) ^ -1
-       * BeamerBeginEnvironments
-       * Lc [[\__piton_begin_line:]]
-       * SpaceIndentation ^ 0
-       * ( space ^ 1 * -1 + space ^ 0 * EOL + Main ) ^ 0
-       * -1
-       * Lc [[\__piton_end_line:]]
-     )
-local Punct = Q ( S ",:;!\\" )
+  local String =
+    WithStyle ( 'String.Short' ,
+                Q "\""
+                * ( VisualSpace
+                    + Q ( ( P "\\\"" + 1 - S " \"" ) ^ 1 )
+                  ) ^ 0
+                * Q "\""
+              )
+  local braces = Compute_braces ( P "\"" * ( P "\\\"" + 1 - P "\"" ) ^ 1 * "\"" )
 
-local Comment =
-  WithStyle ( 'Comment' ,
-              Q "#"
-              * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0 -- $
-            )
-     * ( EOL + -1 )
+  if piton.beamer then Beamer = Compute_Beamer ( 'minimal' , braces ) end
 
-local String =
-  WithStyle ( 'String.Short' ,
-              Q "\""
-              * ( VisualSpace
-                  + Q ( ( P "\\\"" + 1 - S " \"" ) ^ 1 )
-                ) ^ 0
-              * Q "\""
-            )
+  DetectedCommands = Compute_DetectedCommands ( 'minimal' , braces )
 
-local braces = Compute_braces ( P "\"" * ( P "\\\"" + 1 - P "\"" ) ^ 1 * "\"" )
+  LPEG_cleaner['minimal'] = Compute_LPEG_cleaner ( 'minimal' , braces )
 
-if piton.beamer then Beamer = Compute_Beamer ( 'minimal' , braces ) end
+  local identifier = letter * alphanum ^ 0
 
-DetectedCommands = Compute_DetectedCommands ( 'minimal' , braces )
+  local Identifier = K ( 'Identifier.Internal' , identifier )
 
-LPEG_cleaner['minimal'] = Compute_LPEG_cleaner ( 'minimal' , braces )
+  local Delim = Q ( S "{[()]}" )
 
-local identifier = letter * alphanum ^ 0
+  local Main =
+       space ^ 0 * EOL
+       + Space
+       + Tab
+       + Escape + EscapeMath
+       + CommentLaTeX
+       + Beamer
+       + DetectedCommands
+       + Comment
+       + Delim
+       + String
+       + Punct
+       + Identifier
+       + Number
+       + Word
+  LPEG1['minimal'] = Main ^ 0
 
-local Identifier = K ( 'Identifier.Internal' , identifier )
-
-local Delim = Q ( S "{[()]}" )
-
-local Main =
-     Space
-     + Tab
-     + Escape + EscapeMath
-     + CommentLaTeX
-     + Beamer
-     + DetectedCommands
-     + Comment
-     + Delim
-     + String
-     + Punct
-     + Identifier
-     + Number
-     + Word
-
-LPEG1['minimal'] = Main ^ 0
-
-LPEG2['minimal'] =
-  Ct (
-       ( space ^ 0 * "\r" ) ^ -1
-       * BeamerBeginEnvironments
-       * Lc [[\__piton_begin_line:]]
-       * SpaceIndentation ^ 0
-       * ( space ^ 1 * -1 + space ^ 0 * EOL + Main ) ^ 0
-       * -1
-       * Lc [[\__piton_end_line:]]
-     )
-
+  LPEG2['minimal'] =
+    Ct (
+         ( space ^ 0 * "\r" ) ^ -1
+         * BeamerBeginEnvironments
+         * Lc [[\__piton_begin_line:]]
+         * SpaceIndentation ^ 0
+         * ( space ^ 1 * -1 + space ^ 0 * EOL + Main ) ^ 0
+         * -1
+         * Lc [[\__piton_end_line:]]
+       )
+end
 function piton.Parse ( language , code )
   local t = LPEG2[language] : match ( code )
   if t == nil
@@ -1183,7 +1239,8 @@
     end
   end
 end
-function piton.ParseFile ( language , name , first_line , last_line , split )
+function piton.ParseFile
+  ( lang , name , first_line , last_line , splittable , split )
   local s = ''
   local i = 0
   for line in io.lines ( name ) do
@@ -1203,21 +1260,26 @@
     end
   end
   if split == 1 then
-    piton.GobbleSplitParse ( language , 0 , s )
+    piton.RetrieveGobbleSplitParse ( lang , 0 , splittable , s )
   else
-    sprintL3 [[ \bool_if:NT \g__piton_footnote_bool \savenotes \vtop \bgroup ]]
-    piton.Parse ( language , s )
-    sprintL3
-      [[\vspace{2.5pt}\egroup\bool_if:NT\g__piton_footnote_bool\endsavenotes\par]]
+    piton.RetrieveGobbleParse ( lang , 0 , splittable , s )
   end
 end
+function piton.RetrieveGobbleParse ( lang , n , splittable , code )
+  local s
+  s = ( ( P " " ^ 0 * "\r" ) ^ -1 * C ( P ( 1 ) ^ 0 ) * -1 ) : match ( code )
+  piton.GobbleParse ( lang , n , splittable , s )
+end
 function piton.ParseBis ( lang , code )
   local s = ( Cs ( ( P '##' / '#' + 1 ) ^ 0 ) ) : match ( code )
   return piton.Parse ( lang , s )
 end
 function piton.ParseTer ( lang , code )
-  local s = ( Cs ( ( P [[\__piton_breakable_space: ]] / ' ' + 1 ) ^ 0 ) )
-            : match ( code )
+  local s
+  s = ( Cs ( ( P [[\__piton_breakable_space: ]] / ' ' + 1 ) ^ 0 ) )
+      : match ( code )
+  s = ( Cs ( ( P [[\__piton_leading_space: ]] / '' + 1 ) ^ 0 ) )
+      : match ( s )
   return piton.Parse ( lang , s )
 end
 local AutoGobbleLPEG =
@@ -1281,14 +1343,14 @@
     end
   end
 end
-function piton.GobbleParse ( lang , n , code )
+function piton.GobbleParse ( lang , n , splittable , code )
+  piton.ComputeLinesStatus ( code , splittable )
   piton.last_code = gobble ( n , code )
   piton.last_language = lang
   piton.CountLines ( piton.last_code )
   sprintL3 [[ \bool_if:NT \g__piton_footnote_bool \savenotes ]]
-  sprintL3 [[ \vtop \bgroup ]]
   piton.Parse ( lang , piton.last_code )
-  sprintL3 [[ \vspace{2.5pt} \egroup ]]
+  sprintL3 [[ \vspace{2.5pt} ]]
   sprintL3 [[ \bool_if:NT \g__piton_footnote_bool \endsavenotes ]]
   sprintL3 [[ \par ]]
   if piton.write and piton.write ~= '' then
@@ -1301,22 +1363,43 @@
     end
   end
 end
-function piton.GobbleSplitParse ( lang , n , code )
-  P { "E" ,
-      E = ( V "F"
-           * ( P " " ^ 0 * "\r"
-               / ( function ( x ) sprintL3 [[ \__piton_incr_visual_line: ]] end )
-             ) ^ 1
-             / ( function ( x )
-                 sprintL3 ( piton.string_between_chunks )
-                 end )
-          ) ^ 0 * V "F" ,
-      F = C ( V "G" ^ 0 )
-          / ( function ( x ) piton.GobbleParse ( lang , 0 , x ) end ) ,
-      G = ( 1 - P "\r" ) ^ 0 * "\r" - ( P " " ^ 0 * "\r" )
-          + ( ( 1 - P "\r" ) ^ 1 * -1 - ( P " " ^ 0 * -1 ) )
-    } : match ( gobble ( n , code ) )
+function piton.GobbleSplitParse ( lang , n , splittable , code )
+  local chunks
+  chunks =
+     (
+       Ct (
+            (
+              P " " ^ 0 * "\r"
+              +
+              C ( ( ( 1 - P "\r" ) ^ 1 * "\r" - ( P " " ^ 0 * "\r" ) ) ^ 1 )
+            ) ^ 0
+          )
+     ) : match ( gobble ( n , code ) )
+  sprintL3 ( [[ \begingroup ]] )
+  sprintL3
+    (
+      [[ \PitonOptions { split-on-empty-lines=false, gobble = 0, ]]
+      .. "language = " .. lang .. ","
+      .. "splittable = " .. splittable .. "}"
+    )
+  for k , v in pairs ( chunks ) do
+    if k > 1 then
+     sprintL3 ( [[\l__piton_split_separation_tl ]] )
+    end
+    tex.sprint
+      (
+        [[\begin{]] .. piton.env_used_by_split .. "}\r"
+        .. v
+        .. [[\end{]] .. piton.env_used_by_split .. "}"
+      )
+  end
+  sprintL3 ( [[ \endgroup ]] )
 end
+function piton.RetrieveGobbleSplitParse ( lang , n , splittable , code )
+  local s
+  s = ( ( P " " ^ 0 * "\r" ) ^ -1 * C ( P ( 1 ) ^ 0 ) * -1 ) : match ( code )
+  piton.GobbleSplitParse ( lang , n , splittable , s )
+end
 piton.string_between_chunks =
  [[ \par \l__piton_split_separation_tl \mode_leave_vertical: ]]
  .. [[ \int_gzero:N \g__piton_line_int ]]
@@ -1325,8 +1408,13 @@
 end
 function piton.CountLines ( code )
   local count = 0
-  for i in code : gmatch ( "\r" ) do count = count + 1 end
-  sprintL3 ( string.format ( [[ \int_set:Nn  \l__piton_nb_lines_int { % i } ]] , count ) )
+  count =
+     ( Ct ( ( ( 1 - P "\r" ) ^ 0 * C "\r" ) ^ 0
+            * ( ( 1 - P "\r" ) ^ 1 * Cc "\r" ) ^ -1
+            * -1
+          ) / table.getn
+     ) : match ( code )
+  sprintL3 ( string.format ( [[ \int_set:Nn  \l__piton_nb_lines_int { %i } ]] , count ) )
 end
 function piton.CountNonEmptyLines ( code )
   local count = 0
@@ -1338,13 +1426,13 @@
           ) / table.getn
      ) : match ( code )
   sprintL3
-   ( string.format ( [[ \int_set:Nn  \l__piton_nb_non_empty_lines_int { % i } ]] , count ) )
+   ( string.format ( [[ \int_set:Nn  \l__piton_nb_non_empty_lines_int { %i } ]] , count ) )
 end
 function piton.CountLinesFile ( name )
   local count = 0
   for line in io.lines ( name ) do count = count + 1 end
   sprintL3
-   ( string.format ( [[ \int_set:Nn \l__piton_nb_lines_int { %i } ]], count))
+   ( string.format ( [[ \int_set:Nn \l__piton_nb_lines_int { %i } ]], count ) )
 end
 function piton.CountNonEmptyLinesFile ( name )
   local count = 0
@@ -1384,6 +1472,76 @@
       [[ \int_set:Nn \l__piton_first_line_int { ]] .. first_line .. ' + 2 }'
       .. [[ \int_set:Nn \l__piton_last_line_int { ]] .. count .. ' }' )
 end
+function piton.ComputeLinesStatus ( code , splittable )
+  local lpeg_line_beamer
+  if piton.beamer then
+    lpeg_line_beamer =
+       space ^ 0
+        * P "\\begin{" * piton.BeamerEnvironments * "}"
+        * ( "<" * ( 1 - P ">" ) ^ 0 * ">" ) ^ -1
+       +
+       space ^ 0
+        * P "\\end{" * piton.BeamerEnvironments * "}"
+  else
+    lpeg_line_beamer = P ( false )
+  end
+  local lpeg_empty_lines =
+    Ct (
+         ( lpeg_line_beamer * "\r"
+           +
+           P " " ^ 0 * "\r" * Cc ( 0 )
+           +
+           ( 1 - P "\r" ) ^ 0 * "\r" * Cc ( 1 )
+         ) ^ 0
+         *
+         ( lpeg_line_beamer + ( 1 - P "\r" ) ^ 1 * Cc ( 1 ) ) ^ -1
+       )
+    * -1
+  local lpeg_all_lines =
+    Ct (
+         ( lpeg_line_beamer * "\r"
+           +
+           ( 1 - P "\r" ) ^ 0 * "\r" * Cc ( 1 )
+         ) ^ 0
+         *
+         ( lpeg_line_beamer + ( 1 - P "\r" ) ^ 1 * Cc ( 1 ) ) ^ -1
+       )
+    * -1
+  piton.empty_lines = lpeg_empty_lines : match ( code )
+  local lines_status
+  local s = splittable
+  if splittable < 0 then s = - splittable end
+  if splittable > 0 then
+    lines_status = lpeg_all_lines : match ( code )
+  else
+    lines_status = lpeg_empty_lines : match ( code )
+    for i , x in ipairs ( lines_status ) do
+      if x == 0 then
+        for j = 1 , s - 1 do
+          if i + j > #lines_status then break end
+          if lines_status[i+j] == 0 then break end
+            lines_status[i+j] = 2
+        end
+        for j = 1 , s - 1 do
+          if i - j - 1 == 0 then break end
+          if lines_status[i-j-1] == 0 then break end
+          lines_status[i-j-1] = 2
+        end
+      end
+    end
+  end
+  for j = 1 , s - 1 do
+    if j > #lines_status then break end
+    if lines_status[j] == 0 then break end
+    lines_status[j] = 2
+  end
+  for j = 1 , s - 1 do
+    if #lines_status - j == 0 then break end
+    if lines_status[#lines_status - j] == 0 then break end
+    lines_status[#lines_status - j] = 2
+  end
+  piton.lines_status = lines_status
+end
 function piton.new_language ( lang , definition )
   lang = string.lower ( lang )
   local alpha , digit = lpeg.alpha , lpeg.digit
@@ -1544,7 +1702,7 @@
         central_pattern = P ( arg3 .. arg3 ) + central_pattern
       end
       if arg1 == "m"
-      then prefix = lpeg.B ( 1 - letter - ")" - "]" )
+      then prefix = B ( 1 - letter - ")" - "]" )
       else prefix = P ( true )
       end
      long_string = long_string +
@@ -1664,7 +1822,8 @@
   local Delim = Q ( S "{[()]}" )
   local Punct = Q ( S "=,:;!\\'\"" )
   local Main =
-       Space
+       space ^ 0 * EOL
+       + Space
        + Tab
        + Escape + EscapeMath
        + CommentLaTeX

Modified: trunk/Master/texmf-dist/tex/lualatex/piton/piton.sty
===================================================================
--- trunk/Master/texmf-dist/tex/lualatex/piton/piton.sty	2024-09-22 20:22:16 UTC (rev 72350)
+++ trunk/Master/texmf-dist/tex/lualatex/piton/piton.sty	2024-09-22 20:22:25 UTC (rev 72351)
@@ -19,8 +19,8 @@
 %% LaTeX version 2005/12/01 or later.
 %% -------------------------------------------
 %% 
-\def\PitonFileVersion{3.1b}
-\def\PitonFileDate{2024/08/29}
+\def\PitonFileVersion{4.0}
+\def\PitonFileDate{2024/09/22}
 
 
 
@@ -90,13 +90,20 @@
 \bool_new:N \g__piton_math_comments_bool
 \bool_new:N \g__piton_beamer_bool
 \tl_new:N \g__piton_escape_inside_tl
+\bool_new:N \l__piton_old_PitonInputFile_bool
 \keys_define:nn { piton / package }
   {
     footnote .bool_gset:N = \g__piton_footnote_bool ,
     footnotehyper .bool_gset:N = \g__piton_footnotehyper_bool ,
+    footnote .usage:n = load ,
+    footnotehyper .usage:n = load ,
 
     beamer .bool_gset:N = \g__piton_beamer_bool ,
     beamer .default:n = true ,
+    beamer .usage:n = load ,
+    old-PitonInputFile .bool_set:N = \l__piton_old_PitonInputFile_bool ,
+    old-PitonInputFile .default:n = true ,
+    old-PitonInputFile .usage:n = load ,
 
     unknown .code:n = \__piton_error:n { Unknown~key~for~package }
   }
@@ -104,8 +111,8 @@
   {
     Unknown~key.\\
     You~have~used~the~key~'\l_keys_key_str'~but~the~only~keys~available~here~
-    are~'beamer',~'footnote',~'footnotehyper'.~Other~keys~are~available~in~
-    \token_to_str:N \PitonOptions.\\
+    are~'beamer',~'footnote',~'footnotehyper'~and~'old-PitonInputFile'.~
+    Other~keys~are~available~in~\token_to_str:N \PitonOptions.\\
     That~key~will~be~ignored.
   }
 \ProcessKeysOptions { piton / package }
@@ -157,8 +164,8 @@
   }
 \lua_now:n
   {
-    piton.BeamerCommands = lpeg.P ( "\\uncover" )
-          + "\\only" + "\\visible" + "\\invisible" + "\\alert" + "\\action"
+    piton.BeamerCommands = lpeg.P ( [[\uncover]] )
+       + [[\only]] + [[\visible]] + [[\invisible]] + [[\alert]] + [[\action]]
     piton.beamer_environments = { "uncoverenv" , "onlyenv" , "visibleenv" ,
                "invisibleenv" ,  "alertenv" ,  "actionenv" }
     piton.DetectedCommands = lpeg.P ( false )
@@ -172,6 +179,8 @@
 \str_new:N \l__piton_path_write_str
 \bool_new:N \l__piton_in_PitonOptions_bool
 \bool_new:N \l__piton_in_PitonInputFile_bool
+\tl_new:N \l__piton_font_command_tl
+\tl_set:Nn \l__piton_font_command_tl { \ttfamily }
 \int_new:N \l__piton_nb_lines_int
 \int_new:N \l__piton_nb_non_empty_lines_int
 \int_new:N \g__piton_line_int
@@ -227,7 +236,7 @@
 \tl_new:N \l__piton_space_tl
 \tl_set_eq:NN \l__piton_space_tl \nobreakspace
 \int_new:N \g__piton_indentation_int
-\cs_new_protected:Npn \__piton_an_indentation_space:
+\cs_new_protected:Npn \__piton_leading_space:
   { \int_gincr:N \g__piton_indentation_int }
 \cs_new_protected:Npn \__piton_label:n #1
   {
@@ -243,13 +252,11 @@
             }
           }
         \@esphack
-     }
-     { \__piton_error:n { label~with~lines~numbers } }
+      }
+      { \__piton_error:n { label~with~lines~numbers } }
   }
 \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: { \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:
   {
@@ -256,7 +263,7 @@
     \tl_gset:Nn \g__piton_begin_line_hook_tl
       {
         \tl_if_empty:NF \l__piton_prompt_bg_color_tl
-          { \clist_set:NV \l__piton_bg_color_clist \l__piton_prompt_bg_color_tl }
+          { \clist_set:No \l__piton_bg_color_clist \l__piton_prompt_bg_color_tl }
       }
   }
 \cs_new_protected:Npn \__piton_trailing_space: { }
@@ -265,8 +272,8 @@
     \tl_set:Nn \l_tmpa_tl { #1 }
     \bool_if:NTF \l__piton_show_spaces_bool
       {
-        \tl_set:Nn \l__piton_space_tl { ␣ }
-        \regex_replace_all:nnN { \x20 } { ␣ } \l_tmpa_tl % U+2423
+        \tl_set:Nn \l__piton_space_tl { ␣ } % U+2423
+        \regex_replace_all:nnN { \x20 } { ␣ } \l_tmpa_tl
       }
       {
         \bool_if:NT \l__piton_break_lines_in_Piton_bool
@@ -275,10 +282,16 @@
               { \x20 }
               { \c { __piton_breakable_space: } }
               \l_tmpa_tl
+            \regex_replace_all:nnN
+              { \c { l__piton_space_tl } }
+              { \c { __piton_breakable_space: } }
+              \l_tmpa_tl
           }
       }
     \l_tmpa_tl
   }
+
+\cs_set_protected:Npn \__piton_end_line: { }
 \cs_set_protected:Npn \__piton_begin_line: #1 \__piton_end_line:
   {
     \group_begin:
@@ -299,16 +312,27 @@
         \skip_horizontal:N \l__piton_left_margin_dim
         \bool_if:NT \l__piton_line_numbers_bool
           {
-            \bool_if:nF
+            \int_set:Nn \l_tmpa_int
               {
-                \str_if_eq_p:nn { #1 } { \PitonStyle { Prompt } { } }
-                &&
-                \l__piton_skip_empty_lines_bool
+                \lua_now:e
+                  {
+                    tex.sprint
+                      (
+                        luatexbase.catcodetables.expl ,
+                        tostring
+                          ( piton.empty_lines
+                              [ \int_eval:n { \g__piton_line_int + 1 } ]
+                          )
+                      )
+                  }
               }
+            \bool_lazy_or:nnT
+              { \int_compare_p:nNn \l_tmpa_int = \c_one_int }
+              { ! \l__piton_skip_empty_lines_bool }
               { \int_gincr:N \g__piton_visual_line_int }
             \bool_if:nT
               {
-                ! \str_if_eq_p:nn { #1 } { \PitonStyle { Prompt } { } }
+                \int_compare_p:nNn \l_tmpa_int = \c_one_int
                 ||
                 ( ! \l__piton_skip_empty_lines_bool && \l__piton_label_empty_lines_bool )
               }
@@ -317,12 +341,13 @@
         \clist_if_empty:NF \l__piton_bg_color_clist
           {
             \dim_compare:nNnT \l__piton_left_margin_dim = \c_zero_dim
-               { \skip_horizontal:n { 0.5 em } }
+              { \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 }
+    \mode_leave_vertical:
     \clist_if_empty:NTF \l__piton_bg_color_clist
       { \box_use_drop:N \l_tmpa_box }
       {
@@ -339,7 +364,6 @@
             \box_use_drop:N \l_tmpa_box
           }
       }
-    \vspace { - 2.5 pt }
     \group_end:
     \tl_gclear:N \g__piton_begin_line_hook_tl
   }
@@ -360,10 +384,10 @@
   {
     \int_set:Nn \l_tmpa_int { \clist_count:N #1 }
     \int_set:Nn \l_tmpb_int { \int_mod:nn \g__piton_line_int \l_tmpa_int + 1 }
-    \tl_set:Nx \l_tmpa_tl { \clist_item:Nn #1 \l_tmpb_int }
+    \tl_set:Ne \l_tmpa_tl { \clist_item:Nn #1 \l_tmpb_int }
     \tl_if_eq:NnTF \l_tmpa_tl { none }
       { \dim_zero:N \l__piton_width_dim }
-      { \exp_args:NV \__piton_color_i:n \l_tmpa_tl }
+      { \exp_args:No \__piton_color_i:n \l_tmpa_tl }
   }
 \cs_set_protected:Npn \__piton_color_i:n #1
   {
@@ -377,20 +401,23 @@
   }
 \cs_new_protected:Npn \__piton_newline:
   {
+    \bool_if:NT \g__piton_footnote_bool \endsavenotes
     \int_gincr:N \g__piton_line_int
-    \int_compare:nNnT \g__piton_line_int > { \l__piton_splittable_int - 1 }
+    \par
+    \kern -2.5 pt
+    \int_case:nn
       {
-        \int_compare:nNnT
-          { \l__piton_nb_lines_int - \g__piton_line_int + 1 } > \l__piton_splittable_int
+        \lua_now:e
           {
-            \egroup
-            \bool_if:NT \g__piton_footnote_bool \endsavenotes
-            \par
-            \mode_leave_vertical:
-            \bool_if:NT \g__piton_footnote_bool \savenotes
-            \vtop \bgroup
+            tex.sprint
+              (
+                luatexbase.catcodetables.expl ,
+                tostring ( piton.lines_status [ \int_use:N \g__piton_line_int ] )
+              )
           }
-     }
+      }
+      { 1 { \penalty 100 } 2 \nobreak }
+   \bool_if:NT \g__piton_footnote_bool \savenotes
   }
 \cs_set_protected:Npn \__piton_breakable_space:
   {
@@ -429,6 +456,7 @@
 \int_new:N \l__piton_number_lines_start_int
 \bool_new:N \l__piton_resume_bool
 \bool_new:N \l__piton_split_on_empty_lines_bool
+\bool_new:N \l__piton_splittable_on_empty_lines_bool
 \keys_define:nn { PitonOptions / marker }
   {
     beginning .code:n = \cs_set:Nn \__piton_marker_beginning:n { #1 } ,
@@ -493,15 +521,15 @@
 \keys_define:nn { PitonOptions }
   {
     detected-commands .code:n =
-       \lua_now:n { piton.addDetectedCommands('#1') } ,
+      \lua_now:n { piton.addDetectedCommands('#1') } ,
     detected-commands .value_required:n = true ,
     detected-commands .usage:n = preamble ,
     detected-beamer-commands .code:n =
-       \lua_now:n { piton.addBeamerCommands('#1') } ,
+      \lua_now:n { piton.addBeamerCommands('#1') } ,
     detected-beamer-commands .value_required:n = true ,
     detected-beamer-commands .usage:n = preamble ,
     detected-beamer-environments .code:n =
-       \lua_now:n { piton.addBeamerEnvironments('#1') } ,
+      \lua_now:n { piton.addBeamerEnvironments('#1') } ,
     detected-beamer-environments .value_required:n = true ,
     detected-beamer-environments .usage:n = preamble ,
     begin-escape .code:n =
@@ -532,7 +560,7 @@
     math-comments .default:n  = true ,
     math-comments .usage:n = preamble ,
     language         .code:n =
-      \str_set:Nx \l_piton_language_str { \str_lowercase:n { #1 } } ,
+      \str_set:Ne \l_piton_language_str { \str_lowercase:n { #1 } } ,
     language         .value_required:n  = true ,
     path .code:n =
       \seq_clear:N \l__piton_path_seq
@@ -545,6 +573,8 @@
     path             .initial:n         = . ,
     path-write       .str_set:N         = \l__piton_path_write_str ,
     path-write       .value_required:n  = true ,
+    font-command     .tl_set:N          = \l__piton_font_command_tl ,
+    font-command     .value_required:n  = true ,
     gobble           .int_set:N         = \l__piton_gobble_int ,
     gobble           .value_required:n  = true ,
     auto-gobble      .code:n            = \int_set:Nn \l__piton_gobble_int { -1 } ,
@@ -554,6 +584,9 @@
     tabs-auto-gobble .code:n            = \int_set:Nn \l__piton_gobble_int { -3 } ,
     tabs-auto-gobble .value_forbidden:n = true ,
 
+    splittable-on-empty-lines .bool_set:N = \l__piton_splittable_on_empty_lines_bool ,
+    splittable-on-empty-lines .default:n  = true ,
+
     split-on-empty-lines .bool_set:N = \l__piton_split_on_empty_lines_bool ,
     split-on-empty-lines .default:n = true ,
 
@@ -650,6 +683,10 @@
       } ,
     range .value_required:n = true ,
 
+    env-used-by-split .code:n =
+      \lua_now:n { piton.env_used_by_split = '#1'} ,
+    env-used-by-split .initial:n = Piton ,
+
     resume .meta:n = line-numbers/resume ,
 
     unknown .code:n = \__piton_error:n { Unknown~key~for~PitonOptions } ,
@@ -659,10 +696,6 @@
       \bool_set_true:N \l__piton_line_numbers_bool
       \bool_set_false:N \l__piton_skip_empty_lines_bool ,
     all-line-numbers .value_forbidden:n = true ,
-
-    % deprecated
-    numbers-sep .dim_set:N = \l__piton_numbers_sep_dim ,
-    numbers-sep .value_required:n = true
   }
 \cs_new_protected:Npn \__piton_in_PitonInputFile:n #1
   {
@@ -700,7 +733,7 @@
     \tl_if_empty:NF \g__piton_aux_tl
       {
         \iow_now:Nn \@mainaux { \ExplSyntaxOn }
-        \iow_now:Nx \@mainaux
+        \iow_now:Ne \@mainaux
           {
             \tl_gset:cn { c__piton_ \int_use:N \g__piton_env_int _ tl }
               { \exp_not:o \g__piton_aux_tl }
@@ -711,7 +744,7 @@
   }
 \cs_new_protected:Npn \__piton_width_to_aux:
   {
-    \tl_gput_right:Nx \g__piton_aux_tl
+    \tl_gput_right:Ne \g__piton_aux_tl
       {
         \dim_set:Nn \l__piton_line_width_dim
           { \dim_eval:n { \g__piton_tmp_width_dim } }
@@ -743,7 +776,7 @@
   }
 \cs_new_protected:Npn \__piton_NewPitonLanguage:nnn #1 #2 #3
   {
-    \tl_set:Nx \l_tmpa_tl
+    \tl_set:Ne \l_tmpa_tl
       {
         \tl_if_blank:nF { #1 } { [ \str_lowercase:n { #1 } ] }
         \str_lowercase:n { #2 }
@@ -750,7 +783,7 @@
       }
     \keys_set:nn { NewPitonLanguage } { #3 }
     \prop_gput:Non \g__piton_languages_prop \l_tmpa_tl { #3 }
-    \exp_args:NV \__piton_NewPitonLanguage:nn \l_tmpa_tl { #3 }
+    \exp_args:No \__piton_NewPitonLanguage:nn \l_tmpa_tl { #3 }
   }
 \cs_new_protected:Npn \__piton_NewPitonLanguage:nn #1 #2
   {
@@ -759,14 +792,14 @@
   }
 \cs_new_protected:Npn \__piton_NewPitonLanguage:nnnnn #1 #2 #3 #4 #5
   {
-    \tl_set:Nx \l_tmpa_tl
+    \tl_set:Ne \l_tmpa_tl
       {
          \tl_if_blank:nF { #3 } { [ \str_lowercase:n { #3 } ] }
          \str_lowercase:n { #4 }
       }
-     \prop_get:NoNTF \g__piton_languages_prop \l_tmpa_tl \l_tmpb_tl
-       { \__piton_NewPitonLanguage:nnno { #1 } { #2 } { #5 } \l_tmpb_tl }
-       { \__piton_error:n { Language~not~defined } }
+    \prop_get:NoNTF \g__piton_languages_prop \l_tmpa_tl \l_tmpb_tl
+      { \__piton_NewPitonLanguage:nnno { #1 } { #2 } { #5 } \l_tmpb_tl }
+      { \__piton_error:n { Language~not~defined } }
   }
 \cs_new_protected:Npn \__piton_NewPitonLanguage:nnnn #1 #2 #3 #4
   { \__piton_NewPitonLanguage:nnn { #1 } { #2 } { #4 , #3 } }
@@ -783,9 +816,8 @@
     \cs_set_eq:NN \} \c_right_brace_str
     \cs_set_eq:NN \$ \c_dollar_str
     \cs_set_eq:cN { ~ } \space
-    \cs_set_protected:Npn \__piton_begin_line: { }
-    \cs_set_protected:Npn \__piton_end_line: { }
-    \tl_set:Nx \l_tmpa_tl
+    \cs_set_eq:NN \__piton_begin_line: \prg_do_nothing:
+    \tl_set:Ne \l_tmpa_tl
       {
         \lua_now:e
           { piton.ParseBis('\l_piton_language_str',token.scan_string()) }
@@ -798,9 +830,9 @@
           { \regex_replace_all:nnN { \x20 } { \x20 } \l_tmpa_tl }
       }
     \if_mode_math:
-       \text { \ttfamily \l_tmpa_tl }
+       \text { \l__piton_font_command_tl \l_tmpa_tl }
     \else:
-       \ttfamily \l_tmpa_tl
+       \l__piton_font_command_tl \l_tmpa_tl
     \fi:
     \group_end:
   }
@@ -807,11 +839,10 @@
 \NewDocumentCommand { \__piton_piton_verbatim } { v }
   {
     \group_begin:
-    \ttfamily
+    \l__piton_font_command_tl
     \automatichyphenmode = 1
-    \cs_set_protected:Npn \__piton_begin_line: { }
-    \cs_set_protected:Npn \__piton_end_line: { }
-    \tl_set:Nx \l_tmpa_tl
+    \cs_set_eq:NN \__piton_begin_line: \prg_do_nothing:
+    \tl_set:Ne \l_tmpa_tl
       {
         \lua_now:e
           { piton.Parse('\l_piton_language_str',token.scan_string()) }
@@ -824,32 +855,21 @@
   }
 
 \cs_new_protected:Npn \__piton_piton:n #1
+  { \tl_if_blank:nF { #1 } { \__piton_piton_i:n { #1 } } }
+
+\cs_new_protected:Npn \__piton_piton_i:n #1
   {
     \group_begin:
-    \cs_set_protected:Npn \__piton_begin_line: { }
-    \cs_set_protected:Npn \__piton_end_line: { }
+    \cs_set_eq:NN \__piton_begin_line: \prg_do_nothing:
     \cs_set:cpn { pitonStyle _ \l_piton_language_str  _ Prompt } { }
     \cs_set:cpn { pitonStyle _ Prompt } { }
     \cs_set_eq:NN \__piton_trailing_space: \space
-    \bool_lazy_or:nnTF
-      \l__piton_break_lines_in_piton_bool
-      \l__piton_break_lines_in_Piton_bool
+    \tl_set:Ne \l_tmpa_tl
       {
-        \tl_set:Nx \l_tmpa_tl
-          {
-            \lua_now:e
-              { piton.ParseTer('\l_piton_language_str',token.scan_string()) }
-              { #1 }
-          }
+        \lua_now:e
+          { piton.ParseTer('\l_piton_language_str',token.scan_string()) }
+          { #1 }
       }
-      {
-        \tl_set:Nx \l_tmpa_tl
-          {
-            \lua_now:e
-              { piton.Parse('\l_piton_language_str',token.scan_string()) }
-              { #1 }
-          }
-      }
     \bool_if:NT \l__piton_show_spaces_bool
       { \regex_replace_all:nnN { \x20 } { ␣ } \l_tmpa_tl } % U+2423
     \exp_args:No \__piton_replace_spaces:n \l_tmpa_tl
@@ -884,7 +904,7 @@
                   { #2 }
                 \int_to_arabic:n
                   { \g__piton_visual_line_int + \l__piton_nb_non_empty_lines_int }
-               }
+              }
               {
                 \int_to_arabic:n
                   { \g__piton_visual_line_int + \l__piton_nb_lines_int }
@@ -930,14 +950,15 @@
           ####1
           \c_backslash_str end \c_left_brace_str #1 \c_right_brace_str
       }
-         {
+          {
             \group_end:
             \mode_if_vertical:TF { \noindent \mode_leave_vertical: } \newline
+            \lua_now:e { piton.CountLines ( '\lua_escape:n{##1}' ) }
             \__piton_compute_left_margin:nn { CountNonEmptyLines } { ##1 }
             \__piton_compute_width:
-            \ttfamily
+            \l__piton_font_command_tl
             \dim_zero:N \parskip
-            \noindent % added 2024/08/07
+            \noindent
             \str_if_empty:NTF \l__piton_path_write_str
               { \lua_now:e { piton.write = "\l__piton_write_str" } }
               {
@@ -947,16 +968,16 @@
             \str_if_empty:NTF \l__piton_write_str
               { \lua_now:n { piton.write = '' } }
               {
-                \seq_if_in:NVTF \g__piton_write_seq \l__piton_write_str
+                \seq_if_in:NoTF \g__piton_write_seq \l__piton_write_str
                   { \lua_now:n { piton.write_mode = "a" } }
                   {
                     \lua_now:n { piton.write_mode = "w" }
-                    \seq_gput_left:NV \g__piton_write_seq \l__piton_write_str
+                    \seq_gput_left:No \g__piton_write_seq \l__piton_write_str
                   }
               }
             \bool_if:NTF \l__piton_split_on_empty_lines_bool
-              \__piton_gobble_split_parse:n
-              \__piton_gobble_parse:n
+              \__piton_retrieve_gobble_split_parse:n
+              \__piton_retrieve_gobble_parse:n
               { ##1 }
             \bool_if:NT \l__piton_width_min_bool \__piton_width_to_aux:
             \end { #1 }
@@ -978,26 +999,30 @@
       { #4 }
     \AddToHook { env / #1 / begin } { \char_set_catcode_other:N \^^M }
   }
-\cs_new_protected:Npn \__piton_gobble_parse:n
+\cs_new_protected:Npn \__piton_retrieve_gobble_parse:n
   {
     \lua_now:e
       {
-        piton.GobbleParse
+        piton.RetrieveGobbleParse
           (
             '\l_piton_language_str' ,
             \int_use:N \l__piton_gobble_int ,
+            \bool_if:NTF \l__piton_splittable_on_empty_lines_bool
+              { \int_eval:n { - \l__piton_splittable_int } }
+              { \int_use:N \l__piton_splittable_int } ,
             token.scan_argument ( )
           )
       }
   }
-\cs_new_protected:Npn \__piton_gobble_split_parse:n
+\cs_new_protected:Npn \__piton_retrieve_gobble_split_parse:n
   {
     \lua_now:e
       {
-        piton.GobbleSplitParse
+        piton.RetrieveGobbleSplitParse
           (
             '\l_piton_language_str' ,
             \int_use:N \l__piton_gobble_int ,
+            \int_use:N \l__piton_splittable_int ,
             token.scan_argument ( )
           )
       }
@@ -1021,18 +1046,33 @@
 \NewDocumentCommand { \PitonInputFileTF } { d < > O { } m m m }
   {
     \group_begin:
-    \bool_set_false:N \l_tmpa_bool
-    \seq_map_inline:Nn \l__piton_path_seq
+    \bool_if:NTF \l__piton_old_PitonInputFile_bool
       {
-        \str_set:Nn \l__piton_file_name_str { ##1 / #3 }
-        \file_if_exist:nT { \l__piton_file_name_str }
+        \bool_set_false:N \l_tmpa_bool
+        \seq_map_inline:Nn \l__piton_path_seq
           {
+            \str_set:Nn \l__piton_file_name_str { ##1 / #3 }
+            \file_if_exist:nT { \l__piton_file_name_str }
+              {
+                \__piton_input_file:nn { #1 } { #2 }
+                \bool_set_true:N \l_tmpa_bool
+                \seq_map_break:
+              }
+          }
+        \bool_if:NTF \l_tmpa_bool { #4 } { #5 }
+      }
+      {
+        \seq_concat:NNN
+          \l_file_search_path_seq
+          \l__piton_path_seq
+          \l_file_search_path_seq
+        \file_get_full_name:nNTF { #3 } \l__piton_file_name_str
+          {
             \__piton_input_file:nn { #1 } { #2 }
-            \bool_set_true:N \l_tmpa_bool
-            \seq_map_break:
+            #4
           }
+          { #5 }
       }
-    \bool_if:NTF \l_tmpa_bool { #4 } { #5 }
     \group_end:
   }
 \cs_new_protected:Npn \__piton_unknown_file:n #1
@@ -1099,7 +1139,7 @@
       \lua_now:e { piton.CountLinesFile ( '\l__piton_file_name_str' ) }
       \__piton_compute_left_margin:no { CountNonEmptyLinesFile } \l__piton_file_name_str
       \__piton_compute_width:
-      \ttfamily
+      \l__piton_font_command_tl
       \lua_now:e
         {
           piton.ParseFile(
@@ -1107,11 +1147,14 @@
            '\l__piton_file_name_str' ,
            \int_use:N \l__piton_first_line_int ,
            \int_use:N \l__piton_last_line_int ,
+           \bool_if:NTF \l__piton_splittable_on_empty_lines_bool
+             { \int_eval:n { - \l__piton_splittable_int } }
+             { \int_use:N \l__piton_splittable_int } ,
            \bool_if:NTF \l__piton_split_on_empty_lines_bool { 1 } { 0 } )
         }
       \bool_if:NT \l__piton_width_min_bool \__piton_width_to_aux:
     \group_end:
-    \exp_args:Nx \iow_log:n {(\l__piton_file_name_str)}
+    \iow_log:e {(\l__piton_file_name_str)}
     \tl_if_novalue:nF { #1 }
       { \bool_if:NT \g__piton_beamer_bool { \end { uncoverenv } } }
     \__piton_write_aux:
@@ -1118,10 +1161,10 @@
   }
 \cs_new_protected:Npn \__piton_compute_range:
   {
-    \str_set:Nx \l_tmpa_str { \__piton_marker_beginning:n \l__piton_begin_range_str }
-    \str_set:Nx \l_tmpb_str { \__piton_marker_end:n \l__piton_end_range_str }
-    \exp_args:NnV \regex_replace_all:nnN { \\\# } \c_hash_str \l_tmpa_str
-    \exp_args:NnV \regex_replace_all:nnN { \\\# } \c_hash_str \l_tmpb_str
+    \str_set:Ne \l_tmpa_str { \__piton_marker_beginning:n \l__piton_begin_range_str }
+    \str_set:Ne \l_tmpb_str { \__piton_marker_end:n \l__piton_end_range_str }
+    \exp_args:Nno \regex_replace_all:nnN { \\\# } \c_hash_str \l_tmpa_str
+    \exp_args:Nno \regex_replace_all:nnN { \\\# } \c_hash_str \l_tmpb_str
     \lua_now:e
       {
         piton.ComputeRange
@@ -1136,7 +1179,7 @@
 \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_set:Ne \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 }
@@ -1221,7 +1264,7 @@
 \SetPitonStyle[OCaml]
   {
     TypeExpression =
-      \SetPitonStyle { Identifier = \PitonStyle { Name.Type } } \__piton_piton:n
+      \SetPitonStyle { Identifier = \PitonStyle { Name.Type } } \__piton_piton:n ,
   }
 \clist_gput_left:Nn \g__piton_styles_clist { String }
 \clist_gsort:Nn \g__piton_styles_clist
@@ -1267,10 +1310,10 @@
     ParseAgain          = \__piton_piton_no_cr:n ,
     Discard             = \use_none:n
   }
-\AtBeginDocument
+\hook_gput_code:nnn { begindocument } { . }
   {
     \bool_if:NT \g__piton_math_comments_bool
-       { \SetPitonStyle { Comment.Math = \__piton_math_scantokens:n } }
+      { \SetPitonStyle { Comment.Math = \__piton_math_scantokens:n } }
   }
 \NewDocumentCommand { \SetPitonIdentifier } { o m m }
   {
@@ -1281,7 +1324,7 @@
           { \cs_set:cpn { PitonIdentifier _ ##1 } { #3 } }
       }
       {
-        \str_set:Nx \l_tmpa_str { \str_lowercase:n { #1 } }
+        \str_set:Ne \l_tmpa_str { \str_lowercase:n { #1 } }
         \str_if_eq:onT \l_tmpa_str { current-language }
           { \str_set_eq:NN \l_tmpa_str \l_piton_language_str }
         \clist_map_inline:Nn \l_tmpa_clist
@@ -1305,8 +1348,8 @@
     \seq_if_exist:cF { g__piton_functions _ \l_piton_language_str _ seq }
       { \seq_new:c { g__piton_functions _ \l_piton_language_str _ seq } }
     \seq_gput_right:cn { g__piton_functions _ \l_piton_language_str _ seq } { #1 }
-    \seq_if_in:NVF \g__piton_languages_seq \l_piton_language_str
-      { \seq_gput_left:NV \g__piton_languages_seq \l_piton_language_str }
+    \seq_if_in:NoF \g__piton_languages_seq \l_piton_language_str
+      { \seq_gput_left:No \g__piton_languages_seq \l_piton_language_str }
   }
 \NewDocumentCommand \PitonClearUserFunctions { ! o }
   {
@@ -1413,7 +1456,7 @@
 \__piton_msg_new:nn { SyntaxError }
   {
     Syntax~Error.\\
-    Your~code~of~the~language~"\l_piton_language_str"~is~not~
+    Your~code~of~the~language~'\l_piton_language_str'~is~not~
     syntactically~correct.\\
     It~won't~be~printed~in~the~PDF~file.
   }
@@ -1468,6 +1511,8 @@
     end-of-broken-line,~
     end-range,~
     env-gobble,~
+    env-used-by-split,~
+    font-command,~
     gobble,~
     indent-broken-lines,~
     language,~
@@ -1482,6 +1527,7 @@
     show-spaces,~
     show-spaces-in-strings,~
     splittable,~
+    splittable-on-empty-lines,~
     split-on-empty-lines,~
     split-separation,~
     tabs-auto-gobble,~



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