texlive[68075] Master/texmf-dist: piton (26aug23)

commits+karl at tug.org commits+karl at tug.org
Sat Aug 26 22:18:56 CEST 2023


Revision: 68075
          http://tug.org/svn/texlive?view=revision&revision=68075
Author:   karl
Date:     2023-08-26 22:18:56 +0200 (Sat, 26 Aug 2023)
Log Message:
-----------
piton (26aug23)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/lualatex/piton/README.md
    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/source/lualatex/piton/piton.ins
    trunk/Master/texmf-dist/tex/lualatex/piton/piton.sty

Added Paths:
-----------
    trunk/Master/texmf-dist/tex/lualatex/piton/piton.lua

Modified: trunk/Master/texmf-dist/doc/lualatex/piton/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/lualatex/piton/README.md	2023-08-26 20:18:37 UTC (rev 68074)
+++ trunk/Master/texmf-dist/doc/lualatex/piton/README.md	2023-08-26 20:18:56 UTC (rev 68075)
@@ -11,7 +11,7 @@
 
 ## Presentation
 
-The LaTeX package `piton` provides a command `\piton` and an environment `{Piton}` to typeset Python codes by using the Lua library LPEG. It requires the use of `lualatex`. It won't work with `xelatex` nor `pdflatex`. 
+The LaTeX package `piton` provides a command `\piton` and an environment `{Piton}` to typeset Python, OCaml or C++  codes by using the Lua library LPEG. It requires the use of `lualatex`. It won't work with `xelatex` nor `pdflatex`. 
 
 
 
@@ -24,9 +24,9 @@
 * put the files `piton.ins` and `piton.dtx` in the same directory; 
 * run `latex piton.ins` in that directory.
 
-The file `piton.sty` will be generated.
+The files `piton.sty` and `piton.lua` will be generated.
 
-The file `piton.sty` is the only file necessary to use the extension `piton`. 
-You have to put it in the same directory as your document or (best) in a `texmf` tree. 
+These files `piton.sty` and `piton.lua` are the only files necessary to use the extension `piton`. 
+You have to put them in the same directory as your document or (best) in a `texmf` tree. 
 
 

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	2023-08-26 20:18:37 UTC (rev 68074)
+++ trunk/Master/texmf-dist/doc/lualatex/piton/piton-french.tex	2023-08-26 20:18:56 UTC (rev 68075)
@@ -6,8 +6,19 @@
 \usepackage[french]{babel}
 \frenchsetup{og = « , fg = »}
 
-\usepackage[footnotehyper,escape-inside=$$,math-comments]{piton}
+\usepackage[footnotehyper]{piton}
+\PitonOptions
+  { 
+    splittable = 4 ,
+    math-comments,
+    begin-escape = ! ,
+    end-escape = ! ,
+    begin-escape-math = \( , 
+    end-escape-math = \) 
+  }
 
+
+
 \usepackage[executable=python.exe]{pyluatex}
 
 \usepackage{xcolor}
@@ -68,8 +79,8 @@
 
 \begin{document}
 
-\PitonOptions{splittable = 4}
 
+
 \VerbatimFootnotes
 
 
@@ -123,10 +134,12 @@
 \end{Piton}
 
 
-\bigskip
 
-L'extension LaTeX \pkg{piton} est entièrement contenue dans le fichier |piton.sty|. Ce
-fichier peut être placé dans le répertoire courant ou dans une arborescence |texmf|. Le mieux reste néanmoins
+\section{Installation}
+
+L'extension \pkg{piton} est composée de deux fichiers : |piton.sty| et |piton.lua| (le fichier LaTeX |piton.sty|
+chargé par |\usepackage| va à son tour charger le fichier |piton.lua|). Les deux fichiers doivent être présents
+dans un répertoire où LaTeX pourra les trouver, de préférence dans une arborescence |texmf|. Le mieux reste néanmoins
 d'installer \pkg{piton} avec une distribution TeX comme MiKTeX, TeX~Live ou MacTeX.
 
 
@@ -188,8 +201,7 @@
 \item La commande \colorbox{gray!20}{\ttfamily \textbackslash PitonInputFile} doit être utilisée pour insérer et
 composer un fichier extérieur.
 
-Cette commande prend en argument optionnel entre crochets deux clés |first-line| et |last-line| qui permettent de
-n'insérer que la partie du fichier comprise entre les lignes correspondantes.
+Il est possible de n'insérer qu'une partie du fichier : cf. partie~\ref{part-of-a-file}, p.~\pageref{part-of-a-file}.
 \end{itemize}
 
 
@@ -278,11 +290,10 @@
 
 \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|).
+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}
 
 \NewDocumentCommand{\Definition}{m}
@@ -313,27 +324,58 @@
 valeur de~$n$. Le nom de cette clé vient de \emph{environment gobble}: le nombre d'espaces à retirer ne dépend que
 de la position des délimiteurs |\begin{Piton}| et |\end{Piton}| de l'environnement.
 
-\item Avec la clé \Definition{line-numbers}, les lignes \emph{non vides} (et toutes les lignes des
-\emph{docstrings}, y compris celles qui sont vides) sont numérotées dans les environnements \verb|{Piton}| et dans
-les listings produits par la commande |\PitonInputFile|.
+\item La clé \Definition{line-numbers} active la numérotation des lignes (en débordement à gauche) dans les
+environnements \verb|{Piton}| et dans les listings produits par la commande |\PitonInputFile|.
 
-\item Avec la clé \Definition{all-line-numbers}, \emph{toutes} les lignes sont numérotées, y compris les lignes vides.
+\colorbox{yellow!50}{\textbf{Nouveau 2.1}}\enskip Cette clé propose en fait plusieurs sous-clés.
+\begin{itemize}
+\item La clé \Definition{line-numbers/skip-empty-lines} demande que les lignes vides soient considérées comme non existantes en
+ce qui concerne la numérotation des lignes (si la clé \verb|/absolute| est active, la clé \verb|/skip-empty-lines|
+n'a pas d'effet dans \verb|\PitonInputFile|). La valeur initiale de cette clé est \verb|true| (et non
+\verb|false|).\footnote{Avec le language Python, les lignes vides des \emph{docstrings} sont prises en compte.}
 
-\item La clé \Definition{numbers-sep} est la distance horizontale entre les numéros de lignes (insérés par |line-numbers|
-ou |all-line-numbers|) et les lignes du code informatique. La valeur initiale est 0.7~em.
+\item La clé \Definition{line/numbers/label-empty-lines} demande que les labels (c'est-à-dire les numéros) des lignes vides
+soient affichés. Si la clé \verb|/skip-empty-lines| est active, la clé \verb|/label-empty-lines| est sans effet. La
+valeur initiale de cette clé est \verb|true|.
 
+\item La clé \Definition{line-numbers/absolute} demande, pour les listings générés par \verb|\PitonInputFile|, que les numéros de
+lignes affichés soient absolus (c'est-à-dire ceux du fichier d'origine). Elle n'a d'intérêt que si on insère qu'une
+partie du fichier (cf. part~\ref{part-of-a-file}, p.~\pageref{part-of-a-file}). La clé |/absolute| est sans effet dans les environnements \verb|{Piton}|.
+
+\item La clé \Definition{line-numbers/resume} reprend la numérotation là où elle avait été laissée au dernier listing. En fait,
+la clé \verb|line-numbers/resume| a un alias, qui est \verb|resume| tout court. 
+
+\item La clé \Definition{line-numbers/start} impose que la numérotation commence à ce numéro. Elle n'est pas disponible dans
+\verb|\PitonOptions|. 
+
+\item La clé \Definition{sep} est la distance horizontale entre les numéros de lignes (insérés par |line-numbers|)
+et les lignes du code informatique. La valeur initiale est 0.7~em.
+\end{itemize}
+
+Pour la commmodité, un dispositif de factorisation du préfixe |line-numbers| est disponible, c'est-à-dire que l'on
+peut écrire :
+
+\begin{Verbatim}
+\PitonOptions
+  {
+    line-numbers = 
+      { 
+        skip-empty-lines = false ,
+        label-empty-lines = false ,
+        sep = 1 em
+      }
+  }
+\end{Verbatim}
+
+
 \item La clé \Definition{left-margin} fixe une marge sur la gauche. Cette clé peut être utile, en particulier, en
-conjonction avec l'une des clés |line-numbers| et |all-line-numbers| si on ne souhaite pas que les numéros de ligne
-soient dans une position en débordement sur la gauche.
+conjonction avec la clé |line-numbers| si on ne souhaite pas que les numéros de ligne soient dans une position en
+débordement sur la gauche.
 
 Il est possible de donner à la clé |left-margin| la valeur spéciale~|auto|. Avec cette valeur, une marge est
-insérée automatiquement pour les numéros de ligne quand l'une des clés |line-numbers| ou |all-line-numbers| est
-utilisée. Voir un exemple à la partie \ref{example-numbering} p.~\pageref{example-numbering}.
+insérée automatiquement pour les numéros de ligne quand la clé |line-numbers| est utilisée. Voir un exemple à la
+partie \ref{example-numbering} p.~\pageref{example-numbering}.
 
-\item Avec la clé \Definition{resume}, le compteur de lignes n'est pas remis à zéro comme il l'est normalement au
-début d'un environnement |{Piton}| ou bien au début d'un listing produit par |\PitonInputFile|. Cela permet de
-poursuivre la numérotation d'un environnement à l'autre.
-
 \item La clé \Definition{background-color} fixe la couleur de fond des environnements |{Piton}| et des listings
 produits par |\PitonInputFile| (ce fond a une largeur que l'on peut fixer avec la clé |width| décrite ci-dessous).
 La clé |background-color| accepte une couleur définie «à la volée», c'est-à-dire que l'on peut écrire par exemple
@@ -589,6 +631,222 @@
 \section{Fonctionnalités avancées}
 
 
+\subsection{Coupure des pages et des lignes}
+
+\label{breakable}
+
+\subsubsection{Coupure des pages}
+
+Par défaut les listings produits par l'environnement |{Piton}| et par la commande |\PitonInputFile| sont
+insécables.
+
+Néanmoins, la commande |\PitonOptions| propose la clé \Definition{splittable} pour autoriser de telles coupures.
+
+\begin{itemize}
+\item Si la clé |splittable| est utilisée sans valeur, les listings sont sécables n'importe où.
+
+\item Si la clé |splittable| est utilisée avec une valeur numérique $n$ (qui doit être un entier naturel non nul),
+alors les listings seront sécables mais aucune coupure ne pourra avoir lieu entre les $n$~premières lignes, ni
+entre les $n$~dernières. De ce fait, |splittable=1| est équivalent à |splittable|.
+\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ù la clé |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|.}
+
+\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 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 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 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 Avec la clé \Definition{indent-broken-lines}, l'indentation de la ligne coupée est respectée à chaque retour
+à la ligne. 
+
+\item 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 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 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}
+
+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}
+\item On peut spécifier la partie à insérer par les numéros de lignes (dans le fichier d'origine).
+\item \colorbox{yellow!50}{\textbf{Nouveau 2.1}}\enskip On peut aussi spécifier la partie à insérer par des marqueurs textuels.
+\end{itemize}
+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}
+
+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 |line-numbers/start|
+concerne la sortie alors que |first-line| et |last-line| concernent l'entrée).
+
+
+\subsubsection{Avec des marqueurs textuels}
+
+\colorbox{yellow!50}{\textbf{Nouveau 2.1}}
+
+Pour utiliser cette technique, il convient d'abord de spécifier le format des marqueurs marquant le début et la fin
+de la partie du fichier à inclure. Cela se fait avec les deux clés \Definition{marker/beginning} et
+\Definition{marker/end} (usuellement dans la commande |\PitonOptions|). 
+
+\medskip
+Prenons d'abord un exemple.
+
+\medskip
+Supposons que le fichier à inclure contienne des solutions à des exercices de programmation sur le modèle suivant :  
+
+\begin{Verbatim}[formatcom=\small\color{gray}]
+~#[Exercice 1] Version itérative
+def fibo(n):
+    if n==0: return 0 
+    else:
+        u=0
+        v=1
+        for i in range(n-1):
+            w = u+v
+            u = v
+            v = w
+        return v
+~#<Exercice 1>
+\end{Verbatim}
+
+Les marqueurs de début de début et de fin sont les chaînes |#[Exercice 1]| et |#<Exercice 1>|. La chaîne
+«|Exercice 1|» sera appelée le \emph{label} de l'exercice (ou de la partie du fichier à inclure).
+
+Pour spécifier des marqueurs de cette sorte dans \pkg{piton}, on utilisera les clés |marker/beginning| et |marker/end|
+de la manière suivante (le caractère |#| des commentaires de Python doit être inséré sous la forme échappée |\#|). 
+
+\begin{Verbatim}
+\PitonOptions{ ~emphase#marker/beginning@ = \~#[~#1] , ~emphase#marker/end@ = \~#<~#1> } 
+\end{Verbatim}
+
+Comme on le voit, |marker/beginning| est une expression correspondant à la fonction mathématique qui, au nom du
+label (par exemple |Exercice 1|), associe le marqueur de début (dans l'exemple |#[Exercice 1]|). La chaîne |#1|
+correspond aux occurrences de l'argument de cette fonction (c'est la syntaxe habituelle de TeX). De même pour
+|marker/end|.
+
+
+\bigskip
+Pour insérer une partie marquée d'un fichier, il suffit alors d'utiliser la clé \Definition{range} de
+|\PitonInputFile|. 
+
+\smallskip
+\begin{Verbatim}
+\PitonInputFile[~emphase#range = Exercice 1@]{~textsl#nom_du_fichier@}
+\end{Verbatim}
+
+\medskip
+\begin{Piton}
+def fibo(n):
+    if n==0: return 0 
+    else:
+        u=0
+        v=1
+        for i in range(n-1):
+            w = u+v
+            u = v
+            v = w
+        return v
+\end{Piton}
+
+\vspace{1cm}
+La clé \Definition{marker/include-line} demande que les lignes contenant les marqueurs soient également insérées.
+
+\begin{Verbatim}
+\PitonInputFile[~emphase#marker/include-lines@,range = Exercice 1]{~textsl#nom_du_fichier@}
+\end{Verbatim}
+
+\begin{Piton}
+#[Exercice 1] Version itérative
+def fibo(n):
+    if n==0: return 0 
+    else:
+        u=0
+        v=1
+        for i in range(n-1):
+            w = u+v
+            u = v
+            v = w
+        return v
+#<Exercice 1>
+\end{Piton}
+
+
+\bigskip
+Il existe en fait aussi les clés \Definition{begin-range} et \Definition{end-range} pour insérer plusieurs
+contenus marqués simultanément. 
+
+Par exemple, pour insérer les solutions des exercices 3 à 5, on pourra écrire (à condition que le fichier soit
+structuré correctement!):
+
+\begin{Verbatim}
+\PitonInputFile[~emphase#begin-range = Exercice 3, end-range = Exercice 5@]{~textsl#nom_du_fichier@}
+\end{Verbatim}
+
+
+
+
 \subsection{Mise en évidence d'identificateurs}
 
 On peut demander le changement de formatage de certains identificateurs avec la clé |identifiers| de
@@ -731,12 +989,12 @@
 
 \begin{itemize}
 \item Il est possible de changer le marquage syntaxique utilisé (qui vaut initialement~|#>|). Pour ce faire, il
-existe une clé |comment-latex|, disponible seulement au chargement de \pkg{piton} (c'est-à-dire au moment du
-|\usepackage|), qui permet de choisir les caractères qui (précédés par~|#|) serviront de marqueur syntaxique.
+existe une clé |comment-latex|, disponible uniquement dans le préambule du document, qui permet de choisir les
+caractères qui (précédés par~|#|) serviront de marqueur syntaxique.
 
-Par exemple, avec le chargement suivant :
+Par exemple, avec le réglage suivant (fait dans le préambule du document) :
 
-\quad \verb|\usepackage[comment-latex = LaTeX]{piton}|
+\verb|\PitonOptions{comment-latex = LaTeX}|
 
 les commentaires LaTeX commenceront par~|#LaTeX|.
 
@@ -763,11 +1021,11 @@
 
 
 \bigskip 
-Si l'utilisateur a demandé l'affichage des numéros de ligne avec |line-numbers| ou |all-line-numbers|, il est
-possible de faire référence à ce numéro de ligne avec la commande |\label| placée dans un commentaire
-LaTeX.\footnote{Cette fonctionnalité est implémentée en redéfinissant, dans les environnements |{Piton}|, la
-  commande |\label|. Il peut donc y avoir des incompatibilités avec les extensions qui redéfinissent (globalement)
-  cette commande |\label| (comme \pkg{varioref}, \pkg{refcheck}, \pkg{showlabels}, etc.)}
+Si l'utilisateur a demandé l'affichage des numéros de ligne avec |line-numbers|, il est possible de faire référence
+à ce numéro de ligne avec la commande |\label| placée dans un commentaire LaTeX.\footnote{Cette fonctionnalité est
+  implémentée en redéfinissant, dans les environnements |{Piton}|, la commande |\label|. Il peut donc y avoir des
+  incompatibilités avec les extensions qui redéfinissent (globalement) cette commande |\label| (comme
+  \pkg{varioref}, \pkg{refcheck}, \pkg{showlabels}, etc.)}
 
 
 
@@ -778,11 +1036,11 @@
 |#>|), les éléments placés entre symboles \texttt{\$} soient composés en mode mathématique de LaTeX (le reste du
 commentaire restant composé en verbatim).
 
-La clé |math-comments|, qui n'est disponible qu'au chargement de \pkg{piton} (c'est-à-dire au moment du
-|\usepackage|), active ce comportement.
+La clé \Definition{math-comments} (qui ne peut être activée que dans le préambule du document) active ce
+comportement.
 
 \bigskip
-Dans l'exemple suivant, on suppose que la clé |math-comments| a été utilisée au chargement de \pkg{piton}.
+Dans l'exemple suivant, on suppose que |\PitonOptions{math-comments}| a été utilisé dans le préambule du document.
 
 \begin{Verbatim}
 \begin{Piton}
@@ -797,20 +1055,20 @@
 \end{Piton}
 
 
-\subsubsection{Le mécanisme «espace-inside»}
+\subsubsection{Le mécanisme «escape»}
 
 Il est aussi possible de surcharger les listings Python pour y insérer du code LaTeX à peu près n'importe où (mais
 entre deux lexèmes, bien entendu). Cette fonctionnalité n'est pas activée par défaut par \pkg{piton}. Pour
-l'utiliser, il faut spécifier les deux caractères marquant l'échappement (le premier le commençant et le deuxième
-le terminant) en utilisant la clé |escape-inside| au chargement de \pkg{piton} (c'est-à-dire au moment du
-|\usepackage|). Les deux caractères peuvent être identiques.
+l'utiliser, il faut spécifier les deux délimiteurs marquant l'échappement (le premier le commençant et le deuxième
+le terminant) en utilisant les clés \Definition{begin-escape} et \Definition{end-escape} (qui ne sont accessibles
+que dans le préambule du document). Les deux délimiteurs peuvent être identiques.
 
 
 \bigskip
-Dans l'exemple suivant, on suppose que l'extension \pkg{piton} a été chargée de la manière suivante :
+Dans l'exemple suivant, on suppose que le préambule du document contient l'instruction :
 
 \begin{Verbatim}
-\usepackage[~emphase#escape-inside=$$@]{piton}
+\PitonOptions{~emphase#begin-escape=!,end-escape=!@}
 \end{Verbatim}
 
 \medskip
@@ -823,7 +1081,7 @@
     if n==0:
         return 1
     else:
-        ~emphase#$\highLight{$@return n*fact(n-1)~emphase#$}$@
+        ~emphase#!\highLight{!@return n*fact(n-1)~emphase#!}!@
 \end{Piton}
 \end{Verbatim}
 
@@ -832,7 +1090,7 @@
     if n==0:
         return 1
     else:
-        $\highLight{$return n*fact(n-1)$}$
+        !\highLight{!return n*fact(n-1)!}!
 \end{Piton}
 
 \bigskip
@@ -856,7 +1114,7 @@
     if n==0:
         return 1
     else:
-        ~emphase#$\Jaune$@return n*fact(n-1)
+        ~emphase#!\Jaune!@return n*fact(n-1)
 \end{Piton}
 \end{Verbatim}
 
@@ -870,20 +1128,80 @@
     if n==0:
         return 1
     else:
-        $\Jaune$return n*fact(n-1)
+        !\Jaune!return n*fact(n-1)
 \end{Piton}
 
 
 
 \bigskip
-\emph{Attention} : L'échappement vers LaTeX permis par les caractères de |escape-inside| n'est pas actif dans les
-chaînes de caractères ni dans les commentaires (pour avoir un commentaire entièrement en échappement vers LaTeX,
-c'est-à-dire ce qui est 
-appelé dans ce document «commentaire LaTeX», il suffit de le faire débuter par |#>|).
+\emph{Attention} : L'échappement vers LaTeX permis par les clés |begin-escape| et |end-escape| n'est pas actif dans
+les chaînes de caractères ni dans les commentaires (pour avoir un commentaire entièrement en échappement vers
+LaTeX, c'est-à-dire ce qui est appelé dans ce document «commentaire LaTeX», il suffit de le faire débuter par
+|#>|).
 
 
+\subsubsection{Le mécanisme «escape-math»}
 
+Le mécanisme «|escape-math|» est très similaire au mécanisme «|escape|» puisque la seule différence est que les
+éléments en échappement LaTeX y sont composés en mode mathématique.
 
+On active ce mécanisme avec les clés \Definition{begin-escape-math} et \Definition{end-escape-math} (qui ne sont
+accessibles que dans le préambule du document).
+
+\medskip
+Malgré la proximité technique, les usages du mécanisme «|escape-math|» sont en fait assez différents de ceux du
+mécanisme «|escape|». En effet, comme le contenu en échappement est composé en mode mathématique, il est en
+particulier composé dans un groupe TeX et ne pourra donc pas servir à changer le formatage d'autres unités lexicales.
+
+\medskip
+Dans les langages où le caractère \verb|$| ne joue pas un rôle syntaxique important, on peut assez naturellement
+vouloir activer le mécanisme «|escape-math|» avec le caractère \verb|$|:
+\begin{Verbatim}
+\PitonOptions{~emphase#begin-escape-math=$,end-escape-math=$@}
+\end{Verbatim}
+Remarquer que le caractère \verb|$| ne doit \emph{pas} être protégé par une contre-oblique.
+
+\bigskip
+Néanmoins, il est sans doute plus prudent d'utiliser |\(| et |\)|.
+\begin{Verbatim}
+\PitonOptions{~emphase#begin-escape-math=\(,end-escape-math=\)@}
+\end{Verbatim}
+
+\bigskip
+Voici un exemple d'utilisation typique :
+
+\medskip
+\begin{Verbatim}
+\begin{Piton}[line-numbers]
+def arctan(x,n=10):
+    if ~emphase#\(x < 0\)@ :
+        return ~emphase#\(-\arctan(-x)\)@ 
+    elif ~emphase#\(x > 1\)@ : 
+        return ~emphase#\(\pi/2 - \arctan(1/x)\)@ 
+    else: 
+        s = ~emphase#\(0\)@
+        for ~emphase#\(k\)@ in range(~emphase#\(n\)@): s += ~emphase#\(\smash{\frac{(-1)^k}{2k+1} x^{2k+1}}\)@
+        return s
+\end{Piton}
+\end{Verbatim}
+
+
+\bigskip
+
+\begin{Piton}[line-numbers]
+def arctan(x,n=10):
+    if \(x < 0\) :
+        return \(-\arctan(-x)\) 
+    elif \(x > 1\) : 
+        return \(\pi/2 - \arctan(1/x)\) 
+    else: 
+        s = \(0\)
+        for \(k\) in range(\(n\)): s += \(\smash{\frac{(-1)^k}{2k+1} x^{2k+1}}\)
+        return s
+\end{Piton}
+
+
+
 \subsection{Comportement dans la classe Beamer}
 
 \label{beamer}
@@ -898,9 +1216,10 @@
 
 \medskip
 Quand l'extension \pkg{piton} est utilisée dans la classe \cls{beamer}\footnote{L'extension \pkg{piton} détecte la
-  classe \cls{beamer} mais il est aussi possible, si le besoin s'en faisait sentir, d'activer ce comportement avec
-  la clé |beamer| au chargement de \pkg{piton} : |\usepackage[beamer]{piton}|}, le comportement de \pkg{piton} est
-légèrement modifié, comme décrit maintenant.
+  classe \cls{beamer} et l'extension \pkg{beamerarticle} si elle est chargée précédemment, mais il est aussi
+  possible, si le besoin s'en faisait sentir, d'activer ce comportement avec la clé |beamer| au chargement de
+  \pkg{piton} : |\usepackage[beamer]{piton}|}, le comportement de \pkg{piton} est légèrement modifié, comme décrit
+maintenant.
 
 \subsubsection{\{Piton\} et \textbackslash PitonInputFile sont ``overlay-aware''}
 
@@ -933,7 +1252,7 @@
   dans un «commentaire LaTeX», c'est-à-dire en écrivant |#> \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| ;
-\item deux arguments obligatoire : |\alt| ; 
+\item deux arguments obligatoires : |\alt| ; 
 \item trois arguments obligatoires : |\temporal|.
 \end{itemize}
 
@@ -1043,97 +1362,9 @@
 
 
 \bigskip
-\subsection{Coupure des pages et des lignes}
 
-\label{breakable}
 
-\subsubsection{Coupure des pages}
-
-Par défaut les listings produits par l'environnement |{Piton}| et par la commande |\PitonInputFile| sont
-insécables.
-
-Néanmoins, la commande |\PitonOptions| propose la clé \Definition{splittable} pour autoriser de telles coupures.
-
-\begin{itemize}
-\item Si la clé |splittable| est utilisée sans valeur, les listings sont sécables n'importe où.
-
-\item Si la clé |splittable| est utilisée avec une valeur numérique $n$ (qui doit être un entier naturel non nul),
-alors les listings seront sécables mais aucune coupure ne pourra avoir lieu entre les $n$~premières lignes, ni
-entre les $n$~dernières. De ce fait, |splittable=1| est équivalent à |splittable|.
-\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ù la clé |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|.}
-
-\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 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 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 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 Avec la clé \Definition{indent-broken-lines}, l'indentation de la ligne coupée est respectée à chaque retour
-à la ligne. 
-
-\item 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 La clé \Definition{continuation-symbol} correspond au symbole placé à chaque retour de ligne dans la marge
-gauche. Sa valeur initiale est : |+\;|.
-
-\item 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{Notes de pied de page dans les environnements de piton}
 
 \label{footnote}
@@ -1186,7 +1417,7 @@
 
 \label{example-numbering}
 
-On rappelle que l'on peut demander la numérotation des lignes des listings avec la clé |line-numbers| ou la clé |all-line-numbers|.
+On rappelle que l'on peut demander la numérotation des lignes des listings avec la clé |line-numbers|.
 
 Par défaut, les numéros de ligne sont composés par \pkg{piton} en débordement à gauche (en utilisant en interne la commande |\llap| de LaTeX).
 

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	2023-08-26 20:18:37 UTC (rev 68074)
+++ trunk/Master/texmf-dist/source/lualatex/piton/piton.dtx	2023-08-26 20:18:56 UTC (rev 68075)
@@ -1,4 +1,4 @@
-% \iffalse -*- coding: utf-8 ; -*- \fi \iffalse meta-comment
+%  \iffalse -*- coding: utf-8 ; -*- \fi \iffalse meta-comment
 %
 % Copyright (C) 2023 by F. Pantigny
 % -----------------------------------
@@ -15,10 +15,7 @@
 %
 % \fi
 % \iffalse
-\def\myfileversion{2.0}
-\def\myfiledate{2023/08/01}
-%
-%
+% 
 %<*batchfile> 
 \begingroup
 \input l3docstrip.tex
@@ -45,7 +42,13 @@
 %</batchfile>
 %
 %<@@=piton>
+%<*STY>
+\def\myfileversion{2.1}
+\def\myfiledate{2023/08/26}
+%</STY>
 %<*driver>
+\def\myfileversion{2.1}
+\def\myfiledate{2023/08/26}
 \documentclass{l3doc}
 \usepackage{geometry}
 \geometry{left=2.8cm,right=2.8cm,top=2.5cm,bottom=2.5cm,papersize={21cm,29.7cm}}
@@ -56,7 +59,16 @@
 \fvset{commandchars=\~\#\@,formatcom=\color{gray}}
 \captionsetup{labelfont = bf}
 \usepackage{ragged2e}
-\usepackage[footnotehyper,escape-inside=$$,math-comments]{piton} % $$
+\usepackage[footnotehyper]{piton} 
+\PitonOptions
+  { 
+    splittable = 4 ,
+    math-comments,
+    begin-escape = ! ,
+    end-escape = ! ,
+    begin-escape-math = \( , 
+    end-escape-math = \) 
+  }
 
 \parindent 0pt
 \skip\footins = 2\bigskipamount
@@ -68,6 +80,7 @@
 \EnableCrossrefs
 
 \begin{document}
+
 \DocInput{piton.dtx}
 \end{document}
 %</driver>
@@ -128,17 +141,17 @@
 %         return s 
 %    \end{Piton}
 % 
-%
-% \bigskip
-% The package \pkg{piton} is entirely contained in the file
-% |piton.sty|. This file may be put in the current directory or in a
-% |texmf| tree. However, the best is to install \pkg{piton} with a TeX
-% distribution such as MiKTeX, TeX Live or MacTeX.
 % 
+% \section{Installation}
 % 
+% The package \pkg{piton} is contained in two files: |piton.sty| and |piton.lua|
+% (the LaTeX file |piton.sty| loaded by |\usepackage| will load the Lua file
+% |piton.lua|). Both files must be in a repertory where LaTeX will be able to
+% find them, for instance in a |texmf| tree. However, the best is to install
+% \pkg{piton} with a TeX distribution such as MiKTeX, TeX Live or MacTeX.
+% 
 % \section{Use of the package}
 %
-%
 % \subsection{Loading the package}
 % 
 % The package \pkg{piton} should be loaded with the classical command
@@ -193,11 +206,10 @@
 % cf.~\ref{NewPitonEnvironment} p.~\pageref{NewPitonEnvironment}.
 %
 % \item The command \colorbox{gray!20}{\ttfamily\textbackslash PitonInputFile}
-% is used to insert and typeset a whole external file.
+% is used to insert and typeset a external file.
 %
-% That command takes in as optional argument (between square brackets) two keys
-% |first-line| and |last-line|: only the part between the corresponding lines
-% will be inserted.
+% It's possible to insert only a part of the file: cf.
+% part~\ref{part-of-a-file}, p.~\pageref{part-of-a-file}. 
 % \end{itemize}
 %
 % \subsection{The syntax of the command \textbackslash piton}
@@ -327,32 +339,63 @@
 % gobble is set by the position of the commands |\begin{Piton}| and
 % |\end{Piton}| which delimit the current environment.
 %
-% \item With the key \Definition{line-numbers}, the \emph{non empty} lines (and
-% all the lines of the \emph{docstrings}, even the empty ones) are numbered in
-% the environments |{Piton}| and in the listings resulting from the use of
+% \item The key \Definition{line-numbers} activates the line numbering. in the
+% environments |{Piton}| and in the listings resulting from the use of
 % |\PitonInputFile|.
 % 
-% \item With the key \Definition{all-line-numbers}, \emph{all} the lines are numbered,
-% including the empty ones.
+% \colorbox{yellow!50}{\textbf{New 2.1}}\enskip In fact, the key |line-numbers| has
+% several subkeys.
+% \begin{itemize}
+% \item With the key \Definition{line-numbers/skip-empty-lines}, the empty lines
+% are considered as non existent for the line numbering (if the key |/absolute|
+% is in force, the key |/skip-empty-lines| is no-op in |\PitonInputFile|). The
+% initial value of that key is |true| (and not |false|).\footnote{For the
+% language Python, the empty lines in the docstrings are taken into account (by
+% design).}
+% \item With the key \Definition{line-numbers/label-empty-lines}, the labels
+% (that is to say the numbers) of the empty lines are displayed. If the key
+% |/skip-empty-line| is in force, the clé |/label-empty-lines| is no-op. The
+% initial value of that key is~|true|.
+% \item With the key \Definition{line-numbers/absolute}, in the listings
+% generated in |\PitonInputFile|, the numbers of the lines displayed are
+% \emph{absolute} (that is to say: they are the numbers of the lines in the
+% file). That key may be useful when |\PitonInputFile| is used to insert only a
+% part of the file (cf. part~\ref{part-of-a-file}, p.~\pageref{part-of-a-file}).
+% The key |/absolute| is no-op in the environments |{Piton}|.
+% \item The key \Definition{line-numbers/start} requires that the line numbering
+% begins to the value of the key. That key is not available in |\PitonOptions|.
+% \item With the key \Definition{line-numbers/resume}, the counter of lines is
+% not set to zero at the beginning of each environment |{Piton}| or use of
+% |\PitonInputFile| as it is otherwise. That allows a numbering of the lines
+% across several environments.
+% \item The key \Definition{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.
+% \end{itemize}
 %
-% \item The key \Definition{numbers-sep} is the horizontal distance between the
-% numbers of lines (inserted by |line-numbers| of |all-line-numbers|) and the
-% beginning of the lines of code. The initial value is 0.7~em.
+% For convenience, a mechanism of factorisation of the prefix |line-numbers| is
+% provided. That means that it is possible, for instance, to write:
+% \begin{Verbatim}
+% \PitonOptions
+%   {
+%     line-numbers = 
+%       { 
+%         skip-empty-lines = false ,
+%         label-empty-lines = false ,
+%         sep = 1 em
+%       }
+%   }
+% \end{Verbatim}
 %
-% \item With the key \Definition{resume}, the counter of lines is not set to zero
-% at the beginning of each environment |{Piton}| or use of |\PitonInputFile| as
-% it is otherwise. That allows a numbering of the lines across several
-% environments.
 %
 % \item The key \Definition{left-margin} corresponds to a margin on the left.
-% That key may be useful in conjonction with the key |line-numbers| or the key
-% |line-all-numbers| if one does not want the numbers in an overlapping position
-% on the left.
+% That key may be useful in conjonction with the key |line-numbers| if one does
+% not want the numbers in an overlapping position on the left.
 %
 % It's possible to use the key |left-margin| with the value |auto|. With that
-% value, if the key |line-numbers| or the key |all-line-numbers| is used, a
-% margin will be automatically inserted to fit the numbers of lines. See an
-% example part \ref{example-numbering} on page~\pageref{example-numbering}.
+% value, if the key |line-numbers| is in force, a margin will be automatically
+% inserted to fit the numbers of lines. See an example part
+% \ref{example-numbering} on page~\pageref{example-numbering}.
 %
 % \item The key \Definition{background-color} sets the background color of the
 % environments |{Piton}| and the listings produced by |\PitonInputFile| (it's
@@ -374,8 +417,8 @@
 % continuation ``|...|'') characteristic of the Python consoles with
 % \textsc{repl} (\emph{read-eval-print loop}).
 %
-% \item The key |width| will fix the width of the listing. That width applies to
-% the colored backgrounds specified by |background-color| and
+% \item The key \Definition{width} will fix the width of the listing. That width
+% applies to the colored backgrounds specified by |background-color| and
 % |prompt-background-color| but also for the automatic breaking of the lines
 % (when required by |break-lines|: cf.~\ref{line-breaks},
 % p.~\pageref{line-breaks}).
@@ -627,6 +670,240 @@
 %
 % \section{Advanced features}
 %
+% \subsection{Page breaks and line breaks}
+%
+% \label{breakable}
+%
+% \subsubsection{Page breaks}
+%
+% By default, the listings produced by the environment |{Piton}| and the command
+% |\PitonInputFile| are not breakable.
+%
+% However, the command |\PitonOptions| provides the key \Definition{splittable}
+% to allow such breaks.
+%
+% \begin{itemize}
+% \item If the key |splittable| is used without any value, the
+% listings are breakable everywhere.
+% \item If the key |splittable| is used with a numeric value~$n$ (which must be
+% a non-negative integer number), the listings are breakable but no break will
+% occur within the first $n$ lines and within the last $n$ lines. Therefore,
+% |splittable=1| is equivalent to |splittable|.
+% \end{itemize}
+%
+% \medskip
+% Even with a background color (set by the key |background-color|), the pages
+% breaks are allowed, as soon as the key |splittable| is in force.\footnote{With
+% the key |splittable|, the environments \texttt{\{Piton\}} are breakable, even
+% within a (breakable) environment of \pkg{tcolorbox}. Remind that an
+% environment of \pkg{tcolorbox} included in another environment of
+% \pkg{tcolorbox} is \emph{not} breakable, even when both environments use the
+% key |breakable| of \pkg{tcolorbox}.}
+% 
+% \subsubsection{Line breaks}
+% 
+% \label{line-breaks}
+% 
+% By default, the elements produced by \pkg{piton} can't be broken by an end on
+% line. However, there are keys to allow such breaks (the possible breaking
+% points are the spaces, even the spaces in the Python strings).
+% \begin{itemize}
+% \item With the key \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 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 The key \Definition{break-lines} is a conjonction of the two previous keys.
+% \end{itemize}
+% 
+% \bigskip 
+% The package \pkg{piton} provides also several keys to control the appearance
+% on the line breaks allowed by |break-lines-in-Piton|.
+%
+% \begin{itemize}
+% \item With the key \Definition{indent-broken-lines}, the indentation of a
+% broken line is respected at carriage return.
+%
+% \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 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 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}
+%
+%
+% \bigskip
+% \subsection{Insertion of a part of a file}
+%
+% \label{part-of-a-file}
+%
+% The command |\PitonInputFile| inserts (with formating) the content of a file.
+% In fact, it's possible to insert only \emph{a part} of that file. Two
+% mechanisms are provided in this aim.
+% \begin{itemize}
+% \item It's possible to specify the part that we want to insert by the numbers
+% of the lines (in the original file).
+% \item \colorbox{yellow!50}{\textbf{New 2.1}}\enskip It's also possible to
+% specify the part to insert with textual markers.
+% \end{itemize}
+% 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}
+%
+% The command |\PitonInputFile| supports the keys \Definition{first-line} and
+% \Definition{last-line} in order to insert only the part of file between the
+% corresponding lines. Not to be confused with the key |line-numbers/start|
+% which fixes the first line number for the line numbering. In a sens,
+% |line-numbers/start| deals with the output whereas |first-line| and
+% |last-line| deal with the input.
+%
+% \subsubsection{With textual markers}
+%
+% \colorbox{yellow!50}{\textbf{New 2.1}}
+%
+% In order to use that feature, we first have to specify the format of the
+% markers (for the beginning and the end of the part to include) with the keys
+% \Definition{marker-beginning} and \Definition{marker-end} (usually with the
+% command |\PitonOptions|). 
+%
+%
+% \medskip
+% Let us take a practical example.
+%
+% \medskip
+% We assume that the file to include contains solutions to exercises of
+% programmation on the following model.
+%
+% \begin{Verbatim}[formatcom=\small\color{gray}]
+% ~#[Exercise 1] Iterative version
+% def fibo(n):
+%     if n==0: return 0 
+%     else:
+%         u=0
+%         v=1
+%         for i in range(n-1):
+%             w = u+v
+%             u = v
+%             v = w
+%         return v
+% ~#<Exercise 1>
+% \end{Verbatim}
+%
+% The markers of the beginning and the end are the strings |#[Exercise 1]| and
+% |#<Exercise 1>|. The string ``|Exercise 1|'' will be called the \emph{label}
+% of the exercise (or of the part of the file to be included).
+%
+% In order to specify such markers in \pkg{piton}, we will use the keys
+% |marker/beginning| and |marker/end| with the following instruction (the
+% character |#| of the comments of Python must be inserted with the protected
+% form |\#|). 
+%
+% \begin{Verbatim}
+% \PitonOptions{ ~emphase#marker/beginning@ = \~#[~#1] , ~emphase#marker/end@ = \~#<~#1> } 
+% \end{Verbatim}
+%
+% As one can see, |marker/beginning| is an expression corresponding to the
+% mathematical function which transforms the label (here |Exercise 1|) into the
+% the beginning marker (in the example |#[Exercise 1]|). The string |#1|
+% corresponds to the occurrences of the argument of that function, which the
+% classical syntax in TeX. Idem for |marker/end|.
+%
+% \bigskip 
+% Now, you only have to use the key \Definition{range} of |\PitonInputFile| to
+% insert a marked content of the file.
+%
+% \smallskip
+% \begin{Verbatim}
+% \PitonInputFile[~emphase#range = Exercise 1@]{~textsl#file_name@}
+% \end{Verbatim}
+%
+% \medskip
+% \begin{Piton}
+% def fibo(n):
+%     if n==0: return 0 
+%     else:
+%         u=0
+%         v=1
+%         for i in range(n-1):
+%             w = u+v
+%             u = v
+%             v = w
+%         return v
+% \end{Piton}
+%
+% \vspace{1cm}
+% The key \Definition{marker/include-line} requires the insertion of the lines
+% containing the markers.
+%
+% \begin{Verbatim}
+% \PitonInputFile[~emphase#marker/include-lines@,range = Exercise 1]{~textsl#file_name@}
+% \end{Verbatim}
+%
+% \begin{Piton}
+% #[Exercise 1] Iterative version
+% def fibo(n):
+%     if n==0: return 0 
+%     else:
+%         u=0
+%         v=1
+%         for i in range(n-1):
+%             w = u+v
+%             u = v
+%             v = w
+%         return v
+% #<Exercise 1>
+% \end{Piton}
+%
+%
+% \bigskip
+% In fact, there exist also the keys \Definition{begin-range} and
+% \Definition{end-range} to insert several marked contents at the same time.
+%
+% For example, in order to insert the solutions of the exercises~3 to~5, we will
+% write (if the file has the correct structure!):
+%
+%
+% \begin{Verbatim}
+% \PitonInputFile[~emphase#begin-range = Exercise 3, end-range = Exercise 5@]{~textsl#file_name@}
+% \end{Verbatim}
+%
+%
+%
 % \subsection{Highlighting some identifiers}
 %
 % It's possible to require a changement of formating for some identifiers with
@@ -639,17 +916,17 @@
 % instructions}| }|
 %
 % \begin{itemize}
-% \item \textsl{\ttfamily names} is a (comma-separated) list of identifiers
+% \item \textsl{\ttfamily names} is a (comma-separated) list of identifier
 % names; 
 %
 % \item \textsl{\ttfamily instructions} is a list of LaTeX instructions of the
-% same type that \pkg{piton} ``styles'' previously presented (cf~\ref{styles}
+% same type as \pkg{piton} ``styles'' previously presented (cf~\ref{styles}
 % p.~\pageref{styles}). 
 % \end{itemize}
 %
 % \emph{Caution}: Only the identifiers may be concerned by that key. The
 % keywords and the built-in functions won't be affected, even if their name is
-% in the list |\textsl{\ttfamily names}|.
+% in the list \textsl{\ttfamily names}.
 % 
 % \begin{Verbatim}
 % \PitonOptions 
@@ -772,13 +1049,13 @@
 %
 % \begin{itemize}
 % \item It's possible to change the syntatic mark (which, by default, is |#>|).
-% For this purpose, there is a key |comment-latex| available at load-time (that
-% is to say at the |\usepackage|) which allows to choice the characters which,
+% For this purpose, there is a key |comment-latex| available only in the
+% preamble of the document, allows to choice the characters which,
 % preceded by |#|, will be the syntatic marker.
 %
-% For example, with the following loading:
+% For example, if the preamble contains the following instruction:
 % 
-% \quad \verb|\usepackage[comment-latex = LaTeX]{piton}|
+% \quad \verb|\PitonOptions{comment-latex = LaTeX}|
 %
 % the LaTeX comments will begin by |#LaTeX|.
 %
@@ -804,8 +1081,7 @@
 % \end{itemize}
 %
 % \bigskip
-% If the user has required line numbers in the left margin (with the
-% key |line-numbers| or the key |all-line-numbers| of |\PitonOptions|), it's
+% If the user has required line numbers (with the key |line-numbers|), it's
 % possible to refer to a number of line with the command |\label| used in a
 % LaTeX comment.\footnote{That feature is implemented by using a redefinition of
 % the standard command \texttt{\textbackslash label} in the environments
@@ -820,13 +1096,13 @@
 % composed in LaTeX mathematical mode (the other elements of the comment being
 % composed verbatim).
 %
-% That feature is activated by the key |math-comments| at load-time (that is to
-% say with the |\usepackage|).
+% That feature is activated by the key \Definition{math-comments}, which is
+% available only in the preamble of the document.
 %
 % \medskip
-% In the following example, we assume that the key |math-comments| has been used
-% when loading \pkg{piton}.
-%
+% Here is a example, where we have assumed that the preamble of the document
+% contains the instruction |\PitonOptions{math-comment}|:
+% 
 % \begin{Verbatim}
 % \begin{Piton}
 % def square(x):
@@ -839,23 +1115,23 @@
 %     return x*x # compute $x^2$
 % \end{Piton}
 % 
-% \subsubsection{The mechanism ``escape-inside''}
+% \subsubsection{The mechanism ``escape''}
 %
 % It's also possible to overwrite the Python listings to insert LaTeX code
 % almost everywhere (but between lexical units, of course). By default,
-% \pkg{piton} does not fix any character for that kind of escape.
+% \pkg{piton} does not fix any delimiters for that kind of escape.
 %
-% In order to use this mechanism, it's necessary to specify two characters which
+% In order to use this mechanism, it's necessary to specify the delimiters which
 % will delimit the escape (one for the beginning and one for the end) by using
-% the key |escape-inside| at load-time (that is to say at the
-% |\begin{docuemnt}|). 
+% the keys \Definition{begin-escape} and \Definition{end-escape}, available only
+% in the preamble of the document.
 %
 % \medskip
-% In the following example, we assume that the extension \pkg{piton} has been
-% loaded by the following instruction.
+% In the following example, we assume that the preamble of the document contains
+% the following instruction:
 %
 % \begin{Verbatim}
-% \usepackage[~emphase#escape-inside=$$@]{piton}
+% \PitonOptions{~emphase#begin-escape=!,end-escape=!@}
 % \end{Verbatim}
 %
 % \medskip
@@ -869,7 +1145,7 @@
 %     if n==0:
 %         return 1
 %     else:
-%         ~emphase#$\highLight{$@return n*fact(n-1)~emphase#$}$@
+%         ~emphase#!\highLight{!@return n*fact(n-1)~emphase#!}!@
 % \end{Piton}
 % \end{Verbatim}
 %
@@ -878,7 +1154,7 @@
 %     if n==0:
 %         return 1
 %     else:
-%         $\highLight{$return n*fact(n-1)$}$
+%         !\highLight{!return n*fact(n-1)!}!
 %    \end{Piton}
 %         
 % \bigskip
@@ -902,7 +1178,7 @@
 %     if n==0:
 %         return 1
 %     else:
-%         ~emphase#$\Yellow$@return n*fact(n-1)
+%         ~emphase#!\Yellow!@return n*fact(n-1)
 % \end{Piton}
 % \end{Verbatim}
 %
@@ -916,19 +1192,83 @@
 %     if n==0:
 %         return 1
 %     else:
-%         $\Yellow$return n*fact(n-1)
+%         !\Yellow!return n*fact(n-1)
 % \end{Piton}
 %
 %
 %
 % \bigskip
-% \emph{Caution} : The escape to LaTeX allowed by the characters of
-% |escape-inside| is not active in the strings nor in the Python comments
-% (however, it's possible to have a whole Python comment composed in LaTeX by
-% beginning it with |#>|; such comments are merely called ``LaTeX comments'' in
-% this document). 
+% \emph{Caution} : The escape to LaTeX allowed by the |begin-escape| and
+% |end-escape| is not active in the strings nor in the Python comments (however,
+% it's possible to have a whole Python comment composed in LaTeX by beginning it
+% with |#>|; such comments are merely called ``LaTeX comments'' in this
+% document).
 % 
 %
+% \subsubsection{The mechanism ``escape-math''}
+% 
+% The mechanism ``|escape-math|'' is very similar to the mechanism ``|escape|''
+% since the only difference is that the elements sent to LaTeX are composed in
+% the math mode of LaTeX.
+%
+% This mechanism is activated with the keys \Definition{begin-escape-math} and
+% \Definition{end-escape-math} (which are available only in the preamble of the
+% document). 
+%
+% Despite the technical similarity, the use of the the mechanism
+% ``|escape-math|'' is in fact rather different from that of the mechanism
+% ``|escape|''. Indeed, since the elements are composed in a mathématical mode
+% of LaTeX, they are, in particular, composed within a TeX group and therefore,
+% they can't be used to change the formatting of other lexical units.
+%
+% In the langages where the character \verb|$| does not play a important role,
+% it's possible to activate that mechanism ``|escape-math|'' with the character
+% \verb|$|:
+% \begin{Verbatim}
+% \PitonOptions{~emphase#begin-escape-math=$,end-escape-math=$@}
+% \end{Verbatim}
+% Remark that the character \verb|$| must \emph{not} be protected by a backslash.
+%
+% \bigskip
+% However, it's probably more prudent to use |\(| et |\)|.
+% \begin{Verbatim}
+% \PitonOptions{~emphase#begin-escape-math=\(,end-escape-math=\)@}
+% \end{Verbatim}
+% 
+% \bigskip
+% Here is an example of utilisation.
+%
+% \medskip
+% \begin{Verbatim}
+% \begin{Piton}[line-numbers]
+% def arctan(x,n=10):
+%     if ~emphase#\(x < 0\)@ :
+%         return ~emphase#\(-\arctan(-x)\)@ 
+%     elif ~emphase#\(x > 1\)@ : 
+%         return ~emphase#\(\pi/2 - \arctan(1/x)\)@ 
+%     else: 
+%         s = ~emphase#\(0\)@
+%         for ~emphase#\(k\)@ in range(~emphase#\(n\)@): s += ~emphase#\(\smash{\frac{(-1)^k}{2k+1} x^{2k+1}}\)@
+%         return s
+% \end{Piton}
+% \end{Verbatim}
+%
+%
+% \bigskip
+%
+% \begin{Piton}[line-numbers]
+% def arctan(x,n=10):
+%     if \(x < 0\) :
+%         return \(-\arctan(-x)\) 
+%     elif \(x > 1\) : 
+%         return \(\pi/2 - \arctan(1/x)\) 
+%     else: 
+%         s = \(0\)
+%         for \(k\) in range(\(n\)): s += \(\smash{\frac{(-1)^k}{2k+1} x^{2k+1}}\)
+%         return s
+% \end{Piton}
+% 
+%
 % \subsection{Behaviour in the class Beamer}
 %
 % \label{beamer}
@@ -946,6 +1286,7 @@
 % \bigskip
 % When the package \pkg{piton} is used within the class
 % \cls{beamer}\footnote{The extension \pkg{piton} detects the class \cls{beamer}
+% and the package \pkg{beamerarticle} if it is loaded previously
 % but, if needed, it's also possible to activate that mechanism with the key
 % |beamer| provided by \pkg{piton} at load-time: |\textbackslash
 % usepackage[beamer]\{piton\}|}, the behaviour of \pkg{piton} is slightly
@@ -1095,100 +1436,7 @@
 % environments |{Piton}| (we recall that the command |\alert| relies upon that
 % environment |{alertenv}|).
 %
-% \subsection{Page breaks and line breaks}
-%
-% \label{breakable}
-%
-% \subsubsection{Page breaks}
-%
-% By default, the listings produced by the environment |{Piton}| and the command
-% |\PitonInputFile| are not breakable.
-%
-% However, the command |\PitonOptions| provides the key \Definition{splittable}
-% to allow such breaks.
-%
-% \begin{itemize}
-% \item If the key |splittable| is used without any value, the
-% listings are breakable everywhere.
-% \item If the key |splittable| is used with a numeric value~$n$ (which must be
-% a non-negative integer number), the listings are breakable but no break will
-% occur within the first $n$ lines and within the last $n$ lines. Therefore,
-% |splittable=1| is equivalent to |splittable|.
-% \end{itemize}
-%
-% \medskip
-% Even with a background color (set by the key |background-color|), the pages
-% breaks are allowed, as soon as the key |splittable| is in force.\footnote{With
-% the key |splittable|, the environments \texttt{\{Piton\}} are breakable, even
-% within a (breakable) environment of \pkg{tcolorbox}. Remind that an
-% environment of \pkg{tcolorbox} included in another environment of
-% \pkg{tcolorbox} is \emph{not} breakable, even when both environments use the
-% key |breakable| of \pkg{tcolorbox}.}
 % 
-% \subsubsection{Line breaks}
-% 
-% \label{line-breaks}
-% 
-% By default, the elements produced by \pkg{piton} can't be broken by an end on
-% line. However, there are keys to allow such breaks (the possible breaking
-% points are the spaces, even the spaces in the Python strings).
-% \begin{itemize}
-% \item With the key \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 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 The key \Definition{break-lines} is a conjonction of the two previous keys.
-% \end{itemize}
-% 
-% \bigskip 
-% The package \pkg{piton} provides also several keys to control the appearance
-% on the line breaks allowed by |break-lines-in-Piton|.
-%
-% \begin{itemize}
-% \item With the key \Definition{indent-broken-lines}, the indentation of a
-% broken line is respected at carriage return.
-%
-% \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 key \Definition{continuation-symbol} corresponds to the symbol
-% placed at each carriage return. The initial value is: |+\;|.
-%
-% \item 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}
-% 
 % \subsection{Footnotes in the environments of piton}
 % 
 % \label{footnote}
@@ -1247,7 +1495,7 @@
 % \label{example-numbering}
 %
 % We remind that it's possible to have an automatic numbering of the lines in
-% the Python listings by using the key |line-numbers| or the key |all-line-numbers|.
+% the Python listings by using the key |line-numbers|.
 %
 % By default, the numbers of the lines are composed by \pkg{piton} in an
 % overlapping position on the left (by using internally the command |\llap| of LaTeX).
@@ -1802,7 +2050,7 @@
 %
 % \section{Implementation}
 %
-% % \medskip
+% \medskip
 % The development of the extension \pkg{piton} is done on the following GitHub
 % depot:
 %
@@ -1936,6 +2184,7 @@
 %
 % \subsubsection{Declaration of the package}
 %    \begin{macrocode}
+%<*STY>
 \NeedsTeXFormat{LaTeX2e}
 \RequirePackage{l3keys2e}
 \ProvidesExplPackage
@@ -1947,7 +2196,18 @@
 %
 % \bigskip
 %    \begin{macrocode}
-\msg_new:nnn { piton } { LuaLaTeX~mandatory }
+\cs_new_protected:Npn \@@_error:n { \msg_error:nn { piton } }
+\cs_new_protected:Npn \@@_warning:n { \msg_warning:nn { piton } }
+\cs_new_protected:Npn \@@_error:nn { \msg_error:nnn { piton } }
+\cs_new_protected:Npn \@@_error:nnn { \msg_error:nnnn { piton } }
+\cs_new_protected:Npn \@@_fatal:n { \msg_fatal:nn { piton } }
+\cs_new_protected:Npn \@@_fatal:nn { \msg_fatal:nnn { piton } }
+\cs_new_protected:Npn \@@_msg_new:nn { \msg_new:nnn { piton } }
+%    \end{macrocode}
+%
+% \bigskip
+%    \begin{macrocode}
+\@@_msg_new:nn { LuaLaTeX~mandatory }
   { 
     LuaLaTeX~is~mandatory.\\
     The~package~'piton'~requires~the~engine~LuaLaTeX.\\
@@ -1962,32 +2222,48 @@
 %    \begin{macrocode}
 \RequirePackage { luatexbase } 
 %    \end{macrocode}
+% 
+% \bigskip
+%    \begin{macrocode}
+\@@_msg_new:nn { piton.lua~not~found }
+  { 
+    The~file~'piton.lua'~can't~be~found.\\ 
+    The package~'piton'~won't be loaded.
+  }
+%    \end{macrocode}
 %
 % \bigskip
-% The boolean |\c_@@_footnotehyper_bool| will indicate if the option
+%    \begin{macrocode}
+\file_if_exist:nF { piton.lua }
+  { \msg_critical:nn { piton } { piton.lua~not~found } }
+%    \end{macrocode}
+%
+%
+% \bigskip
+% The boolean |\g_@@_footnotehyper_bool| will indicate if the option
 % |footnotehyper| is used.
 %    \begin{macrocode}
-\bool_new:N \c_@@_footnotehyper_bool
+\bool_new:N \g_@@_footnotehyper_bool
 %    \end{macrocode}
 %
 % \medskip
-% The boolean |\c_@@_footnote_bool| will indicate if the option |footnote| is
+% The boolean |\g_@@_footnote_bool| will indicate if the option |footnote| is
 % used, but quicky, it will also be set to |true| if the option |footnotehyper|
 % is used.
 %    \begin{macrocode}
-\bool_new:N \c_@@_footnote_bool
+\bool_new:N \g_@@_footnote_bool
 %    \end{macrocode}
 %
 % \medskip
 % The following boolean corresponds to the key |math-comments| (only at load-time).
 %    \begin{macrocode}
-\bool_new:N \c_@@_math_comments_bool
+\bool_new:N \g_@@_math_comments_bool
 %    \end{macrocode}
 %
 % \medskip
-% The following boolean corresponds to the key |beamer|. 
 %    \begin{macrocode}
-\bool_new:N \c_@@_beamer_bool
+\bool_new:N \g_@@_beamer_bool
+\tl_new:N \g_@@_escape_inside_tl 
 %    \end{macrocode}
 % 
 % \bigskip
@@ -1995,31 +2271,54 @@
 %    \begin{macrocode}
 \keys_define:nn { piton / package }
   { 
-    footnote .bool_set:N = \c_@@_footnote_bool ,
-    footnotehyper .bool_set:N = \c_@@_footnotehyper_bool ,
-    escape-inside .tl_set:N = \c_@@_escape_inside_tl ,
-    escape-inside .initial:n = , 
-    comment-latex .code:n = { \lua_now:n { comment_latex = "#1" } } ,   
-    comment-latex .value_required:n = true ,
-    math-comments .bool_set:N = \c_@@_math_comments_bool ,
-    math-comments .default:n  = true ,
-    beamer        .bool_set:N = \c_@@_beamer_bool ,
-    beamer        .default:n = true , 
-    unknown .code:n = \msg_error:nn { piton } { unknown~key~for~package }
+    footnote .bool_gset:N = \g_@@_footnote_bool ,
+    footnotehyper .bool_gset:N = \g_@@_footnotehyper_bool ,
+
+    beamer .bool_gset:N = \g_@@_beamer_bool ,
+    beamer .default:n = true , 
+  
+    escape-inside .code:n = \@@_error:n { key-escape-inside-deleted } , 
+    math-comments .code:n = \@@_error:n { moved~to~preamble } , 
+    comment-latex .code:n = \@@_error:n { moved~to~preamble } , 
+
+    unknown .code:n = \@@_error:n { Unknown~key~for~package }
   }
 %    \end{macrocode}
 %
+% \bigskip
 %    \begin{macrocode}
-\msg_new:nnn { piton } { unknown~key~for~package }
+\@@_msg_new:nn { key-escape-inside-deleted }
   {
+    The~key~'escape-inside'~has~been~deleted.~You~must~now~use~
+    the~keys~'begin-escape'~and~'end-escape'~in~
+    \token_to_str:N \PitonOptions.\\
+    That~key~will~be~ignored.
+  }
+%    \end{macrocode}
+%
+% \bigskip
+%    \begin{macrocode}
+\@@_msg_new:nn { moved~to~preamble }
+  {
+    The~key~'\l_keys_key_str'~*must*~now~be~used~with~
+    \token_to_str:N \PitonOptions`in~the~preamble~of~your~
+    document.\\
+    That~key~will~be~ignored.
+  }
+%    \end{macrocode}
+% 
+%    \begin{macrocode}
+\@@_msg_new:nn { Unknown~key~for~package }
+  {
     Unknown~key.\\
     You~have~used~the~key~'\l_keys_key_str'~but~the~only~keys~available~here~
-    are~'beamer',~'comment-latex',~'escape-inside',~'footnote',~'footnotehyper'~and~ 
-    'math-comments'.~Other~keys~are~available~in~\token_to_str:N \PitonOptions.\\
+    are~'beamer',~'footnote',~'footnotehyper'.~Other~keys~are~available~in~
+    \token_to_str:N \PitonOptions.\\ 
     That~key~will~be~ignored.
   }
 %    \end{macrocode}
 %
+%
 % \bigskip
 % We process the options provided by the user at load-time.
 %    \begin{macrocode}
@@ -2026,25 +2325,12 @@
 \ProcessKeysOptions { piton / package }
 %    \end{macrocode}
 %
-% \bigskip
-%    \begin{macrocode}
-\begingroup
-\cs_new_protected:Npn \@@_set_escape_char:nn #1 #2 
-  {
-    \lua_now:n { piton_begin_escape = "#1" }
-    \lua_now:n { piton_end_escape = "#2" }
-  }
-\cs_generate_variant:Nn \@@_set_escape_char:nn { x x }
-\@@_set_escape_char:xx 
-  { \tl_head:V \c_@@_escape_inside_tl }
-  { \tl_tail:V \c_@@_escape_inside_tl }
-\endgroup
-%    \end{macrocode}
 % 
 % \bigskip
 %    \begin{macrocode}
-\@ifclassloaded { beamer } { \bool_set_true:N \c_@@_beamer_bool } { }
-\bool_if:NT \c_@@_beamer_bool { \lua_now:n { piton_beamer = true } }
+\@ifclassloaded { beamer } { \bool_gset_true:N \g_@@_beamer_bool } { }
+\@ifpackageloaded { beamerarticle } { \bool_gset_true:N \g_@@_beamer_bool } { }
+\bool_if:NT \g_@@_beamer_bool { \lua_now:n { piton_beamer = true } } 
 %    \end{macrocode}
 % 
 % \bigskip
@@ -2058,7 +2344,7 @@
 %    \end{macrocode}
 %
 %    \begin{macrocode}     
-\msg_new:nnn { piton } { xcolor~not~loaded }
+\@@_msg_new:nn { xcolor~not~loaded }
   {
     xcolor~not~loaded \\
     The~package~'xcolor'~is~required~by~'piton'.\\
@@ -2068,7 +2354,7 @@
 % 
 %
 %    \begin{macrocode}
-\msg_new:nnn { piton } { footnote~with~footnotehyper~package }
+\@@_msg_new:nn { footnote~with~footnotehyper~package }
   { 
     Footnote~forbidden.\\
     You~can't~use~the~option~'footnote'~because~the~package~
@@ -2081,7 +2367,7 @@
 %    \end{macrocode}
 %
 %    \begin{macrocode}
-\msg_new:nnn { piton } { footnotehyper~with~footnote~package }
+\@@_msg_new:nn { footnotehyper~with~footnote~package }
   { 
     You~can't~use~the~option~'footnotehyper'~because~the~package~
     footnote~has~already~been~loaded.~
@@ -2094,7 +2380,7 @@
 %
 % \medskip
 %    \begin{macrocode}
-\bool_if:NT \c_@@_footnote_bool 
+\bool_if:NT \g_@@_footnote_bool 
   { 
 %    \end{macrocode}
 % The class \cls{beamer} has its own system to extract footnotes and that's why
@@ -2101,7 +2387,7 @@
 % we have nothing to do if \cls{beamer} is used. 
 %    \begin{macrocode}
     \@ifclassloaded { beamer }
-      { \bool_set_false:N \c_@@_footnote_bool }
+      { \bool_gset_false:N \g_@@_footnote_bool }
       { 
         \@ifpackageloaded { footnotehyper }
           { \@@_error:n { footnote~with~footnotehyper~package } }
@@ -2111,7 +2397,7 @@
 %    \end{macrocode}
 %
 %    \begin{macrocode}
-\bool_if:NT \c_@@_footnotehyper_bool 
+\bool_if:NT \g_@@_footnotehyper_bool 
   { 
 %    \end{macrocode}
 % The class \cls{beamer} has its own system to extract footnotes and that's why
@@ -2118,18 +2404,23 @@
 % we have nothing to do if \cls{beamer} is used. 
 %    \begin{macrocode}
     \@ifclassloaded { beamer }
-      { \bool_set_false:N \c_@@_footnote_bool }
+      { \bool_gset_false:N \g_@@_footnote_bool }
       { 
         \@ifpackageloaded { footnote }
           { \@@_error:n { footnotehyper~with~footnote~package } }
           { \usepackage { footnotehyper } }
-        \bool_set_true:N \c_@@_footnote_bool 
+        \bool_gset_true:N \g_@@_footnote_bool 
       }
   }
 %    \end{macrocode}
-% The flag |\c_@@_footnote_bool| is raised and so, we will only have to test
-% |\c_@@_footnote_bool| in order to know if we have to insert an environment
+% The flag |\g_@@_footnote_bool| is raised and so, we will only have to test
+% |\g_@@_footnote_bool| in order to know if we have to insert an environment
 % |{savenotes}|.
+%
+% \bigskip
+%    \begin{macrocode}
+\lua_now:n { piton = piton~or { } }
+%    \end{macrocode}
 % 
 % \bigskip
 % \subsubsection{Parameters and technical definitions}
@@ -2142,6 +2433,20 @@
 \str_set:Nn \l_@@_language_str { python }
 %    \end{macrocode}
 % 
+% \medskip
+% In order to have a better control over the keys.
+%    \begin{macrocode}
+\bool_new:N \l_@@_in_PitonOptions_bool 
+\bool_new:N \l_@@_in_PitonInputFile_bool 
+%    \end{macrocode}
+%
+% \medskip
+% The following flag will be raised in the |\AtBeginDocument|.
+%    \begin{macrocode}
+\bool_new:N \g_@@_in_document_bool
+%    \end{macrocode}
+% 
+% \medskip
 % We will compute (with Lua) the numbers of lines of the Python code and store
 % it in the following counter.
 %    \begin{macrocode}
@@ -2161,7 +2466,7 @@
 %    \end{macrocode}
 % 
 % \medskip
-% The following token list will contains the (potential) informations to write
+% The following token list will contain the (potential) informations to write
 % on the |aux| (to be used in the next compilation).
 %    \begin{macrocode}
 \tl_new:N \g_@@_aux_tl
@@ -2197,9 +2502,22 @@
 %    \begin{macrocode}
 \tl_new:N \l_@@_prompt_bg_color_tl
 %    \end{macrocode}
-% 
 %
 % \medskip
+% The following parameters correspond to the keys |begin-range| and |end-range| of
+% the command |\PitonInputFile|.
+%    \begin{macrocode}
+\str_new:N \l_@@_begin_range_str
+\str_new:N \l_@@_end_range_str
+%    \end{macrocode}
+%
+% \medskip
+% The argument of |\PitonInputFile|.
+%    \begin{macrocode}
+\str_new:N \l_@@_file_name_str 
+%    \end{macrocode}
+%
+% \medskip
 % We will count the environments |{Piton}| (and, in fact, also the commands
 % |\PitonInputFile|, despite the name |\g_@@_env_int|).
 %    \begin{macrocode}
@@ -2395,19 +2713,29 @@
           } 
         \@esphack
      }
-     { \msg_error:nn { piton } { label~with~lines~numbers } }
+     { \@@_error:n { label~with~lines~numbers } }
   }
 %    \end{macrocode}
 %
+% \bigskip
+% The following commands corresponds to the keys |marker/beginning| and
+% |marker/end|. The values of that keys are functions that will be applied to
+% the ``\emph{range}'' specified by the final user in an individual
+% |\PitonInputFile|. They will construct the markers used to find textually in
+% the external file loaded by \pkg{piton} the part which must be included (and
+% formatted). 
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_marker_beginning:n #1 { }
+\cs_new_protected:Npn \@@_marker_end:n #1 { }
+%    \end{macrocode}
 % 
+% 
 % \bigskip
 % The following commands are a easy way to insert safely braces (|{| and |}|) in
 % the TeX flow.
 %    \begin{macrocode}
-\cs_new_protected:Npn \@@_open_brace:
-  { \directlua { piton.open_brace() } }
-\cs_new_protected:Npn \@@_close_brace:
-  { \directlua { piton.close_brace() } }
+\cs_new_protected:Npn \@@_open_brace: { \directlua { piton.open_brace() } }
+\cs_new_protected:Npn \@@_close_brace: { \directlua { piton.close_brace() } }
 %    \end{macrocode}
 % 
 % \bigskip
@@ -2504,12 +2832,22 @@
         \skip_horizontal:N \l_@@_left_margin_dim
         \bool_if:NT \l_@@_line_numbers_bool
           {
-            \bool_if:NF \l_@@_all_line_numbers_bool
-              { \tl_if_eq:nnF  { #1 } { \PitonStyle {Prompt}{} } } 
-%    \end{macrocode}
-% Remember that |\@@_print_number:| always uses |\hbox_overlap_left:n|.
-%    \begin{macrocode}
-              \@@_print_number:
+            \bool_if:nF
+              { 
+                \str_if_eq_p:nn { #1 } { \PitonStyle {Prompt}{} } 
+                && 
+                \l_@@_skip_empty_lines_bool 
+              }
+              { \int_gincr:N \g_@@_visual_line_int}
+
+            \bool_if:nT
+              { 
+                ! \str_if_eq_p:nn { #1 } { \PitonStyle {Prompt}{} } 
+                ||
+                ( ! \l_@@_skip_empty_lines_bool && \l_@@_label_empty_lines_bool ) 
+              }
+              \@@_print_number: 
+
           }
 %    \end{macrocode}
 % If there is a background, we must remind that there is a left margin of 0.5~em
@@ -2588,7 +2926,7 @@
       { 
         \hbox_to_wd:nn \l_@@_line_width_dim 
 %    \end{macrocode}
-% We unpack the bock in order to free the potential |\hfill| springs present in
+% We unpack the block in order to free the potential |\hfill| springs present in
 % the LaTeX comments (cf. section~\ref{example-comments}, p.~\pageref{example-comments}).
 %    \begin{macrocode}
           { \hbox_unpack:N \l_tmpa_box \hfil } 
@@ -2644,9 +2982,9 @@
           { \l_@@_nb_lines_int - \g_@@_line_int } > \l_@@_splittable_int 
           {
             \egroup
-            \bool_if:NT \c_@@_footnote_bool { \end { savenotes } } 
+            \bool_if:NT \g_@@_footnote_bool { \end { savenotes } } 
             \par \mode_leave_vertical: % \newline
-            \bool_if:NT \c_@@_footnote_bool { \begin { savenotes } } 
+            \bool_if:NT \g_@@_footnote_bool { \begin { savenotes } } 
             \vtop \bgroup
           }
      }
@@ -2687,18 +3025,91 @@
 % \subsubsection{PitonOptions}
 %
 % \medskip
-% The following parameters correspond to the keys |line-numbers| and
-% |all-line-numbers|.
 %    \begin{macrocode}
 \bool_new:N \l_@@_line_numbers_bool 
-\bool_new:N \l_@@_all_line_numbers_bool 
+\bool_new:N \l_@@_skip_empty_lines_bool 
+\bool_set_true:N \l_@@_skip_empty_lines_bool 
+\bool_new:N \l_@@_line_numbers_absolute_bool
+\bool_new:N \l_@@_label_empty_lines_bool
+\bool_set_true:N \l_@@_label_empty_lines_bool 
+\int_new:N \l_@@_number_lines_start_int
+\bool_new:N \l_@@_resume_bool 
 %    \end{macrocode}
 % 
-% \medskip
-% The following flag corresponds to the key |resume|.
+%
+%  \bigskip
 %    \begin{macrocode}
-\bool_new:N \l_@@_resume_bool 
+\keys_define:nn { PitonOptions / marker }
+  {
+    beginning .code:n = \cs_set:Nn \@@_marker_beginning:n { #1 } ,   
+    beginning .value_required:n = true , 
+    end .code:n = \cs_set:Nn \@@_marker_end:n { #1 } ,   
+    end .value_required:n = true ,
+    include-lines .bool_set:N = \l_@@_marker_include_lines_bool ,
+    include-lines .default:n = true ,
+    unknown .code:n = \@@_error:n { Unknown~key~for~marker } 
+  }
 %    \end{macrocode}
+%
+% \bigskip
+%    \begin{macrocode}
+\keys_define:nn { PitonOptions / line-numbers }
+  {
+    true .code:n = \bool_set_true:N \l_@@_line_numbers_bool , 
+    false .code:n = \bool_set_false:N \l_@@_line_numbers_bool , 
+
+    start .code:n = 
+      \bool_if:NTF \l_@@_in_PitonOptions_bool
+        { Invalid~key }
+        {
+          \bool_set_true:N \l_@@_line_numbers_bool 
+          \int_set:Nn \l_@@_number_lines_start_int { #1 }  
+        } ,
+    start .value_required:n = true ,
+
+    skip-empty-lines .code:n = 
+      \bool_if:NF \l_@@_in_PitonOptions_bool
+        { \bool_set_true:N \l_@@_line_numbers_bool }
+      \str_if_eq:nnTF { #1 } { false }
+        { \bool_set_false:N \l_@@_skip_empty_lines_bool } 
+        { \bool_set_true:N \l_@@_skip_empty_lines_bool } ,
+    skip-empty-lines .default:n = true , 
+
+    label-empty-lines .code:n = 
+      \bool_if:NF \l_@@_in_PitonOptions_bool
+        { \bool_set_true:N \l_@@_line_numbers_bool }
+      \str_if_eq:nnTF { #1 } { false }
+        { \bool_set_false:N \l_@@_label_empty_lines_bool } 
+        { \bool_set_true:N \l_@@_label_empty_lines_bool } ,
+    label-empty-lines .default:n = true ,
+
+    absolute .code:n = 
+      \bool_if:NTF \l_@@_in_PitonOptions_bool
+        { \bool_set_true:N \l_@@_line_numbers_absolute_bool }
+        { \bool_set_true:N \l_@@_line_numbers_bool }
+      \bool_if:NT \l_@@_in_PitonInputFile_bool 
+        { 
+          \bool_set_true:N \l_@@_line_numbers_absolute_bool 
+          \bool_set_false:N \l_@@_skip_empty_lines_bool 
+        }
+      \bool_lazy_or:nnF
+        \l_@@_in_PitonInputFile_bool 
+        \l_@@_in_PitonOptions_bool 
+        { \@@_error:n { Invalid~key } } ,
+    absolute .value_forbidden:n = true ,
+
+    resume .code:n = 
+      \bool_set_true:N \l_@@_resume_bool 
+      \bool_if:NF \l_@@_in_PitonOptions_bool 
+        { \bool_set_true:N \l_@@_line_numbers_bool } , 
+    resume .value_forbidden:n = true ,
+
+    sep .dim_set:N = \l_@@_numbers_sep_dim ,
+    sep .value_required:n = true , 
+
+    unknown .code:n = \@@_error:n { Unknown~key~for~line-numbers } 
+  }
+%    \end{macrocode}
 % 
 % \bigskip
 % Be careful! The name of the following set of keys must be considered as
@@ -2707,6 +3118,41 @@
 %    \begin{macrocode}
 \keys_define:nn { PitonOptions }
   {
+%    \end{macrocode}
+% First, we put keys that should be avalaible only in the preamble.
+%    \begin{macrocode}
+    begin-escape .code:n = 
+      \lua_now:e { piton.begin_escape = "\lua_escape:n{#1}" } ,
+    begin-escape .value_required:n = true , 
+    begin-escape .usage:n = preamble , 
+
+    end-escape   .code:n = 
+      \lua_now:e { piton.end_escape = "\lua_escape:n{#1}" } ,
+    end-escape   .value_required:n = true ,
+    end-escape .usage:n = preamble ,
+
+    begin-escape-math .code:n = 
+      \lua_now:e { piton.begin_escape_math = "\lua_escape:n{#1}" } ,
+    begin-escape-math .value_required:n = true , 
+    begin-escape-math .usage:n = preamble ,
+
+    end-escape-math .code:n = 
+      \lua_now:e { piton.end_escape_math = "\lua_escape:n{#1}" } ,
+    end-escape-math .value_required:n = true ,
+    end-escape-math .usage:n = preamble ,
+
+    comment-latex .code:n = \lua_now:n { comment_latex = "#1" } ,   
+    comment-latex .value_required:n = true ,
+    comment-latex .usage:n = preamble ,
+
+    math-comments .bool_set:N = \g_@@_math_comments_bool ,
+    math-comments .default:n  = true ,
+    math-comments .usage:n = preamble , 
+%    \end{macrocode}
+% 
+% \bigskip
+% Now, general keys.
+%    \begin{macrocode}
     language         .code:n = 
       \str_set:Nx \l_@@_language_str { \str_lowercase:n { #1 } } , 
     language         .value_required:n  = true ,
@@ -2718,14 +3164,20 @@
     env-gobble       .value_forbidden:n = true ,
     tabs-auto-gobble .code:n            = \int_set:Nn \l_@@_gobble_int { -3 } , 
     tabs-auto-gobble .value_forbidden:n = true ,
-    line-numbers     .bool_set:N        = \l_@@_line_numbers_bool ,
-    line-numbers     .default:n         = true ,
-    all-line-numbers .code:n = 
-      \bool_set_true:N \l_@@_line_numbers_bool 
-      \bool_set_true:N \l_@@_all_line_numbers_bool ,
-    all-line-numbers .value_forbidden:n = true  ,
-    resume           .bool_set:N        = \l_@@_resume_bool ,
-    resume           .value_forbidden:n = true ,
+ 
+    marker .code:n = 
+      \bool_lazy_or:nnTF
+        \l_@@_in_PitonInputFile_bool 
+        \l_@@_in_PitonOptions_bool 
+        { \keys_set:nn { PitonOptions / marker } { #1 } } 
+        { \@@_error:n { Invalid~key } } , 
+    marker .value_required:n = true , 
+
+    line-numbers .code:n = 
+      \keys_set:nn { PitonOptions / line-numbers } { #1 } ,
+    line-numbers .default:n = true , 
+
+
     splittable       .int_set:N         = \l_@@_splittable_int ,
     splittable       .default:n         = 1 , 
     background-color .clist_set:N       = \l_@@_bg_color_clist ,
@@ -2732,7 +3184,8 @@
     background-color .value_required:n  = true ,
     prompt-background-color .tl_set:N         = \l_@@_prompt_bg_color_tl ,
     prompt-background-color .value_required:n = true ,
-    width            .code:n = 
+
+    width .code:n = 
       \str_if_eq:nnTF  { #1 } { min } 
         { 
           \bool_set_true:N \l_@@_width_min_bool 
@@ -2742,7 +3195,8 @@
           \bool_set_false:N \l_@@_width_min_bool
           \dim_set:Nn \l_@@_width_dim { #1 } 
         } , 
-    width            .value_required:n  = true ,
+    width .value_required:n  = true ,
+
     left-margin      .code:n =
       \str_if_eq:nnTF { #1 } { auto }
         { 
@@ -2754,8 +3208,7 @@
           \bool_set_false:N \l_@@_left_margin_auto_bool
         } ,
     left-margin      .value_required:n  = true ,
-    numbers-sep      .dim_set:N         = \l_@@_numbers_sep_dim ,
-    numbers-sep      .value_required:n  = true , 
+
     tab-size         .code:n            = \@@_set_tab_tl:n { #1 } ,
     tab-size         .value_required:n  = true , 
     show-spaces      .bool_set:N        = \l_@@_show_spaces_bool , 
@@ -2776,27 +3229,80 @@
     continuation-symbol .value_required:n = true , 
     continuation-symbol-on-indentation .tl_set:N = \l_@@_csoi_tl ,
     continuation-symbol-on-indentation .value_required:n = true , 
-    unknown          .code:n = 
-      \msg_error:nn { piton } { Unknown~key~for~PitonOptions }
+
+    first-line .code:n = \@@_in_PitonInputFile:n 
+      { \int_set:Nn \l_@@_first_line_int { #1 } } ,
+    first-line .value_required:n = true ,
+
+    last-line .code:n = \@@_in_PitonInputFile:n 
+      { \int_set:Nn \l_@@_last_line_int { #1 } } ,
+    last-line .value_required:n = true , 
+
+    begin-range .code:n = \@@_in_PitonInputFile:n 
+      { \str_set:Nn \l_@@_begin_range_str { #1 } } ,
+    begin-range .value_required:n = true ,
+
+    end-range .code:n = \@@_in_PitonInputFile:n 
+      { \str_set:Nn \l_@@_end_range_str { #1 } } ,
+    end-range .value_required:n = true ,
+
+    range .code:n = \@@_in_PitonInputFile:n 
+      { 
+        \str_set:Nn \l_@@_begin_range_str { #1 } 
+        \str_set:Nn \l_@@_end_range_str { #1 } 
+      } ,
+    range .value_required:n = true ,
+
+    resume .meta:n = line-numbers/resume , 
+
+    unknown .code:n = \@@_error:n { Unknown~key~for~PitonOptions } ,
+
+    % deprecated
+    all-line-numbers .code:n = 
+      \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}
 %
+% \bigskip
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_in_PitonInputFile:n #1
+  {
+    \bool_if:NTF \l_@@_in_PitonInputFile_bool 
+      { #1 }
+      { \@@_error:n { Invalid~key } } 
+  }
+%    \end{macrocode}
 % 
-%  \bigskip
-% 
+%
 % \bigskip
-% The argument of |\PitonOptions| is provided by curryfication.
 %    \begin{macrocode}
-\NewDocumentCommand \PitonOptions { } { \keys_set:nn { PitonOptions } }
+\NewDocumentCommand \PitonOptions { m } 
+  { 
+    \bool_set_true:N \l_@@_in_PitonOptions_bool
+    \keys_set:nn { PitonOptions } { #1 }
+    \bool_set_false:N \l_@@_in_PitonOptions_bool
+  }
 %    \end{macrocode}
 %
+%
 % \bigskip
+%    \begin{macrocode}
+\hook_gput_code:nnn { begindocument } { . }
+  { \bool_gset_true:N \g_@@_in_document_bool }
+%    \end{macrocode}
+% 
+% \bigskip
 % \subsubsection{The numbers of the lines}
 %
 % \medskip
 % The following counter will be used to count the lines in the code when the
-% user requires the numbers of the lines to be printed (with |line-numbers| or
-% |all-line-numbers|). 
+% user requires the numbers of the lines to be printed (with |line-numbers|).
 %
 %    \begin{macrocode}
 \int_new:N \g_@@_visual_line_int 
@@ -2806,10 +3312,13 @@
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_print_number:
   {
-    \int_gincr:N \g_@@_visual_line_int
     \hbox_overlap_left:n
       { 
-        { \color { gray } \footnotesize \int_to_arabic:n \g_@@_visual_line_int }
+        { 
+          \color { gray } 
+          \footnotesize 
+          \int_to_arabic:n \g_@@_visual_line_int 
+        } 
         \skip_horizontal:N \l_@@_numbers_sep_dim  
       }
   }
@@ -3028,18 +3537,7 @@
   }
 %    \end{macrocode}
 % 
-% \bigskip
-%    \begin{macrocode}
-\keys_define:nn { PitonInputFile }
-  {
-    first-line .int_set:N = \l_@@_first_line_int ,  
-    first-line .value_required:n = true ,
-    last-line .int_set:N = \l_@@_last_line_int , 
-    last-line .value_required:n = true , 
-  }
-%    \end{macrocode}
 %
-%
 % \bigskip
 % If the final user has used both |left-margin=auto| and |line-numbers|, we have
 % to compute the width of the maximal number of lines at the end of the
@@ -3054,12 +3552,8 @@
         \hbox_set:Nn \l_tmpa_box
           {
             \footnotesize
-            \bool_if:NTF \l_@@_all_line_numbers_bool
+            \bool_if:NTF \l_@@_skip_empty_lines_bool
               {
-                \int_to_arabic:n 
-                  { \g_@@_visual_line_int + \l_@@_nb_lines_int }  
-              }
-              {
                 \lua_now:n 
                   { piton.#1(token.scan_argument()) }
                   { #2 }
@@ -3066,6 +3560,10 @@
                 \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 }  
+              }
            }
          \dim_set:Nn \l_@@_left_margin_dim 
            { \box_wd:N \l_tmpa_box + \l_@@_numbers_sep_dim + 0.1 em }
@@ -3169,10 +3667,10 @@
             \ttfamily
             \dim_zero:N \parskip % added 2023/07/06
 %    \end{macrocode}
-% |\c_@@_footnote_bool| is raised when the package \pkg{piton} has been load
+% |\g_@@_footnote_bool| is raised when the package \pkg{piton} has been load
 % with the key |footnote| \emph{or} the key |footnotehyper|.
 %    \begin{macrocode}
-            \bool_if:NT \c_@@_footnote_bool { \begin { savenotes } } 
+            \bool_if:NT \g_@@_footnote_bool { \begin { savenotes } } 
             \vtop \bgroup 
             \lua_now:e 
               { 
@@ -3186,7 +3684,7 @@
               { ##1 }
             \vspace { 2.5 pt } 
             \egroup 
-            \bool_if:NT \c_@@_footnote_bool { \end { savenotes } } 
+            \bool_if:NT \g_@@_footnote_bool { \end { savenotes } } 
 %    \end{macrocode}
 % If the user has used the key |width| with the special value~|min|, we write on
 % the |aux| file the value of |\l_@@_line_width_dim| (largest width of the lines
@@ -3211,6 +3709,8 @@
       {
         #3 
         \@@_pre_env:
+        \int_compare:nNnT \l_@@_number_lines_start_int > 0 
+          { \int_gset:Nn \g_@@_visual_line_int { \l_@@_number_lines_start_int - 1 } }
         \group_begin:
         \tl_map_function:nN 
           { \ \\ \{ \} \$ \& \# \^ \_ \% \~ \^^I } 
@@ -3238,11 +3738,11 @@
 % provided by the package \pkg{piton}. Of course, you use
 % |\NewPitonEnvironment|. 
 %    \begin{macrocode}
-\bool_if:NTF \c_@@_beamer_bool
+\bool_if:NTF \g_@@_beamer_bool
   {
     \NewPitonEnvironment { Piton } { d < > O { } }
       { 
-        \PitonOptions { #2 } 
+        \keys_set:nn { PitonOptions } { #2 } 
         \IfValueTF { #1 }
           { \begin { uncoverenv } < #1 > }
           { \begin { uncoverenv } }
@@ -3249,8 +3749,9 @@
       }
       { \end { uncoverenv } } 
   }
-  { \NewPitonEnvironment { Piton } { O { } } 
-      { \PitonOptions { #1 } } 
+  { 
+    \NewPitonEnvironment { Piton } { O { } } 
+      { \keys_set:nn { PitonOptions } { #1 } } 
       { } 
   }
 %    \end{macrocode}
@@ -3265,7 +3766,7 @@
   {
     \file_if_exist:nTF { #3 }
       { \@@_input_file:nnn { #1 } { #2 } { #3 } }
-      { \msg_error:nnn { piton } { unknown~file } { #3 } } 
+      { \msg_error:nnn { piton } { Unknown~file } { #3 } } 
   }
 %    \end{macrocode}
 %
@@ -3272,6 +3773,7 @@
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_input_file:nnn #1 #2 #3
   {
+    \str_set:Nn \l_@@_file_name_str { #3 }
 %    \end{macrocode}
 % We recall that, if we are in Beamer, the command |\PitonInputFile| is
 % ``overlay-aware'' and that's why there is an optional argument between angular
@@ -3279,16 +3781,58 @@
 %    \begin{macrocode}
     \tl_if_novalue:nF { #1 }
       {
-        \bool_if:NTF \c_@@_beamer_bool
+        \bool_if:NTF \g_@@_beamer_bool
           { \begin { uncoverenv } < #1 > }     
-          { \msg_error:nn { piton } { overlay~without~beamer } }
+          { \@@_error:n { overlay~without~beamer } }
       }
     \group_begin:
       \int_zero_new:N \l_@@_first_line_int
       \int_zero_new:N \l_@@_last_line_int 
       \int_set_eq:NN \l_@@_last_line_int \c_max_int
-      \keys_set:nn { PitonInputFile } { #2 }
+      \bool_set_true:N \l_@@_in_PitonInputFile_bool
+      \keys_set:nn { PitonOptions } { #2 }
+      \bool_if:NT \l_@@_line_numbers_absolute_bool
+        { \bool_set_false:N \l_@@_skip_empty_lines_bool }
+      \bool_if:nTF
+        {
+          ( 
+            \int_compare_p:nNn \l_@@_first_line_int > 0 
+            || \int_compare_p:nNn \l_@@_last_line_int < \c_max_int 
+          )
+          && ! \str_if_empty_p:N \l_@@_begin_range_str
+        }
+        { 
+          \@@_error:n { bad~range~specification } 
+          \int_zero:N \l_@@_first_line_int
+          \int_set_eq:NN \l_@@_last_line_int \c_max_int
+        }
+        { 
+          \str_if_empty:NF \l_@@_begin_range_str 
+            { 
+              \@@_compute_range: 
+              \bool_lazy_or:nnT 
+                \l_@@_marker_include_lines_bool
+                { ! \str_if_eq_p:NN \l_@@_begin_range_str \l_@@_end_range_str } 
+                {
+                  \int_decr:N \l_@@_first_line_int
+                  \int_incr:N \l_@@_last_line_int
+                }
+            }
+        }
       \@@_pre_env:
+      \bool_if:NT \l_@@_line_numbers_absolute_bool
+        { \int_gset:Nn \g_@@_visual_line_int { \l_@@_first_line_int - 1 } } 
+      \int_compare:nNnT \l_@@_number_lines_start_int > 0 
+        { 
+          \int_gset:Nn \g_@@_visual_line_int 
+            { \l_@@_number_lines_start_int - 1 } 
+        }
+%    \end{macrocode}
+% The following case arise when the code |line-numbers/absolute| is in force
+% without the use of a marked range.
+%    \begin{macrocode}
+      \int_compare:nNnT \g_@@_visual_line_int < 0 
+        { \int_gzero:N \g_@@_visual_line_int  }
       \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
@@ -3295,7 +3839,7 @@
 % stored by Lua in |\l_@@_nb_lines_int|. That information will be used to allow
 % or disallow page breaks.
 %    \begin{macrocode}
-      \lua_now:n { piton.CountLinesFile(token.scan_argument()) } { #3 }  
+      \lua_now:e { piton.CountLinesFile('\l_@@_file_name_str') } 
 %    \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.
@@ -3303,19 +3847,18 @@
       \@@_compute_left_margin:nn { CountNonEmptyLinesFile } { #3 }
       \@@_compute_width:
       \ttfamily
-      \bool_if:NT \c_@@_footnote_bool { \begin { savenotes } } 
+      \bool_if:NT \g_@@_footnote_bool { \begin { savenotes } } 
       \vtop \bgroup 
       \lua_now:e
         { 
           piton.ParseFile(
-           '\l_@@_language_str',
-           token.scan_argument() ,
+           '\l_@@_language_str' ,
+           '\l_@@_file_name_str' ,
            \int_use:N \l_@@_first_line_int , 
            \int_use:N \l_@@_last_line_int ) 
         } 
-        { #3 }
       \egroup 
-      \bool_if:NT \c_@@_footnote_bool { \end { savenotes } } 
+      \bool_if:NT \g_@@_footnote_bool { \end { savenotes } } 
       \bool_if:NT \l_@@_width_min_bool \@@_width_to_aux:
     \group_end:
 %    \end{macrocode}
@@ -3324,12 +3867,40 @@
 % that we have opened at the beginning of the command.
 %    \begin{macrocode}
     \tl_if_novalue:nF { #1 }
-      { \bool_if:NT \c_@@_beamer_bool { \end { uncoverenv } } }
+      { \bool_if:NT \g_@@_beamer_bool { \end { uncoverenv } } }
     \@@_write_aux:
   }
 %    \end{macrocode}
 %
+% 
 % \bigskip
+% The following command computes the values of |\l_@@_first_line_int| and
+% |\l_@@_last_line_int| when |\PitonInputFile| is used with textual markers. 
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_compute_range: 
+  {
+%    \end{macrocode}
+% 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 }
+%    \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
+    \lua_now:e
+      { 
+        piton.ComputeRange
+          ( '\l_tmpa_str' , '\l_tmpb_str' , '\l_@@_file_name_str' ) 
+      } 
+  }
+%    \end{macrocode}
+% 
+% \bigskip
 % \subsubsection{The styles}
 % 
 % \medskip
@@ -3406,7 +3977,7 @@
     ParseAgain.noCR .tl_set:c = pitonStyle ParseAgain.noCR , 
     ParseAgain.noCR .value_required:n = true ,
     unknown         .code:n = 
-      \msg_error:nn { piton } { Unknown~key~for~SetPitonStyle }
+      \@@_error:n { Unknown~key~for~SetPitonStyle }
   }
 %    \end{macrocode}
 %
@@ -3425,7 +3996,7 @@
   { 
     \str_compare:nNnTF { #1 } < { #2 } 
       \sort_return_same:    
-      \sort_return_swapped:
+      \sort_return_swapped:  
   } 
 %    \end{macrocode}
 % 
@@ -3480,7 +4051,7 @@
 % However, maybe we will document in a future version the possibility to write
 % change the style \emph{locally} in a document)].
 %    \begin{macrocode}
-\bool_if:NT \c_@@_math_comments_bool { \SetPitonStyle { Comment.Math } }
+\bool_if:NT \g_@@_math_comments_bool { \SetPitonStyle { Comment.Math } }
 %    \end{macrocode}
 % 
 % \bigskip
@@ -3592,7 +4163,7 @@
 % 
 % 
 %    \begin{macrocode}
-\msg_new:nnn { piton } { Unknown~key~for~SetPitonStyle } 
+\@@_msg_new:nn { Unknown~key~for~SetPitonStyle } 
   {
     The~style~'\l_keys_key_str'~is~unknown.\\
     This~key~will~be~ignored.\\
@@ -3601,8 +4172,53 @@
   }
 %    \end{macrocode}
 %
+%    \begin{macrocode}
+\@@_msg_new:nn { Invalid~key }
+  {
+    Wrong~use~of~key.\\
+    You~can't~use~the~key~'\l_keys_key_str'~here.\\
+    That~key~will~be~ignored.
+  }
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\@@_msg_new:nn { Unknown~key~for~line-numbers } 
+  { 
+    Unknown~key. \\
+    The~key~'line-numbers / \l_keys_key_str'~is~unknown.\\
+    The~available~keys~of~the~family~'line-numbers'~are~(in~
+    alphabetic~order):~
+    absolute,~false,~label-empty-lines,~resume,~skip-empty-lines,~
+    sep,~start~and~true.\\
+    That~key~will~be~ignored.
+  }
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\@@_msg_new:nn { Unknown~key~for~marker } 
+  { 
+    Unknown~key. \\
+    The~key~'marker / \l_keys_key_str'~is~unknown.\\
+    The~available~keys~of~the~family~'marker'~are~(in~
+    alphabetic~order):~ beginning,~end~and~include-lines.\\
+    That~key~will~be~ignored.
+  }
+%    \end{macrocode}
+% 
+% 
+% 
+%    \begin{macrocode}
+\@@_msg_new:nn { bad~range~specification } 
+  {
+    Incompatible~keys.\\
+    You~can't~specify~the~range~of~lines~to~include~by~using~both~
+    markers~and~explicit~number~of~lines.\\
+    Your~whole~file~'\l_@@_file_name_str'~will~be~included.
+  }
+%    \end{macrocode}
+% 
 %   \begin{macrocode}
-\msg_new:nnn { piton } { syntax~error }
+\@@_msg_new:nn { syntax~error }
   {
     Your~code~is~not~syntactically~correct.\\
     It~won't~be~printed~in~the~PDF~file.
@@ -3611,12 +4227,43 @@
 %
 %    \begin{macrocode}
 \NewDocumentCommand \PitonSyntaxError { }
-  { \msg_error:nn { piton } { syntax~error } }
+  { \@@_error:n { syntax~error } }
 %    \end{macrocode}
+%
+%
+%    \begin{macrocode}
+\@@_msg_new:nn { begin~marker~not~found }
+  {
+    Marker~not~found.\\
+    The~range~'\l_@@_begin_range_str'~provided~to~the~  
+    command~\token_to_str:N \PitonInputFile\ has~not~been~found.~
+    The~whole~file~'\l_@@_file_name_str'~will~be~inserted.
+  }
+%    \end{macrocode}
+%
 % 
 %    \begin{macrocode}
-\msg_new:nnn { piton } { unknown~file }
+\@@_msg_new:nn { end~marker~not~found }
   {
+    Marker~not~found.\\
+    The~marker~of~end~of~the~range~'\l_@@_end_range_str'~
+    provided~to~the~command~\token_to_str:N \PitonInputFile\ 
+    has~not~been~found.~The~file~'\l_@@_file_name_str'~will~
+    be~inserted~till~the~end.
+  }
+%    \end{macrocode}
+% 
+%
+%    \begin{macrocode}
+\NewDocumentCommand \PitonBeginMarkerNotFound { } 
+  { \@@_error:n { begin~marker~not~found } }
+\NewDocumentCommand \PitonEndMarkerNotFound { } 
+  { \@@_error:n { end~marker~not~found } }
+%    \end{macrocode}
+% 
+%    \begin{macrocode}
+\@@_msg_new:nn { Unknown~file }
+  {
     Unknown~file. \\
     The~file~'#1'~is~unknown.\\
     Your~command~\token_to_str:N \PitonInputFile\ will~be~discarded.
@@ -3633,15 +4280,15 @@
   }
   {
     The~available~keys~are~(in~alphabetic~order):~
-    all-line-numbers,~
     auto-gobble,~
     background-color,~
     break-lines,~
     break-lines-in-piton,~
     break-lines-in-Piton,~
-    continuation-symbol,~
+    continuation-symbol,~ 
     continuation-symbol-on-indentation,~
     end-of-broken-line,~
+    end-range,~
     env-gobble,~
     gobble,~
     identifiers,~
@@ -3648,7 +4295,8 @@
     indent-broken-lines,~
     language,~
     left-margin,~
-    line-numbers,~
+    line-numbers/,~
+    marker/,~
     prompt-background-color,~
     resume,~
     show-spaces,~
@@ -3661,11 +4309,10 @@
 %
 % \bigskip
 %    \begin{macrocode}
-\msg_new:nnn { piton } { label~with~lines~numbers } 
+\@@_msg_new:nn { label~with~lines~numbers } 
   {
     You~can't~use~the~command~\token_to_str:N \label\
-    because~the~key~'line-numbers'~(or~'all-line-numbers')~
-    is~not~active.\\
+    because~the~key~'line-numbers'~is~not~active.\\
     If~you~go~on,~that~command~will~ignored.
   }
 %    \end{macrocode}
@@ -3672,7 +4319,7 @@
 % 
 % \bigskip
 %    \begin{macrocode}
-\msg_new:nnn { piton } { cr~not~allowed }
+\@@_msg_new:nn { cr~not~allowed }
   {
     You~can't~put~any~carriage~return~in~the~argument~
     of~a~command~\c_backslash_str
@@ -3685,7 +4332,7 @@
 %
 % \bigskip
 %    \begin{macrocode}
-\msg_new:nnn { piton } { overlay~without~beamer }
+\@@_msg_new:nn { overlay~without~beamer }
   {
     You~can't~use~an~argument~<...>~for~your~command~
     \token_to_str:N \PitonInputFile\ because~you~are~not~
@@ -3696,20 +4343,26 @@
 %
 % \bigskip
 %    \begin{macrocode}
-\msg_new:nnn { Piton } { Python~error }
+\@@_msg_new:nn { Python~error }
   { A~Python~error~has~been~detected. }
 %    \end{macrocode}
-% 
+%
 % \bigskip
-% \subsection{The Lua part of the implementation}
+% \subsubsection{We load piton.lua}
 %
+%
 % \bigskip
 %    \begin{macrocode}
-\ExplSyntaxOff
-\RequirePackage{luacode}
+\hook_gput_code:nnn { begindocument } { . }
+  { \lua_now:e { require("piton.lua") } }
+%</STY>
 %    \end{macrocode}
 % 
+% \bigskip
+% \subsection{The Lua part of the implementation}
 %
+% 
+%
 % \bigskip
 % The Lua code will be loaded via a |{luacode*}| environment. The environment
 % is by itself a Lua block and the local declarations will be local to that
@@ -3716,13 +4369,9 @@
 % block. All the global functions (used by the L3 parts of the implementation)
 % will be put in a Lua table |piton|.
 %
-% \medskip
-%    \begin{macrocode}
-\begin{luacode*}
-piton = piton or { }
-%    \end{macrocode}
 % 
 %    \begin{macrocode}
+%<*LUA>
 if piton.comment_latex == nil then piton.comment_latex = ">" end 
 piton.comment_latex = "#" .. piton.comment_latex 
 %    \end{macrocode}
@@ -3773,7 +4422,7 @@
 % with standard LaTeX catcodes for all the characters: the elements captured
 % will be formatted as normal LaTeX codes. It's suitable for the ``LaTeX
 % comments'' in the environments |{Piton}| and the elements beetween 
-% ``|escape-inside|''. That function won't be much used.
+% |begin-escape| and |end-escape|. That function won't be much used.
 %    \begin{macrocode}
 local function L(pattern)
   return Ct ( C ( pattern ) ) 
@@ -3827,21 +4476,35 @@
 % 
 % \bigskip
 % The following \textsc{lpeg} catches the Python chunks which are in LaTeX
-% escapes (and that chunks will be considered as normal LaTeX constructions). We
-% recall that |piton.begin_espace| and |piton_end_escape| are Lua strings
-% corresponding to the key |escape-inside|\footnote{The \pkg{piton} key
-% |escape-inside| is available at load-time only.}. Since the elements that will
-% be catched must be sent to LaTeX with standard LaTeX catcodes, we put the
-% capture (done by the function |C|) in a table (by using |Ct|, which is an
-% alias for |lpeg.Ct|) without number of catcode table at the first component of
-% the table.
+% escapes (and that chunks will be considered as normal LaTeX constructions).
+% Since the elements that will be catched must be sent to LaTeX with standard
+% LaTeX catcodes, we put the capture (done by the function |C|) in a table (by
+% using |Ct|, which is an alias for |lpeg.Ct|) without number of catcode table
+% at the first component of the table.
 %    \begin{macrocode}
-local Escape = 
-  P(piton_begin_escape)
-  * L ( ( 1 - P(piton_end_escape) ) ^ 1 ) 
-  * P(piton_end_escape)
+Escape = P ( false ) 
+if piton.begin_escape ~= nil
+then 
+  Escape = 
+    P(piton.begin_escape)
+    * L ( ( 1 - P(piton.end_escape) ) ^ 1 ) 
+    * P(piton.end_escape)
+end
 %    \end{macrocode}
 % 
+%    \begin{macrocode}
+EscapeMath = P ( false ) 
+if piton.begin_escape_math ~= nil
+then 
+  EscapeMath = 
+    P(piton.begin_escape_math)
+    * Lc ( "\\ensuremath{" ) 
+    * L ( ( 1 - P(piton.end_escape_math) ) ^ 1 )
+    * Lc ( "}" ) 
+    * P(piton.end_escape_math)
+end
+%    \end{macrocode}
+% 
 % \vspace{1cm}
 % The following line is mandatory.
 %    \begin{macrocode}
@@ -3907,13 +4570,11 @@
 %
 % \bigskip
 % We recall that |piton.begin_espace| and |piton_end_escape| are Lua strings
-% corresponding to the key |escape-inside|\footnote{The \pkg{piton} key
-% |escape-inside| is available at load-time only.}. Of course, if the final user
-% has not used the key |escape-inside|, these strings are empty.
+% corresponding to the keys |begin-escape| and |end-escape|. 
 %    \begin{macrocode}
 local Word
-if piton_begin_escape ~= ''
-then Word = Q ( ( ( 1 - space - P(piton_begin_escape) - P(piton_end_escape) ) 
+if piton.begin_escape ~= nil -- before : ''
+then Word = Q ( ( ( 1 - space - P(piton.begin_escape) - P(piton.end_escape) ) 
                    - S "'\"\r[()]" - digit ) ^ 1 )
 else Word = Q ( ( ( 1 - space ) - S "'\"\r[()]" - digit ) ^ 1 )
 end
@@ -4624,7 +5285,7 @@
        EOL
      + Space 
      + Tab
-     + Escape 
+     + Escape + EscapeMath
      + CommentLaTeX
      + Beamer
      + LongString 
@@ -5137,7 +5798,7 @@
        EOL
      + Space 
      + Tab
-     + Escape 
+     + Escape + EscapeMath
      + Beamer 
      + TypeParameter
      + String + QuotedString + Char
@@ -5472,7 +6133,7 @@
        EOL
      + Space 
      + Tab
-     + Escape 
+     + Escape + EscapeMath 
      + CommentLaTeX
      + Beamer
      + Preproc
@@ -5831,10 +6492,45 @@
       '\\int_set:Nn \\l_@@_nb_non_empty_lines_int {' .. count .. '}' )
 end 
 %    \end{macrocode}
+%
 % 
+% \bigskip
+% The following function stores in |\l_@@_first_line_int| and
+% |\l_@@_last_line_int| the numbers of lines of the file |file_name|
+% corresponding to the strings |marker_beginning| and |marker_end|.
 %    \begin{macrocode}
-\end{luacode*}
+function piton.ComputeRange(marker_beginning,marker_end,file_name)
+  local s = ( Cs ( ( P '##' / '#' + 1 ) ^ 0 ) ) : match ( marker_beginning )
+  local t = ( Cs ( ( P '##' / '#' + 1 ) ^ 0 ) ) : match ( marker_end )
+  local first_line = -1
+  local count = 0
+  local last_found = false
+  for line in io.lines(file_name)
+  do if first_line == -1
+     then if string.sub(line,1,#s) == s 
+          then first_line = count 
+          end 
+     else if string.sub(line,1,#t) == t
+          then last_found = true 
+               break 
+          end 
+     end 
+     count = count + 1 
+  end
+  if first_line == -1 
+  then tex.sprint("\\PitonBeginMarkerNotFound")
+  else if last_found == false
+       then tex.sprint("\\PitonEndMarkerNotFound")
+       end
+  end
+  tex.sprint( 
+      luatexbase.catcodetables.expl , 
+      '\\int_set:Nn \\l_@@_first_line_int {' .. first_line .. ' + 2 }' 
+      .. '\\int_set:Nn \\l_@@_last_line_int {' .. count .. ' }' )
+end
+%</LUA>
 %    \end{macrocode}
+% 
 %
 % 
 % \vspace{1cm}
@@ -5855,6 +6551,22 @@
 %
 % \verb|https://github.com/fpantigny/piton|
 %
+% \subsection*{Changes between versions 2.0 and 2.1}
+%
+% The key |line-numbers| has now subkeys |line-numbers/skip-empty-lines|,
+% |line-numbers/label-empty-lines|, etc. 
+%
+% The key |all-line-numbers| is deprecated: use
+% |line-numbers/skip-empty-lines=false|. 
+%
+% New system to import, with |\PitonInputFile|, only a part (of the file)
+% delimited by textual markers. 
+%
+% New keys |begin-escape|, |end-escape|, |begin-escape-math| and |end-escape-math|.
+%
+% The key |escape-inside| is deprecated: use |begin-escape| and |end-escape|.
+%
+%
 % \subsection*{Changes between versions 1.6 and 2.0}
 %
 % The extension \pkg{piton} nows supports the computer languages OCaml and C

Modified: trunk/Master/texmf-dist/source/lualatex/piton/piton.ins
===================================================================
--- trunk/Master/texmf-dist/source/lualatex/piton/piton.ins	2023-08-26 20:18:37 UTC (rev 68074)
+++ trunk/Master/texmf-dist/source/lualatex/piton/piton.ins	2023-08-26 20:18:56 UTC (rev 68075)
@@ -30,13 +30,16 @@
 LaTeX version 2005/12/01 or later.
 
 \endpreamble
-\generate{\file{piton.sty}{\from{piton.dtx}{package}}}
+\generate{\file{piton.sty}{\from{piton.dtx}{STY}}}
+\nopreamble
+\nopostamble
+\generate{\file{piton.lua}{\from{piton.dtx}{LUA}}}
 \Msg{*********************************************************}
 \Msg{*}
 \Msg{* To finish the installation you have to move the}
 \Msg{* following files into a directory searched by TeX:}
 \Msg{*}
-\Msg{* \space\space piton.sty}
+\Msg{* \space\space piton.sty, piton.lua}
 \Msg{*}
 \Msg{* To produce the documentation run the file piton.dtx}
 \Msg{* through LuaLaTeX.}

Added: trunk/Master/texmf-dist/tex/lualatex/piton/piton.lua
===================================================================
--- trunk/Master/texmf-dist/tex/lualatex/piton/piton.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/tex/lualatex/piton/piton.lua	2023-08-26 20:18:56 UTC (rev 68075)
@@ -0,0 +1,1232 @@
+
+
+if piton.comment_latex == nil then piton.comment_latex = ">" end
+piton.comment_latex = "#" .. piton.comment_latex
+function piton.open_brace ()
+   tex.sprint("{")
+end
+function piton.close_brace ()
+   tex.sprint("}")
+end
+local P, S, V, C, Ct, Cc = lpeg.P, lpeg.S, lpeg.V, lpeg.C, lpeg.Ct, lpeg.Cc
+local Cf, Cs , Cg , Cmt , Cb = lpeg.Cf, lpeg.Cs, lpeg.Cg , lpeg.Cmt , lpeg.Cb
+local R = lpeg.R
+local function Q(pattern)
+  return Ct ( Cc ( luatexbase.catcodetables.CatcodeTableOther ) * C ( pattern ) )
+end
+local function L(pattern)
+  return Ct ( C ( pattern ) )
+end
+local function Lc(string)
+  return Cc ( { luatexbase.catcodetables.expl , string } )
+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
+     * Ct ( Cc "Close" )
+end
+Escape = P ( false )
+if piton.begin_escape ~= nil
+then
+  Escape =
+    P(piton.begin_escape)
+    * L ( ( 1 - P(piton.end_escape) ) ^ 1 )
+    * P(piton.end_escape)
+end
+EscapeMath = P ( false )
+if piton.begin_escape_math ~= nil
+then
+  EscapeMath =
+    P(piton.begin_escape_math)
+    * Lc ( "\\ensuremath{" )
+    * L ( ( 1 - P(piton.end_escape_math) ) ^ 1 )
+    * Lc ( "}" )
+    * P(piton.end_escape_math)
+end
+lpeg.locale(lpeg)
+local alpha, digit = lpeg.alpha, lpeg.digit
+local space = P " "
+local letter = alpha + P "_"
+  + P "â" + P "à" + P "ç" + P "é" + P "è" + P "ê" + P "ë" + P "ï" + P "î"
+  + P "ô" + P "û" + P "ü" + P "Â" + P "À" + P "Ç" + P "É" + P "È" + P "Ê"
+  + P "Ë" + P "Ï" + P "Î" + P "Ô" + P "Û" + P "Ü"
+
+local alphanum = letter + digit
+local identifier = letter * alphanum ^ 0
+local Identifier = K ( 'Identifier' , identifier)
+local Number =
+  K ( 'Number' ,
+      ( digit^1 * P "." * digit^0 + digit^0 * P "." * digit^1 + digit^1 )
+      * ( S "eE" * S "+-" ^ -1 * digit^1 ) ^ -1
+      + digit^1
+    )
+local Word
+if piton.begin_escape ~= nil -- before : ''
+then Word = Q ( ( ( 1 - space - P(piton.begin_escape) - P(piton.end_escape) )
+                   - S "'\"\r[()]" - digit ) ^ 1 )
+else Word = Q ( ( ( 1 - space ) - S "'\"\r[()]" - digit ) ^ 1 )
+end
+local Space = ( Q " " ) ^ 1
+
+local SkipSpace = ( Q " " ) ^ 0
+
+local Punct = Q ( S ".,:;!" )
+
+local Tab = P "\t" * Lc ( '\\l__piton_tab_tl' )
+local SpaceIndentation = Lc ( '\\__piton_an_indentation_space:' ) * ( Q " " )
+local Delim = Q ( S "[()]" )
+local VisualSpace = space * Lc "\\l__piton_space_tl"
+local Beamer = P ( false )
+local BeamerBeginEnvironments = P ( true )
+local BeamerEndEnvironments = P ( true )
+if piton_beamer
+then
+  local BeamerNamesEnvironments =
+    P "uncoverenv" + P "onlyenv" + P "visibleenv" + P "invisibleenv"
+    + P "alertenv" + P "actionenv"
+  BeamerBeginEnvironments =
+      ( space ^ 0 *
+        L
+          (
+            P "\\begin{" * BeamerNamesEnvironments * "}"
+            * ( P "<" * ( 1 - P ">" ) ^ 0 * P ">" ) ^ -1
+          )
+        * P "\r"
+      ) ^ 0
+  BeamerEndEnvironments =
+      ( space ^ 0 *
+        L ( P "\\end{" * BeamerNamesEnvironments * P "}" )
+        * P "\r"
+      ) ^ 0
+  function OneBeamerEnvironment(name,lpeg)
+    return
+        Ct ( Cc "Open"
+              * C (
+                    P ( "\\begin{" .. name ..   "}" )
+                    * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1
+                  )
+             * Cc ( "\\end{" .. name ..  "}" )
+            )
+       * (
+           C ( ( 1 - P ( "\\end{" .. name .. "}" ) ) ^ 0 )
+           / ( function (s) return lpeg : match(s) end )
+         )
+       * P ( "\\end{" .. name ..  "}" ) * Ct ( Cc "Close" )
+  end
+end
+local languages = { }
+local Operator =
+  K ( 'Operator' ,
+      P "!=" + P "<>" + P "==" + P "<<" + P ">>" + P "<=" + P ">=" + P ":="
+      + P "//" + P "**" + S "-~+/*%=<>&.@|"
+    )
+
+local OperatorWord =
+  K ( 'Operator.Word' , P "in" + P "is" + P "and" + P "or" + P "not" )
+
+local Keyword =
+  K ( 'Keyword' ,
+      P "as" + P "assert" + P "break" + P "case" + P "class" + P "continue"
+      + P "def" + P "del" + P "elif" + P "else" + P "except" + P "exec"
+      + P "finally" + P "for" + P "from" + P "global" + P "if" + P "import"
+      + P "lambda" + P "non local" + P "pass" + P "return" + P "try"
+      + P "while" + P "with" + P "yield" + P "yield from" )
+  + K ( 'Keyword.Constant' ,P "True" + P "False" + P "None" )
+
+local Builtin =
+  K ( 'Name.Builtin' ,
+      P "__import__" + P "abs" + P "all" + P "any" + P "bin" + P "bool"
+    + P "bytearray" + P "bytes" + P "chr" + P "classmethod" + P "compile"
+    + P "complex" + P "delattr" + P "dict" + P "dir" + P "divmod"
+    + P "enumerate" + P "eval" + P "filter" + P "float" + P "format"
+    + P "frozenset" + P "getattr" + P "globals" + P "hasattr" + P "hash"
+    + P "hex" + P "id" + P "input" + P "int" + P "isinstance" + P "issubclass"
+    + P "iter" + P "len" + P "list" + P "locals" + P "map" + P "max"
+    + P "memoryview" + P "min" + P "next" + P "object" + P "oct" + P "open"
+    + P "ord" + P "pow" + P "print" + P "property" + P "range" + P "repr"
+    + P "reversed" + P "round" + P "set" + P "setattr" + P "slice" + P "sorted"
+    + P "staticmethod" + P "str" + P "sum" + P "super" + P "tuple" + P "type"
+    + P "vars" + P "zip" )
+
+local Exception =
+  K ( 'Exception' ,
+      P "ArithmeticError" + P "AssertionError" + P "AttributeError"
+   + P "BaseException" + P "BufferError" + P "BytesWarning" + P "DeprecationWarning"
+   + P "EOFError" + P "EnvironmentError" + P "Exception" + P "FloatingPointError"
+   + P "FutureWarning" + P "GeneratorExit" + P "IOError" + P "ImportError"
+   + P "ImportWarning" + P "IndentationError" + P "IndexError" + P "KeyError"
+   + P "KeyboardInterrupt" + P "LookupError" + P "MemoryError" + P "NameError"
+   + P "NotImplementedError" + P "OSError" + P "OverflowError"
+   + P "PendingDeprecationWarning" + P "ReferenceError" + P "ResourceWarning"
+   + P "RuntimeError" + P "RuntimeWarning" + P "StopIteration"
+   + P "SyntaxError" + P "SyntaxWarning" + P "SystemError" + P "SystemExit"
+   + P "TabError" + P "TypeError" + P "UnboundLocalError" + P "UnicodeDecodeError"
+   + P "UnicodeEncodeError" + P "UnicodeError" + P "UnicodeTranslateError"
+   + P "UnicodeWarning" + P "UserWarning" + P "ValueError" + P "VMSError"
+   + P "Warning" + P "WindowsError" + P "ZeroDivisionError"
+   + P "BlockingIOError" + P "ChildProcessError" + P "ConnectionError"
+   + P "BrokenPipeError" + P "ConnectionAbortedError" + P "ConnectionRefusedError"
+   + P "ConnectionResetError" + P "FileExistsError" + P "FileNotFoundError"
+   + P "InterruptedError" + P "IsADirectoryError" + P "NotADirectoryError"
+   + P "PermissionError" + P "ProcessLookupError" + P "TimeoutError"
+   + P "StopAsyncIteration" + P "ModuleNotFoundError" + P "RecursionError" )
+
+local RaiseException = K ( 'Keyword' , P "raise" ) * SkipSpace * Exception * Q ( P "(" )
+
+local Decorator = K ( 'Name.Decorator' , P "@" * letter^1  )
+local DefClass =
+  K ( 'Keyword' , P "class" ) * Space * K ( 'Name.Class' , identifier )
+local ImportAs =
+  K ( 'Keyword' , P "import" )
+   * Space
+   * K ( 'Name.Namespace' ,
+         identifier * ( P "." * identifier ) ^ 0 )
+   * (
+       ( Space * K ( 'Keyword' , P "as" ) * Space
+          * K ( 'Name.Namespace' , identifier ) )
+       +
+       ( SkipSpace * Q ( P "," ) * SkipSpace
+          * K ( 'Name.Namespace' , identifier ) ) ^ 0
+     )
+local FromImport =
+  K ( 'Keyword' , P "from" )
+    * Space * K ( 'Name.Namespace' , identifier )
+    * Space * K ( 'Keyword' , P "import" )
+local PercentInterpol =
+  K ( 'String.Interpol' ,
+      P "%"
+      * ( P "(" * alphanum ^ 1 * P ")" ) ^ -1
+      * ( S "-#0 +" ) ^ 0
+      * ( digit ^ 1 + P "*" ) ^ -1
+      * ( P "." * ( digit ^ 1 + P "*" ) ) ^ -1
+      * ( S "HlL" ) ^ -1
+      * S "sdfFeExXorgiGauc%"
+    )
+local SingleShortString =
+  WithStyle ( 'String.Short' ,
+         Q ( P "f'" + P "F'" )
+         * (
+             K ( 'String.Interpol' , P "{" )
+              * K ( 'Interpol.Inside' , ( 1 - S "}':" ) ^ 0  )
+              * Q ( P ":" * (1 - S "}:'") ^ 0 ) ^ -1
+              * K ( 'String.Interpol' , P "}" )
+             +
+             VisualSpace
+             +
+             Q ( ( P "\\'" + P "{{" + P "}}" + 1 - S " {}'" ) ^ 1 )
+           ) ^ 0
+         * Q ( P "'" )
+       +
+         Q ( P "'" + P "r'" + P "R'" )
+         * ( Q ( ( P "\\'" + 1 - S " '\r%" ) ^ 1 )
+             + VisualSpace
+             + PercentInterpol
+             + Q ( P "%" )
+           ) ^ 0
+         * Q ( P "'" ) )
+
+local DoubleShortString =
+  WithStyle ( 'String.Short' ,
+         Q ( P "f\"" + P "F\"" )
+         * (
+             K ( 'String.Interpol' , P "{" )
+               * Q ( ( 1 - S "}\":" ) ^ 0 , 'Interpol.Inside' )
+               * ( K ( 'String.Interpol' , P ":" ) * Q ( (1 - S "}:\"") ^ 0 ) ) ^ -1
+               * K ( 'String.Interpol' , P "}" )
+             +
+             VisualSpace
+             +
+             Q ( ( P "\\\"" + P "{{" + P "}}" + 1 - S " {}\"" ) ^ 1 )
+            ) ^ 0
+         * Q ( P "\"" )
+       +
+         Q ( P "\"" + P "r\"" + P "R\"" )
+         * ( Q ( ( P "\\\"" + 1 - S " \"\r%" ) ^ 1 )
+             + VisualSpace
+             + PercentInterpol
+             + Q ( P "%" )
+           ) ^ 0
+         * Q ( P "\"" ) )
+
+local ShortString = SingleShortString + DoubleShortString
+local balanced_braces =
+  P { "E" ,
+       E =
+           (
+             P "{" * V "E" * P "}"
+             +
+             ShortString
+             +
+             ( 1 - S "{}" )
+           ) ^ 0
+    }
+if piton_beamer
+then
+  Beamer =
+      L ( P "\\pause" * ( P "[" * ( 1 - P "]" ) ^ 0 * P "]" ) ^ -1 )
+    +
+      Ct ( Cc "Open"
+            * C (
+                  (
+                    P "\\uncover" + P "\\only" + P "\\alert" + P "\\visible"
+                    + P "\\invisible" + P "\\action"
+                  )
+                  * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1
+                  * P "{"
+                )
+            * Cc "}"
+         )
+       * ( C ( balanced_braces ) / (function (s) return MainLoopPython:match(s) end ) )
+       * P "}" * Ct ( Cc "Close" )
+    + OneBeamerEnvironment ( "uncoverenv" , MainLoopPython )
+    + OneBeamerEnvironment ( "onlyenv" , MainLoopPython )
+    + OneBeamerEnvironment ( "visibleenv" , MainLoopPython )
+    + OneBeamerEnvironment ( "invisibleenv" , MainLoopPython )
+    + OneBeamerEnvironment ( "alertenv" , MainLoopPython )
+    + OneBeamerEnvironment ( "actionenv" , MainLoopPython )
+    +
+      L (
+          ( P "\\alt" )
+          * P "<" * (1 - P ">") ^ 0 * P ">"
+          * P "{"
+        )
+      * K ( 'ParseAgain.noCR' , balanced_braces )
+      * L ( P "}{" )
+      * K ( 'ParseAgain.noCR' , balanced_braces )
+      * L ( P "}" )
+    +
+      L (
+          ( P "\\temporal" )
+          * P "<" * (1 - P ">") ^ 0 * P ">"
+          * P "{"
+        )
+      * K ( 'ParseAgain.noCR' , balanced_braces )
+      * L ( P "}{" )
+      * K ( 'ParseAgain.noCR' , balanced_braces )
+      * L ( P "}{" )
+      * K ( 'ParseAgain.noCR' , balanced_braces )
+      * L ( P "}" )
+end
+local PromptHastyDetection = ( # ( P ">>>" + P "..." ) * Lc ( '\\__piton_prompt:' ) ) ^ -1
+local Prompt = K ( 'Prompt' , ( ( P ">>>" + P "..." ) * P " " ^ -1 ) ^ -1  )
+local EOL =
+  P "\r"
+  *
+  (
+    ( space^0 * -1 )
+    +
+    Ct (
+         Cc "EOL"
+         *
+         Ct (
+              Lc "\\__piton_end_line:"
+              * BeamerEndEnvironments
+              * BeamerBeginEnvironments
+              * PromptHastyDetection
+              * Lc "\\__piton_newline: \\__piton_begin_line:"
+              * Prompt
+            )
+       )
+  )
+  *
+  SpaceIndentation ^ 0
+local SingleLongString =
+  WithStyle ( 'String.Long' ,
+     ( Q ( S "fF" * P "'''" )
+         * (
+             K ( 'String.Interpol' , P "{"  )
+               * K ( 'Interpol.Inside' , ( 1 - S "}:\r" - P "'''" ) ^ 0  )
+               * Q ( P ":" * (1 - S "}:\r" - P "'''" ) ^ 0 ) ^ -1
+               * K ( 'String.Interpol' , P "}"  )
+             +
+             Q ( ( 1 - P "'''" - S "{}'\r" ) ^ 1 )
+             +
+             EOL
+           ) ^ 0
+       +
+         Q ( ( S "rR" ) ^ -1  * P "'''" )
+         * (
+             Q ( ( 1 - P "'''" - S "\r%" ) ^ 1 )
+             +
+             PercentInterpol
+             +
+             P "%"
+             +
+             EOL
+           ) ^ 0
+      )
+      * Q ( P "'''" ) )
+
+local DoubleLongString =
+  WithStyle ( 'String.Long' ,
+     (
+        Q ( S "fF" * P "\"\"\"" )
+        * (
+            K ( 'String.Interpol', P "{"  )
+              * K ( 'Interpol.Inside' , ( 1 - S "}:\r" - P "\"\"\"" ) ^ 0 )
+              * Q ( P ":" * (1 - S "}:\r" - P "\"\"\"" ) ^ 0 ) ^ -1
+              * K ( 'String.Interpol' , P "}"  )
+            +
+            Q ( ( 1 - P "\"\"\"" - S "{}\"\r" ) ^ 1 )
+            +
+            EOL
+          ) ^ 0
+      +
+        Q ( ( S "rR" ) ^ -1  * P "\"\"\"" )
+        * (
+            Q ( ( 1 - P "\"\"\"" - S "%\r" ) ^ 1 )
+            +
+            PercentInterpol
+            +
+            P "%"
+            +
+            EOL
+          ) ^ 0
+     )
+     * Q ( P "\"\"\"" )
+  )
+local LongString = SingleLongString + DoubleLongString
+local StringDoc =
+    K ( 'String.Doc' , P "\"\"\"" )
+      * ( K ( 'String.Doc' , (1 - P "\"\"\"" - P "\r" ) ^ 0  ) * EOL
+          * Tab ^ 0
+        ) ^ 0
+      * K ( 'String.Doc' , ( 1 - P "\"\"\"" - P "\r" ) ^ 0 * P "\"\"\"" )
+local CommentMath =
+  P "$" * K ( 'Comment.Math' , ( 1 - S "$\r" ) ^ 1  ) * P "$"
+
+local Comment =
+  WithStyle ( 'Comment' ,
+     Q ( P "#" )
+     * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0 )
+  * ( EOL + -1 )
+local CommentLaTeX =
+  P(piton.comment_latex)
+  * Lc "{\\PitonStyle{Comment.LaTeX}{\\ignorespaces"
+  * L ( ( 1 - P "\r" ) ^ 0 )
+  * Lc "}}"
+  * ( EOL + -1 )
+local expression =
+  P { "E" ,
+       E = ( P "'" * ( P "\\'" + 1 - S "'\r" ) ^ 0 * P "'"
+             + P "\"" * (P "\\\"" + 1 - S "\"\r" ) ^ 0 * P "\""
+             + P "{" * V "F" * P "}"
+             + P "(" * V "F" * P ")"
+             + P "[" * V "F" * P "]"
+             + ( 1 - S "{}()[]\r," ) ) ^ 0 ,
+       F = ( P "{" * V "F" * P "}"
+             + P "(" * V "F" * P ")"
+             + P "[" * V "F" * P "]"
+             + ( 1 - S "{}()[]\r\"'" ) ) ^ 0
+    }
+local Param =
+  SkipSpace * Identifier * SkipSpace
+   * (
+         K ( 'InitialValues' , P "=" * expression )
+       + Q ( P ":" ) * SkipSpace * K ( 'Name.Type' , letter ^ 1  )
+     ) ^ -1
+local Params = ( Param * ( Q "," * Param ) ^ 0 ) ^ -1
+local DefFunction =
+  K ( 'Keyword' , P "def" )
+  * Space
+  * K ( 'Name.Function.Internal' , identifier )
+  * SkipSpace
+  * Q ( P "(" ) * Params * Q ( P ")" )
+  * SkipSpace
+  * ( Q ( P "->" ) * SkipSpace * K ( 'Name.Type' , identifier  ) ) ^ -1
+  * K ( 'ParseAgain' , ( 1 - S ":\r" )^0  )
+  * Q ( P ":" )
+  * ( SkipSpace
+      * ( EOL + CommentLaTeX + Comment ) -- in all cases, that contains an EOL
+      * Tab ^ 0
+      * SkipSpace
+      * StringDoc ^ 0 -- there may be additionnal docstrings
+    ) ^ -1
+local ExceptionInConsole = Exception *  Q ( ( 1 - P "\r" ) ^ 0 ) * EOL
+local MainPython =
+       EOL
+     + Space
+     + Tab
+     + Escape + EscapeMath
+     + CommentLaTeX
+     + Beamer
+     + LongString
+     + Comment
+     + ExceptionInConsole
+     + Delim
+     + Operator
+     + OperatorWord * ( Space + Punct + Delim + EOL + -1 )
+     + ShortString
+     + Punct
+     + FromImport
+     + RaiseException
+     + DefFunction
+     + DefClass
+     + Keyword * ( Space + Punct + Delim + EOL + -1 )
+     + Decorator
+     + Builtin * ( Space + Punct + Delim + EOL + -1 )
+     + Identifier
+     + Number
+     + Word
+MainLoopPython =
+  (  ( space^1 * -1 )
+     + MainPython
+  ) ^ 0
+local python = P ( true )
+
+python =
+  Ct (
+       ( ( space - P "\r" ) ^0 * P "\r" ) ^ -1
+       * BeamerBeginEnvironments
+       * PromptHastyDetection
+       * Lc '\\__piton_begin_line:'
+       * Prompt
+       * SpaceIndentation ^ 0
+       * MainLoopPython
+       * -1
+       * Lc '\\__piton_end_line:'
+     )
+languages['python'] = python
+local Delim = Q ( P "[|" + 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" + P "_") * ( R "az" + R "AZ" + S "_'" + digit ) ^ 0
+local Identifier = K ( 'Identifier' , identifier )
+local expression_for_fields =
+  P { "E" ,
+       E = ( P "{" * V "F" * P "}"
+             + P "(" * V "F" * P ")"
+             + P "[" * V "F" * P "]"
+             + P "\"" * (P "\\\"" + 1 - S "\"\r" )^0 * P "\""
+             + P "'" * ( P "\\'" + 1 - S "'\r" )^0 * P "'"
+             + ( 1 - S "{}()[]\r;" ) ) ^ 0 ,
+       F = ( P "{" * V "F" * P "}"
+             + P "(" * V "F" * P ")"
+             + P "[" * V "F" * P "]"
+             + ( 1 - S "{}()[]\r\"'" ) ) ^ 0
+    }
+local OneFieldDefinition =
+    ( K ( 'KeyWord' , P "mutable" ) * SkipSpace ) ^ -1
+  * K ( 'Name.Field' , identifier ) * SkipSpace
+  * Q ":" * SkipSpace
+  * K ( 'Name.Type' , expression_for_fields )
+  * SkipSpace
+
+local OneField =
+    K ( 'Name.Field' , identifier ) * SkipSpace
+  * Q "=" * SkipSpace
+  * ( C ( expression_for_fields ) / ( function (s) return LoopOCaml:match(s) end ) )
+  * SkipSpace
+
+local Record =
+  Q "{" * SkipSpace
+  *
+    (
+      OneFieldDefinition * ( Q ";" * SkipSpace * OneFieldDefinition ) ^ 0
+      +
+      OneField * ( Q ";" * SkipSpace * OneField ) ^ 0
+    )
+  *
+  Q "}"
+local DotNotation =
+  (
+      K ( 'Name.Module' , cap_identifier )
+        * Q "."
+        * ( Identifier + Constructor + Q "(" + Q "[" + Q "{" )
+
+      +
+      Identifier
+        * Q "."
+        * K ( 'Name.Field' , identifier )
+  )
+  * ( Q "." * K ( 'Name.Field' , identifier ) ) ^ 0
+local Operator =
+  K ( 'Operator' ,
+      P "!=" + P "<>" + P "==" + P "<<" + P ">>" + P "<=" + P ">=" + P ":="
+      + P "||" + P "&&" + P "//" + P "**" + P ";;" + P "::" + P "->"
+      + P "+." + P "-." + P "*." + P "/."
+      + S "-~+/*%=<>&@|"
+    )
+
+local OperatorWord =
+  K ( 'Operator.Word' ,
+      P "and" + P "asr" + P "land" + P "lor" + P "lsl" + P "lxor"
+      + P "mod" + P "or" )
+
+local Keyword =
+  K ( 'Keyword' ,
+      P "assert" + P "as" + P "begin" + P "class" + P "constraint" + P "done"
+  + P "downto" + P "do" + P "else" + P "end" + P "exception" + P "external"
+  + P "for" + P "function" + P "functor" + P "fun"  + P "if"
+  + P "include" + P "inherit" + P "initializer" + P "in"  + P "lazy" + P "let"
+  + P "match" + P "method" + P "module" + P "mutable" + P "new" + P "object"
+  + P "of" + P "open" + P "private" + P "raise" + P "rec" + P "sig"
+  + P "struct" + P "then" + P "to" + P "try" + P "type"
+  + P "value" + P "val" + P "virtual" + P "when" + P "while" + P "with" )
+  + K ( 'Keyword.Constant' , P "true" + P "false" )
+
+local Builtin =
+  K ( 'Name.Builtin' , P "not" + P "incr" + P "decr" + P "fst" + P "snd" )
+local Exception =
+  K (   'Exception' ,
+       P "Division_by_zero" + P "End_of_File" + P "Failure"
+     + P "Invalid_argument" + P "Match_failure" + P "Not_found"
+     + P "Out_of_memory" + P "Stack_overflow" + P "Sys_blocked_io"
+     + P "Sys_error" + P "Undefined_recursive_module" )
+local Char =
+  K ( 'String.Short' , P "'" * ( ( 1 - P "'" ) ^ 0 + P "\\'" ) * P "'" )
+local balanced_braces =
+  P { "E" ,
+       E =
+           (
+             P "{" * V "E" * P "}"
+             +
+             P "\"" * ( 1 - S "\"" ) ^ 0 * P "\""  -- OCaml strings
+             +
+             ( 1 - S "{}" )
+           ) ^ 0
+    }
+if piton_beamer
+then
+  Beamer =
+      L ( P "\\pause" * ( P "[" * ( 1 - P "]" ) ^ 0 * P "]" ) ^ -1 )
+    +
+      Ct ( Cc "Open"
+            * C (
+                  (
+                    P "\\uncover" + P "\\only" + P "\\alert" + P "\\visible"
+                    + P "\\invisible" + P "\\action"
+                  )
+                  * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1
+                  * P "{"
+                )
+            * Cc "}"
+         )
+       * ( C ( balanced_braces ) / (function (s) return MainLoopOCaml:match(s) end ) )
+       * P "}" * Ct ( Cc "Close" )
+    + OneBeamerEnvironment ( "uncoverenv" , MainLoopOCaml )
+    + OneBeamerEnvironment ( "onlyenv" , MainLoopOCaml )
+    + OneBeamerEnvironment ( "visibleenv" , MainLoopOCaml )
+    + OneBeamerEnvironment ( "invisibleenv" , MainLoopOCaml )
+    + OneBeamerEnvironment ( "alertenv" , MainLoopOCaml )
+    + OneBeamerEnvironment ( "actionenv" , MainLoopOCaml )
+    +
+      L (
+          ( P "\\alt" )
+          * P "<" * (1 - P ">") ^ 0 * P ">"
+          * P "{"
+        )
+      * K ( 'ParseAgain.noCR' , balanced_braces )
+      * L ( P "}{" )
+      * K ( 'ParseAgain.noCR' , balanced_braces )
+      * L ( P "}" )
+    +
+      L (
+          ( P "\\temporal" )
+          * P "<" * (1 - P ">") ^ 0 * P ">"
+          * P "{"
+        )
+      * K ( 'ParseAgain.noCR' , balanced_braces )
+      * L ( P "}{" )
+      * K ( 'ParseAgain.noCR' , balanced_braces )
+      * L ( P "}{" )
+      * K ( 'ParseAgain.noCR' , balanced_braces )
+      * L ( P "}" )
+end
+local EOL =
+  P "\r"
+  *
+  (
+    ( space^0 * -1 )
+    +
+    Ct (
+         Cc "EOL"
+         *
+         Ct (
+              Lc "\\__piton_end_line:"
+              * BeamerEndEnvironments
+              * BeamerBeginEnvironments
+              * PromptHastyDetection
+              * Lc "\\__piton_newline: \\__piton_begin_line:"
+              * Prompt
+            )
+       )
+  )
+  *
+  SpaceIndentation ^ 0
+local ocaml_string =
+       Q ( P "\"" )
+     * (
+         VisualSpace
+         +
+         Q ( ( 1 - S " \"\r" ) ^ 1 )
+         +
+         EOL
+       ) ^ 0
+     * Q ( P "\"" )
+local String = WithStyle ( 'String.Long' , ocaml_string )
+local ext = ( R "az" + P "_" ) ^ 0
+local open = "{" * Cg(ext, 'init') * "|"
+local close = "|" * C(ext) * "}"
+local closeeq =
+  Cmt ( close * Cb('init'),
+        function (s, i, a, b) return a==b end )
+local QuotedStringBis =
+  WithStyle ( 'String.Long' ,
+      (
+        VisualSpace
+        +
+        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 - P "(*" - P "*)" - S "\r$\"" ) ^ 1 ) -- $
+                 + ocaml_string
+                 + P "$" * K ( 'Comment.Math' , ( 1 - S "$\r" ) ^ 1 ) * P "$" -- $
+                 + EOL
+               ) ^ 0
+             * Q "*)"
+       }   )
+local balanced_parens =
+  P { "E" ,
+       E =
+           (
+             P "(" * V "E" * P ")"
+             +
+             ( 1 - S "()" )
+           ) ^ 0
+    }
+local Argument =
+  K ( 'Identifier' , identifier )
+  + Q "(" * SkipSpace
+    * K ( 'Identifier' , identifier ) * SkipSpace
+    * Q ":" * SkipSpace
+    * K ( 'Name.Type' , balanced_parens ) * SkipSpace
+    * Q ")"
+local DefFunction =
+  K ( 'Keyword' , P "let open" )
+   * Space
+   * K ( 'Name.Module' , cap_identifier )
+  +
+  K ( 'Keyword' , P "let rec" + P "let" + P "and" )
+    * Space
+    * K ( 'Name.Function.Internal' , identifier )
+    * Space
+    * (
+        Q "=" * SkipSpace * K ( 'Keyword' , P "function" )
+        +
+        Argument
+         * ( SkipSpace * Argument ) ^ 0
+         * (
+             SkipSpace
+             * Q ":"
+             * K ( 'Name.Type' , ( 1 - P "=" ) ^ 0 )
+           ) ^ -1
+      )
+local DefModule =
+  K ( 'Keyword' , P "module" ) * Space
+  *
+    (
+          K ( 'Keyword' , P "type" ) * Space
+        * K ( 'Name.Type' , cap_identifier )
+      +
+        K ( 'Name.Module' , cap_identifier ) * SkipSpace
+        *
+          (
+            Q "(" * SkipSpace
+              * K ( 'Name.Module' , cap_identifier ) * SkipSpace
+              * Q ":" * SkipSpace
+              * K ( 'Name.Type' , cap_identifier ) * SkipSpace
+              *
+                (
+                  Q "," * SkipSpace
+                    * K ( 'Name.Module' , cap_identifier ) * SkipSpace
+                    * Q ":" * SkipSpace
+                    * K ( 'Name.Type' , cap_identifier ) * SkipSpace
+                ) ^ 0
+              * Q ")"
+          ) ^ -1
+        *
+          (
+            Q "=" * SkipSpace
+            * K ( 'Name.Module' , cap_identifier )  * SkipSpace
+            * Q "("
+            * K ( 'Name.Module' , cap_identifier ) * SkipSpace
+              *
+              (
+                Q ","
+                *
+                K ( 'Name.Module' , cap_identifier ) * SkipSpace
+              ) ^ 0
+            * Q ")"
+          ) ^ -1
+    )
+  +
+  K ( 'Keyword' , P "include" + P "open" )
+  * Space * K ( 'Name.Module' , cap_identifier )
+local TypeParameter = K ( 'TypeParameter' , P "'" * alpha * # ( 1 - P "'" ) )
+MainOCaml =
+       EOL
+     + Space
+     + Tab
+     + Escape + EscapeMath
+     + Beamer
+     + TypeParameter
+     + String + QuotedString + Char
+     + Comment
+     + Delim
+     + Operator
+     + Punct
+     + FromImport
+     + Exception
+     + DefFunction
+     + DefModule
+     + Record
+     + Keyword * ( Space + Punct + Delim + EOL + -1 )
+     + OperatorWord * ( Space + Punct + Delim + EOL + -1 )
+     + Builtin * ( Space + Punct + Delim + EOL + -1 )
+     + DotNotation
+     + Constructor
+     + Identifier
+     + Number
+     + Word
+
+LoopOCaml = MainOCaml ^ 0
+
+MainLoopOCaml =
+  (  ( space^1 * -1 )
+     + MainOCaml
+  ) ^ 0
+local ocaml = P ( true )
+
+ocaml =
+  Ct (
+       ( ( space - P "\r" ) ^0 * P "\r" ) ^ -1
+       * BeamerBeginEnvironments
+       * Lc ( '\\__piton_begin_line:' )
+       * SpaceIndentation ^ 0
+       * MainLoopOCaml
+       * -1
+       * Lc ( '\\__piton_end_line:' )
+     )
+languages['ocaml'] = ocaml
+local Operator =
+  K ( 'Operator' ,
+      P "!=" + P "==" + P "<<" + P ">>" + P "<=" + P ">="
+      + P "||" + P "&&" + S "-~+/*%=<>&.@|!"
+    )
+
+local Keyword =
+  K ( 'Keyword' ,
+      P "alignas" + P "asm" + P "auto" + P "break" + P "case" + P "catch"
+      + P "class" + P "const" + P "constexpr" + P "continue"
+      + P "decltype" + P "do" + P "else" + P "enum" + P "extern"
+      + P "for" + P "goto" + P "if" + P "nexcept" + P "private" + P "public"
+      + P "register" + P "restricted" + P "return" + P "static" + P "static_assert"
+      + P "struct" + P "switch" + P "thread_local" + P "throw" + P "try"
+      + P "typedef" + P "union" + P "using" + P "virtual" + P "volatile"
+      + P "while"
+    )
+  + K ( 'Keyword.Constant' ,
+        P "default" + P "false" + P "NULL" + P "nullptr" + P "true"
+      )
+
+local Builtin =
+  K ( 'Name.Builtin' ,
+      P "alignof" + P "malloc" + P "printf" + P "scanf" + P "sizeof"
+    )
+
+local Type =
+  K ( 'Name.Type' ,
+      P "bool" + P "char" + P "char16_t" + P "char32_t" + P "double"
+      + P "float" + P "int" + P "int8_t" + P "int16_t" + P "int32_t"
+      + P "int64_t" + P "long" + P "short" + P "signed" + P "unsigned"
+      + P "void" + P "wchar_t"
+    )
+
+local DefFunction =
+  Type
+  * Space
+  * K ( 'Name.Function.Internal' , identifier )
+  * SkipSpace
+  * # P "("
+local DefClass =
+  K ( 'Keyword' , P "class" ) * Space * K ( 'Name.Class' , identifier )
+local String =
+  WithStyle ( 'String.Long' ,
+      Q "\""
+      * ( VisualSpace
+          + K ( 'String.Interpol' ,
+                P "%" * ( S "difcspxXou" + P "ld" + P "li" + P "hd" + P "hi" )
+              )
+          + Q ( ( P "\\\"" + 1 - S " \"" ) ^ 1 )
+        ) ^ 0
+      * Q "\""
+    )
+local balanced_braces =
+  P { "E" ,
+       E =
+           (
+             P "{" * V "E" * P "}"
+             +
+             String
+             +
+             ( 1 - S "{}" )
+           ) ^ 0
+    }
+if piton_beamer
+then
+  Beamer =
+      L ( P "\\pause" * ( P "[" * ( 1 - P "]" ) ^ 0 * P "]" ) ^ -1 )
+    +
+      Ct ( Cc "Open"
+            * C (
+                  (
+                    P "\\uncover" + P "\\only" + P "\\alert" + P "\\visible"
+                    + P "\\invisible" + P "\\action"
+                  )
+                  * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1
+                  * P "{"
+                )
+            * Cc "}"
+         )
+       * ( C ( balanced_braces ) / (function (s) return MainLoopC:match(s) end ) )
+       * P "}" * Ct ( Cc "Close" )
+    + OneBeamerEnvironment ( "uncoverenv" , MainLoopC )
+    + OneBeamerEnvironment ( "onlyenv" , MainLoopC )
+    + OneBeamerEnvironment ( "visibleenv" , MainLoopC )
+    + OneBeamerEnvironment ( "invisibleenv" , MainLoopC )
+    + OneBeamerEnvironment ( "alertenv" , MainLoopC )
+    + OneBeamerEnvironment ( "actionenv" , MainLoopC )
+    +
+      L (
+          ( P "\\alt" )
+          * P "<" * (1 - P ">") ^ 0 * P ">"
+          * P "{"
+        )
+      * K ( 'ParseAgain.noCR' , balanced_braces )
+      * L ( P "}{" )
+      * K ( 'ParseAgain.noCR' , balanced_braces )
+      * L ( P "}" )
+    +
+      L (
+          ( P "\\temporal" )
+          * P "<" * (1 - P ">") ^ 0 * P ">"
+          * P "{"
+        )
+      * K ( 'ParseAgain.noCR' , balanced_braces )
+      * L ( P "}{" )
+      * K ( 'ParseAgain.noCR' , balanced_braces )
+      * L ( P "}{" )
+      * K ( 'ParseAgain.noCR' , balanced_braces )
+      * L ( P "}" )
+end
+local PromptHastyDetection = ( # ( P ">>>" + P "..." ) * Lc ( '\\__piton_prompt:' ) ) ^ -1
+local Prompt = K ( 'Prompt' , ( ( P ">>>" + P "..." ) * P " " ^ -1 ) ^ -1  )
+local EOL =
+  P "\r"
+  *
+  (
+    ( space^0 * -1 )
+    +
+    Ct (
+         Cc "EOL"
+         *
+         Ct (
+              Lc "\\__piton_end_line:"
+              * BeamerEndEnvironments
+              * BeamerBeginEnvironments
+              * PromptHastyDetection
+              * Lc "\\__piton_newline: \\__piton_begin_line:"
+              * Prompt
+            )
+       )
+  )
+  *
+  SpaceIndentation ^ 0
+local Preproc =
+  K ( 'Preproc' , P "#" * (1 - P "\r" ) ^ 0  ) * ( EOL + -1 )
+local CommentMath =
+  P "$" * K ( 'Comment.Math' , ( 1 - S "$\r" ) ^ 1  ) * P "$"
+
+local Comment =
+  WithStyle ( 'Comment' ,
+     Q ( P "//" )
+     * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0 )
+  * ( EOL + -1 )
+
+local LongComment =
+  WithStyle ( 'Comment' ,
+               Q ( P "/*" )
+               * ( CommentMath + Q ( ( 1 - P "*/" - S "$\r" ) ^ 1 ) + EOL ) ^ 0
+               * Q ( P "*/" )
+            ) -- $
+local CommentLaTeX =
+  P(piton.comment_latex)
+  * Lc "{\\PitonStyle{Comment.LaTeX}{\\ignorespaces"
+  * L ( ( 1 - P "\r" ) ^ 0 )
+  * Lc "}}"
+  * ( EOL + -1 )
+local MainC =
+       EOL
+     + Space
+     + Tab
+     + Escape + EscapeMath
+     + CommentLaTeX
+     + Beamer
+     + Preproc
+     + Comment + LongComment
+     + Delim
+     + Operator
+     + String
+     + Punct
+     + DefFunction
+     + DefClass
+     + Type * ( Q ( "*" ) ^ -1 + Space + Punct + Delim + EOL + -1 )
+     + Keyword * ( Space + Punct + Delim + EOL + -1 )
+     + Builtin * ( Space + Punct + Delim + EOL + -1 )
+     + Identifier
+     + Number
+     + Word
+MainLoopC =
+  (  ( space^1 * -1 )
+     + MainC
+  ) ^ 0
+languageC =
+  Ct (
+       ( ( space - P "\r" ) ^0 * P "\r" ) ^ -1
+       * BeamerBeginEnvironments
+       * PromptHastyDetection
+       * Lc '\\__piton_begin_line:'
+       * Prompt
+       * SpaceIndentation ^ 0
+       * MainLoopC
+       * -1
+       * Lc '\\__piton_end_line:'
+     )
+languages['c'] = languageC
+function piton.Parse(language,code)
+  local t = languages[language] : match ( code )
+  if t == nil
+  then
+    tex.sprint("\\PitonSyntaxError")
+    return -- to exit in force the function
+  end
+  local left_stack = {}
+  local right_stack = {}
+  for _ , one_item in ipairs(t)
+  do
+     if one_item[1] == "EOL"
+     then
+          for _ , s in ipairs(right_stack)
+            do tex.sprint(s)
+            end
+          for _ , s in ipairs(one_item[2])
+            do tex.tprint(s)
+            end
+          for _ , s in ipairs(left_stack)
+            do tex.sprint(s)
+            end
+     else
+          if one_item[1] == "Open"
+          then
+               tex.sprint( one_item[2] )
+               table.insert(left_stack,one_item[2])
+               table.insert(right_stack,one_item[3])
+          else
+               if one_item[1] == "Close"
+               then
+                    tex.sprint( right_stack[#right_stack] )
+                    left_stack[#left_stack] = nil
+                    right_stack[#right_stack] = nil
+               else
+                    tex.tprint(one_item)
+               end
+          end
+     end
+  end
+end
+function piton.ParseFile(language,name,first_line,last_line)
+  local s = ''
+  local i = 0
+  for line in io.lines(name)
+  do i = i + 1
+     if i >= first_line
+     then s = s .. '\r' .. line
+     end
+     if i >= last_line then break end
+  end
+  if string.byte(s,1) == 13
+  then if string.byte(s,2) == 239
+       then if string.byte(s,3) == 187
+            then if string.byte(s,4) == 191
+                 then s = string.sub(s,5,-1)
+                 end
+            end
+       end
+  end
+  piton.Parse(language,s)
+end
+function piton.ParseBis(language,code)
+  local s = ( Cs ( ( P '##' / '#' + 1 ) ^ 0 ) ) : match ( code )
+  return piton.Parse(language,s)
+end
+function piton.ParseTer(language,code)
+  local s = ( Cs ( ( P '\\__piton_breakable_space:' / ' ' + 1 ) ^ 0 ) )
+            : match ( code )
+  return piton.Parse(language,s)
+end
+local function gobble(n,code)
+  function concat(acc,new_value)
+    return acc .. new_value
+  end
+  if n==0
+  then return code
+  else
+       return Cf (
+                   Cc ( "" ) *
+                   ( 1 - P "\r" ) ^ (-n)  * C ( ( 1 - P "\r" ) ^ 0 )
+                     * ( C ( P "\r" )
+                     * ( 1 - P "\r" ) ^ (-n)
+                     * C ( ( 1 - P "\r" ) ^ 0 )
+                    ) ^ 0 ,
+                    concat
+                 ) : match ( code )
+  end
+end
+local function add(acc,new_value)
+  return acc + new_value
+end
+local AutoGobbleLPEG =
+    ( space ^ 0 * P "\r" ) ^ -1
+    * Cf (
+           (
+             ( P " " ) ^ 0 * P "\r"
+             +
+             Cf ( Cc(0) * ( P " " * Cc(1) ) ^ 0 , add )
+             * ( 1 - P " " ) * ( 1 - P "\r" ) ^ 0 * P "\r"
+           ) ^ 0
+           *
+           ( Cf ( Cc(0) * ( P " " * Cc(1) ) ^ 0 , add )
+           * ( 1 - P " " ) * ( 1 - P "\r" ) ^ 0 ) ^ -1 ,
+           math.min
+         )
+local TabsAutoGobbleLPEG =
+    ( space ^ 0 * P "\r" ) ^ -1
+    * Cf (
+           (
+             ( P "\t" ) ^ 0 * P "\r"
+             +
+             Cf ( Cc(0) * ( P "\t" * Cc(1) ) ^ 0 , add )
+             * ( 1 - P "\t" ) * ( 1 - P "\r" ) ^ 0 * P "\r"
+           ) ^ 0
+           *
+           ( Cf ( Cc(0) * ( P "\t" * Cc(1) ) ^ 0 , add )
+           * ( 1 - P "\t" ) * ( 1 - P "\r" ) ^ 0 ) ^ -1 ,
+           math.min
+         )
+local EnvGobbleLPEG =
+  ( ( 1 - P "\r" ) ^ 0 * P "\r" ) ^ 0
+    * Cf ( Cc(0) * ( P " " * Cc(1) ) ^ 0 , add ) * -1
+function piton.GobbleParse(language,n,code)
+  if n==-1
+  then n = AutoGobbleLPEG : match(code)
+  else if n==-2
+       then n = EnvGobbleLPEG : match(code)
+       else if n==-3
+            then n = TabsAutoGobbleLPEG : match(code)
+            end
+       end
+  end
+  piton.Parse(language,gobble(n,code))
+end
+function piton.CountLines(code)
+  local count = 0
+  for i in code : gmatch ( "\r" ) do count = count + 1 end
+  tex.sprint(
+      luatexbase.catcodetables.expl ,
+      '\\int_set:Nn \\l__piton_nb_lines_int {' .. count .. '}' )
+end
+function piton.CountNonEmptyLines(code)
+  local count = 0
+  count =
+  ( Cf (  Cc(0) *
+          (
+            ( P " " ) ^ 0 * P "\r"
+            + ( 1 - P "\r" ) ^ 0 * P "\r" * Cc(1)
+          ) ^ 0
+          * (1 - P "\r" ) ^ 0 ,
+         add
+       ) * -1 ) : match (code)
+  tex.sprint(
+      luatexbase.catcodetables.expl ,
+      '\\int_set:Nn \\l__piton_nb_non_empty_lines_int {' .. count .. '}' )
+end
+function piton.CountLinesFile(name)
+  local count = 0
+  for line in io.lines(name) do count = count + 1 end
+  tex.sprint(
+      luatexbase.catcodetables.expl ,
+      '\\int_set:Nn \\l__piton_nb_lines_int {' .. count .. '}' )
+end
+function piton.CountNonEmptyLinesFile(name)
+  local count = 0
+  for line in io.lines(name)
+  do if not ( ( ( P " " ) ^ 0 * -1 ) : match ( line ) )
+     then count = count + 1
+     end
+  end
+  tex.sprint(
+      luatexbase.catcodetables.expl ,
+      '\\int_set:Nn \\l__piton_nb_non_empty_lines_int {' .. count .. '}' )
+end
+function piton.ComputeRange(marker_beginning,marker_end,file_name)
+  local s = ( Cs ( ( P '##' / '#' + 1 ) ^ 0 ) ) : match ( marker_beginning )
+  local t = ( Cs ( ( P '##' / '#' + 1 ) ^ 0 ) ) : match ( marker_end )
+  local first_line = -1
+  local count = 0
+  local last_found = false
+  for line in io.lines(file_name)
+  do if first_line == -1
+     then if string.sub(line,1,#s) == s
+          then first_line = count
+          end
+     else if string.sub(line,1,#t) == t
+          then last_found = true
+               break
+          end
+     end
+     count = count + 1
+  end
+  if first_line == -1
+  then tex.sprint("\\PitonBeginMarkerNotFound")
+  else if last_found == false
+       then tex.sprint("\\PitonEndMarkerNotFound")
+       end
+  end
+  tex.sprint(
+      luatexbase.catcodetables.expl ,
+      '\\int_set:Nn \\l__piton_first_line_int {' .. first_line .. ' + 2 }'
+      .. '\\int_set:Nn \\l__piton_last_line_int {' .. count .. ' }' )
+end
+


Property changes on: trunk/Master/texmf-dist/tex/lualatex/piton/piton.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: trunk/Master/texmf-dist/tex/lualatex/piton/piton.sty
===================================================================
--- trunk/Master/texmf-dist/tex/lualatex/piton/piton.sty	2023-08-26 20:18:37 UTC (rev 68074)
+++ trunk/Master/texmf-dist/tex/lualatex/piton/piton.sty	2023-08-26 20:18:56 UTC (rev 68075)
@@ -4,7 +4,7 @@
 %%
 %% The original source files were:
 %%
-%% piton.dtx  (with options: `package')
+%% piton.dtx  (with options: `STY')
 %% 
 %% Copyright (C) 2022-2023 by F. Pantigny
 %% 
@@ -18,8 +18,8 @@
 %% and version 1.3 or later is part of all distributions of
 %% LaTeX version 2005/12/01 or later.
 %% 
-\def\myfileversion{2.0}
-\def\myfiledate{2023/08/01}
+\def\myfileversion{2.1}
+\def\myfiledate{2023/08/26}
 
 
 \NeedsTeXFormat{LaTeX2e}
@@ -29,7 +29,14 @@
   {\myfiledate}
   {\myfileversion}
   {Highlight Python codes with LPEG on LuaLaTeX}
-\msg_new:nnn { piton } { LuaLaTeX~mandatory }
+\cs_new_protected:Npn \__piton_error:n { \msg_error:nn { piton } }
+\cs_new_protected:Npn \__piton_warning:n { \msg_warning:nn { piton } }
+\cs_new_protected:Npn \__piton_error:nn { \msg_error:nnn { piton } }
+\cs_new_protected:Npn \__piton_error:nnn { \msg_error:nnnn { piton } }
+\cs_new_protected:Npn \__piton_fatal:n { \msg_fatal:nn { piton } }
+\cs_new_protected:Npn \__piton_fatal:nn { \msg_fatal:nnn { piton } }
+\cs_new_protected:Npn \__piton_msg_new:nn { \msg_new:nnn { piton } }
+\__piton_msg_new:nn { LuaLaTeX~mandatory }
   {
     LuaLaTeX~is~mandatory.\\
     The~package~'piton'~requires~the~engine~LuaLaTeX.\\
@@ -39,46 +46,58 @@
   }
 \sys_if_engine_luatex:F { \msg_critical:nn { piton } { LuaLaTeX~mandatory } }
 \RequirePackage { luatexbase }
-\bool_new:N \c__piton_footnotehyper_bool
-\bool_new:N \c__piton_footnote_bool
-\bool_new:N \c__piton_math_comments_bool
-\bool_new:N \c__piton_beamer_bool
+\__piton_msg_new:nn { piton.lua~not~found }
+  {
+    The~file~'piton.lua'~can't~be~found.\\
+    The package~'piton'~won't be loaded.
+  }
+\file_if_exist:nF { piton.lua }
+  { \msg_critical:nn { piton } { piton.lua~not~found } }
+\bool_new:N \g__piton_footnotehyper_bool
+\bool_new:N \g__piton_footnote_bool
+\bool_new:N \g__piton_math_comments_bool
+\bool_new:N \g__piton_beamer_bool
+\tl_new:N \g__piton_escape_inside_tl
 \keys_define:nn { piton / package }
   {
-    footnote .bool_set:N = \c__piton_footnote_bool ,
-    footnotehyper .bool_set:N = \c__piton_footnotehyper_bool ,
-    escape-inside .tl_set:N = \c__piton_escape_inside_tl ,
-    escape-inside .initial:n = ,
-    comment-latex .code:n = { \lua_now:n { comment_latex = "#1" } } ,
-    comment-latex .value_required:n = true ,
-    math-comments .bool_set:N = \c__piton_math_comments_bool ,
-    math-comments .default:n  = true ,
-    beamer        .bool_set:N = \c__piton_beamer_bool ,
-    beamer        .default:n = true ,
-    unknown .code:n = \msg_error:nn { piton } { unknown~key~for~package }
+    footnote .bool_gset:N = \g__piton_footnote_bool ,
+    footnotehyper .bool_gset:N = \g__piton_footnotehyper_bool ,
+
+    beamer .bool_gset:N = \g__piton_beamer_bool ,
+    beamer .default:n = true ,
+
+    escape-inside .code:n = \__piton_error:n { key-escape-inside-deleted } ,
+    math-comments .code:n = \__piton_error:n { moved~to~preamble } ,
+    comment-latex .code:n = \__piton_error:n { moved~to~preamble } ,
+
+    unknown .code:n = \__piton_error:n { Unknown~key~for~package }
   }
-\msg_new:nnn { piton } { unknown~key~for~package }
+\__piton_msg_new:nn { key-escape-inside-deleted }
   {
+    The~key~'escape-inside'~has~been~deleted.~You~must~now~use~
+    the~keys~'begin-escape'~and~'end-escape'~in~
+    \token_to_str:N \PitonOptions.\\
+    That~key~will~be~ignored.
+  }
+\__piton_msg_new:nn { moved~to~preamble }
+  {
+    The~key~'\l_keys_key_str'~*must*~now~be~used~with~
+    \token_to_str:N \PitonOptions`in~the~preamble~of~your~
+    document.\\
+    That~key~will~be~ignored.
+  }
+\__piton_msg_new:nn { Unknown~key~for~package }
+  {
     Unknown~key.\\
     You~have~used~the~key~'\l_keys_key_str'~but~the~only~keys~available~here~
-    are~'beamer',~'comment-latex',~'escape-inside',~'footnote',~'footnotehyper'~and~
-    'math-comments'.~Other~keys~are~available~in~\token_to_str:N \PitonOptions.\\
+    are~'beamer',~'footnote',~'footnotehyper'.~Other~keys~are~available~in~
+    \token_to_str:N \PitonOptions.\\
     That~key~will~be~ignored.
   }
 \ProcessKeysOptions { piton / package }
-\begingroup
-\cs_new_protected:Npn \__piton_set_escape_char:nn #1 #2
-  {
-    \lua_now:n { piton_begin_escape = "#1" }
-    \lua_now:n { piton_end_escape = "#2" }
-  }
-\cs_generate_variant:Nn \__piton_set_escape_char:nn { x x }
-\__piton_set_escape_char:xx
-  { \tl_head:V \c__piton_escape_inside_tl }
-  { \tl_tail:V \c__piton_escape_inside_tl }
-\endgroup
-\@ifclassloaded { beamer } { \bool_set_true:N \c__piton_beamer_bool } { }
-\bool_if:NT \c__piton_beamer_bool { \lua_now:n { piton_beamer = true } }
+\@ifclassloaded { beamer } { \bool_gset_true:N \g__piton_beamer_bool } { }
+\@ifpackageloaded { beamerarticle } { \bool_gset_true:N \g__piton_beamer_bool } { }
+\bool_if:NT \g__piton_beamer_bool { \lua_now:n { piton_beamer = true } }
 \hook_gput_code:nnn { begindocument } { . }
   {
     \@ifpackageloaded { xcolor }
@@ -85,13 +104,13 @@
       { }
       { \msg_fatal:nn { piton } { xcolor~not~loaded } }
   }
-\msg_new:nnn { piton } { xcolor~not~loaded }
+\__piton_msg_new:nn { xcolor~not~loaded }
   {
     xcolor~not~loaded \\
     The~package~'xcolor'~is~required~by~'piton'.\\
     This~error~is~fatal.
   }
-\msg_new:nnn { piton } { footnote~with~footnotehyper~package }
+\__piton_msg_new:nn { footnote~with~footnotehyper~package }
   {
     Footnote~forbidden.\\
     You~can't~use~the~option~'footnote'~because~the~package~
@@ -101,7 +120,7 @@
     of~the~package~footnotehyper.\\
     If~you~go~on,~the~package~footnote~won't~be~loaded.
   }
-\msg_new:nnn { piton } { footnotehyper~with~footnote~package }
+\__piton_msg_new:nn { footnotehyper~with~footnote~package }
   {
     You~can't~use~the~option~'footnotehyper'~because~the~package~
     footnote~has~already~been~loaded.~
@@ -110,10 +129,10 @@
     of~the~package~footnote.\\
     If~you~go~on,~the~package~footnotehyper~won't~be~loaded.
   }
-\bool_if:NT \c__piton_footnote_bool
+\bool_if:NT \g__piton_footnote_bool
   {
     \@ifclassloaded { beamer }
-      { \bool_set_false:N \c__piton_footnote_bool }
+      { \bool_gset_false:N \g__piton_footnote_bool }
       {
         \@ifpackageloaded { footnotehyper }
           { \__piton_error:n { footnote~with~footnotehyper~package } }
@@ -120,19 +139,23 @@
           { \usepackage { footnote } }
       }
   }
-\bool_if:NT \c__piton_footnotehyper_bool
+\bool_if:NT \g__piton_footnotehyper_bool
   {
     \@ifclassloaded { beamer }
-      { \bool_set_false:N \c__piton_footnote_bool }
+      { \bool_gset_false:N \g__piton_footnote_bool }
       {
         \@ifpackageloaded { footnote }
           { \__piton_error:n { footnotehyper~with~footnote~package } }
           { \usepackage { footnotehyper } }
-        \bool_set_true:N \c__piton_footnote_bool
+        \bool_gset_true:N \g__piton_footnote_bool
       }
   }
+\lua_now:n { piton = piton~or { } }
 \str_new:N \l__piton_language_str
 \str_set:Nn \l__piton_language_str { python }
+\bool_new:N \l__piton_in_PitonOptions_bool
+\bool_new:N \l__piton_in_PitonInputFile_bool
+\bool_new:N \g__piton_in_document_bool
 \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
@@ -141,6 +164,9 @@
 \int_set:Nn \l__piton_splittable_int { 100 }
 \clist_new:N \l__piton_bg_color_clist
 \tl_new:N \l__piton_prompt_bg_color_tl
+\str_new:N \l__piton_begin_range_str
+\str_new:N \l__piton_end_range_str
+\str_new:N \l__piton_file_name_str
 \int_new:N \g__piton_env_int
 \bool_new:N \l__piton_show_spaces_bool
 \bool_new:N \l__piton_break_lines_in_Piton_bool
@@ -194,12 +220,12 @@
           }
         \@esphack
      }
-     { \msg_error:nn { piton } { label~with~lines~numbers } }
+     { \__piton_error:n { label~with~lines~numbers } }
   }
-\cs_new_protected:Npn \__piton_open_brace:
-  { \directlua { piton.open_brace() } }
-\cs_new_protected:Npn \__piton_close_brace:
-  { \directlua { piton.close_brace() } }
+\cs_new_protected:Npn \__piton_marker_beginning:n #1 { }
+\cs_new_protected:Npn \__piton_marker_end:n #1 { }
+\cs_new_protected:Npn \__piton_open_brace: { \directlua { piton.open_brace() } }
+\cs_new_protected:Npn \__piton_close_brace: { \directlua { piton.close_brace() } }
 \tl_new:N \g__piton_begin_line_hook_tl
 \cs_new_protected:Npn \__piton_prompt:
   {
@@ -246,9 +272,22 @@
         \skip_horizontal:N \l__piton_left_margin_dim
         \bool_if:NT \l__piton_line_numbers_bool
           {
-            \bool_if:NF \l__piton_all_line_numbers_bool
-              { \tl_if_eq:nnF  { #1 } { \PitonStyle {Prompt}{} } }
+            \bool_if:nF
+              {
+                \str_if_eq_p:nn { #1 } { \PitonStyle {Prompt}{} }
+                &&
+                \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}{} }
+                ||
+                ( ! \l__piton_skip_empty_lines_bool && \l__piton_label_empty_lines_bool )
+              }
               \__piton_print_number:
+
           }
         \clist_if_empty:NF \l__piton_bg_color_clist
           {
@@ -321,9 +360,9 @@
           { \l__piton_nb_lines_int - \g__piton_line_int } > \l__piton_splittable_int
           {
             \egroup
-            \bool_if:NT \c__piton_footnote_bool { \end { savenotes } }
+            \bool_if:NT \g__piton_footnote_bool { \end { savenotes } }
             \par \mode_leave_vertical: % \newline
-            \bool_if:NT \c__piton_footnote_bool { \begin { savenotes } }
+            \bool_if:NT \g__piton_footnote_bool { \begin { savenotes } }
             \vtop \bgroup
           }
      }
@@ -355,10 +394,108 @@
       { \hbox { ~ } }
   }
 \bool_new:N \l__piton_line_numbers_bool
-\bool_new:N \l__piton_all_line_numbers_bool
+\bool_new:N \l__piton_skip_empty_lines_bool
+\bool_set_true:N \l__piton_skip_empty_lines_bool
+\bool_new:N \l__piton_line_numbers_absolute_bool
+\bool_new:N \l__piton_label_empty_lines_bool
+\bool_set_true:N \l__piton_label_empty_lines_bool
+\int_new:N \l__piton_number_lines_start_int
 \bool_new:N \l__piton_resume_bool
+\keys_define:nn { PitonOptions / marker }
+  {
+    beginning .code:n = \cs_set:Nn \__piton_marker_beginning:n { #1 } ,
+    beginning .value_required:n = true ,
+    end .code:n = \cs_set:Nn \__piton_marker_end:n { #1 } ,
+    end .value_required:n = true ,
+    include-lines .bool_set:N = \l__piton_marker_include_lines_bool ,
+    include-lines .default:n = true ,
+    unknown .code:n = \__piton_error:n { Unknown~key~for~marker }
+  }
+\keys_define:nn { PitonOptions / line-numbers }
+  {
+    true .code:n = \bool_set_true:N \l__piton_line_numbers_bool ,
+    false .code:n = \bool_set_false:N \l__piton_line_numbers_bool ,
+
+    start .code:n =
+      \bool_if:NTF \l__piton_in_PitonOptions_bool
+        { Invalid~key }
+        {
+          \bool_set_true:N \l__piton_line_numbers_bool
+          \int_set:Nn \l__piton_number_lines_start_int { #1 }
+        } ,
+    start .value_required:n = true ,
+
+    skip-empty-lines .code:n =
+      \bool_if:NF \l__piton_in_PitonOptions_bool
+        { \bool_set_true:N \l__piton_line_numbers_bool }
+      \str_if_eq:nnTF { #1 } { false }
+        { \bool_set_false:N \l__piton_skip_empty_lines_bool }
+        { \bool_set_true:N \l__piton_skip_empty_lines_bool } ,
+    skip-empty-lines .default:n = true ,
+
+    label-empty-lines .code:n =
+      \bool_if:NF \l__piton_in_PitonOptions_bool
+        { \bool_set_true:N \l__piton_line_numbers_bool }
+      \str_if_eq:nnTF { #1 } { false }
+        { \bool_set_false:N \l__piton_label_empty_lines_bool }
+        { \bool_set_true:N \l__piton_label_empty_lines_bool } ,
+    label-empty-lines .default:n = true ,
+
+    absolute .code:n =
+      \bool_if:NTF \l__piton_in_PitonOptions_bool
+        { \bool_set_true:N \l__piton_line_numbers_absolute_bool }
+        { \bool_set_true:N \l__piton_line_numbers_bool }
+      \bool_if:NT \l__piton_in_PitonInputFile_bool
+        {
+          \bool_set_true:N \l__piton_line_numbers_absolute_bool
+          \bool_set_false:N \l__piton_skip_empty_lines_bool
+        }
+      \bool_lazy_or:nnF
+        \l__piton_in_PitonInputFile_bool
+        \l__piton_in_PitonOptions_bool
+        { \__piton_error:n { Invalid~key } } ,
+    absolute .value_forbidden:n = true ,
+
+    resume .code:n =
+      \bool_set_true:N \l__piton_resume_bool
+      \bool_if:NF \l__piton_in_PitonOptions_bool
+        { \bool_set_true:N \l__piton_line_numbers_bool } ,
+    resume .value_forbidden:n = true ,
+
+    sep .dim_set:N = \l__piton_numbers_sep_dim ,
+    sep .value_required:n = true ,
+
+    unknown .code:n = \__piton_error:n { Unknown~key~for~line-numbers }
+  }
 \keys_define:nn { PitonOptions }
   {
+    begin-escape .code:n =
+      \lua_now:e { piton.begin_escape = "\lua_escape:n{#1}" } ,
+    begin-escape .value_required:n = true ,
+    begin-escape .usage:n = preamble ,
+
+    end-escape   .code:n =
+      \lua_now:e { piton.end_escape = "\lua_escape:n{#1}" } ,
+    end-escape   .value_required:n = true ,
+    end-escape .usage:n = preamble ,
+
+    begin-escape-math .code:n =
+      \lua_now:e { piton.begin_escape_math = "\lua_escape:n{#1}" } ,
+    begin-escape-math .value_required:n = true ,
+    begin-escape-math .usage:n = preamble ,
+
+    end-escape-math .code:n =
+      \lua_now:e { piton.end_escape_math = "\lua_escape:n{#1}" } ,
+    end-escape-math .value_required:n = true ,
+    end-escape-math .usage:n = preamble ,
+
+    comment-latex .code:n = \lua_now:n { comment_latex = "#1" } ,
+    comment-latex .value_required:n = true ,
+    comment-latex .usage:n = preamble ,
+
+    math-comments .bool_set:N = \g__piton_math_comments_bool ,
+    math-comments .default:n  = true ,
+    math-comments .usage:n = preamble ,
     language         .code:n =
       \str_set:Nx \l__piton_language_str { \str_lowercase:n { #1 } } ,
     language         .value_required:n  = true ,
@@ -370,14 +507,19 @@
     env-gobble       .value_forbidden:n = true ,
     tabs-auto-gobble .code:n            = \int_set:Nn \l__piton_gobble_int { -3 } ,
     tabs-auto-gobble .value_forbidden:n = true ,
-    line-numbers     .bool_set:N        = \l__piton_line_numbers_bool ,
-    line-numbers     .default:n         = true ,
-    all-line-numbers .code:n =
-      \bool_set_true:N \l__piton_line_numbers_bool
-      \bool_set_true:N \l__piton_all_line_numbers_bool ,
-    all-line-numbers .value_forbidden:n = true  ,
-    resume           .bool_set:N        = \l__piton_resume_bool ,
-    resume           .value_forbidden:n = true ,
+
+    marker .code:n =
+      \bool_lazy_or:nnTF
+        \l__piton_in_PitonInputFile_bool
+        \l__piton_in_PitonOptions_bool
+        { \keys_set:nn { PitonOptions / marker } { #1 } }
+        { \__piton_error:n { Invalid~key } } ,
+    marker .value_required:n = true ,
+
+    line-numbers .code:n =
+      \keys_set:nn { PitonOptions / line-numbers } { #1 } ,
+    line-numbers .default:n = true ,
+
     splittable       .int_set:N         = \l__piton_splittable_int ,
     splittable       .default:n         = 1 ,
     background-color .clist_set:N       = \l__piton_bg_color_clist ,
@@ -384,7 +526,8 @@
     background-color .value_required:n  = true ,
     prompt-background-color .tl_set:N         = \l__piton_prompt_bg_color_tl ,
     prompt-background-color .value_required:n = true ,
-    width            .code:n =
+
+    width .code:n =
       \str_if_eq:nnTF  { #1 } { min }
         {
           \bool_set_true:N \l__piton_width_min_bool
@@ -394,7 +537,8 @@
           \bool_set_false:N \l__piton_width_min_bool
           \dim_set:Nn \l__piton_width_dim { #1 }
         } ,
-    width            .value_required:n  = true ,
+    width .value_required:n  = true ,
+
     left-margin      .code:n =
       \str_if_eq:nnTF { #1 } { auto }
         {
@@ -406,8 +550,7 @@
           \bool_set_false:N \l__piton_left_margin_auto_bool
         } ,
     left-margin      .value_required:n  = true ,
-    numbers-sep      .dim_set:N         = \l__piton_numbers_sep_dim ,
-    numbers-sep      .value_required:n  = true ,
+
     tab-size         .code:n            = \__piton_set_tab_tl:n { #1 } ,
     tab-size         .value_required:n  = true ,
     show-spaces      .bool_set:N        = \l__piton_show_spaces_bool ,
@@ -428,17 +571,68 @@
     continuation-symbol .value_required:n = true ,
     continuation-symbol-on-indentation .tl_set:N = \l__piton_csoi_tl ,
     continuation-symbol-on-indentation .value_required:n = true ,
-    unknown          .code:n =
-      \msg_error:nn { piton } { Unknown~key~for~PitonOptions }
+
+    first-line .code:n = \__piton_in_PitonInputFile:n
+      { \int_set:Nn \l__piton_first_line_int { #1 } } ,
+    first-line .value_required:n = true ,
+
+    last-line .code:n = \__piton_in_PitonInputFile:n
+      { \int_set:Nn \l__piton_last_line_int { #1 } } ,
+    last-line .value_required:n = true ,
+
+    begin-range .code:n = \__piton_in_PitonInputFile:n
+      { \str_set:Nn \l__piton_begin_range_str { #1 } } ,
+    begin-range .value_required:n = true ,
+
+    end-range .code:n = \__piton_in_PitonInputFile:n
+      { \str_set:Nn \l__piton_end_range_str { #1 } } ,
+    end-range .value_required:n = true ,
+
+    range .code:n = \__piton_in_PitonInputFile:n
+      {
+        \str_set:Nn \l__piton_begin_range_str { #1 }
+        \str_set:Nn \l__piton_end_range_str { #1 }
+      } ,
+    range .value_required:n = true ,
+
+    resume .meta:n = line-numbers/resume ,
+
+    unknown .code:n = \__piton_error:n { Unknown~key~for~PitonOptions } ,
+
+    % deprecated
+    all-line-numbers .code:n =
+      \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
   }
-\NewDocumentCommand \PitonOptions { } { \keys_set:nn { PitonOptions } }
+\cs_new_protected:Npn \__piton_in_PitonInputFile:n #1
+  {
+    \bool_if:NTF \l__piton_in_PitonInputFile_bool
+      { #1 }
+      { \__piton_error:n { Invalid~key } }
+  }
+\NewDocumentCommand \PitonOptions { m }
+  {
+    \bool_set_true:N \l__piton_in_PitonOptions_bool
+    \keys_set:nn { PitonOptions } { #1 }
+    \bool_set_false:N \l__piton_in_PitonOptions_bool
+  }
+\hook_gput_code:nnn { begindocument } { . }
+  { \bool_gset_true:N \g__piton_in_document_bool }
 \int_new:N \g__piton_visual_line_int
 \cs_new_protected:Npn \__piton_print_number:
   {
-    \int_gincr:N \g__piton_visual_line_int
     \hbox_overlap_left:n
       {
-        { \color { gray } \footnotesize \int_to_arabic:n \g__piton_visual_line_int }
+        {
+          \color { gray }
+          \footnotesize
+          \int_to_arabic:n \g__piton_visual_line_int
+        }
         \skip_horizontal:N \l__piton_numbers_sep_dim
       }
   }
@@ -589,13 +783,6 @@
     \dim_zero:N \parindent
     \cs_set_eq:NN \label \__piton_label:n
   }
-\keys_define:nn { PitonInputFile }
-  {
-    first-line .int_set:N = \l__piton_first_line_int ,
-    first-line .value_required:n = true ,
-    last-line .int_set:N = \l__piton_last_line_int ,
-    last-line .value_required:n = true ,
-  }
 \cs_new_protected:Npn \__piton_compute_left_margin:nn #1 #2
   {
     \bool_lazy_and:nnT \l__piton_left_margin_auto_bool \l__piton_line_numbers_bool
@@ -603,12 +790,8 @@
         \hbox_set:Nn \l_tmpa_box
           {
             \footnotesize
-            \bool_if:NTF \l__piton_all_line_numbers_bool
+            \bool_if:NTF \l__piton_skip_empty_lines_bool
               {
-                \int_to_arabic:n
-                  { \g__piton_visual_line_int + \l__piton_nb_lines_int }
-              }
-              {
                 \lua_now:n
                   { piton.#1(token.scan_argument()) }
                   { #2 }
@@ -615,6 +798,10 @@
                 \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 }
+              }
            }
          \dim_set:Nn \l__piton_left_margin_dim
            { \box_wd:N \l_tmpa_box + \l__piton_numbers_sep_dim + 0.1 em }
@@ -663,7 +850,7 @@
             \__piton_compute_width:
             \ttfamily
             \dim_zero:N \parskip % added 2023/07/06
-            \bool_if:NT \c__piton_footnote_bool { \begin { savenotes } }
+            \bool_if:NT \g__piton_footnote_bool { \begin { savenotes } }
             \vtop \bgroup
             \lua_now:e
               {
@@ -677,7 +864,7 @@
               { ##1 }
             \vspace { 2.5 pt }
             \egroup
-            \bool_if:NT \c__piton_footnote_bool { \end { savenotes } }
+            \bool_if:NT \g__piton_footnote_bool { \end { savenotes } }
             \bool_if:NT \l__piton_width_min_bool \__piton_width_to_aux:
             \end { #1 }
             \__piton_write_aux:
@@ -686,6 +873,8 @@
       {
         #3
         \__piton_pre_env:
+        \int_compare:nNnT \l__piton_number_lines_start_int > 0
+          { \int_gset:Nn \g__piton_visual_line_int { \l__piton_number_lines_start_int - 1 } }
         \group_begin:
         \tl_map_function:nN
           { \ \\ \{ \} \$ \& \# \^ \_ \% \~ \^^I }
@@ -695,11 +884,11 @@
       { #4 }
     \AddToHook { env / #1 / begin } { \char_set_catcode_other:N \^^M }
   }
-\bool_if:NTF \c__piton_beamer_bool
+\bool_if:NTF \g__piton_beamer_bool
   {
     \NewPitonEnvironment { Piton } { d < > O { } }
       {
-        \PitonOptions { #2 }
+        \keys_set:nn { PitonOptions } { #2 }
         \IfValueTF { #1 }
           { \begin { uncoverenv } < #1 > }
           { \begin { uncoverenv } }
@@ -706,8 +895,9 @@
       }
       { \end { uncoverenv } }
   }
-  { \NewPitonEnvironment { Piton } { O { } }
-      { \PitonOptions { #1 } }
+  {
+    \NewPitonEnvironment { Piton } { O { } }
+      { \keys_set:nn { PitonOptions } { #1 } }
       { }
   }
 \NewDocumentCommand { \PitonInputFile } { d < > O { } m }
@@ -714,46 +904,96 @@
   {
     \file_if_exist:nTF { #3 }
       { \__piton_input_file:nnn { #1 } { #2 } { #3 } }
-      { \msg_error:nnn { piton } { unknown~file } { #3 } }
+      { \msg_error:nnn { piton } { Unknown~file } { #3 } }
   }
 \cs_new_protected:Npn \__piton_input_file:nnn #1 #2 #3
   {
+    \str_set:Nn \l__piton_file_name_str { #3 }
     \tl_if_novalue:nF { #1 }
       {
-        \bool_if:NTF \c__piton_beamer_bool
+        \bool_if:NTF \g__piton_beamer_bool
           { \begin { uncoverenv } < #1 > }
-          { \msg_error:nn { piton } { overlay~without~beamer } }
+          { \__piton_error:n { overlay~without~beamer } }
       }
     \group_begin:
       \int_zero_new:N \l__piton_first_line_int
       \int_zero_new:N \l__piton_last_line_int
       \int_set_eq:NN \l__piton_last_line_int \c_max_int
-      \keys_set:nn { PitonInputFile } { #2 }
+      \bool_set_true:N \l__piton_in_PitonInputFile_bool
+      \keys_set:nn { PitonOptions } { #2 }
+      \bool_if:NT \l__piton_line_numbers_absolute_bool
+        { \bool_set_false:N \l__piton_skip_empty_lines_bool }
+      \bool_if:nTF
+        {
+          (
+            \int_compare_p:nNn \l__piton_first_line_int > 0
+            || \int_compare_p:nNn \l__piton_last_line_int < \c_max_int
+          )
+          && ! \str_if_empty_p:N \l__piton_begin_range_str
+        }
+        {
+          \__piton_error:n { bad~range~specification }
+          \int_zero:N \l__piton_first_line_int
+          \int_set_eq:NN \l__piton_last_line_int \c_max_int
+        }
+        {
+          \str_if_empty:NF \l__piton_begin_range_str
+            {
+              \__piton_compute_range:
+              \bool_lazy_or:nnT
+                \l__piton_marker_include_lines_bool
+                { ! \str_if_eq_p:NN \l__piton_begin_range_str \l__piton_end_range_str }
+                {
+                  \int_decr:N \l__piton_first_line_int
+                  \int_incr:N \l__piton_last_line_int
+                }
+            }
+        }
       \__piton_pre_env:
+      \bool_if:NT \l__piton_line_numbers_absolute_bool
+        { \int_gset:Nn \g__piton_visual_line_int { \l__piton_first_line_int - 1 } }
+      \int_compare:nNnT \l__piton_number_lines_start_int > 0
+        {
+          \int_gset:Nn \g__piton_visual_line_int
+            { \l__piton_number_lines_start_int - 1 }
+        }
+      \int_compare:nNnT \g__piton_visual_line_int < 0
+        { \int_gzero:N \g__piton_visual_line_int  }
       \mode_if_vertical:TF \mode_leave_vertical: \newline
-      \lua_now:n { piton.CountLinesFile(token.scan_argument()) } { #3 }
+      \lua_now:e { piton.CountLinesFile('\l__piton_file_name_str') }
       \__piton_compute_left_margin:nn { CountNonEmptyLinesFile } { #3 }
       \__piton_compute_width:
       \ttfamily
-      \bool_if:NT \c__piton_footnote_bool { \begin { savenotes } }
+      \bool_if:NT \g__piton_footnote_bool { \begin { savenotes } }
       \vtop \bgroup
       \lua_now:e
         {
           piton.ParseFile(
-           '\l__piton_language_str',
-           token.scan_argument() ,
+           '\l__piton_language_str' ,
+           '\l__piton_file_name_str' ,
            \int_use:N \l__piton_first_line_int ,
            \int_use:N \l__piton_last_line_int )
         }
-        { #3 }
       \egroup
-      \bool_if:NT \c__piton_footnote_bool { \end { savenotes } }
+      \bool_if:NT \g__piton_footnote_bool { \end { savenotes } }
       \bool_if:NT \l__piton_width_min_bool \__piton_width_to_aux:
     \group_end:
     \tl_if_novalue:nF { #1 }
-      { \bool_if:NT \c__piton_beamer_bool { \end { uncoverenv } } }
+      { \bool_if:NT \g__piton_beamer_bool { \end { uncoverenv } } }
     \__piton_write_aux:
   }
+\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
+    \lua_now:e
+      {
+        piton.ComputeRange
+          ( '\l_tmpa_str' , '\l_tmpb_str' , '\l__piton_file_name_str' )
+      }
+  }
 \NewDocumentCommand { \PitonStyle } { m } { \use:c { pitonStyle #1 } }
 \NewDocumentCommand { \SetPitonStyle } { } { \keys_set:nn { piton / Styles } }
 \cs_new_protected:Npn \__piton_math_scantokens:n #1
@@ -812,7 +1052,7 @@
     ParseAgain.noCR .tl_set:c = pitonStyle ParseAgain.noCR ,
     ParseAgain.noCR .value_required:n = true ,
     unknown         .code:n =
-      \msg_error:nn { piton } { Unknown~key~for~SetPitonStyle }
+      \__piton_error:n { Unknown~key~for~SetPitonStyle }
   }
 \clist_gput_left:Nn \g__piton_styles_clist { String }
 \clist_gsort:Nn \g__piton_styles_clist
@@ -853,7 +1093,7 @@
     ParseAgain.noCR    = \__piton_piton_no_cr:n ,
     ParseAgain         = \__piton_piton:n ,
   }
-\bool_if:NT \c__piton_math_comments_bool { \SetPitonStyle { Comment.Math } }
+\bool_if:NT \g__piton_math_comments_bool { \SetPitonStyle { Comment.Math } }
 \cs_new_protected:Npn \__piton_identifier:n #1
   { \cs_if_exist_use:c { PitonIdentifier _ \l__piton_language_str _ #1 } { #1 } }
 \keys_define:nn { PitonOptions }
@@ -903,7 +1143,7 @@
     \token_to_str:N \piton\ but~there~is~no~environment~
     {piton}.~This~error~is~fatal.
   }
-\msg_new:nnn { piton } { Unknown~key~for~SetPitonStyle }
+\__piton_msg_new:nn { Unknown~key~for~SetPitonStyle }
   {
     The~style~'\l_keys_key_str'~is~unknown.\\
     This~key~will~be~ignored.\\
@@ -910,15 +1150,65 @@
     The~available~styles~are~(in~alphabetic~order):~
     \clist_use:Nnnn \g__piton_styles_clist { ~and~ } { ,~ } { ~and~ }.
   }
-\msg_new:nnn { piton } { syntax~error }
+\__piton_msg_new:nn { Invalid~key }
   {
+    Wrong~use~of~key.\\
+    You~can't~use~the~key~'\l_keys_key_str'~here.\\
+    That~key~will~be~ignored.
+  }
+\__piton_msg_new:nn { Unknown~key~for~line-numbers }
+  {
+    Unknown~key. \\
+    The~key~'line-numbers / \l_keys_key_str'~is~unknown.\\
+    The~available~keys~of~the~family~'line-numbers'~are~(in~
+    alphabetic~order):~
+    absolute,~false,~label-empty-lines,~resume,~skip-empty-lines,~
+    sep,~start~and~true.\\
+    That~key~will~be~ignored.
+  }
+\__piton_msg_new:nn { Unknown~key~for~marker }
+  {
+    Unknown~key. \\
+    The~key~'marker / \l_keys_key_str'~is~unknown.\\
+    The~available~keys~of~the~family~'marker'~are~(in~
+    alphabetic~order):~ beginning,~end~and~include-lines.\\
+    That~key~will~be~ignored.
+  }
+\__piton_msg_new:nn { bad~range~specification }
+  {
+    Incompatible~keys.\\
+    You~can't~specify~the~range~of~lines~to~include~by~using~both~
+    markers~and~explicit~number~of~lines.\\
+    Your~whole~file~'\l__piton_file_name_str'~will~be~included.
+  }
+\__piton_msg_new:nn { syntax~error }
+  {
     Your~code~is~not~syntactically~correct.\\
     It~won't~be~printed~in~the~PDF~file.
   }
 \NewDocumentCommand \PitonSyntaxError { }
-  { \msg_error:nn { piton } { syntax~error } }
-\msg_new:nnn { piton } { unknown~file }
+  { \__piton_error:n { syntax~error } }
+\__piton_msg_new:nn { begin~marker~not~found }
   {
+    Marker~not~found.\\
+    The~range~'\l__piton_begin_range_str'~provided~to~the~
+    command~\token_to_str:N \PitonInputFile\ has~not~been~found.~
+    The~whole~file~'\l__piton_file_name_str'~will~be~inserted.
+  }
+\__piton_msg_new:nn { end~marker~not~found }
+  {
+    Marker~not~found.\\
+    The~marker~of~end~of~the~range~'\l__piton_end_range_str'~
+    provided~to~the~command~\token_to_str:N \PitonInputFile\
+    has~not~been~found.~The~file~'\l__piton_file_name_str'~will~
+    be~inserted~till~the~end.
+  }
+\NewDocumentCommand \PitonBeginMarkerNotFound { }
+  { \__piton_error:n { begin~marker~not~found } }
+\NewDocumentCommand \PitonEndMarkerNotFound { }
+  { \__piton_error:n { end~marker~not~found } }
+\__piton_msg_new:nn { Unknown~file }
+  {
     Unknown~file. \\
     The~file~'#1'~is~unknown.\\
     Your~command~\token_to_str:N \PitonInputFile\ will~be~discarded.
@@ -932,7 +1222,6 @@
   }
   {
     The~available~keys~are~(in~alphabetic~order):~
-    all-line-numbers,~
     auto-gobble,~
     background-color,~
     break-lines,~
@@ -941,6 +1230,7 @@
     continuation-symbol,~
     continuation-symbol-on-indentation,~
     end-of-broken-line,~
+    end-range,~
     env-gobble,~
     gobble,~
     identifiers,~
@@ -947,7 +1237,8 @@
     indent-broken-lines,~
     language,~
     left-margin,~
-    line-numbers,~
+    line-numbers/,~
+    marker/,~
     prompt-background-color,~
     resume,~
     show-spaces,~
@@ -956,14 +1247,13 @@
     tabs-auto-gobble,~
     tab-size~and~width.
   }
-\msg_new:nnn { piton } { label~with~lines~numbers }
+\__piton_msg_new:nn { label~with~lines~numbers }
   {
     You~can't~use~the~command~\token_to_str:N \label\
-    because~the~key~'line-numbers'~(or~'all-line-numbers')~
-    is~not~active.\\
+    because~the~key~'line-numbers'~is~not~active.\\
     If~you~go~on,~that~command~will~ignored.
   }
-\msg_new:nnn { piton } { cr~not~allowed }
+\__piton_msg_new:nn { cr~not~allowed }
   {
     You~can't~put~any~carriage~return~in~the~argument~
     of~a~command~\c_backslash_str
@@ -972,7 +1262,7 @@
     corresponding~environment.\\
     That~error~is~fatal.
   }
-\msg_new:nnn { piton } { overlay~without~beamer }
+\__piton_msg_new:nn { overlay~without~beamer }
   {
     You~can't~use~an~argument~<...>~for~your~command~
     \token_to_str:N \PitonInputFile\ because~you~are~not~
@@ -979,1200 +1269,11 @@
     in~Beamer.\\
     If~you~go~on,~that~argument~will~be~ignored.
   }
-\msg_new:nnn { Piton } { Python~error }
+\__piton_msg_new:nn { Python~error }
   { A~Python~error~has~been~detected. }
-\ExplSyntaxOff
-\RequirePackage{luacode}
-\begin{luacode*}
-piton = piton or { }
-if piton.comment_latex == nil then piton.comment_latex = ">" end
-piton.comment_latex = "#" .. piton.comment_latex
-function piton.open_brace ()
-   tex.sprint("{")
-end
-function piton.close_brace ()
-   tex.sprint("}")
-end
-local P, S, V, C, Ct, Cc = lpeg.P, lpeg.S, lpeg.V, lpeg.C, lpeg.Ct, lpeg.Cc
-local Cf, Cs , Cg , Cmt , Cb = lpeg.Cf, lpeg.Cs, lpeg.Cg , lpeg.Cmt , lpeg.Cb
-local R = lpeg.R
-local function Q(pattern)
-  return Ct ( Cc ( luatexbase.catcodetables.CatcodeTableOther ) * C ( pattern ) )
-end
-local function L(pattern)
-  return Ct ( C ( pattern ) )
-end
-local function Lc(string)
-  return Cc ( { luatexbase.catcodetables.expl , string } )
-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
-     * Ct ( Cc "Close" )
-end
-local Escape =
-  P(piton_begin_escape)
-  * L ( ( 1 - P(piton_end_escape) ) ^ 1 )
-  * P(piton_end_escape)
-lpeg.locale(lpeg)
-local alpha, digit = lpeg.alpha, lpeg.digit
-local space = P " "
-local letter = alpha + P "_"
-  + P "â" + P "à" + P "ç" + P "é" + P "è" + P "ê" + P "ë" + P "ï" + P "î"
-  + P "ô" + P "û" + P "ü" + P "Â" + P "À" + P "Ç" + P "É" + P "È" + P "Ê"
-  + P "Ë" + P "Ï" + P "Î" + P "Ô" + P "Û" + P "Ü"
+\hook_gput_code:nnn { begindocument } { . }
+  { \lua_now:e { require("piton.lua") } }
 
-local alphanum = letter + digit
-local identifier = letter * alphanum ^ 0
-local Identifier = K ( 'Identifier' , identifier)
-local Number =
-  K ( 'Number' ,
-      ( digit^1 * P "." * digit^0 + digit^0 * P "." * digit^1 + digit^1 )
-      * ( S "eE" * S "+-" ^ -1 * digit^1 ) ^ -1
-      + digit^1
-    )
-local Word
-if piton_begin_escape ~= ''
-then Word = Q ( ( ( 1 - space - P(piton_begin_escape) - P(piton_end_escape) )
-                   - S "'\"\r[()]" - digit ) ^ 1 )
-else Word = Q ( ( ( 1 - space ) - S "'\"\r[()]" - digit ) ^ 1 )
-end
-local Space = ( Q " " ) ^ 1
-
-local SkipSpace = ( Q " " ) ^ 0
-
-local Punct = Q ( S ".,:;!" )
-
-local Tab = P "\t" * Lc ( '\\l__piton_tab_tl' )
-local SpaceIndentation = Lc ( '\\__piton_an_indentation_space:' ) * ( Q " " )
-local Delim = Q ( S "[()]" )
-local VisualSpace = space * Lc "\\l__piton_space_tl"
-local Beamer = P ( false )
-local BeamerBeginEnvironments = P ( true )
-local BeamerEndEnvironments = P ( true )
-if piton_beamer
-then
-  local BeamerNamesEnvironments =
-    P "uncoverenv" + P "onlyenv" + P "visibleenv" + P "invisibleenv"
-    + P "alertenv" + P "actionenv"
-  BeamerBeginEnvironments =
-      ( space ^ 0 *
-        L
-          (
-            P "\\begin{" * BeamerNamesEnvironments * "}"
-            * ( P "<" * ( 1 - P ">" ) ^ 0 * P ">" ) ^ -1
-          )
-        * P "\r"
-      ) ^ 0
-  BeamerEndEnvironments =
-      ( space ^ 0 *
-        L ( P "\\end{" * BeamerNamesEnvironments * P "}" )
-        * P "\r"
-      ) ^ 0
-  function OneBeamerEnvironment(name,lpeg)
-    return
-        Ct ( Cc "Open"
-              * C (
-                    P ( "\\begin{" .. name ..   "}" )
-                    * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1
-                  )
-             * Cc ( "\\end{" .. name ..  "}" )
-            )
-       * (
-           C ( ( 1 - P ( "\\end{" .. name .. "}" ) ) ^ 0 )
-           / ( function (s) return lpeg : match(s) end )
-         )
-       * P ( "\\end{" .. name ..  "}" ) * Ct ( Cc "Close" )
-  end
-end
-local languages = { }
-local Operator =
-  K ( 'Operator' ,
-      P "!=" + P "<>" + P "==" + P "<<" + P ">>" + P "<=" + P ">=" + P ":="
-      + P "//" + P "**" + S "-~+/*%=<>&.@|"
-    )
-
-local OperatorWord =
-  K ( 'Operator.Word' , P "in" + P "is" + P "and" + P "or" + P "not" )
-
-local Keyword =
-  K ( 'Keyword' ,
-      P "as" + P "assert" + P "break" + P "case" + P "class" + P "continue"
-      + P "def" + P "del" + P "elif" + P "else" + P "except" + P "exec"
-      + P "finally" + P "for" + P "from" + P "global" + P "if" + P "import"
-      + P "lambda" + P "non local" + P "pass" + P "return" + P "try"
-      + P "while" + P "with" + P "yield" + P "yield from" )
-  + K ( 'Keyword.Constant' ,P "True" + P "False" + P "None" )
-
-local Builtin =
-  K ( 'Name.Builtin' ,
-      P "__import__" + P "abs" + P "all" + P "any" + P "bin" + P "bool"
-    + P "bytearray" + P "bytes" + P "chr" + P "classmethod" + P "compile"
-    + P "complex" + P "delattr" + P "dict" + P "dir" + P "divmod"
-    + P "enumerate" + P "eval" + P "filter" + P "float" + P "format"
-    + P "frozenset" + P "getattr" + P "globals" + P "hasattr" + P "hash"
-    + P "hex" + P "id" + P "input" + P "int" + P "isinstance" + P "issubclass"
-    + P "iter" + P "len" + P "list" + P "locals" + P "map" + P "max"
-    + P "memoryview" + P "min" + P "next" + P "object" + P "oct" + P "open"
-    + P "ord" + P "pow" + P "print" + P "property" + P "range" + P "repr"
-    + P "reversed" + P "round" + P "set" + P "setattr" + P "slice" + P "sorted"
-    + P "staticmethod" + P "str" + P "sum" + P "super" + P "tuple" + P "type"
-    + P "vars" + P "zip" )
-
-local Exception =
-  K ( 'Exception' ,
-      P "ArithmeticError" + P "AssertionError" + P "AttributeError"
-   + P "BaseException" + P "BufferError" + P "BytesWarning" + P "DeprecationWarning"
-   + P "EOFError" + P "EnvironmentError" + P "Exception" + P "FloatingPointError"
-   + P "FutureWarning" + P "GeneratorExit" + P "IOError" + P "ImportError"
-   + P "ImportWarning" + P "IndentationError" + P "IndexError" + P "KeyError"
-   + P "KeyboardInterrupt" + P "LookupError" + P "MemoryError" + P "NameError"
-   + P "NotImplementedError" + P "OSError" + P "OverflowError"
-   + P "PendingDeprecationWarning" + P "ReferenceError" + P "ResourceWarning"
-   + P "RuntimeError" + P "RuntimeWarning" + P "StopIteration"
-   + P "SyntaxError" + P "SyntaxWarning" + P "SystemError" + P "SystemExit"
-   + P "TabError" + P "TypeError" + P "UnboundLocalError" + P "UnicodeDecodeError"
-   + P "UnicodeEncodeError" + P "UnicodeError" + P "UnicodeTranslateError"
-   + P "UnicodeWarning" + P "UserWarning" + P "ValueError" + P "VMSError"
-   + P "Warning" + P "WindowsError" + P "ZeroDivisionError"
-   + P "BlockingIOError" + P "ChildProcessError" + P "ConnectionError"
-   + P "BrokenPipeError" + P "ConnectionAbortedError" + P "ConnectionRefusedError"
-   + P "ConnectionResetError" + P "FileExistsError" + P "FileNotFoundError"
-   + P "InterruptedError" + P "IsADirectoryError" + P "NotADirectoryError"
-   + P "PermissionError" + P "ProcessLookupError" + P "TimeoutError"
-   + P "StopAsyncIteration" + P "ModuleNotFoundError" + P "RecursionError" )
-
-local RaiseException = K ( 'Keyword' , P "raise" ) * SkipSpace * Exception * Q ( P "(" )
-
-local Decorator = K ( 'Name.Decorator' , P "@" * letter^1  )
-local DefClass =
-  K ( 'Keyword' , P "class" ) * Space * K ( 'Name.Class' , identifier )
-local ImportAs =
-  K ( 'Keyword' , P "import" )
-   * Space
-   * K ( 'Name.Namespace' ,
-         identifier * ( P "." * identifier ) ^ 0 )
-   * (
-       ( Space * K ( 'Keyword' , P "as" ) * Space
-          * K ( 'Name.Namespace' , identifier ) )
-       +
-       ( SkipSpace * Q ( P "," ) * SkipSpace
-          * K ( 'Name.Namespace' , identifier ) ) ^ 0
-     )
-local FromImport =
-  K ( 'Keyword' , P "from" )
-    * Space * K ( 'Name.Namespace' , identifier )
-    * Space * K ( 'Keyword' , P "import" )
-local PercentInterpol =
-  K ( 'String.Interpol' ,
-      P "%"
-      * ( P "(" * alphanum ^ 1 * P ")" ) ^ -1
-      * ( S "-#0 +" ) ^ 0
-      * ( digit ^ 1 + P "*" ) ^ -1
-      * ( P "." * ( digit ^ 1 + P "*" ) ) ^ -1
-      * ( S "HlL" ) ^ -1
-      * S "sdfFeExXorgiGauc%"
-    )
-local SingleShortString =
-  WithStyle ( 'String.Short' ,
-         Q ( P "f'" + P "F'" )
-         * (
-             K ( 'String.Interpol' , P "{" )
-              * K ( 'Interpol.Inside' , ( 1 - S "}':" ) ^ 0  )
-              * Q ( P ":" * (1 - S "}:'") ^ 0 ) ^ -1
-              * K ( 'String.Interpol' , P "}" )
-             +
-             VisualSpace
-             +
-             Q ( ( P "\\'" + P "{{" + P "}}" + 1 - S " {}'" ) ^ 1 )
-           ) ^ 0
-         * Q ( P "'" )
-       +
-         Q ( P "'" + P "r'" + P "R'" )
-         * ( Q ( ( P "\\'" + 1 - S " '\r%" ) ^ 1 )
-             + VisualSpace
-             + PercentInterpol
-             + Q ( P "%" )
-           ) ^ 0
-         * Q ( P "'" ) )
-
-local DoubleShortString =
-  WithStyle ( 'String.Short' ,
-         Q ( P "f\"" + P "F\"" )
-         * (
-             K ( 'String.Interpol' , P "{" )
-               * Q ( ( 1 - S "}\":" ) ^ 0 , 'Interpol.Inside' )
-               * ( K ( 'String.Interpol' , P ":" ) * Q ( (1 - S "}:\"") ^ 0 ) ) ^ -1
-               * K ( 'String.Interpol' , P "}" )
-             +
-             VisualSpace
-             +
-             Q ( ( P "\\\"" + P "{{" + P "}}" + 1 - S " {}\"" ) ^ 1 )
-            ) ^ 0
-         * Q ( P "\"" )
-       +
-         Q ( P "\"" + P "r\"" + P "R\"" )
-         * ( Q ( ( P "\\\"" + 1 - S " \"\r%" ) ^ 1 )
-             + VisualSpace
-             + PercentInterpol
-             + Q ( P "%" )
-           ) ^ 0
-         * Q ( P "\"" ) )
-
-local ShortString = SingleShortString + DoubleShortString
-local balanced_braces =
-  P { "E" ,
-       E =
-           (
-             P "{" * V "E" * P "}"
-             +
-             ShortString
-             +
-             ( 1 - S "{}" )
-           ) ^ 0
-    }
-if piton_beamer
-then
-  Beamer =
-      L ( P "\\pause" * ( P "[" * ( 1 - P "]" ) ^ 0 * P "]" ) ^ -1 )
-    +
-      Ct ( Cc "Open"
-            * C (
-                  (
-                    P "\\uncover" + P "\\only" + P "\\alert" + P "\\visible"
-                    + P "\\invisible" + P "\\action"
-                  )
-                  * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1
-                  * P "{"
-                )
-            * Cc "}"
-         )
-       * ( C ( balanced_braces ) / (function (s) return MainLoopPython:match(s) end ) )
-       * P "}" * Ct ( Cc "Close" )
-    + OneBeamerEnvironment ( "uncoverenv" , MainLoopPython )
-    + OneBeamerEnvironment ( "onlyenv" , MainLoopPython )
-    + OneBeamerEnvironment ( "visibleenv" , MainLoopPython )
-    + OneBeamerEnvironment ( "invisibleenv" , MainLoopPython )
-    + OneBeamerEnvironment ( "alertenv" , MainLoopPython )
-    + OneBeamerEnvironment ( "actionenv" , MainLoopPython )
-    +
-      L (
-          ( P "\\alt" )
-          * P "<" * (1 - P ">") ^ 0 * P ">"
-          * P "{"
-        )
-      * K ( 'ParseAgain.noCR' , balanced_braces )
-      * L ( P "}{" )
-      * K ( 'ParseAgain.noCR' , balanced_braces )
-      * L ( P "}" )
-    +
-      L (
-          ( P "\\temporal" )
-          * P "<" * (1 - P ">") ^ 0 * P ">"
-          * P "{"
-        )
-      * K ( 'ParseAgain.noCR' , balanced_braces )
-      * L ( P "}{" )
-      * K ( 'ParseAgain.noCR' , balanced_braces )
-      * L ( P "}{" )
-      * K ( 'ParseAgain.noCR' , balanced_braces )
-      * L ( P "}" )
-end
-local PromptHastyDetection = ( # ( P ">>>" + P "..." ) * Lc ( '\\__piton_prompt:' ) ) ^ -1
-local Prompt = K ( 'Prompt' , ( ( P ">>>" + P "..." ) * P " " ^ -1 ) ^ -1  )
-local EOL =
-  P "\r"
-  *
-  (
-    ( space^0 * -1 )
-    +
-    Ct (
-         Cc "EOL"
-         *
-         Ct (
-              Lc "\\__piton_end_line:"
-              * BeamerEndEnvironments
-              * BeamerBeginEnvironments
-              * PromptHastyDetection
-              * Lc "\\__piton_newline: \\__piton_begin_line:"
-              * Prompt
-            )
-       )
-  )
-  *
-  SpaceIndentation ^ 0
-local SingleLongString =
-  WithStyle ( 'String.Long' ,
-     ( Q ( S "fF" * P "'''" )
-         * (
-             K ( 'String.Interpol' , P "{"  )
-               * K ( 'Interpol.Inside' , ( 1 - S "}:\r" - P "'''" ) ^ 0  )
-               * Q ( P ":" * (1 - S "}:\r" - P "'''" ) ^ 0 ) ^ -1
-               * K ( 'String.Interpol' , P "}"  )
-             +
-             Q ( ( 1 - P "'''" - S "{}'\r" ) ^ 1 )
-             +
-             EOL
-           ) ^ 0
-       +
-         Q ( ( S "rR" ) ^ -1  * P "'''" )
-         * (
-             Q ( ( 1 - P "'''" - S "\r%" ) ^ 1 )
-             +
-             PercentInterpol
-             +
-             P "%"
-             +
-             EOL
-           ) ^ 0
-      )
-      * Q ( P "'''" ) )
-
-local DoubleLongString =
-  WithStyle ( 'String.Long' ,
-     (
-        Q ( S "fF" * P "\"\"\"" )
-        * (
-            K ( 'String.Interpol', P "{"  )
-              * K ( 'Interpol.Inside' , ( 1 - S "}:\r" - P "\"\"\"" ) ^ 0 )
-              * Q ( P ":" * (1 - S "}:\r" - P "\"\"\"" ) ^ 0 ) ^ -1
-              * K ( 'String.Interpol' , P "}"  )
-            +
-            Q ( ( 1 - P "\"\"\"" - S "{}\"\r" ) ^ 1 )
-            +
-            EOL
-          ) ^ 0
-      +
-        Q ( ( S "rR" ) ^ -1  * P "\"\"\"" )
-        * (
-            Q ( ( 1 - P "\"\"\"" - S "%\r" ) ^ 1 )
-            +
-            PercentInterpol
-            +
-            P "%"
-            +
-            EOL
-          ) ^ 0
-     )
-     * Q ( P "\"\"\"" )
-  )
-local LongString = SingleLongString + DoubleLongString
-local StringDoc =
-    K ( 'String.Doc' , P "\"\"\"" )
-      * ( K ( 'String.Doc' , (1 - P "\"\"\"" - P "\r" ) ^ 0  ) * EOL
-          * Tab ^ 0
-        ) ^ 0
-      * K ( 'String.Doc' , ( 1 - P "\"\"\"" - P "\r" ) ^ 0 * P "\"\"\"" )
-local CommentMath =
-  P "$" * K ( 'Comment.Math' , ( 1 - S "$\r" ) ^ 1  ) * P "$"
-
-local Comment =
-  WithStyle ( 'Comment' ,
-     Q ( P "#" )
-     * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0 )
-  * ( EOL + -1 )
-local CommentLaTeX =
-  P(piton.comment_latex)
-  * Lc "{\\PitonStyle{Comment.LaTeX}{\\ignorespaces"
-  * L ( ( 1 - P "\r" ) ^ 0 )
-  * Lc "}}"
-  * ( EOL + -1 )
-local expression =
-  P { "E" ,
-       E = ( P "'" * ( P "\\'" + 1 - S "'\r" ) ^ 0 * P "'"
-             + P "\"" * (P "\\\"" + 1 - S "\"\r" ) ^ 0 * P "\""
-             + P "{" * V "F" * P "}"
-             + P "(" * V "F" * P ")"
-             + P "[" * V "F" * P "]"
-             + ( 1 - S "{}()[]\r," ) ) ^ 0 ,
-       F = ( P "{" * V "F" * P "}"
-             + P "(" * V "F" * P ")"
-             + P "[" * V "F" * P "]"
-             + ( 1 - S "{}()[]\r\"'" ) ) ^ 0
-    }
-local Param =
-  SkipSpace * Identifier * SkipSpace
-   * (
-         K ( 'InitialValues' , P "=" * expression )
-       + Q ( P ":" ) * SkipSpace * K ( 'Name.Type' , letter ^ 1  )
-     ) ^ -1
-local Params = ( Param * ( Q "," * Param ) ^ 0 ) ^ -1
-local DefFunction =
-  K ( 'Keyword' , P "def" )
-  * Space
-  * K ( 'Name.Function.Internal' , identifier )
-  * SkipSpace
-  * Q ( P "(" ) * Params * Q ( P ")" )
-  * SkipSpace
-  * ( Q ( P "->" ) * SkipSpace * K ( 'Name.Type' , identifier  ) ) ^ -1
-  * K ( 'ParseAgain' , ( 1 - S ":\r" )^0  )
-  * Q ( P ":" )
-  * ( SkipSpace
-      * ( EOL + CommentLaTeX + Comment ) -- in all cases, that contains an EOL
-      * Tab ^ 0
-      * SkipSpace
-      * StringDoc ^ 0 -- there may be additionnal docstrings
-    ) ^ -1
-local ExceptionInConsole = Exception *  Q ( ( 1 - P "\r" ) ^ 0 ) * EOL
-local MainPython =
-       EOL
-     + Space
-     + Tab
-     + Escape
-     + CommentLaTeX
-     + Beamer
-     + LongString
-     + Comment
-     + ExceptionInConsole
-     + Delim
-     + Operator
-     + OperatorWord * ( Space + Punct + Delim + EOL + -1 )
-     + ShortString
-     + Punct
-     + FromImport
-     + RaiseException
-     + DefFunction
-     + DefClass
-     + Keyword * ( Space + Punct + Delim + EOL + -1 )
-     + Decorator
-     + Builtin * ( Space + Punct + Delim + EOL + -1 )
-     + Identifier
-     + Number
-     + Word
-MainLoopPython =
-  (  ( space^1 * -1 )
-     + MainPython
-  ) ^ 0
-local python = P ( true )
-
-python =
-  Ct (
-       ( ( space - P "\r" ) ^0 * P "\r" ) ^ -1
-       * BeamerBeginEnvironments
-       * PromptHastyDetection
-       * Lc '\\__piton_begin_line:'
-       * Prompt
-       * SpaceIndentation ^ 0
-       * MainLoopPython
-       * -1
-       * Lc '\\__piton_end_line:'
-     )
-languages['python'] = python
-local Delim = Q ( P "[|" + 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" + P "_") * ( R "az" + R "AZ" + S "_'" + digit ) ^ 0
-local Identifier = K ( 'Identifier' , identifier )
-local expression_for_fields =
-  P { "E" ,
-       E = ( P "{" * V "F" * P "}"
-             + P "(" * V "F" * P ")"
-             + P "[" * V "F" * P "]"
-             + P "\"" * (P "\\\"" + 1 - S "\"\r" )^0 * P "\""
-             + P "'" * ( P "\\'" + 1 - S "'\r" )^0 * P "'"
-             + ( 1 - S "{}()[]\r;" ) ) ^ 0 ,
-       F = ( P "{" * V "F" * P "}"
-             + P "(" * V "F" * P ")"
-             + P "[" * V "F" * P "]"
-             + ( 1 - S "{}()[]\r\"'" ) ) ^ 0
-    }
-local OneFieldDefinition =
-    ( K ( 'KeyWord' , P "mutable" ) * SkipSpace ) ^ -1
-  * K ( 'Name.Field' , identifier ) * SkipSpace
-  * Q ":" * SkipSpace
-  * K ( 'Name.Type' , expression_for_fields )
-  * SkipSpace
-
-local OneField =
-    K ( 'Name.Field' , identifier ) * SkipSpace
-  * Q "=" * SkipSpace
-  * ( C ( expression_for_fields ) / ( function (s) return LoopOCaml:match(s) end ) )
-  * SkipSpace
-
-local Record =
-  Q "{" * SkipSpace
-  *
-    (
-      OneFieldDefinition * ( Q ";" * SkipSpace * OneFieldDefinition ) ^ 0
-      +
-      OneField * ( Q ";" * SkipSpace * OneField ) ^ 0
-    )
-  *
-  Q "}"
-local DotNotation =
-  (
-      K ( 'Name.Module' , cap_identifier )
-        * Q "."
-        * ( Identifier + Constructor + Q "(" + Q "[" + Q "{" )
-
-      +
-      Identifier
-        * Q "."
-        * K ( 'Name.Field' , identifier )
-  )
-  * ( Q "." * K ( 'Name.Field' , identifier ) ) ^ 0
-local Operator =
-  K ( 'Operator' ,
-      P "!=" + P "<>" + P "==" + P "<<" + P ">>" + P "<=" + P ">=" + P ":="
-      + P "||" + P "&&" + P "//" + P "**" + P ";;" + P "::" + P "->"
-      + P "+." + P "-." + P "*." + P "/."
-      + S "-~+/*%=<>&@|"
-    )
-
-local OperatorWord =
-  K ( 'Operator.Word' ,
-      P "and" + P "asr" + P "land" + P "lor" + P "lsl" + P "lxor"
-      + P "mod" + P "or" )
-
-local Keyword =
-  K ( 'Keyword' ,
-      P "assert" + P "as" + P "begin" + P "class" + P "constraint" + P "done"
-  + P "downto" + P "do" + P "else" + P "end" + P "exception" + P "external"
-  + P "for" + P "function" + P "functor" + P "fun"  + P "if"
-  + P "include" + P "inherit" + P "initializer" + P "in"  + P "lazy" + P "let"
-  + P "match" + P "method" + P "module" + P "mutable" + P "new" + P "object"
-  + P "of" + P "open" + P "private" + P "raise" + P "rec" + P "sig"
-  + P "struct" + P "then" + P "to" + P "try" + P "type"
-  + P "value" + P "val" + P "virtual" + P "when" + P "while" + P "with" )
-  + K ( 'Keyword.Constant' , P "true" + P "false" )
-
-local Builtin =
-  K ( 'Name.Builtin' , P "not" + P "incr" + P "decr" + P "fst" + P "snd" )
-local Exception =
-  K (   'Exception' ,
-       P "Division_by_zero" + P "End_of_File" + P "Failure"
-     + P "Invalid_argument" + P "Match_failure" + P "Not_found"
-     + P "Out_of_memory" + P "Stack_overflow" + P "Sys_blocked_io"
-     + P "Sys_error" + P "Undefined_recursive_module" )
-local Char =
-  K ( 'String.Short' , P "'" * ( ( 1 - P "'" ) ^ 0 + P "\\'" ) * P "'" )
-local balanced_braces =
-  P { "E" ,
-       E =
-           (
-             P "{" * V "E" * P "}"
-             +
-             P "\"" * ( 1 - S "\"" ) ^ 0 * P "\""  -- OCaml strings
-             +
-             ( 1 - S "{}" )
-           ) ^ 0
-    }
-if piton_beamer
-then
-  Beamer =
-      L ( P "\\pause" * ( P "[" * ( 1 - P "]" ) ^ 0 * P "]" ) ^ -1 )
-    +
-      Ct ( Cc "Open"
-            * C (
-                  (
-                    P "\\uncover" + P "\\only" + P "\\alert" + P "\\visible"
-                    + P "\\invisible" + P "\\action"
-                  )
-                  * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1
-                  * P "{"
-                )
-            * Cc "}"
-         )
-       * ( C ( balanced_braces ) / (function (s) return MainLoopOCaml:match(s) end ) )
-       * P "}" * Ct ( Cc "Close" )
-    + OneBeamerEnvironment ( "uncoverenv" , MainLoopOCaml )
-    + OneBeamerEnvironment ( "onlyenv" , MainLoopOCaml )
-    + OneBeamerEnvironment ( "visibleenv" , MainLoopOCaml )
-    + OneBeamerEnvironment ( "invisibleenv" , MainLoopOCaml )
-    + OneBeamerEnvironment ( "alertenv" , MainLoopOCaml )
-    + OneBeamerEnvironment ( "actionenv" , MainLoopOCaml )
-    +
-      L (
-          ( P "\\alt" )
-          * P "<" * (1 - P ">") ^ 0 * P ">"
-          * P "{"
-        )
-      * K ( 'ParseAgain.noCR' , balanced_braces )
-      * L ( P "}{" )
-      * K ( 'ParseAgain.noCR' , balanced_braces )
-      * L ( P "}" )
-    +
-      L (
-          ( P "\\temporal" )
-          * P "<" * (1 - P ">") ^ 0 * P ">"
-          * P "{"
-        )
-      * K ( 'ParseAgain.noCR' , balanced_braces )
-      * L ( P "}{" )
-      * K ( 'ParseAgain.noCR' , balanced_braces )
-      * L ( P "}{" )
-      * K ( 'ParseAgain.noCR' , balanced_braces )
-      * L ( P "}" )
-end
-local EOL =
-  P "\r"
-  *
-  (
-    ( space^0 * -1 )
-    +
-    Ct (
-         Cc "EOL"
-         *
-         Ct (
-              Lc "\\__piton_end_line:"
-              * BeamerEndEnvironments
-              * BeamerBeginEnvironments
-              * PromptHastyDetection
-              * Lc "\\__piton_newline: \\__piton_begin_line:"
-              * Prompt
-            )
-       )
-  )
-  *
-  SpaceIndentation ^ 0
-local ocaml_string =
-       Q ( P "\"" )
-     * (
-         VisualSpace
-         +
-         Q ( ( 1 - S " \"\r" ) ^ 1 )
-         +
-         EOL
-       ) ^ 0
-     * Q ( P "\"" )
-local String = WithStyle ( 'String.Long' , ocaml_string )
-local ext = ( R "az" + P "_" ) ^ 0
-local open = "{" * Cg(ext, 'init') * "|"
-local close = "|" * C(ext) * "}"
-local closeeq =
-  Cmt ( close * Cb('init'),
-        function (s, i, a, b) return a==b end )
-local QuotedStringBis =
-  WithStyle ( 'String.Long' ,
-      (
-        VisualSpace
-        +
-        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 - P "(*" - P "*)" - S "\r$\"" ) ^ 1 ) -- $
-                 + ocaml_string
-                 + P "$" * K ( 'Comment.Math' , ( 1 - S "$\r" ) ^ 1 ) * P "$" -- $
-                 + EOL
-               ) ^ 0
-             * Q "*)"
-       }   )
-local balanced_parens =
-  P { "E" ,
-       E =
-           (
-             P "(" * V "E" * P ")"
-             +
-             ( 1 - S "()" )
-           ) ^ 0
-    }
-local Argument =
-  K ( 'Identifier' , identifier )
-  + Q "(" * SkipSpace
-    * K ( 'Identifier' , identifier ) * SkipSpace
-    * Q ":" * SkipSpace
-    * K ( 'Name.Type' , balanced_parens ) * SkipSpace
-    * Q ")"
-local DefFunction =
-  K ( 'Keyword' , P "let open" )
-   * Space
-   * K ( 'Name.Module' , cap_identifier )
-  +
-  K ( 'Keyword' , P "let rec" + P "let" + P "and" )
-    * Space
-    * K ( 'Name.Function.Internal' , identifier )
-    * Space
-    * (
-        Q "=" * SkipSpace * K ( 'Keyword' , P "function" )
-        +
-        Argument
-         * ( SkipSpace * Argument ) ^ 0
-         * (
-             SkipSpace
-             * Q ":"
-             * K ( 'Name.Type' , ( 1 - P "=" ) ^ 0 )
-           ) ^ -1
-      )
-local DefModule =
-  K ( 'Keyword' , P "module" ) * Space
-  *
-    (
-          K ( 'Keyword' , P "type" ) * Space
-        * K ( 'Name.Type' , cap_identifier )
-      +
-        K ( 'Name.Module' , cap_identifier ) * SkipSpace
-        *
-          (
-            Q "(" * SkipSpace
-              * K ( 'Name.Module' , cap_identifier ) * SkipSpace
-              * Q ":" * SkipSpace
-              * K ( 'Name.Type' , cap_identifier ) * SkipSpace
-              *
-                (
-                  Q "," * SkipSpace
-                    * K ( 'Name.Module' , cap_identifier ) * SkipSpace
-                    * Q ":" * SkipSpace
-                    * K ( 'Name.Type' , cap_identifier ) * SkipSpace
-                ) ^ 0
-              * Q ")"
-          ) ^ -1
-        *
-          (
-            Q "=" * SkipSpace
-            * K ( 'Name.Module' , cap_identifier )  * SkipSpace
-            * Q "("
-            * K ( 'Name.Module' , cap_identifier ) * SkipSpace
-              *
-              (
-                Q ","
-                *
-                K ( 'Name.Module' , cap_identifier ) * SkipSpace
-              ) ^ 0
-            * Q ")"
-          ) ^ -1
-    )
-  +
-  K ( 'Keyword' , P "include" + P "open" )
-  * Space * K ( 'Name.Module' , cap_identifier )
-local TypeParameter = K ( 'TypeParameter' , P "'" * alpha * # ( 1 - P "'" ) )
-MainOCaml =
-       EOL
-     + Space
-     + Tab
-     + Escape
-     + Beamer
-     + TypeParameter
-     + String + QuotedString + Char
-     + Comment
-     + Delim
-     + Operator
-     + Punct
-     + FromImport
-     + Exception
-     + DefFunction
-     + DefModule
-     + Record
-     + Keyword * ( Space + Punct + Delim + EOL + -1 )
-     + OperatorWord * ( Space + Punct + Delim + EOL + -1 )
-     + Builtin * ( Space + Punct + Delim + EOL + -1 )
-     + DotNotation
-     + Constructor
-     + Identifier
-     + Number
-     + Word
-
-LoopOCaml = MainOCaml ^ 0
-
-MainLoopOCaml =
-  (  ( space^1 * -1 )
-     + MainOCaml
-  ) ^ 0
-local ocaml = P ( true )
-
-ocaml =
-  Ct (
-       ( ( space - P "\r" ) ^0 * P "\r" ) ^ -1
-       * BeamerBeginEnvironments
-       * Lc ( '\\__piton_begin_line:' )
-       * SpaceIndentation ^ 0
-       * MainLoopOCaml
-       * -1
-       * Lc ( '\\__piton_end_line:' )
-     )
-languages['ocaml'] = ocaml
-local Operator =
-  K ( 'Operator' ,
-      P "!=" + P "==" + P "<<" + P ">>" + P "<=" + P ">="
-      + P "||" + P "&&" + S "-~+/*%=<>&.@|!"
-    )
-
-local Keyword =
-  K ( 'Keyword' ,
-      P "alignas" + P "asm" + P "auto" + P "break" + P "case" + P "catch"
-      + P "class" + P "const" + P "constexpr" + P "continue"
-      + P "decltype" + P "do" + P "else" + P "enum" + P "extern"
-      + P "for" + P "goto" + P "if" + P "nexcept" + P "private" + P "public"
-      + P "register" + P "restricted" + P "return" + P "static" + P "static_assert"
-      + P "struct" + P "switch" + P "thread_local" + P "throw" + P "try"
-      + P "typedef" + P "union" + P "using" + P "virtual" + P "volatile"
-      + P "while"
-    )
-  + K ( 'Keyword.Constant' ,
-        P "default" + P "false" + P "NULL" + P "nullptr" + P "true"
-      )
-
-local Builtin =
-  K ( 'Name.Builtin' ,
-      P "alignof" + P "malloc" + P "printf" + P "scanf" + P "sizeof"
-    )
-
-local Type =
-  K ( 'Name.Type' ,
-      P "bool" + P "char" + P "char16_t" + P "char32_t" + P "double"
-      + P "float" + P "int" + P "int8_t" + P "int16_t" + P "int32_t"
-      + P "int64_t" + P "long" + P "short" + P "signed" + P "unsigned"
-      + P "void" + P "wchar_t"
-    )
-
-local DefFunction =
-  Type
-  * Space
-  * K ( 'Name.Function.Internal' , identifier )
-  * SkipSpace
-  * # P "("
-local DefClass =
-  K ( 'Keyword' , P "class" ) * Space * K ( 'Name.Class' , identifier )
-local String =
-  WithStyle ( 'String.Long' ,
-      Q "\""
-      * ( VisualSpace
-          + K ( 'String.Interpol' ,
-                P "%" * ( S "difcspxXou" + P "ld" + P "li" + P "hd" + P "hi" )
-              )
-          + Q ( ( P "\\\"" + 1 - S " \"" ) ^ 1 )
-        ) ^ 0
-      * Q "\""
-    )
-local balanced_braces =
-  P { "E" ,
-       E =
-           (
-             P "{" * V "E" * P "}"
-             +
-             String
-             +
-             ( 1 - S "{}" )
-           ) ^ 0
-    }
-if piton_beamer
-then
-  Beamer =
-      L ( P "\\pause" * ( P "[" * ( 1 - P "]" ) ^ 0 * P "]" ) ^ -1 )
-    +
-      Ct ( Cc "Open"
-            * C (
-                  (
-                    P "\\uncover" + P "\\only" + P "\\alert" + P "\\visible"
-                    + P "\\invisible" + P "\\action"
-                  )
-                  * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1
-                  * P "{"
-                )
-            * Cc "}"
-         )
-       * ( C ( balanced_braces ) / (function (s) return MainLoopC:match(s) end ) )
-       * P "}" * Ct ( Cc "Close" )
-    + OneBeamerEnvironment ( "uncoverenv" , MainLoopC )
-    + OneBeamerEnvironment ( "onlyenv" , MainLoopC )
-    + OneBeamerEnvironment ( "visibleenv" , MainLoopC )
-    + OneBeamerEnvironment ( "invisibleenv" , MainLoopC )
-    + OneBeamerEnvironment ( "alertenv" , MainLoopC )
-    + OneBeamerEnvironment ( "actionenv" , MainLoopC )
-    +
-      L (
-          ( P "\\alt" )
-          * P "<" * (1 - P ">") ^ 0 * P ">"
-          * P "{"
-        )
-      * K ( 'ParseAgain.noCR' , balanced_braces )
-      * L ( P "}{" )
-      * K ( 'ParseAgain.noCR' , balanced_braces )
-      * L ( P "}" )
-    +
-      L (
-          ( P "\\temporal" )
-          * P "<" * (1 - P ">") ^ 0 * P ">"
-          * P "{"
-        )
-      * K ( 'ParseAgain.noCR' , balanced_braces )
-      * L ( P "}{" )
-      * K ( 'ParseAgain.noCR' , balanced_braces )
-      * L ( P "}{" )
-      * K ( 'ParseAgain.noCR' , balanced_braces )
-      * L ( P "}" )
-end
-local PromptHastyDetection = ( # ( P ">>>" + P "..." ) * Lc ( '\\__piton_prompt:' ) ) ^ -1
-local Prompt = K ( 'Prompt' , ( ( P ">>>" + P "..." ) * P " " ^ -1 ) ^ -1  )
-local EOL =
-  P "\r"
-  *
-  (
-    ( space^0 * -1 )
-    +
-    Ct (
-         Cc "EOL"
-         *
-         Ct (
-              Lc "\\__piton_end_line:"
-              * BeamerEndEnvironments
-              * BeamerBeginEnvironments
-              * PromptHastyDetection
-              * Lc "\\__piton_newline: \\__piton_begin_line:"
-              * Prompt
-            )
-       )
-  )
-  *
-  SpaceIndentation ^ 0
-local Preproc =
-  K ( 'Preproc' , P "#" * (1 - P "\r" ) ^ 0  ) * ( EOL + -1 )
-local CommentMath =
-  P "$" * K ( 'Comment.Math' , ( 1 - S "$\r" ) ^ 1  ) * P "$"
-
-local Comment =
-  WithStyle ( 'Comment' ,
-     Q ( P "//" )
-     * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0 )
-  * ( EOL + -1 )
-
-local LongComment =
-  WithStyle ( 'Comment' ,
-               Q ( P "/*" )
-               * ( CommentMath + Q ( ( 1 - P "*/" - S "$\r" ) ^ 1 ) + EOL ) ^ 0
-               * Q ( P "*/" )
-            ) -- $
-local CommentLaTeX =
-  P(piton.comment_latex)
-  * Lc "{\\PitonStyle{Comment.LaTeX}{\\ignorespaces"
-  * L ( ( 1 - P "\r" ) ^ 0 )
-  * Lc "}}"
-  * ( EOL + -1 )
-local MainC =
-       EOL
-     + Space
-     + Tab
-     + Escape
-     + CommentLaTeX
-     + Beamer
-     + Preproc
-     + Comment + LongComment
-     + Delim
-     + Operator
-     + String
-     + Punct
-     + DefFunction
-     + DefClass
-     + Type * ( Q ( "*" ) ^ -1 + Space + Punct + Delim + EOL + -1 )
-     + Keyword * ( Space + Punct + Delim + EOL + -1 )
-     + Builtin * ( Space + Punct + Delim + EOL + -1 )
-     + Identifier
-     + Number
-     + Word
-MainLoopC =
-  (  ( space^1 * -1 )
-     + MainC
-  ) ^ 0
-languageC =
-  Ct (
-       ( ( space - P "\r" ) ^0 * P "\r" ) ^ -1
-       * BeamerBeginEnvironments
-       * PromptHastyDetection
-       * Lc '\\__piton_begin_line:'
-       * Prompt
-       * SpaceIndentation ^ 0
-       * MainLoopC
-       * -1
-       * Lc '\\__piton_end_line:'
-     )
-languages['c'] = languageC
-function piton.Parse(language,code)
-  local t = languages[language] : match ( code )
-  if t == nil
-  then
-    tex.sprint("\\PitonSyntaxError")
-    return -- to exit in force the function
-  end
-  local left_stack = {}
-  local right_stack = {}
-  for _ , one_item in ipairs(t)
-  do
-     if one_item[1] == "EOL"
-     then
-          for _ , s in ipairs(right_stack)
-            do tex.sprint(s)
-            end
-          for _ , s in ipairs(one_item[2])
-            do tex.tprint(s)
-            end
-          for _ , s in ipairs(left_stack)
-            do tex.sprint(s)
-            end
-     else
-          if one_item[1] == "Open"
-          then
-               tex.sprint( one_item[2] )
-               table.insert(left_stack,one_item[2])
-               table.insert(right_stack,one_item[3])
-          else
-               if one_item[1] == "Close"
-               then
-                    tex.sprint( right_stack[#right_stack] )
-                    left_stack[#left_stack] = nil
-                    right_stack[#right_stack] = nil
-               else
-                    tex.tprint(one_item)
-               end
-          end
-     end
-  end
-end
-function piton.ParseFile(language,name,first_line,last_line)
-  local s = ''
-  local i = 0
-  for line in io.lines(name)
-  do i = i + 1
-     if i >= first_line
-     then s = s .. '\r' .. line
-     end
-     if i >= last_line then break end
-  end
-  if string.byte(s,1) == 13
-  then if string.byte(s,2) == 239
-       then if string.byte(s,3) == 187
-            then if string.byte(s,4) == 191
-                 then s = string.sub(s,5,-1)
-                 end
-            end
-       end
-  end
-  piton.Parse(language,s)
-end
-function piton.ParseBis(language,code)
-  local s = ( Cs ( ( P '##' / '#' + 1 ) ^ 0 ) ) : match ( code )
-  return piton.Parse(language,s)
-end
-function piton.ParseTer(language,code)
-  local s = ( Cs ( ( P '\\__piton_breakable_space:' / ' ' + 1 ) ^ 0 ) )
-            : match ( code )
-  return piton.Parse(language,s)
-end
-local function gobble(n,code)
-  function concat(acc,new_value)
-    return acc .. new_value
-  end
-  if n==0
-  then return code
-  else
-       return Cf (
-                   Cc ( "" ) *
-                   ( 1 - P "\r" ) ^ (-n)  * C ( ( 1 - P "\r" ) ^ 0 )
-                     * ( C ( P "\r" )
-                     * ( 1 - P "\r" ) ^ (-n)
-                     * C ( ( 1 - P "\r" ) ^ 0 )
-                    ) ^ 0 ,
-                    concat
-                 ) : match ( code )
-  end
-end
-local function add(acc,new_value)
-  return acc + new_value
-end
-local AutoGobbleLPEG =
-    ( space ^ 0 * P "\r" ) ^ -1
-    * Cf (
-           (
-             ( P " " ) ^ 0 * P "\r"
-             +
-             Cf ( Cc(0) * ( P " " * Cc(1) ) ^ 0 , add )
-             * ( 1 - P " " ) * ( 1 - P "\r" ) ^ 0 * P "\r"
-           ) ^ 0
-           *
-           ( Cf ( Cc(0) * ( P " " * Cc(1) ) ^ 0 , add )
-           * ( 1 - P " " ) * ( 1 - P "\r" ) ^ 0 ) ^ -1 ,
-           math.min
-         )
-local TabsAutoGobbleLPEG =
-    ( space ^ 0 * P "\r" ) ^ -1
-    * Cf (
-           (
-             ( P "\t" ) ^ 0 * P "\r"
-             +
-             Cf ( Cc(0) * ( P "\t" * Cc(1) ) ^ 0 , add )
-             * ( 1 - P "\t" ) * ( 1 - P "\r" ) ^ 0 * P "\r"
-           ) ^ 0
-           *
-           ( Cf ( Cc(0) * ( P "\t" * Cc(1) ) ^ 0 , add )
-           * ( 1 - P "\t" ) * ( 1 - P "\r" ) ^ 0 ) ^ -1 ,
-           math.min
-         )
-local EnvGobbleLPEG =
-  ( ( 1 - P "\r" ) ^ 0 * P "\r" ) ^ 0
-    * Cf ( Cc(0) * ( P " " * Cc(1) ) ^ 0 , add ) * -1
-function piton.GobbleParse(language,n,code)
-  if n==-1
-  then n = AutoGobbleLPEG : match(code)
-  else if n==-2
-       then n = EnvGobbleLPEG : match(code)
-       else if n==-3
-            then n = TabsAutoGobbleLPEG : match(code)
-            end
-       end
-  end
-  piton.Parse(language,gobble(n,code))
-end
-function piton.CountLines(code)
-  local count = 0
-  for i in code : gmatch ( "\r" ) do count = count + 1 end
-  tex.sprint(
-      luatexbase.catcodetables.expl ,
-      '\\int_set:Nn \\l__piton_nb_lines_int {' .. count .. '}' )
-end
-function piton.CountNonEmptyLines(code)
-  local count = 0
-  count =
-  ( Cf (  Cc(0) *
-          (
-            ( P " " ) ^ 0 * P "\r"
-            + ( 1 - P "\r" ) ^ 0 * P "\r" * Cc(1)
-          ) ^ 0
-          * (1 - P "\r" ) ^ 0 ,
-         add
-       ) * -1 ) : match (code)
-  tex.sprint(
-      luatexbase.catcodetables.expl ,
-      '\\int_set:Nn \\l__piton_nb_non_empty_lines_int {' .. count .. '}' )
-end
-function piton.CountLinesFile(name)
-  local count = 0
-  for line in io.lines(name) do count = count + 1 end
-  tex.sprint(
-      luatexbase.catcodetables.expl ,
-      '\\int_set:Nn \\l__piton_nb_lines_int {' .. count .. '}' )
-end
-function piton.CountNonEmptyLinesFile(name)
-  local count = 0
-  for line in io.lines(name)
-  do if not ( ( ( P " " ) ^ 0 * -1 ) : match ( line ) )
-     then count = count + 1
-     end
-  end
-  tex.sprint(
-      luatexbase.catcodetables.expl ,
-      '\\int_set:Nn \\l__piton_nb_non_empty_lines_int {' .. count .. '}' )
-end
-\end{luacode*}
-
 \endinput
 %%
 %% End of file `piton.sty'.



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