texlive[64979] Master/texmf-dist: piton (9nov22)

commits+karl at tug.org commits+karl at tug.org
Wed Nov 9 22:08:16 CET 2022


Revision: 64979
          http://tug.org/svn/texlive?view=revision&revision=64979
Author:   karl
Date:     2022-11-09 22:08:15 +0100 (Wed, 09 Nov 2022)
Log Message:
-----------
piton (9nov22)

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/tex/lualatex/piton/piton.sty

Modified: trunk/Master/texmf-dist/doc/lualatex/piton/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/lualatex/piton/README.md	2022-11-09 21:08:02 UTC (rev 64978)
+++ trunk/Master/texmf-dist/doc/lualatex/piton/README.md	2022-11-09 21:08:15 UTC (rev 64979)
@@ -24,7 +24,7 @@
 
 The file `piton.sty` will be generated.
 
-The file `nicematrix.sty` is the only file necessary to use the extension `nicematrix`. 
+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. 
 
 

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	2022-11-09 21:08:02 UTC (rev 64978)
+++ trunk/Master/texmf-dist/doc/lualatex/piton/piton-french.tex	2022-11-09 21:08:15 UTC (rev 64979)
@@ -6,8 +6,10 @@
 \usepackage[french]{babel}
 \frenchsetup{og = « , fg = »}
 
-\usepackage[footnotehyper,escape-inside=$$]{piton}
+\usepackage[footnotehyper,escape-inside=$$,math-comments]{piton}
 
+\usepackage[executable=python.exe]{pyluatex}
+
 \usepackage{xcolor}
 
 \usepackage{geometry}
@@ -65,6 +67,8 @@
 
 \begin{document}
 
+\PitonOptions{splittable = 4}
+
 \VerbatimFootnotes
 
 
@@ -105,7 +109,7 @@
         return -arctan(-x) # appel récursif
     elif x > 1: 
         return pi/2 - arctan(1/x) 
-        ## (on a utilisé le fait que $\arctan(x)+\arctan(1/x)=\pi/2$ pour $x>0$)\footnote{Cet échappement vers LaTeX a été obtenu en débutant par \ttfamily\#\#.} 
+        #> (on a utilisé le fait que $\arctan(x)+\arctan(1/x)=\pi/2$ pour $x>0$)\footnote{Cet échappement vers LaTeX a été obtenu en débutant par \ttfamily\#>.} 
     else: 
         s = 0
         for k in range(n):
@@ -149,14 +153,13 @@
 commande |\NewPitonEnvironment| : cf. partie \ref{NewPitonEnvironment} p.~\pageref{NewPitonEnvironment}. 
 
 \item La commande |\PitonInputFile| doit être utilisée pour insérer et composer un fichier extérieur.
+
+\colorbox{yellow!50}{\textbf{Nouveau 0.95}}\enskip La commande |\PitonInputFile| 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.
 \end{itemize}
 
-\bigskip
-Il est possible de composer des commentaires en LaTeX en commençant par |##| (c'est un échappement vers LaTeX). Les
-caractères |##| eux-mêmes ne seront pas imprimés et les espaces qui les suivent sont supprimés. Ces commentaires
-seront simplement appelés «commentaires LaTeX» dans ce document.
 
-
 \section{Personnalisation}
 
 \subsection{La commande \textbackslash PitonOptions}
@@ -170,7 +173,7 @@
 nécessairement des espaces.
 
 \item Quand la clé |auto-gobble| est activée, l'extension \pkg{piton} détermine la valeur minimale $n$ du nombre
-d'espaces successifs débutant chaque ligne (non vide) de l'environnment |{Piton}| et applique |gobble| avec cette
+d'espaces successifs débutant chaque ligne (non vide) de l'environnement |{Piton}| et applique |gobble| avec cette
 valeur de~$n$.
 
 \item Quand la clé |env-gobble| est activée, \pkg{piton} analyse la dernière ligne de l'environnement, c'est-à-dire
@@ -179,15 +182,21 @@
 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é |line-numbers|, les lignes \emph{non vides} sont numérotées (à gauche) dans les environnements
-\verb|{Piton}| et dans les listings produits par la commande |\PitonInputFile|.
+\item Avec la clé |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 Avec la clé |all-line-numbers|, \emph{toutes} les lignes sont numérotées, y compris les lignes vides.
 
 \item La clé |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. Voir un exemple à la partie \ref{example-numbering} p.~\pageref{example-numbering}.
+une position en débordement sur la gauche. 
 
+\colorbox{yellow!50}{\textbf{Nouveau 0.95}}\enskip 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}.
+
 \item Avec la clé |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.
@@ -196,10 +205,10 @@
 |\PitonInputFile|.
 
 \smallskip
-\colorbox{yellow!50}{\textbf{Nouveau 0.9}}\enskip On peut donner comme valeur à la clé |splittable| un entier
-naturel~$n$. Avec une telle valeur, les environnements |{Piton}| et les listings produits par |\PitonInputFile|
-sont sécables mais aucune coupure ne pourra avoir lieu entre les $n$~premières lignes, ni entre les $n$~dernières.
-La valeur par défaut de la clé |splittable| vaut en fait $1$, qui autorise les sauts de page partout.
+On peut donner comme valeur à la clé |splittable| un entier naturel~$n$. Avec une telle valeur, les environnements
+|{Piton}| et les listings produits par |\PitonInputFile| sont sécables mais aucune coupure ne pourra avoir lieu
+entre les $n$~premières lignes, ni entre les $n$~dernières. La valeur par défaut de la clé |splittable| vaut en
+fait $1$, qui autorise les sauts de page partout.
 
 \item La clé |background-color| fixe la couleur de fond des environnements |{Piton}| et des listings produits par
 |\PitonInputFile| (ce fond a une largeur égale à la valeur courante de |\linewidth|). Même avec une couleur de
@@ -207,8 +216,20 @@
   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|.}\end{itemize}
+  quand les deux utilisent la clé |breakable|.}
+\item \colorbox{yellow!50}{\textbf{Nouveau 0.95}}\enskip En activant la clé |show-spaces|, les espaces dans
+les chaînes courtes (c'est-à-dire celles délimitées par |'| ou |"|) sont matérialisés par le caractère ␣ (U+2423 :
+\textsc{open box}). Bien sûr, le caractère U+2423 doit être présent dans la fonte mono-chasse
+utilisée.\footnote{L'extension \pkg{piton} utilise simplement la fonte mono-chasse courante. Pour la changer, le
+  mieux est d'utiliser |\setmonofont| de \pkg{fontspec}.}
 
+
+\begingroup
+\PitonOptions{show-spaces}
+Exemple : \piton|my_string = 'Très bonne réponse'|
+\endgroup
+\end{itemize}
+
 \bigskip
 
 \begingroup
@@ -227,7 +248,7 @@
             return -arctan(-x) # appel récursif
         elif x > 1: 
             return pi/2 - arctan(1/x) 
-            ## (on a utilisé le fait que $\arctan(x)+\arctan(1/x)=\pi/2$ pour $x>0$)
+            #> (on a utilisé le fait que $\arctan(x)+\arctan(1/x)=\pi/2$ pour $x>0$)
         else: 
             s = 0
             for k in range(n):
@@ -251,7 +272,7 @@
             return -arctan(-x) # appel récursif
         elif x > 1: 
             return pi/2 - arctan(1/x) 
-            ## (on a utilisé le fait que $\arctan(x)+\arctan(1/x)=\pi/2$ pour $x>0$)
+            #> (on a utilisé le fait que $\arctan(x)+\arctan(1/x)=\pi/2$ pour $x>0$)
         else: 
             s = 0
             for k in range(n):
@@ -260,48 +281,7 @@
 \end{Piton}
 \endgroup
 
-\subsection{L'option escape-inside}
 
-L'option |escape-inside| doit être utilisée au chargement de \pkg{piton} (c'est-à-dire dans l'instruction
-|\usepackage|). Pour des raisons techniques, elle ne peut pas être fixée dans |\PitonOptions|. Elle prend comme
-valeur deux caractères qui seront utilisés pour délimiter des parties qui seront composées en LaTeX.
-
-
-\bigskip
-Dans l'exemple suivant, on suppose que l'extension \pkg{piton} a été chargée de la manière suivante :
-
-\smallskip
-\begin{Verbatim}
-\usepackage[~emphase#escape-inside=$$@]{piton}
-\end{Verbatim}
-
-\medskip
-Dans le code suivant, qui est une programmation récursive de la factorielle, on décide de surligner en jaune
-l'instruction qui contient l'appel récursif.
-\begin{Verbatim}
-\begin{Piton}
-def fact(n):
-    if n==0:
-        return 1
-    else:
-        ~emphase#$\colorbox{yellow!50}{$@return n*fact(n-1)~emphase#$}$@
-\end{Piton}
-\end{Verbatim}
-
-\begin{Piton}
-def fact(n):
-    if n==0:
-        return 1
-    else:
-        $\colorbox{yellow!50}{$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 |##|).
-
 \subsection{Les styles}
 
 \label{styles}
@@ -371,7 +351,7 @@
 Name.Class & le nom des classes au moment de leur définition, c'est-à-dire après le mot-clé \verb|class| \\
 Exception & le nom des exceptions prédéfinies (eg: SyntaxError) \\
 Comment & les commentaires commençant par \texttt{\#} \\
-Comment.LaTeX & les commentaires commençant par \texttt{\#\#} qui sont composés en LaTeX par \pkg{piton} (et
+Comment.LaTeX & les commentaires commençant par \texttt{\#>} qui sont composés en LaTeX par \pkg{piton} (et
                 appelés simplement «commentaires LaTeX» dans ce document) \\
 Keyword.Constant & |True|, |False| et |None| \\
 Keyword & les mots-clés suivants :
@@ -386,6 +366,9 @@
 
 
 
+
+
+
 \subsection{Définition de nouveaux environnements}
 
 \label{NewPitonEnvironment}
@@ -423,7 +406,122 @@
 
 \section{Fonctionnalités avancées}
 
+\subsection{Les échappements vers LaTeX}
+
+L'extension \pkg{piton} propose plusieurs mécanismes d'échappement vers LaTeX :
+\begin{itemize}
+\item Il est possible d'avoir des commentaires entièrement composés en LaTeX.
+\item Il est possible d'avoir, dans les commentaires Python, les éléments entre \texttt{\$} composés en mode
+mathématique de LaTeX.
+\item Il est possible d'insérer du code LaTeX à n'importe quel endroit d'un listing Python.
+\end{itemize}
+
+
+\subsubsection{Les «commentaires LaTeX»}
+
+Dans ce document, on appelle «commentaire LaTeX» des commentaires qui débutent par |#>|. Tout ce qui suit ces deux 
+caractères, et jusqu'à la fin de la ligne, sera composé comme du code LaTeX standard.
+
+Il y a deux outils pour personnaliser ces commentaires.
+
+\begin{itemize}
+\item \colorbox{yellow!50}{\bfseries Nouveau 0.95}\enskip 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. 
+
+Par exemple, avec le chargement suivant :
+
+\quad \verb|\usepackage[comment-latex = LaTeX]{piton}|
+
+les commentaires LaTeX commenceront par~|#LaTeX|.
+
+Si on donne la valeur nulle à la clé |comment-latex|, tous les commentaires Python (débutant par~|#|) seront en
+fait des «commentaires LaTeX».
+
+\smallskip
+\item Il est possible de changer le formatage du commentaire LaTeX lui-même en changeant le style \pkg{piton}
+|Comment.LaTeX|.
+
+Par exemple, avec |\SetPitonStyle{Comment.LaTeX = \normalfont\color{blue}}|, les commentaires LaTeX seront composés
+en bleu.
+
+Pour d'autres exemples de personnalisation des commentaires LaTeX, voir la partie \ref{example-comments}
+p.~\pageref{example-comments}. 
+\end{itemize}
+
+
+\subsubsection{La clé «math-comments»}
+
+\colorbox{yellow!50}{\textbf{Nouveau 0.95}}\enskip Il est possible de demander que, dans les commentaires Python
+normaux, c'est-à-dire débutant par |#| (et non par |#>|), les élements 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.
+
 \bigskip
+Dans l'exemple suivant, on suppose que la clé |math-comments| a été utilisée au chargement de \pkg{piton}.
+
+\begin{Verbatim}
+\begin{Piton}
+def carré(x):
+    return x*x ~# renvoie $x^2$
+\end{Piton}
+\end{Verbatim}
+
+\begin{Piton}
+def carré(x):
+    return x*x # renvoie $x^2$
+\end{Piton}
+
+
+\subsubsection{Le mécanisme «espace-inside»}
+
+Il est aussi possible de surcharger les listings Python pour y insérer du code LaTeX à peu près n'importe où. 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.
+
+
+\bigskip
+Dans l'exemple suivant, on suppose que l'extension \pkg{piton} a été chargée de la manière suivante :
+
+\begin{Verbatim}
+\usepackage[~emphase#escape-inside=$$@]{piton}
+\end{Verbatim}
+
+\medskip
+Dans le code suivant, qui est une programmation récursive de la factorielle, on décide de surligner en jaune
+l'instruction qui contient l'appel récursif.
+\begin{Verbatim}
+\begin{Piton}
+def fact(n):
+    if n==0:
+        return 1
+    else:
+        ~emphase#$\colorbox{yellow!50}{$@return n*fact(n-1)~emphase#$}$@
+\end{Piton}
+\end{Verbatim}
+
+\begin{Piton}
+def fact(n):
+    if n==0:
+        return 1
+    else:
+        $\colorbox{yellow!50}{$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 |#>|).
+
+
+
+\bigskip
 \subsection{Notes de pied de page dans les environnements de piton}
 
 \label{footnote}
@@ -434,7 +532,7 @@
 
 \smallskip
 Néanmoins, il est également possible d'extraire les notes de pieds de page avec l'extension \pkg{footnote} ou bien
-l'extension pkg{footnotehyper}.
+l'extension \pkg{footnotehyper}.
 
 \smallskip
 Si \pkg{piton} est chargée avec l'option |footnote| (avec |\usepackage[footnote]{piton}|) l'extension
@@ -459,16 +557,16 @@
 \subsection{Tabulations}
 
 \smallskip
-\colorbox{yellow!50}{\textbf{Nouveau 0.9}}\enskip Même s'il est recommandé d'indenter les listings Python avec des
-espaces (cf. PEP~8), \pkg{piton} accepte les caractères de tabulations (U+0009) en début de ligne. Chaque caractère
-U+0009 est remplacé par $n$ espaces. La valeur initiale de~$n$ est~4 mais on peut la changer avec la clé |tab-size|
-de |\PitonOptions|.
+Même s'il est recommandé d'indenter les listings Python avec des espaces (cf. PEP~8), \pkg{piton} accepte les
+caractères de tabulations (U+0009) en début de ligne. Chaque caractère U+0009 est remplacé par $n$ espaces. La
+valeur initiale de~$n$ est~4 mais on peut la changer avec la clé |tab-size| de |\PitonOptions|.
 
+\emph{Remarque} : Contrairement à ce qui se passe avec l'extension \pkg{listings}, la clé |gobble| (et ses
+variantes |auto-gobble| et |env-gobble|) agit \emph{avant} la transformation des tabulations en espaces.
+
 \section{Exemples}
 
-\PitonOptions{splittable}
 
-
 \subsection{Numérotation des lignes}
 
 \label{example-numbering}
@@ -477,19 +575,20 @@
 
 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).
 
-Si on ne veut pas de débordement, il faut réserver une place à gauche pour les numéros de lignes avec la clé |left-margin|.
+Si on ne veut pas de débordement, on peut utiliser l'option |left-margin=auto| qui va insérer une marge adaptée aux
+numéros qui seront insérés (elle est plus large quand les numéros dépassent 10).
 
 
 \begingroup
 \fvset{commandchars=\~\&\@,formatcom=\small\color{gray}}
 \begin{Verbatim}
-~emphase&\PitonOptions{background-color=gray!10, left-margin = 5mm, line-numbers}@
+~emphase&\PitonOptions{background-color=gray!10, left-margin = auto, line-numbers}@
 \begin{Piton}
 def arctan(x,n=10):
     if x < 0:
-        return -arctan(-x)        ## (appel récursif)
+        return -arctan(-x)        #> (appel récursif)
     elif x > 1: 
-        return pi/2 - arctan(1/x) ## (autre appel récursif) 
+        return pi/2 - arctan(1/x) #> (autre appel récursif) 
     else: 
         return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) 
 \end{Piton}
@@ -499,13 +598,13 @@
 
 
 \begingroup
-\PitonOptions{background-color=gray!10,left-margin = 5mm, line-numbers}
+\PitonOptions{background-color=gray!10,left-margin = auto, line-numbers}
 \begin{Piton}
 def arctan(x,n=10):
     if x < 0:
-        return -arctan(-x)        ## (appel récursif)
+        return -arctan(-x)        #> (appel récursif)
     elif x > 1: 
-        return pi/2 - arctan(1/x) ## (autre appel récursif) 
+        return pi/2 - arctan(1/x) #> (autre appel récursif) 
     else: 
         return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) 
 \end{Piton}
@@ -512,13 +611,14 @@
 \endgroup
 
 
+\bigskip
 
-
 \subsection{Formatage des commentaires LaTeX}
 
+\label{example-comments}
 
 On peut modifier le style |Comment.LaTeX| (avec |\SetPitonStyle|) pour faire afficher les commentaires 
-LaTeX (qui débutent par |##|) en butée à droite.
+LaTeX (qui débutent par |#>|) en butée à droite.
 
 \begingroup
 \fvset{commandchars=\~\&\@,formatcom=\small\color{gray}}
@@ -528,9 +628,9 @@
 \begin{Piton}
 def arctan(x,n=10):
     if x < 0:
-        return -arctan(-x)        ## appel récursif
+        return -arctan(-x)        #> appel récursif
     elif x > 1: 
-        return pi/2 - arctan(1/x) ## autre appel récursif 
+        return pi/2 - arctan(1/x) #> autre appel récursif 
     else: 
         return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) 
 \end{Piton}
@@ -543,9 +643,9 @@
 \begin{Piton}
 def arctan(x,n=10):
     if x < 0:
-        return -arctan(-x)        ## appel récursif
+        return -arctan(-x)        #> appel récursif
     elif x > 1: 
-        return pi/2 - arctan(1/x) ## autre appel récursif 
+        return pi/2 - arctan(1/x) #> autre appel récursif 
     else: 
         return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) 
 \end{Piton}
@@ -567,9 +667,9 @@
 \begin{Piton}
 def arctan(x,n=10):
     if x < 0:
-        return -arctan(-x)       ## appel récursif
+        return -arctan(-x)       #> appel récursif
     elif x > 1: 
-        return pi/2 - arctan(1/x) ## autre appel récursif 
+        return pi/2 - arctan(1/x) #> autre appel récursif 
     else: 
         s = 0
         for k in range(n):
@@ -590,9 +690,9 @@
 \begin{Piton}
 def arctan(x,n=10):
     if x < 0:
-        return -arctan(-x)       ## appel récursif
+        return -arctan(-x)       #> appel récursif
     elif x > 1: 
-        return pi/2 - arctan(1/x) ## autre appel récursif 
+        return pi/2 - arctan(1/x) #> autre appel récursif 
     else: 
         s = 0
         for k in range(n):
@@ -602,8 +702,8 @@
 \end{minipage}
 \endgroup
 
+\bigskip
 
-
 \subsection{Notes dans les listings}
 
 Pour pouvoir extraire les notes (introduites par |\footnote|), l'extension |piton| doit être chargée, soit avec la
@@ -610,7 +710,7 @@
 clé |footnote|, soit avec la clé |footnotehyper|, comme expliqué à la section \ref{footnote} p.~\pageref{footnote}.
 Dans le présent document, l'extension \pkg{piton} a été chargée par la clé |footnotehyper|.
 
-Bien entendu, une commande |\footnote| ne peut apparaître que dans un commentaire LaTeX (qui débute par |##|). Un
+Bien entendu, une commande |\footnote| ne peut apparaître que dans un commentaire LaTeX (qui débute par |#>|). Un
 tel commentaire peut se limiter à cette unique commande |\footnote|, comme dans l'exemple suivant.
 
 \begingroup
@@ -620,9 +720,9 @@
 \begin{Piton}
 def arctan(x,n=10):
     if x < 0:
-        return -arctan(-x)~emphase&##\footnote{Un premier appel récursif.}]@
+        return -arctan(-x)~emphase&#>\footnote{Un premier appel récursif.}]@
     elif x > 1: 
-        return pi/2 - arctan(1/x)~emphase&##\footnote{Un deuxième appel récursif.}@
+        return pi/2 - arctan(1/x)~emphase&#>\footnote{Un deuxième appel récursif.}@
     else: 
         return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) 
 \end{Piton}
@@ -634,9 +734,9 @@
 \begin{Piton}
 def arctan(x,n=10):
     if x < 0:
-        return -arctan(-x)##\footnote{Un premier appel récursif.}
+        return -arctan(-x)#>\footnote{Un premier appel récursif.}
     elif x > 1: 
-        return pi/2 - arctan(1/x)##\footnote{Un deuxième appel récursif.}
+        return pi/2 - arctan(1/x)#>\footnote{Un deuxième appel récursif.}
     else: 
         return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) 
 \end{Piton}
@@ -658,9 +758,9 @@
 \begin{Piton}
 def arctan(x,n=10):
     if x < 0:
-        return -arctan(-x)~emphase&##\footnote{Un premier appel récursif.}@
+        return -arctan(-x)~emphase&#>\footnote{Un premier appel récursif.}@
     elif x > 1: 
-        return pi/2 - arctan(1/x)~emphase&##\footnote{Un deuxième appel récursif.}@
+        return pi/2 - arctan(1/x)~emphase&#>\footnote{Un deuxième appel récursif.}@
     else: 
         return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) 
 \end{Piton}
@@ -674,9 +774,9 @@
 \begin{Piton}
 def arctan(x,n=10):
     if x < 0:
-        return -arctan(-x)##\footnote{Un premier appel récursif.}
+        return -arctan(-x)#>\footnote{Un premier appel récursif.}
     elif x > 1: 
-        return pi/2 - arctan(1/x)##\footnote{Un deuxième appel récursif.}
+        return pi/2 - arctan(1/x)#>\footnote{Un deuxième appel récursif.}
     else: 
         return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) 
 \end{Piton}
@@ -698,9 +798,9 @@
 \begin{Piton}
 def arctan(x,n=10):
     if x < 0:
-        return -arctan(-x)~emphase&##\footnote{Un premier appel récursif.}@
+        return -arctan(-x)~emphase&#>\footnote{Un premier appel récursif.}@
     elif x > 1: 
-        return pi/2 - arctan(1/x)~emphase&##\footnote{Un deuxième appel récursif.}@
+        return pi/2 - arctan(1/x)~emphase&#>\footnote{Un deuxième appel récursif.}@
     else: 
         return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) 
 \end{Piton}
@@ -717,9 +817,9 @@
 \begin{Piton}
 def arctan(x,n=10):
     if x < 0:
-        return -arctan(-x)##\footnote{Un premier appel récursif.}
+        return -arctan(-x)#>\footnote{Un premier appel récursif.}
     elif x > 1: 
-        return pi/2 - arctan(1/x)##\footnote{Un deuxième appel récursif.}
+        return pi/2 - arctan(1/x)#>\footnote{Un deuxième appel récursif.}
     else: 
         return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) 
 \end{Piton}
@@ -726,6 +826,8 @@
 \end{minipage}
 \end{savenotes}
 
+\bigskip
+
 \subsection{Un exemple de réglage des styles}
 
 Les styles graphiques ont été présentés à la partie \ref{styles}, p.~\pageref{styles}.
@@ -759,7 +861,9 @@
 \end{Verbatim}
 
 
+\begingroup
 
+
 \setmonofont[Scale=0.85]{DejaVu Sans Mono}
 
 \SetPitonStyle
@@ -795,7 +899,7 @@
         return -arctan(-x) # appel récursif
     elif x > 1: 
         return pi/2 - arctan(1/x) 
-        ## (on a utilisé le fait que $\arctan(x)+\arctan(1/x)=\pi/2$ pour $x>0$)
+        #> (on a utilisé le fait que $\arctan(x)+\arctan(1/x)=\pi/2$ pour $x>0$)
     else: 
         s = 0
         for k in range(n):
@@ -804,7 +908,87 @@
 \end{Piton}
 
 
+\endgroup
 
+\section{Utilisation avec pyluatex}
+
+L'extension \pkg{pyluatex} est une extension iqui permet l'exécution de code Python à partir |lualatex| (pourvu
+que Python soit installé sur la machine et que la compilation soit effectuée avec |lualatex| et |--shell-escape|).
+
+Voici, à titre d'exemple, un environnement |{PitonExecute}| qui formate un listing Python (avec \pkg{piton}) et qui
+affiche également dessous le résultat de l'exécution de ce code avec Python.
+
+
+\begin{Verbatim}
+\ExplSyntaxOn
+\NewDocumentEnvironment { ~emphase#PitonExecute@ } { ! O { } } 
+  { 
+    \PyLTVerbatimEnv
+    \begin{pythonq} 
+  }
+  {
+    \end{pythonq}
+    \directlua
+      {
+        tex.print("\\PitonOptions{~#1}")
+        tex.print("\\begin{Piton}")
+        tex.print(pyluatex.get_last_code())
+        tex.print("\\end{Piton}")
+        tex.print("") 
+      }
+    \begin{center}
+      \directlua{tex.print(pyluatex.get_last_output())}
+    \end{center}
+  }
+\ExplSyntaxOff
+\end{Verbatim}
+
+\ExplSyntaxOn
+\NewDocumentEnvironment { PitonExecute } { ! O { } } 
+  { 
+    \PyLTVerbatimEnv
+    \begin{pythonq} 
+  }
+  {
+    \end{pythonq}
+    \directlua
+      {
+        tex.print("\\PitonOptions{~#1}")
+        tex.print("\\begin{Piton}")
+        tex.print(pyluatex.get_last_code())
+        tex.print("\\end{Piton}")
+        tex.print("") 
+      }
+    \begin{center}
+      \directlua{tex.print(pyluatex.get_last_output())}
+    \end{center}
+  }
+\ExplSyntaxOff
+
+Cet environnement |{PitonExcecute}| prend en argument optionnel (entre crochets) les options proposées par la
+commande |\PitonOptions|.
+
+\bigskip
+Voici un exemple d'utilisation de cet environnement |{PitonExecute}| :
+
+\begin{Verbatim}
+\begin{~emphase#PitonExecute@}[background-color=gray!15]
+def square(x):
+    return x*x
+print(f'The square of 12 is {square(12)}.')
+\end{~emphase#PitonExecute@}
+\end{Verbatim}
+
+
+\medskip
+\begin{PitonExecute}[background-color=gray!15]
+def square(x):
+    return x*x
+print(f'The square of 12 is {square(12)}.')
+\end{PitonExecute}
+
+
+
 \section*{Autre documentation}
 
 Le document |piton.pdf| (fourni avec l'extension \pkg{piton}) contient une traduction anglaise de la

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	2022-11-09 21:08:02 UTC (rev 64978)
+++ trunk/Master/texmf-dist/source/lualatex/piton/piton.dtx	2022-11-09 21:08:15 UTC (rev 64979)
@@ -15,8 +15,8 @@
 %
 % \fi
 % \iffalse
-\def\myfileversion{0.9}
-\def\myfiledate{2022/10/31}
+\def\myfileversion{0.95}
+\def\myfiledate{2022/11/09}
 %
 %
 %<*batchfile> 
@@ -56,10 +56,8 @@
 \fvset{commandchars=\~\#\@,formatcom=\color{gray}}
 \captionsetup{labelfont = bf}
 \usepackage{ragged2e}
-\usepackage[footnotehyper,escape-inside=$$]{piton} % $$
+\usepackage[footnotehyper,escape-inside=$$,math-comments]{piton} % $$
 
-
-\def\interitem{\vskip 7mm plus 2 mm minus 3mm}          
 \parindent 0pt
 \skip\footins = 2\bigskipamount
 
@@ -118,7 +116,7 @@
 %         return -arctan(-x) # recursive call
 %     elif x > 1: 
 %         return pi/2 - arctan(1/x) 
-%         ## (we have used that $\arctan(x)+\arctan(1/x)=\frac{\pi}{2}$ for $x>0$)\footnote{This LaTeX escape has been done by beginning the comment by \ttfamily\#\#.}
+%         #> (we have used that $\arctan(x)+\arctan(1/x)=\frac{\pi}{2}$ for $x>0$)\footnote{This LaTeX escape has been done by beginning the comment by \ttfamily\#>.}
 %     else: 
 %         s = 0
 %         for k in range(n):
@@ -166,13 +164,12 @@
 % cf.~\ref{NewPitonEnvironment} p.~\pageref{NewPitonEnvironment}.
 % \item The command |\PitonInputFile| is used to insert and typeset a whole
 % external file.
+%
+% \colorbox{yellow!50}{\textbf{New 0.95}}\enskip The command |\PitonInputFile|
+% takes in as optional argument (between square brackets) two keys |first-line|
+% and |last-line|: only the part between the corresponding lines will be inserted.
 % \end{itemize}
 %
-% \bigskip
-% It's possible to compose comments in LaTeX by beginning them with |##| (it's a
-% ``LaTeX escape''). The characters |##| themselves won't be printed and the
-% spaces after |##| are removed. These comments will be called ``LaTeX
-% comments'' in this document.
 % 
 % \section{Customization}
 %
@@ -203,35 +200,40 @@
 % gobble is set by the position of the commands |\begin{Piton}| and
 % |\end{Piton}| which delimit the current environment.
 %
-% \item With the key |line-numbers|, the \emph{non empty} lines are numbered (on
-% the left) in the environments |{Piton}| and in the listings resulting from the
-% use of |\PitonInputFile|.
+% \item With the key |line-numbers|, the \emph{non empty} lines (and all the
+% lines of the \emph{docstrings}, even the empty ones) are numbered in the
+% environments |{Piton}| and in the listings resulting from the use of
+% |\PitonInputFile|.
 % 
 % \item With the key |all-line-numbers|, \emph{all} the lines are numbered,
 % including the empty ones.
 %
 % \item With the key |resume| the counter of lines is not set to zero at the
-% beginning of each environment |{Piton}| or use |\PitonInputFile| as it is
-% otherwise. That's allows a numbering of the lines accross several
-% environments. See an example part \ref{example-numbering} on
-% page~\pageref{example-numbering}.
+% 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 |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.
+% on the left. 
 %
-% \item The key |splittable| allows pages breaks within the environments
+% \colorbox{yellow!50}{\textbf{New 0.95}}\enskip It's possible to use the key
+% |left-margin| with the value |auto|. With that value, if the key
+% |line-numbers| or the key |all-line-numbers| is used, a margin will be
+% automatically inserted to fit the numbers of lines. See an example part
+% \ref{example-numbering} on page~\pageref{example-numbering}.
+%
+% \item The key |splittable| allows page breaks within the environments
 % |{Piton}| and the listings produced by 
 % |\PitonInputFile|. 
 %
 % \smallskip
-% \colorbox{yellow!50}{\textbf{New 0.9}}\enskip It's possible to give as value to
-% the key |splittable| a positive integer~$n$. With that value, the environments
-% |{Piton}| and the listings produced by |\PitonInputFile| are splittable but no
-% page break can occur within the first $n$ lines and within the last $n$ lines.
-% The default value of the key |splittable| is, in fact, $1$, which allows pages
-% breaks everywhere.
+% It's possible to give as value to the key |splittable| a positive integer~$n$.
+% With that value, the environments |{Piton}| and the listings produced by
+% |\PitonInputFile| are splittable but no page break can occur within the first
+% $n$ lines and within the last $n$ lines. The default value of the key
+% |splittable| is, in fact, $1$, which allows pages breaks everywhere.
 %
 % \item The key |background-color| sets the background color of the environments
 % |{Piton}| and the listings produced by |\PitonInputFile| (that background has
@@ -242,6 +244,19 @@
 % \pkg{tcolorbox} included in another environment of \pkg{tcolorbox} is
 % \emph{not} breakable, even when both environments use the key |breakable| of
 % \pkg{tcolorbox}.}
+%
+% \item \colorbox{yellow!50}{\textbf{New 0.95}}\enskip When the key
+% |show-spaces| is activated, the spaces in the short strings (that is to say
+% those delimited by |'| or |"|) are replaced by the character~␣ (U+2423 :
+% \textsc{open box}). Of course, that character~U+2423 must be present in the
+% monospaced font which is used.\footnote{The package \pkg{piton} simply uses
+% the current monospaced font. The best way to change that font is to use the
+% command \texttt{\textbackslash setmonofont} of \pkg{fontspec}.}
+%
+% \begingroup
+% \PitonOptions{show-spaces}
+% Example : \piton|my_string = 'Very good answer'|
+% \endgroup
 % \end{itemize}
 %
 % \bigskip
@@ -261,7 +276,7 @@
 %             return -arctan(-x) # recursive call
 %         elif x > 1: 
 %             return pi/2 - arctan(1/x) 
-%             ## (we have used that $\arctan(x)+\arctan(1/x)=\frac{\pi}{2}$ pour $x>0$)
+%             #> (we have used that $\arctan(x)+\arctan(1/x)=\frac{\pi}{2}$ pour $x>0$)
 %         else 
 %             s = 0
 %             for k in range(n):
@@ -285,7 +300,7 @@
 %         return -arctan(-x) # recursive call
 %     elif x > 1: 
 %         return pi/2 - arctan(1/x) 
-%         ## (we have used that $\arctan(x)+\arctan(1/x)=\frac{\pi}{2}$ for $x>0$)
+%         #> (we have used that $\arctan(x)+\arctan(1/x)=\frac{\pi}{2}$ for $x>0$)
 %     else 
 %         s = 0
 %         for k in range(n):
@@ -294,53 +309,8 @@
 %    \end{Piton}
 % \endgroup
 % 
-% \subsection{The key escape-inside}
 %
-% The key |escape-inside| must be used when loading the package \pkg{piton}
-% (that is to say in the instruction |\usepackage|). For technical reasons, it
-% can't be used in the command |\PitonOptions|. That option takes in as value
-% two characters which will be used to delimit pieces of code which will
-% thrown directly to LaTeX (and composed by LaTeX).
 %
-% \medskip
-% In the following example, we assume that the extension \pkg{piton} has been
-% loaded by the following instruction.
-%
-% \begin{Verbatim}
-% \usepackage[~emphase#escape-inside=$$@]{piton}
-% \end{Verbatim}
-%
-% \medskip
-% In the following code, which is a recursive programmation of the mathematical
-% factorial, we decide to highlight in yellow the instruction which contains the
-% recursive call. 
-% \begin{Verbatim}
-% \begin{Piton}
-% def fact(n):
-%     if n==0:
-%         return 1
-%     else:
-%         ~emphase#$\colorbox{yellow!50}{$@return n*fact(n-1)~emphase#$}$@
-% \end{Piton}
-% \end{Verbatim}
-%
-%    \begin{Piton}
-% def fact(n):
-%     if n==0:
-%         return 1
-%     else:
-%         $\colorbox{yellow!50}{$return n*fact(n-1)$}$
-%    \end{Piton}
-%         
-% \bigskip
-%
-% \emph{Caution} : The escape to LaTeX allowed by the characters of
-% |escape-inside| is not active in the strings nor in the Python comments
-% (however, it's possible to have a whole Python comment composed in LaTeX by
-% beginning it with |##|; such comments are merely called ``LaTeX comments'' in
-% this document). 
-%
-%
 % \subsection{The styles}
 %
 % \label{styles}
@@ -420,7 +390,7 @@
 % to say after the keyword |class|) \\
 % Exception & the names of the exceptions (eg: \texttt{SyntaxError}) \\
 % Comment & the comments beginning with \verb|#| \\
-% Comment.LaTeX & the comments beginning by \verb|##|, which are composed in LaTeX by
+% Comment.LaTeX & the comments beginning by \verb|#>|, which are composed in LaTeX by
 % \pkg{piton} (and simply called ``LaTeX comments'' in this document) \\
 % Keyword.Constant & |True|, |False| and |None| \\
 % Keyword & the following keywords :
@@ -477,6 +447,125 @@
 %
 % \section{Advanced features}
 %
+% \subsection{Mechanisms to escape to LaTeX}
+%
+% The package \pkg{piton} provides several mechanisms for escaping to LaTeX:
+% \begin{itemize}
+% \item It's possible to compose comments entirely in LaTeX.
+% \item It's possible to have the elements between \texttt{\$} in the comments
+% composed in LateX mathematical mode.
+% \item It's also possible to insert LaTeX code almost everywhere in a Python listing.
+% \end{itemize}
+%
+% \subsubsection{The ``LaTeX comments''}
+%
+% In this document, we call ``LaTeX comments'' the comments which begins by
+% |#>|. The code following those characters, until the end of the line, will be
+% composed as standard LaTeX code. There is two tools to customize those
+% comments.
+%
+% \begin{itemize}
+% \item It's possible to change the syntatic mark (which, by default, is |#>|).
+% For this purpose, there is a key |comment-latex| available at load-time (that
+% is to say at the |\usepackage|) which allows to choice the characters which,
+% preceded by |#|, will be the syntatic marker.
+%
+% For example, with the following loading:
+% 
+% \quad \verb|\usepackage[comment-latex = LaTeX]{piton}|
+%
+% the LaTeX comments will begin by |#LaTeX|.
+%
+% If the key |comment-latex| is used with the empty value, all the Python
+% comments (which begins by |#|) will, in fact, be ``LaTeX comments''.
+%
+% \smallskip
+% \item \colorbox{yellow!50}{\bfseries New 0.95}\enskip It's possible to change
+% the formatting of the LaTeX comment itself by changing the \pkg{piton} style
+% |Comment.LaTeX|. 
+%
+% For example, with |\SetPitonStyle{Comment.LaTeX = \normalfont\color{blue}}|,
+% the LaTeX comments will be composed in blue.
+%
+% For other examples of customization of the LaTeX comments, see the part
+% \ref{example-comments} p.~\pageref{example-comments}
+% \end{itemize}
+%
+% \subsubsection{The key ``math-comments''}
+%
+% \colorbox{yellow!50}{\textbf{New 0.95}}\enskip It's possible to request that,
+% in the standard Python comments (that is to say those beginning by |#| and not
+% |#>|), the elements between \texttt{\$} be composed in LaTeX mathematical mode
+% (the other elements of the comment being composed verbatim).
+%
+% That feature is activated by the key |math-comments| at load-time (that is to
+% say with the |\usepackage|).
+%
+% \medskip
+% In the following example, we assume that the key |math-comments| has been used
+% when loading \pkg{piton}.
+%
+% \begin{Verbatim}
+% \begin{Piton}
+% def square(x):
+%     return x*x ~# compute $x^2$
+% \end{Piton}
+% \end{Verbatim}
+%
+% \begin{Piton}
+% def square(x):
+%     return x*x # compute $x^2$
+% \end{Piton}
+% 
+% \subsubsection{The mechanism ``escape-inside''}
+%
+% It's also possible to overwrite the Python listings to insert LaTeX code
+% almost everywhere. By default, \pkg{piton} does not fix any character for that
+% kind of escape.
+%
+% In order to use this mechanism, it's necessary to specify two characters which
+% will delimit the escape (one for the beginning and one for the end) by using
+% the key |escape-inside| at load-time (that is to say a the
+% |\begin{docuemnt}|). 
+%
+% \medskip
+% In the following example, we assume that the extension \pkg{piton} has been
+% loaded by the following instruction.
+%
+% \begin{Verbatim}
+% \usepackage[~emphase#escape-inside=$$@]{piton}
+% \end{Verbatim}
+%
+% \medskip
+% In the following code, which is a recursive programmation of the mathematical
+% factorial, we decide to highlight in yellow the instruction which contains the
+% recursive call. 
+% \begin{Verbatim}
+% \begin{Piton}
+% def fact(n):
+%     if n==0:
+%         return 1
+%     else:
+%         ~emphase#$\colorbox{yellow!50}{$@return n*fact(n-1)~emphase#$}$@
+% \end{Piton}
+% \end{Verbatim}
+%
+%    \begin{Piton}
+% def fact(n):
+%     if n==0:
+%         return 1
+%     else:
+%         $\colorbox{yellow!50}{$return n*fact(n-1)$}$
+%    \end{Piton}
+%         
+% \bigskip
+%
+% \emph{Caution} : The escape to LaTeX allowed by the characters of
+% |escape-inside| is not active in the strings nor in the Python comments
+% (however, it's possible to have a whole Python comment composed in LaTeX by
+% beginning it with |#>|; such comments are merely called ``LaTeX comments'' in
+% this document). 
+% 
 % \subsection{Footnotes in the environments of piton}
 % 
 % \label{footnote}
@@ -514,13 +603,17 @@
 % \subsection{Tabulations}
 %
 % \smallskip 
-% \colorbox{yellow!50}{\textbf{New 0.9}}\enskip Even though it's recommended to
-% indent the Python listings with spaces (see PEP~8), \pkg{piton} accepts the
-% characters of tabulation (that is to say the characters U+0009) at the
-% beginning of the lines. Each character U+0009 is replaced by $n$~spaces. The
-% initial value of $n$ is $4$ but it's possible to change it with the key
-% |tab-size| of |\PitonOptions|.
+% Even though it's recommended to indent the Python listings with spaces (see
+% PEP~8), \pkg{piton} accepts the characters of tabulation (that is to say the
+% characters U+0009) at the beginning of the lines. Each character U+0009 is
+% replaced by $n$~spaces. The initial value of $n$ is $4$ but it's possible to
+% change it with the key |tab-size| of |\PitonOptions|.
 %
+% \smallskip
+% \emph{Remark}: Unlike with the package \pkg{listings}, the key |gobble| and
+% its variants (|auto-gobble| and |env-gobble|) are applied \emph{before} the
+% transformation of the characters of tabulation in spaces.
+%
 % \section{Examples}
 %
 % \subsection{Line numbering}
@@ -533,21 +626,21 @@
 % By default, the numbers of the lines are composed by \pkg{piton} in an
 % overlapping position on the left (by using internally the command |\llap| of LaTeX).
 %
-% In order to avoid that overlapping, it's necessary to reserve a place for the
-% number of the lines with the key |left-margin|.
+% In order to avoid that overlapping, it's possible to use the option |left-margin=auto|
+% which will insert automatically a margin adapted to the numbers of lines that
+% will be written (that margin is larger when the numbers are greater than~10).
 %
 %
-%
 % \begingroup
 % \fvset{commandchars=\~\&\@,formatcom=\small\color{gray}}
 % \begin{Verbatim}
-% ~emphase&\PitonOptions{background-color=gray!10, left-margin = 5mm, line-numbers}@
+% ~emphase&\PitonOptions{background-color=gray!10, left-margin = auto, line-numbers}@
 % \begin{Piton}
 % def arctan(x,n=10):
 %     if x < 0:
-%         return -arctan(-x)        ## (appel récursif)
+%         return -arctan(-x)        #> (appel récursif)
 %     elif x > 1: 
-%         return pi/2 - arctan(1/x) ## (autre appel récursif) 
+%         return pi/2 - arctan(1/x) #> (autre appel récursif) 
 %     else: 
 %         return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) 
 % \end{Piton}
@@ -557,13 +650,13 @@
 %
 %
 % \begingroup
-% \PitonOptions{background-color=gray!10,left-margin = 5mm, line-numbers}
+% \PitonOptions{background-color=gray!10,left-margin = auto, line-numbers}
 % \begin{Piton}
 % def arctan(x,n=10):
 %     if x < 0:
-%         return -arctan(-x)        ## (appel récursif)
+%         return -arctan(-x)        #> (appel récursif)
 %     elif x > 1: 
-%         return pi/2 - arctan(1/x) ## (autre appel récursif) 
+%         return pi/2 - arctan(1/x) #> (autre appel récursif) 
 %     else: 
 %         return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) 
 % \end{Piton}
@@ -571,11 +664,13 @@
 %
 %
 %
-%
+% \bigskip
 % \subsection{Formatting of the LaTeX comments}
 %
+% \label{example-comments}
+%
 % It's possible to modify the style |Comment.LaTeX| (with |\SetPitonStyle|) in
-% order to display the LaTeX comments (which begin with |##|) aligned on the
+% order to display the LaTeX comments (which begin with |#>|) aligned on the
 % right margin.
 %
 %
@@ -587,9 +682,9 @@
 % \begin{Piton}
 % def arctan(x,n=10):
 %     if x < 0:
-%         return -arctan(-x)        ## appel récursif
+%         return -arctan(-x)        #> appel récursif
 %     elif x > 1: 
-%         return pi/2 - arctan(1/x) ## autre appel récursif 
+%         return pi/2 - arctan(1/x) #> autre appel récursif 
 %     else: 
 %         return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) 
 % \end{Piton}
@@ -602,9 +697,9 @@
 % \begin{Piton}
 % def arctan(x,n=10):
 %     if x < 0:
-%         return -arctan(-x)        ## appel récursif
+%         return -arctan(-x)        #> appel récursif
 %     elif x > 1: 
-%         return pi/2 - arctan(1/x) ## autre appel récursif 
+%         return pi/2 - arctan(1/x) #> autre appel récursif 
 %     else: 
 %         return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) 
 % \end{Piton}
@@ -626,9 +721,9 @@
 % \begin{Piton}
 % def arctan(x,n=10):
 %     if x < 0:
-%         return -arctan(-x)       ## appel récursif
+%         return -arctan(-x)       #> appel récursif
 %     elif x > 1: 
-%         return pi/2 - arctan(1/x) ## autre appel récursif 
+%         return pi/2 - arctan(1/x) #> autre appel récursif 
 %     else: 
 %         s = 0
 %         for k in range(n):
@@ -649,9 +744,9 @@
 % \begin{Piton}
 % def arctan(x,n=10):
 %     if x < 0:
-%         return -arctan(-x)       ## appel récursif
+%         return -arctan(-x)       #> appel récursif
 %     elif x > 1: 
-%         return pi/2 - arctan(1/x) ## autre appel récursif 
+%         return pi/2 - arctan(1/x) #> autre appel récursif 
 %     else: 
 %         s = 0
 %         for k in range(n):
@@ -662,7 +757,7 @@
 % \endgroup
 %
 %
-%
+% \bigskip
 % \subsection{Notes in the listings}
 %
 % \label{notes-examples}
@@ -674,7 +769,7 @@
 % loaded with the key |footnotehyper|.
 %
 % Of course, in an environment |{Piton}|, a command |\footnote| may appear only
-% within a LaTeX comment (which begins with |##|). It's possible to have comments
+% within a LaTeX comment (which begins with |#>|). It's possible to have comments
 % which contain only that command |\footnote|. That's the case in the following example.
 %
 %
@@ -686,9 +781,9 @@
 % \begin{Piton}
 % def arctan(x,n=10):
 %     if x < 0:
-%         return -arctan(-x)~emphase&##\footnote{First recursive call.}]@
+%         return -arctan(-x)~emphase&#>\footnote{First recursive call.}]@
 %     elif x > 1: 
-%         return pi/2 - arctan(1/x)~emphase&##\footnote{Second recursive call.}@
+%         return pi/2 - arctan(1/x)~emphase&#>\footnote{Second recursive call.}@
 %     else: 
 %         return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) 
 % \end{Piton}
@@ -700,9 +795,9 @@
 % \begin{Piton}
 % def arctan(x,n=10):
 %     if x < 0:
-%         return -arctan(-x)##\footnote{First recursive call.}
+%         return -arctan(-x)#>\footnote{First recursive call.}
 %     elif x > 1: 
-%         return pi/2 - arctan(1/x)##\footnote{Second recursive call.}
+%         return pi/2 - arctan(1/x)#>\footnote{Second recursive call.}
 %     else: 
 %         return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) 
 % \end{Piton}
@@ -724,9 +819,9 @@
 % \begin{Piton}
 % def arctan(x,n=10):
 %     if x < 0:
-%         return -arctan(-x)~emphase&##\footnote{First recursive call.}@
+%         return -arctan(-x)~emphase&#>\footnote{First recursive call.}@
 %     elif x > 1: 
-%         return pi/2 - arctan(1/x)~emphase&##\footnote{Second recursive call.}@
+%         return pi/2 - arctan(1/x)~emphase&#>\footnote{Second recursive call.}@
 %     else: 
 %         return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) 
 % \end{Piton}
@@ -740,9 +835,9 @@
 % \begin{Piton}
 % def arctan(x,n=10):
 %     if x < 0:
-%         return -arctan(-x)##\footnote{First recursive call.}
+%         return -arctan(-x)#>\footnote{First recursive call.}
 %     elif x > 1: 
-%         return pi/2 - arctan(1/x)##\footnote{Second recursive call.}
+%         return pi/2 - arctan(1/x)#>\footnote{Second recursive call.}
 %     else: 
 %         return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) 
 % \end{Piton}
@@ -766,9 +861,9 @@
 % \begin{Piton}
 % def arctan(x,n=10):
 %     if x < 0:
-%         return -arctan(-x)~emphase&##\footnote{First recursive call.}@
+%         return -arctan(-x)~emphase&#>\footnote{First recursive call.}@
 %     elif x > 1: 
-%         return pi/2 - arctan(1/x)~emphase&##\footnote{Second recursive call.}@
+%         return pi/2 - arctan(1/x)~emphase&#>\footnote{Second recursive call.}@
 %     else: 
 %         return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) 
 % \end{Piton}
@@ -785,9 +880,9 @@
 % \begin{Piton}
 % def arctan(x,n=10):
 %     if x < 0:
-%         return -arctan(-x)##\footnote{First recursive call.}
+%         return -arctan(-x)#>\footnote{First recursive call.}
 %     elif x > 1: 
-%         return pi/2 - arctan(1/x)##\footnote{Second recursive call.}
+%         return pi/2 - arctan(1/x)#>\footnote{Second recursive call.}
 %     else: 
 %         return sum( (-1)**k/(2*k+1)*x**(2*k+1) for k in range(n) ) 
 % \end{Piton}
@@ -794,6 +889,7 @@
 % \end{minipage}
 % \end{savenotes}
 %
+% \bigskip
 %
 % \subsection{An example of tuning of the styles}
 %
@@ -869,7 +965,7 @@
 %         return -arctan(-x) # appel récursif
 %     elif x > 1: 
 %         return pi/2 - arctan(1/x) 
-%         ## (we have used that $\arctan(x)+\arctan(1/x)=\pi/2$ for $x>0$)
+%         #> (we have used that $\arctan(x)+\arctan(1/x)=\pi/2$ for $x>0$)
 %     else: 
 %         s = 0
 %         for k in range(n):
@@ -879,7 +975,67 @@
 %
 % \endgroup
 % 
+% \subsection{Use with pyluatex}
 %
+% The package \pkg{pyluatex} is an extension which allows the execution of some
+% Python code from |lualatex| (provided that Python is installed on the machine
+% and that the compilation is done with |lualatex| and |--shell-escape|).
+%
+% Here is, for example, an environment |{PitonExecute}| which formats a Python
+% listing (with \pkg{piton}) but display also the output of the execution of the
+% code with Python. 
+%
+%
+% \begin{Verbatim}
+% \ExplSyntaxOn
+% \NewDocumentEnvironment { ~emphase#PitonExecute@ } { ! O { } } 
+%   { 
+%     \PyLTVerbatimEnv
+%     \begin{pythonq} 
+%   }
+%   {
+%     \end{pythonq}
+%     \directlua
+%       {
+%         tex.print("\\PitonOptions{~#1}")
+%         tex.print("\\begin{Piton}")
+%         tex.print(pyluatex.get_last_code())
+%         tex.print("\\end{Piton}")
+%         tex.print("") 
+%       }
+%     \begin{center}
+%       \directlua{tex.print(pyluatex.get_last_output())}
+%     \end{center}
+%   }
+% \ExplSyntaxOff
+% \end{Verbatim}
+%
+% \ExplSyntaxOn
+% \NewDocumentEnvironment { PitonExecute } { ! O { } } 
+%   { 
+%     \PyLTVerbatimEnv
+%     \begin{pythonq} 
+%   }
+%   {
+%     \end{pythonq}
+%     \directlua
+%       {
+%         tex.print("\\PitonOptions{~#1}")
+%         tex.print("\\begin{Piton}")
+%         tex.print(pyluatex.get_last_code())
+%         tex.print("\\end{Piton}")
+%         tex.print("") 
+%       }
+%     \begin{center}
+%       \directlua{tex.print(pyluatex.get_last_output())}
+%     \end{center}
+%   }
+% \ExplSyntaxOff
+%
+% This environment |{PitonExecute}| takes in as optional argument (between
+% square brackets) the options of the command |\PitonOptions|.
+%
+%
 % \bigskip
 % \clearpage
 %
@@ -1048,6 +1204,12 @@
 %    \begin{macrocode}
 \bool_new:N \c_@@_footnote_bool
 %    \end{macrocode}
+%
+% \medskip
+% The following boolean corresponds to the key |math-comments| (only at load-time).
+%    \begin{macrocode}
+\bool_new:N \c_@@_math_comments_bool
+%    \end{macrocode}
 % 
 % \bigskip
 % We define a set of keys for the options at load-time.
@@ -1058,6 +1220,10 @@
     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 , 
     unknown .code:n = \msg_error:nn { piton } { unknown~key~for~package }
   }
 %    \end{macrocode}
@@ -1067,12 +1233,12 @@
   {
     Unknown~key.\\
     You~have~used~the~key~'\l_keys_key_str'~but~the~only~keys~available~here~
-    are~'escape-inside',~'footnote'~and~'footnotehyper'.~Other~keys~are~
-    available~in~\token_to_str:N \PitonOptions.\\
+    are~'comment-latex',~'escape-inside',~'footnote',~'footnotehyper'~and~
+    'math-comments'.~Other~keys~are~available~in~\token_to_str:N \PitonOptions.\\
     That~key~will~be~ignored.
   }
 %    \end{macrocode}
-% 
+%
 % \bigskip
 % We process the options provided by the user at load-time.
 %    \begin{macrocode}
@@ -1084,8 +1250,8 @@
 \begingroup
 \cs_new_protected:Npn \@@_set_escape_char:nn #1 #2 
   {
-    \lua_now:n { begin_escape = "#1" }
-    \lua_now:n { end_escape = "#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 
@@ -1188,6 +1354,11 @@
 \int_new:N \l_@@_nb_lines_int
 %    \end{macrocode}
 % 
+% The same for the number of non-empty lines of the Python codes.
+%    \begin{macrocode}
+\int_new:N \l_@@_nb_non_empty_lines_int
+%    \end{macrocode}
+% 
 % The following counter will be used to count the lines during the composition.
 % It will count all the lines, empty or not empty. It won't be used to print the
 % numbers of the lines.
@@ -1252,7 +1423,9 @@
 %    \end{macrocode}
 %
 % \medskip
-% The following dimension corresponds to the key |left-margin| of |\PitonOptions|.
+% The following dimension corresponds to the key |left-margin| of
+% |\PitonOptions|. By convention, when the final user will uses
+% |left-margin=auto|, |\l_@@_left_margin_dim| will be equal to -1~cm.
 %    \begin{macrocode}
 \dim_new:N \l_@@_left_margin_dim
 %    \end{macrocode}
@@ -1274,26 +1447,6 @@
 \@@_set_tab_tl:n { 4 }
 %    \end{macrocode}
 % 
-% \medskip  
-%    \begin{macrocode}
-\cs_new_protected:Npn \@@_newline: 
-  { 
-    \int_gincr:N \g_@@_line_int
-    \int_compare:nNnT \g_@@_line_int > { \l_@@_splittable_int - 1 }
-      {
-        \int_compare:nNnT 
-          { \l_@@_nb_lines_int - \g_@@_line_int } > \l_@@_splittable_int 
-          {
-            \egroup
-            \bool_if:NT \c_@@_footnote_bool { \end { savenotes } } 
-            \newline
-            \bool_if:NT \c_@@_footnote_bool { \begin { savenotes } } 
-            \vtop \bgroup
-          }
-     }
-  } 
-%    \end{macrocode}
-% 
 % \medskip
 % The following integer corresponds to the key |gobble|.
 %    \begin{macrocode}
@@ -1300,6 +1453,12 @@
 \int_new:N \l_@@_gobble_int 
 %    \end{macrocode}
 %
+% \medskip
+%    \begin{macrocode}
+\tl_new:N \l_@@_space_tl
+\tl_set:Nn \l_@@_space_tl { ~ } 
+%    \end{macrocode}
+% 
 % \bigskip
 % \subsubsection{Treatment of a line of code}
 % 
@@ -1364,6 +1523,25 @@
   }
 %    \end{macrocode}
 %
+% \bigskip
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_newline: 
+  { 
+    \int_gincr:N \g_@@_line_int
+    \int_compare:nNnT \g_@@_line_int > { \l_@@_splittable_int - 1 }
+      {
+        \int_compare:nNnT 
+          { \l_@@_nb_lines_int - \g_@@_line_int } > \l_@@_splittable_int 
+          {
+            \egroup
+            \bool_if:NT \c_@@_footnote_bool { \end { savenotes } } 
+            \newline
+            \bool_if:NT \c_@@_footnote_bool { \begin { savenotes } } 
+            \vtop \bgroup
+          }
+     }
+  } 
+%    \end{macrocode}
 % 
 % \bigskip
 % \subsubsection{PitonOptions}
@@ -1409,10 +1587,15 @@
     background-color .value_required:n  = true ,
     slim             .bool_set:N        = \l_@@_slim_bool ,
     slim             .default:n         = true ,
-    left-margin      .dim_set:N         = \l_@@_left_margin_dim ,
+    left-margin      .code:n =
+      \str_if_eq:nnTF { #1 } { auto }
+        { \dim_set:Nn \l_@@_left_margin_dim { -1cm } }
+        { \dim_set:Nn \l_@@_left_margin_dim { #1 } } ,
     left-margin      .value_required:n  = true ,
     tab-size         .code:n            = \@@_set_tab_tl:n { #1 } ,
     tab-size         .value_required:n  = true , 
+    show-spaces      .code:n            = \tl_set:Nn \l_@@_space_tl { ␣ } , % U+2423
+    show-spaces      .value_forbidden:n = true ,
     unknown          .code:n = 
       \msg_error:nn { piton } { Unknown~key~for~PitonOptions }
   }
@@ -1426,7 +1609,7 @@
     Unknown~key. \\
     The~key~'\l_keys_key_str'~is~unknown~for~\token_to_str:N \PitonOptions.~The~
     available~keys~are:~all-line-numbers,~auto-gobble,~env-gobble,~gobble,~
-    left-margin,~line-numbers,~resume,~slim~splittable~and~tab-size.\\
+    left-margin,~line-numbers,~resume,~show-spaces,~slim,~splittable~and~tab-size.\\ 
     If~you~go~on,~that~key~will~be~ignored.
   }
 %    \end{macrocode}
@@ -1510,7 +1693,7 @@
       \ttfamily
       \cs_set_protected:Npn \@@_begin_line: { }
       \cs_set_protected:Npn \@@_end_line: { }
-      \lua_now:n { Parse(token.scan_argument()) } { #1 }
+      \lua_now:n { piton.Parse(token.scan_argument()) } { #1 }
     \group_end:
   }
 %    \end{macrocode}
@@ -1523,7 +1706,7 @@
     \group_begin:
       \cs_set_protected:Npn \@@_begin_line: { }
       \cs_set_protected:Npn \@@_end_line: { }
-      \lua_now:e { Parse(token.scan_argument()) } { #1 }
+      \lua_now:n { piton.Parse(token.scan_argument()) } { #1 }
     \group_end:
   }
 %    \end{macrocode}
@@ -1536,8 +1719,7 @@
   {
     \int_gincr:N \g_@@_env_int 
     \tl_gclear:N \g_@@_aux_tl
-    \tl_if_exist:cT { c_@@ _ \int_use:N \g_@@_env_int _ tl }
-      { \use:c { c_@@ _ \int_use:N \g_@@_env_int _ tl } }
+    \cs_if_exist_use:c { c_@@ _ \int_use:N \g_@@_env_int _ tl }
     \dim_compare:nNnT \l_@@_width_on_aux_dim = \c_zero_dim
       { \dim_set_eq:NN \l_@@_width_on_aux_dim \linewidth }
     \bool_if:NF \l_@@_resume_bool { \int_gzero:N \g_@@_visual_line_int }
@@ -1550,9 +1732,24 @@
 % 
 % \bigskip
 %    \begin{macrocode}
-\NewDocumentCommand { \PitonInputFile } { m }
+\keys_define:nn { PitonInputFile }
   {
+    first-line .int_set:N = \l_@@_first_line_int ,  
+    first-line .value_required:n = true ,
+    last-line .int_set:N = \l_@@_last_line_int , 
+    last-line .value_required:n = true , 
+  }
+%    \end{macrocode}
+% 
+% \bigskip
+%    \begin{macrocode}
+\NewDocumentCommand { \PitonInputFile } { O { } m }
+  {
     \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 } { #1 }
       \@@_pre_env:
       \mode_if_vertical:TF \mode_leave_vertical: \newline 
 %    \end{macrocode}
@@ -1560,11 +1757,51 @@
 % stored by Lua in |\l_@@_nb_lines_int|. That information will be used to allow
 % or disallow page breaks.
 %    \begin{macrocode}
-      \lua_now:n { CountLinesFile(token.scan_argument()) } { #1 }  
+      \lua_now:n { piton.CountLinesFile(token.scan_argument()) } { #2 }  
+% If the final user has used both |left-margin=auto| and |line-numbers| or
+% |all-line-numbers|, we have to compute the width of the maximal number of
+% lines at the end of the composition of the listing to fix the correct value to
+% |left-margin|. Par convention, when |left-margin=auto|, the dimension
+% |\l_@@_left_margin_dim| is set to -1~cm.
+%    \begin{macrocode}
+      \dim_compare:nNnT \l_@@_left_margin_dim < \c_zero_dim 
+        {
+          \bool_if:NT \l_@@_line_numbers_bool
+            {
+             \hbox_set:Nn \l_tmpa_box
+               {
+                 \footnotesize
+                 \bool_if:NTF \l_@@_all_line_numbers_bool
+                   {
+                      \int_to_arabic:n 
+                        { \g_@@_visual_line_int + \l_@@_nb_lines_int }  
+                   }
+                   {
+                      \lua_now:n 
+                        { piton.CountNonEmptyLinesFile(token.scan_argument()) } 
+                        { #2 }
+                      \int_to_arabic:n 
+                        { 
+                          \g_@@_visual_line_int +
+                          \l_@@_nb_non_empty_lines_int 
+                        }   
+                    }
+                }
+              \dim_set:Nn \l_@@_left_margin_dim { \box_wd:N \l_tmpa_box + 0.5em }
+            }
+        }
+%    \end{macrocode}
+% Now, the main job.
+%    \begin{macrocode}
       \ttfamily
       \bool_if:NT \c_@@_footnote_bool { \begin { savenotes } } 
       \vtop \bgroup 
-      \lua_now:n { ParseFile(token.scan_argument()) } { #1 }
+      \lua_now:e
+        { piton.ParseFile(token.scan_argument(),
+           \int_use:N \l_@@_first_line_int , 
+           \int_use:N \l_@@_last_line_int ) 
+        } 
+        { #2 }
       \egroup 
       \bool_if:NT \c_@@_footnote_bool { \end { savenotes } } 
       \@@_width_to_aux:
@@ -1601,13 +1838,52 @@
 % stored by Lua in |\l_@@_nb_lines_int|. That information will be used to allow
 % or disallow page breaks.
 %    \begin{macrocode}
-            \lua_now:n { CountLines(token.scan_argument()) } { ##1 }  
+            \lua_now:n { piton.CountLines(token.scan_argument()) } { ##1 }  
+%    \end{macrocode}
+% If the final user has used both |left-margin=auto| and |line-numbers|, we have
+% to compute the width of the maximal number of lines at the end of the
+% environment to fix the correct value to |left-margin|.
+%    \begin{macrocode}
+            \dim_compare:nNnT \l_@@_left_margin_dim < \c_zero_dim 
+              {
+                \bool_if:NT \l_@@_line_numbers_bool
+                  {
+                    \bool_if:NTF \l_@@_all_line_numbers_bool
+                      {
+                        \hbox_set:Nn \l_tmpa_box
+                          { 
+                            \footnotesize
+                            \int_to_arabic:n 
+                              { \g_@@_visual_line_int + \l_@@_nb_lines_int }  
+                          }
+                      }
+                      {
+                        \lua_now:n 
+                          { piton.CountNonEmptyLines(token.scan_argument()) } 
+                          { ##1 }  
+                        \hbox_set:Nn \l_tmpa_box
+                          { 
+                            \footnotesize
+                            \int_to_arabic:n 
+                              { 
+                                \g_@@_visual_line_int +
+                                \l_@@_nb_non_empty_lines_int 
+                              }   
+                          }
+                      }
+                    \dim_set:Nn \l_@@_left_margin_dim
+                      { \box_wd:N \l_tmpa_box + 0.5 em }
+                  }
+              }
+%    \end{macrocode}
+% Now, the main job.
+%    \begin{macrocode}
             \ttfamily
             \bool_if:NT \c_@@_footnote_bool { \begin { savenotes } } 
             \vtop \bgroup 
             \lua_now:e 
               { 
-                GobbleParse
+                piton.GobbleParse
                   ( \int_use:N \l_@@_gobble_int , token.scan_argument() ) 
               } 
               { ##1 }
@@ -1807,6 +2083,16 @@
 % The last style |Post.Function| should be considered as an ``internal style''
 % (not available for the final user).
 %
+% \medskip
+% If the key |math-comments| has been used at load-time, we change the style
+% |Comment.Math| which should be considered only at an ``internal style''.
+% However, maybe we will document in a future version the possibility to write
+% change the style \emph{locally} in a document).
+%    \begin{macrocode}
+\bool_if:NT \c_@@_math_comments_bool
+  { \SetPitonStyle { Comment.Math } }
+%    \end{macrocode}
+% 
 % \bigskip
 % \subsubsection{Security}
 %
@@ -1832,20 +2118,36 @@
 \ExplSyntaxOff
 \RequirePackage{luacode}
 %    \end{macrocode}
-%   
+% 
+%
+% \bigskip
+% The Lua code will be loaded via a |{luacode*}| environment. Thei environment
+% is by itself a Lua block and the local declarations will be local to that
+% block. All the global functions (used by the L3 parts of the implementation)
+% will be put in a Lua table |piton|.
+%
 % \medskip
 %    \begin{macrocode}
 \begin{luacode*}
+piton = piton or { }
 %    \end{macrocode}
-%
+% 
+%    \begin{macrocode}
+if piton.comment_latex == nil then piton.comment_latex = ">" end 
+piton.comment_latex = "#" .. piton.comment_latex 
+%    \end{macrocode}
+% 
+% 
 % \bigskip
 % \subsubsection{Special functions dealing with LPEG}
 %
+% 
 % \medskip
 % We will use the Lua library \pkg{lpeg} which is built in LuaTeX. That's why we
 % define first aliases for several functions of that library.
 %    \begin{macrocode}
-local P, S, V, C, Ct, Cc, Cf = lpeg.P, lpeg.S, lpeg.V, lpeg.C, lpeg.Ct, lpeg.Cc, lpeg.Cf
+local P, S, V, C, Ct, Cc = lpeg.P, lpeg.S, lpeg.V, lpeg.C, lpeg.Ct, lpeg.Cc
+local Cf, Cs = lpeg.Cf, lpeg.Cs
 %    \end{macrocode}
 % 
 %
@@ -1854,7 +2156,7 @@
 % \emph{which does a capture} of the pattern. That capture will be sent to LaTeX
 % with the catcode ``other'' for all the characters: it's suitable for elements
 % of the Python listings that \pkg{piton} will typeset verbatim (thanks to the
-% catcode ``other''). That function will be widely used.
+% catcode ``other''). 
 %    \begin{macrocode}
 local function Q(pattern)
   return Ct ( Cc ( luatexbase.catcodetables.CatcodeTableOther ) * C ( pattern ) )
@@ -1861,6 +2163,7 @@
 end 
 %    \end{macrocode}
 %
+%
 % \bigskip
 % The function |L| takes in as argument a pattern and returns a \textsc{lpeg}
 % \emph{which does a capture} of the pattern. That capture will be sent to LaTeX
@@ -1888,18 +2191,24 @@
 %    \end{macrocode}
 % 
 % \bigskip
-% The function |K| function creates a \textsc{lpeg} which will return as capture
+% The function |K| creates a \textsc{lpeg} which will return as capture
 % the whole LaTeX code corresponding to a Python chunk (that is to say with the
 % LaTeX formatting instructions corresponding to the syntactic nature of that
 % Python chunk). The first argument is a pattern (that is to say a \textsc{lpeg}
 % without capture) and the second element is a Lua string corresponding to the
-% name of a \pkg{piton} style.
+% name of a \pkg{piton} style. If the seconde argument is not present, the
+% function |K| behaves as the function |Q| does.
 %    \begin{macrocode}
 local function K(pattern, style)
+  if style 
+  then
   return 
      Lc ( "{\\PitonStyle{" .. style .. "}{" )
      * Q ( pattern )
      * Lc ( "}}" )
+  else 
+  return Q ( pattern ) 
+  end
 end
 %    \end{macrocode}
 % The formatting commands in a given \pkg{piton} style (eg. the style |Keyword|)
@@ -1911,17 +2220,18 @@
 % \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 |begin_espace| and |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.
+% recall that |piton.begin_espace| and |piton_end_escape| are Lua strings
+% corresponding to the key |escape-inside|\footnote{The \pkg{piton} key
+% |escape-inside| is available at load-time only.}. Since the elements that will
+% be catched must be sent to LaTeX with standard LaTeX catcodes, we put the
+% capture (done by the function |C|) in a table (by using |Ct|, which is an
+% alias for |lpeg.Ct|) without number of catcode table at the first component of
+% the table.
 %    \begin{macrocode}
 local Escape = 
-  P(begin_escape)
-  * L ( ( 1 - P(end_escape) ) ^ 1 ) 
-  * P(end_escape)
+  P(piton_begin_escape)
+  * L ( ( 1 - P(piton_end_escape) ) ^ 1 ) 
+  * P(piton_end_escape)
 %    \end{macrocode}
 % 
 % \vspace{1cm}
@@ -1959,13 +2269,9 @@
 % 
 % \medskip
 % On the other hand, the \textsc{lpeg} |Identifier| (with a capital) also return
-% a \emph{capture}. Since no special LaTeX formatting will be applied to the
-% Python identifiers, we use the function~|Q| and not the function~|K|. For
-% elements which require formatting, we will usually use our function~|K|
-% instead of the function~|C|. See just below for an example of use of the
-% function~|K|.
+% a \emph{capture}.
 %    \begin{macrocode}
-local Identifier = Q ( identifier )
+local Identifier = K ( identifier )
 %    \end{macrocode}
 %
 % \bigskip
@@ -1992,25 +2298,26 @@
 %    \end{macrocode}
 %
 % \bigskip
-% We recall that |begin_espace| and |end_escape| are Lua strings 
+% We recall that |piton.begin_espace| and |piton_end_escape| are Lua strings
 % corresponding to the key |escape-inside|\footnote{The \pkg{piton} key
 % |escape-inside| is available at load-time only.}. Of course, if the final user
 % has not used the key |escape-inside|, these strings are empty.
 %    \begin{macrocode}
-if begin_escape ~= ''
-then Word = Q ( ( ( 1 - space - P(begin_escape) - P(end_escape) ) 
+local Word
+if piton_begin_escape ~= ''
+then Word = K ( ( ( 1 - space - P(piton_begin_escape) - P(piton_end_escape) ) 
                    - S "'\"\r[()]" - digit ) ^ 1 )
-else Word = Q ( ( ( 1 - space ) - S "'\"\r[()]" - digit ) ^ 1 )
+else Word = K ( ( ( 1 - space ) - S "'\"\r[()]" - digit ) ^ 1 )
 end
 %    \end{macrocode}
 %
 % \bigskip
 %    \begin{macrocode}
-local Space = Q ( ( space - P "\r" ) ^ 1 )
+local Space = K ( ( space - P "\r" ) ^ 1 )
 
-local SkipSpace = Q ( ( space - P "\r" ) ^ 0 )
+local SkipSpace = K ( ( space - P "\r" ) ^ 0 )
 
-local Punct = Q ( S ".,:;!" )
+local Punct = K ( S ".,:;!" )
 %    \end{macrocode}
 %
 % \bigskip
@@ -2040,10 +2347,19 @@
 %
 % \bigskip
 %    \begin{macrocode}
-local Delim = Q ( S "[()]" )
-
+local Delim = K ( S "[()]" )
+%    \end{macrocode}
+% 
+% \bigskip
+% Some strings of length 2 are explicit because we want the corresponding
+% ligatures in the font \emph{Fira Code} to be active.
+%    \begin{macrocode}
 local Operator = 
-  K ( P "!=" + P "==" + P "<<" + P ">>" + S "-~+/*%=<>&.@|" , 'Operator')
+  K ( P "!=" + P "<>" + P "==" + P "<<" + P ">>" + P "<=" + P ">=" + P ":=" 
+      + P "//" + P "**" + S "-~+/*%=<>&.@|" 
+      , 
+      'Operator'
+    )
 
 local OperatorWord = 
   K ( P "in" + P "is" + P "and" + P "or" + P "not" , 'Operator.Word')
@@ -2095,9 +2411,9 @@
    + P "StopAsyncIteration" + P "ModuleNotFoundError" + P "RecursionError" ,
   'Exception' )
 
-local RaiseException = K ( P "raise" , 'Keyword' ) * SkipSpace * Exception * Q ( P "(" ) 
+local RaiseException = K ( P "raise" , 'Keyword' ) * SkipSpace * Exception * K ( P "(" ) 
 
-local ExceptionInConsole = Exception *  Q ( ( 1 - P "\r" ) ^ 0 ) * EOL  
+local ExceptionInConsole = Exception *  K ( ( 1 - P "\r" ) ^ 0 ) * EOL  
 %    \end{macrocode}
 %
 % \bigskip
@@ -2148,7 +2464,7 @@
    * ( 
        ( Space * K ( P "as" , 'Keyword' ) * Space * K ( identifier , 'Name.Namespace' ) )
        + 
-       ( SkipSpace * Q ( P "," ) * SkipSpace * K ( identifier , 'Name.Namespace' ) ) ^ 0 
+       ( SkipSpace * K ( P "," ) * SkipSpace * K ( identifier , 'Name.Namespace' ) ) ^ 0 
      ) 
 %    \end{macrocode}
 % Be careful: there is no commutativity of |+| in the previous expression.
@@ -2210,44 +2526,72 @@
 local SingleShortInterpol =
     K ( P "{" , 'String.Interpol')
   * K ( ( 1 - S "}':" ) ^ 0 , 'Interpol.Inside' )
-  * Q ( P ":" * (1 - S "}:'") ^ 0 ) ^ -1
+  * K ( P ":" * (1 - S "}:'") ^ 0 ) ^ -1
   * K ( P "}" , 'String.Interpol' )
 
 local DoubleShortInterpol =
     K ( P "{" , 'String.Interpol' )
   * K ( ( 1 - S "}\":" ) ^ 0 , 'Interpol.Inside' )
-  * ( K ( P ":" , 'String.Interpol' ) * Q ( (1 - S "}:\"") ^ 0 ) ) ^ -1
+  * ( K ( P ":" , 'String.Interpol' ) * K ( (1 - S "}:\"") ^ 0 ) ) ^ -1
   * K ( P "}" , 'String.Interpol' )
 
 local SingleLongInterpol =
     K ( P "{" , 'String.Interpol' )
   * K ( ( 1 - S "}:\r" - P "'''" ) ^ 0 , 'Interpol.Inside' )
-  * Q ( P ":" * (1 - S "}:\r" - P "'''" ) ^ 0 ) ^ -1
+  * K ( P ":" * (1 - S "}:\r" - P "'''" ) ^ 0 ) ^ -1
   * K ( P "}" , 'String.Interpol' )
 
 local DoubleLongInterpol =
     K ( P "{" , 'String.Interpol' )
   * K ( ( 1 - S "}:\r" - P "\"\"\"" ) ^ 0 , 'Interpol.Inside' )
-  * Q ( P ":" * (1 - S "}:\r" - P "\"\"\"" ) ^ 0 ) ^ -1
+  * K ( P ":" * (1 - S "}:\r" - P "\"\"\"" ) ^ 0 ) ^ -1
   * K ( P "}" , 'String.Interpol' )
 %    \end{macrocode}
 %
+% 
 % \bigskip
+% The following \textsc{lpeg} catches a space (U+0032) and replace it by
+% |\l_@@_space_tl|. It will be used in the short strings. Usually,
+% |\l_@@_space_tl| will contain a space and therefore there won't be difference.
+% However, when the key |show-spaces| is in force, |\\l_@@_space_tl| will
+% contain ␣ (U+2423) in order to visualize the spaces.
+%    \begin{macrocode}
+local VisualSpace = P " " * Lc "\\l_@@_space_tl" 
+%    \end{macrocode}
+%
+% \bigskip
 % Now, we define \textsc{lpeg} for the parts of the strings which are \emph{not}
 % in the interpolations.
+%
 %    \begin{macrocode}
 local SingleShortPureString = 
-  Q ( ( P "\\'" + P "{{" + P "}}" + 1 - S "{}'" ) ^ 1 )
+  ( K ( ( P "\\'" + P "{{" + P "}}" + 1 - S " {}'" ) ^ 1 ) + VisualSpace )  ^ 1 
 
 local DoubleShortPureString = 
-  Q ( ( P "\\\"" + P "{{" + P "}}" + 1 - S "{}\"" ) ^ 1 )
+  ( K ( ( P "\\\"" + P "{{" + P "}}" + 1 - S " {}\"" ) ^ 1 ) + VisualSpace ) ^ 1
 
 local SingleLongPureString = 
-  Q ( ( 1 - P "'''" - S "{}'\r" ) ^ 1 )
+  K ( ( 1 - P "'''" - S "{}'\r" ) ^ 1 )
 
 local DoubleLongPureString = 
-  Q ( ( 1 - P "\"\"\"" - S "{}\"\r" ) ^ 1 ) 
+  K ( ( 1 - P "\"\"\"" - S " {}\"\r" ) ^ 1 )
 %    \end{macrocode}
+%
+% \bigskip
+% The interpolations beginning by |%| (even though there is more modern
+% technics now in Python).
+%    \begin{macrocode}
+local PercentInterpol =  
+  K ( P "%" 
+      * ( P "(" * alphanum ^ 1 * P ")" ) ^ -1 
+      * ( S "-#0 +" ) ^ 0 
+      * ( digit ^ 1 + P "*" ) ^ -1 
+      * ( P "." * ( digit ^ 1 + P "*" ) ) ^ -1 
+      * ( S "HlL" ) ^ -1
+      * S "sdfFeExXorgiGauc%" ,
+      'String.Interpol' 
+    ) 
+%    \end{macrocode}
 % 
 % \bigskip
 % We can now define the \textsc{lpeg} for the four kinds of strings. It's not
@@ -2263,15 +2607,20 @@
 %    \end{macrocode}
 % First, we deal with the f-strings of Python, which are prefixed by |f| or |F|.
 %    \begin{macrocode}
-         Q ( P "f'" + P "F'" ) 
+         K ( P "f'" + P "F'" ) 
          * ( SingleShortInterpol + SingleShortPureString ) ^ 0 
-         * Q ( P "'" )
+         * K ( P "'" )
        + 
 %    \end{macrocode}
 % Now, we deal with the standard strings of Python, but also the ``raw strings''.
 %    \begin{macrocode}
-         Q ( ( P "'" + P "r'" + P "R'" ) 
-         * ( P "\\'" + 1 - S "'\r" ) ^ 0 * P "'" )
+         K ( P "'" + P "r'" + P "R'" ) 
+         * ( K ( ( P "\\'" + 1 - S " '\r%" ) ^ 1 ) 
+             + VisualSpace 
+             + PercentInterpol 
+             + K ( P "%" ) 
+           ) ^ 0 
+         * K ( P "'" )
      )
    * Lc ( "}}" ) 
 
@@ -2278,12 +2627,17 @@
 local DoubleShortString =
   Lc ( "{\\PitonStyle{String.Short}{" )
    * (
-         Q ( P "f\"" + P "F\"" ) 
+         K ( P "f\"" + P "F\"" ) 
          * ( DoubleShortInterpol + DoubleShortPureString ) ^ 0 
-         * Q ( P "\"" )
+         * K ( P "\"" )
        +
-         Q ( ( P "\"" + P "r\"" + P "R\"" ) 
-         * ( P "\\\"" + 1 - S "\"\r" ) ^ 0 * P "\"" )
+         K ( P "\"" + P "r\"" + P "R\"" ) 
+         * ( K ( ( P "\\\"" + 1 - S " \"\r%" ) ^ 1 ) 
+             + VisualSpace 
+             + PercentInterpol 
+             + K ( P "%" ) 
+           ) ^ 0 
+         * K ( P "\"" )
      )
    * Lc ( "}}" ) 
 
@@ -2299,7 +2653,7 @@
 local SingleLongString =
   Lc "{\\PitonStyle{String.Long}{" 
    * (
-         Q ( S "fF" * P "'''" )
+         K ( S "fF" * P "'''" )
          * ( SingleLongInterpol + SingleLongPureString ) ^ 0
          * Lc "}}" 
          * (
@@ -2313,19 +2667,19 @@
          * Lc "{\\PitonStyle{String.Long}{" 
          * ( SingleLongInterpol + SingleLongPureString ) ^ 0
        +
-         Q ( ( S "rR" ) ^ -1  * P "'''" 
+         K ( ( S "rR" ) ^ -1  * P "'''" 
              * ( 1 - P "'''" - P "\r" ) ^ 0 ) 
          * Lc "}}" 
          * (
              Lc "{\\PitonStyle{String.Long}{" 
-             * Q ( ( 1 - P "'''" - P "\r" ) ^ 0 )
+             * K ( ( 1 - P "'''" - P "\r" ) ^ 0 )  
              * Lc "}}" 
              * EOL
            ) ^ 0 
          * Lc "{\\PitonStyle{String.Long}{" 
-         * Q ( ( 1 - P "'''" - P "\r" ) ^ 0 )
+         * K ( ( 1 - P "'''" - P "\r" ) ^ 0 )
       )
-   * Q ( P "'''" )
+   * K ( P "'''" )
    * Lc "}}" 
 
 
@@ -2332,7 +2686,7 @@
 local DoubleLongString =
   Lc "{\\PitonStyle{String.Long}{" 
    * (
-         Q ( S "fF" * P "\"\"\"" )
+         K ( S "fF" * P "\"\"\"" )
          * ( DoubleLongInterpol + DoubleLongPureString ) ^ 0
          * Lc "}}" 
          * (
@@ -2346,19 +2700,19 @@
          * Lc "{\\PitonStyle{String.Long}{" 
          * ( DoubleLongInterpol + DoubleLongPureString ) ^ 0
        +
-         Q ( ( S "rR" ) ^ -1  * P "\"\"\""
+         K ( ( S "rR" ) ^ -1  * P "\"\"\""
               * ( 1 - P "\"\"\"" - P "\r" ) ^ 0 ) 
          * Lc "}}" 
          * (
              Lc "{\\PitonStyle{String.Long}{" 
-             * Q ( ( 1 - P "\"\"\"" - P "\r" ) ^ 0 )
+             * K ( ( 1 - P "\"\"\"" - P "\r" ) ^ 0 )
              * Lc "}}" 
              * EOL
            ) ^ 0 
          * Lc "{\\PitonStyle{String.Long}{" 
-         * Q ( ( 1 - P "\"\"\"" - P "\r" ) ^ 0 )
+         * K ( ( 1 - P "\"\"\"" - P "\r" ) ^ 0 )
       )
-   * Q ( P "\"\"\"" )
+   * K ( P "\"\"\"" )
    * Lc "}}" 
 %    \end{macrocode}
 %
@@ -2388,14 +2742,14 @@
 
 local Comment = 
   Lc ( "{\\PitonStyle{Comment}{" ) 
-  * Q ( P "#" ) 
-  * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0
+  * K ( P "#" ) 
+  * ( CommentMath + K ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0
   * Lc ( "}}" )
   * ( EOL + -1 )
 %    \end{macrocode}
 % 
-
-
+%
+%
 % \bigskip
 % The following \textsc{lpeg} |CommentLaTeX| is for what is called in that
 % document the ``LaTeX comments''. Since the elements that will be catched must
@@ -2403,7 +2757,7 @@
 % the function~|C|) in a table (by using~|Ct|, which is an alias for |lpeg.Ct|).
 %    \begin{macrocode}
 local CommentLaTeX =
-  P "##"
+  P(piton.comment_latex) 
   * Lc "{\\PitonStyle{Comment.LaTeX}{\\ignorespaces" 
   * L ( ( 1 - P "\r" ) ^ 0 ) 
   * Lc "}}" 
@@ -2456,13 +2810,13 @@
   SkipSpace * Identifier * SkipSpace
    * ( 
          K ( P "=" * Expression , 'InitialValues' )
-       + Q ( P ":" ) * SkipSpace * K ( letter^1 , 'Name.Type' ) 
+       + K ( P ":" ) * SkipSpace * K ( letter^1 , 'Name.Type' ) 
      ) ^ -1
 %    \end{macrocode}
 % 
 % \medskip
 %    \begin{macrocode}
-local Params = ( Param * ( Q "," * Param ) ^ 0 ) ^ -1
+local Params = ( Param * ( K "," * Param ) ^ 0 ) ^ -1
 %    \end{macrocode}
 % 
 % \bigskip
@@ -2477,8 +2831,9 @@
   * Space
   * K ( identifier , 'Name.Function' ) 
   * SkipSpace 
-  * Q ( P "(" ) * Params * Q ( P ")" ) 
+  * K ( P "(" ) * Params * K ( P ")" ) 
   * SkipSpace
+  * ( K ( P "->" ) * SkipSpace * K ( identifier , 'Name.Type' ) ) ^ -1
 %    \end{macrocode}
 % Here, we need a \pkg{piton} style |Post.Function| which will be linked to
 % |\@@_piton:n| (that means that the capture will be parsed once again by
@@ -2486,7 +2841,7 @@
 % grammar but we have probably here a better legibility.
 %    \begin{macrocode}
   * K ( ( 1 - S ":\r" )^0 , 'Post.Function' ) 
-  * Q ( P ":" )
+  * K ( P ":" )
   * ( SkipSpace
       * ( EOL + CommentLaTeX + Comment ) -- in all cases, that contains an EOL
       * Tab ^ 0 
@@ -2527,15 +2882,14 @@
 %
 %    \begin{macrocode}
 local ItemDict = 
-  ShortString * SkipSpace * Q ( P ":" ) * K ( Expression , 'Dict.Value' ) 
+  ShortString * SkipSpace * K ( P ":" ) * K ( Expression , 'Dict.Value' ) 
 
 local ItemOfSet = SkipSpace * ( ItemDict + ShortString ) * SkipSpace 
 
 local Set = 
-  Q ( P "{" ) 
-  * ItemOfSet * ( Q ( P "," ) * ItemOfSet )  ^ 0 
-  * Q ( P "}" )
-
+  K ( P "{" ) 
+  * ItemOfSet * ( K ( P "," ) * ItemOfSet )  ^ 0 
+  * K ( P "}" )
 %    \end{macrocode}
 %
 %
@@ -2587,7 +2941,7 @@
       ) ^0 * -1 * Lc ( '\\@@_end_line:' )
 %    \end{macrocode}
 %
-% We have written a auxiliary \textsc{lpeg} |SyntaxPythonAux| for legibility only.
+% We have written an auxiliary \textsc{lpeg} |SyntaxPythonAux| for legibility only.
 %    \begin{macrocode}
 local SyntaxPython = Ct ( SyntaxPythonAux ) 
 %    \end{macrocode}
@@ -2603,8 +2957,8 @@
 % 
 % \bigskip
 %    \begin{macrocode}
-function Parse(code)
-  local t = SyntaxPython : match ( code )
+function piton.Parse(code)
+  local t = SyntaxPython : match ( code ) -- match is a method of the LPEG
   for _ , s in ipairs(t) do tex.tprint(s) end 
 end
 %    \end{macrocode}
@@ -2614,10 +2968,17 @@
 % That function merely reads the whole file (that is to say all its lines) and
 % then apply the function~|Parse| to the resulting Lua string.
 %    \begin{macrocode}
-function ParseFile(name)
+function piton.ParseFile(name,first_line,last_line)
   s = ''
-  for line in io.lines(name) do s = s .. '\r' .. line end
-  Parse(s) 
+  local i = 0 
+  for line in io.lines(name) 
+  do i = i + 1 
+     if i >= first_line
+     then s = s .. '\r' .. line 
+     end
+     if i >= last_line then break end 
+  end
+  piton.Parse(s) 
 end
 %    \end{macrocode}
 %
@@ -2633,7 +2994,7 @@
 % a \textsc{lpeg} that we have to compute dynamically because if depends on the
 % value of~$n$.
 %    \begin{macrocode}
-function gobble(n,code)
+local function gobble(n,code)
   function concat(acc,new_value)
     return acc .. new_value
   end 
@@ -2653,18 +3014,6 @@
 end
 %    \end{macrocode}
 %
-% \bigskip
-%    \begin{macrocode}
-function GobbleParse(n,code)
-  if n==-1 
-  then n = AutoGobbleLPEG : match(code)
-  else if n==-2 
-       then n = EnvGobbleLPEG : match(code)
-       end
-  end
-  Parse(gobble(n,code))
-end 
-%    \end{macrocode}
 % 
 % 
 % \bigskip
@@ -2671,7 +3020,7 @@
 % The following function |add| will be used in the following \textsc{lpeg}
 % |AutoGobbleLPEG| and |EnvGobbleLPEG|.
 %    \begin{macrocode}
-function add(acc,new_value)
+local function add(acc,new_value)
   return acc + new_value
 end 
 %    \end{macrocode}
@@ -2682,7 +3031,7 @@
 % captures} (|lpeg.Cf|), one using |add| and the other (encompassing the
 % previous one) using |math.min| as folding operator.
 %    \begin{macrocode}
-AutoGobbleLPEG = 
+local AutoGobbleLPEG = 
     ( space ^ 0 * P "\r" ) ^ -1 
     * Cf (
            (
@@ -2711,19 +3060,32 @@
 % traditionnal way to indent in LaTeX). The main work is done by a \emph{fold
 % capture} (|lpeg.Cf|) using the function |add| as folding operator.
 %    \begin{macrocode}
-EnvGobbleLPEG =
+local EnvGobbleLPEG =
   ( ( 1 - P "\r" ) ^ 0 * P "\r" ) ^ 0 
     * Cf ( Cc(0) * ( P " " * Cc(1) ) ^ 0 , add ) * -1
 %    \end{macrocode}
 % 
 % \bigskip
+%    \begin{macrocode}
+function piton.GobbleParse(n,code)
+  if n==-1 
+  then n = AutoGobbleLPEG : match(code)
+  else if n==-2 
+       then n = EnvGobbleLPEG : match(code)
+       end
+  end
+  piton.Parse(gobble(n,code))
+end 
+%    \end{macrocode}
+%
+% \bigskip
 % \subsubsection{To count the number of lines}
 %
 % \medskip
 %    \begin{macrocode}
-function CountLines(code)
+function piton.CountLines(code)
   local count = 0 
-  for i in code:gmatch("\r") do count = count + 1 end 
+  for i in code : gmatch ( "\r" ) do count = count + 1 end 
   tex.sprint( 
       luatexbase.catcodetables.expl , 
       '\\int_set:Nn \\l_@@_nb_lines_int {' .. count .. '}' )
@@ -2730,9 +3092,27 @@
 end 
 %    \end{macrocode}
 %
+%    \begin{macrocode}
+function piton.CountNonEmptyLines(code)
+  local count = 0 
+  count = 
+  ( Cf (  Cc(0) * 
+          ( 
+            ( P " " ) ^ 0 * P "\r"  
+            + ( 1 - P "\r" ) ^ 0 * P "\r" * Cc(1) 
+          ) ^ 0 
+          * (1 - P "\r" ) ^ 0 ,
+         add
+       ) * -1 ) : match (code) 
+  tex.sprint( 
+      luatexbase.catcodetables.expl , 
+      '\\int_set:Nn \\l_@@_nb_non_empty_lines_int {' .. count .. '}' )
+end 
+%    \end{macrocode}
+%
 % \bigskip
 %    \begin{macrocode}
-function CountLinesFile(name)
+function piton.CountLinesFile(name)
   local count = 0 
   for line in io.lines(name) do count = count + 1 end
   tex.sprint( 
@@ -2740,7 +3120,24 @@
       '\\int_set:Nn \\l_@@_nb_lines_int {' .. count .. '}' )
 end 
 %    \end{macrocode}
+%
+%
+% \bigskip
+%    \begin{macrocode}
+function piton.CountNonEmptyLinesFile(name)
+  local count = 0 
+  for line in io.lines(name) 
+  do if not ( ( ( P " " ) ^ 0 * -1 ) : match ( line ) ) 
+     then count = count + 1 
+     end
+  end
+  tex.sprint( 
+      luatexbase.catcodetables.expl , 
+      '\\int_set:Nn \\l_@@_nb_non_empty_lines_int {' .. count .. '}' )
+end 
+%    \end{macrocode}
 % 
+% 
 % \bigskip
 %    \begin{macrocode}
 \end{luacode*}
@@ -2769,6 +3166,18 @@
 %
 % Integer value for the key |splittable|.
 %
+% \subsection*{Changes between versions 0.9 and 0.95}
+%
+% New key |show-spaces|.
+%
+% The key |left-margin| now accepts the special value |auto|.
+%
+% New key |latex-comment| at load-time and replacement of |##| by |#>|
+%
+% New key |math-comments| at load-time.
+%
+% New keys |first-line| and |last-line| for the command |\InputPitonFile|.
+%
 % \end{document}
 % 
 %

Modified: trunk/Master/texmf-dist/tex/lualatex/piton/piton.sty
===================================================================
--- trunk/Master/texmf-dist/tex/lualatex/piton/piton.sty	2022-11-09 21:08:02 UTC (rev 64978)
+++ trunk/Master/texmf-dist/tex/lualatex/piton/piton.sty	2022-11-09 21:08:15 UTC (rev 64979)
@@ -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{0.9}
-\def\myfiledate{2022/10/31}
+\def\myfileversion{0.95}
+\def\myfiledate{2022/11/09}
 
 
 
@@ -36,6 +36,7 @@
 \RequirePackage { luatexbase }
 \bool_new:N \c__piton_footnotehyper_bool
 \bool_new:N \c__piton_footnote_bool
+\bool_new:N \c__piton_math_comments_bool
 \keys_define:nn { piton / package }
   {
     footnote .bool_set:N = \c__piton_footnote_bool ,
@@ -42,6 +43,10 @@
     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 ,
     unknown .code:n = \msg_error:nn { piton } { unknown~key~for~package }
   }
 \msg_new:nnn { piton } { unknown~key~for~package }
@@ -48,8 +53,8 @@
   {
     Unknown~key.\\
     You~have~used~the~key~'\l_keys_key_str'~but~the~only~keys~available~here~
-    are~'escape-inside',~'footnote'~and~'footnotehyper'.~Other~keys~are~
-    available~in~\token_to_str:N \PitonOptions.\\
+    are~'comment-latex',~'escape-inside',~'footnote',~'footnotehyper'~and~
+    'math-comments'.~Other~keys~are~available~in~\token_to_str:N \PitonOptions.\\
     That~key~will~be~ignored.
   }
 \ProcessKeysOptions { piton / package }
@@ -56,8 +61,8 @@
 \begingroup
 \cs_new_protected:Npn \__piton_set_escape_char:nn #1 #2
   {
-    \lua_now:n { begin_escape = "#1" }
-    \lua_now:n { end_escape = "#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
@@ -117,6 +122,7 @@
       }
   }
 \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
 \tl_new:N \g__piton_aux_tl
 \int_new:N \l__piton_splittable_int
@@ -135,23 +141,9 @@
       { \tl_put_right:Nn \l__piton_tab_tl { ~ } }
   }
 \__piton_set_tab_tl:n { 4 }
-\cs_new_protected:Npn \__piton_newline:
-  {
-    \int_gincr:N \g__piton_line_int
-    \int_compare:nNnT \g__piton_line_int > { \l__piton_splittable_int - 1 }
-      {
-        \int_compare:nNnT
-          { \l__piton_nb_lines_int - \g__piton_line_int } > \l__piton_splittable_int
-          {
-            \egroup
-            \bool_if:NT \c__piton_footnote_bool { \end { savenotes } }
-            \newline
-            \bool_if:NT \c__piton_footnote_bool { \begin { savenotes } }
-            \vtop \bgroup
-          }
-     }
-  }
 \int_new:N \l__piton_gobble_int
+\tl_new:N \l__piton_space_tl
+\tl_set:Nn \l__piton_space_tl { ~ }
 \cs_set_protected:Npn \__piton_begin_line: #1 \__piton_end_line:
   {
     \bool_if:NTF \l__piton_slim_bool
@@ -199,6 +191,22 @@
       }
     \vspace { - 2.5 pt }
   }
+\cs_new_protected:Npn \__piton_newline:
+  {
+    \int_gincr:N \g__piton_line_int
+    \int_compare:nNnT \g__piton_line_int > { \l__piton_splittable_int - 1 }
+      {
+        \int_compare:nNnT
+          { \l__piton_nb_lines_int - \g__piton_line_int } > \l__piton_splittable_int
+          {
+            \egroup
+            \bool_if:NT \c__piton_footnote_bool { \end { savenotes } }
+            \newline
+            \bool_if:NT \c__piton_footnote_bool { \begin { savenotes } }
+            \vtop \bgroup
+          }
+     }
+  }
 \bool_new:N \l__piton_line_numbers_bool
 \bool_new:N \l__piton_all_line_numbers_bool
 \bool_new:N \l__piton_resume_bool
@@ -224,10 +232,15 @@
     background-color .value_required:n  = true ,
     slim             .bool_set:N        = \l__piton_slim_bool ,
     slim             .default:n         = true ,
-    left-margin      .dim_set:N         = \l__piton_left_margin_dim ,
+    left-margin      .code:n =
+      \str_if_eq:nnTF { #1 } { auto }
+        { \dim_set:Nn \l__piton_left_margin_dim { -1cm } }
+        { \dim_set:Nn \l__piton_left_margin_dim { #1 } } ,
     left-margin      .value_required:n  = true ,
     tab-size         .code:n            = \__piton_set_tab_tl:n { #1 } ,
     tab-size         .value_required:n  = true ,
+    show-spaces      .code:n            = \tl_set:Nn \l__piton_space_tl { ␣ } , % U+2423
+    show-spaces      .value_forbidden:n = true ,
     unknown          .code:n =
       \msg_error:nn { piton } { Unknown~key~for~PitonOptions }
   }
@@ -236,7 +249,7 @@
     Unknown~key. \\
     The~key~'\l_keys_key_str'~is~unknown~for~\token_to_str:N \PitonOptions.~The~
     available~keys~are:~all-line-numbers,~auto-gobble,~env-gobble,~gobble,~
-    left-margin,~line-numbers,~resume,~slim~splittable~and~tab-size.\\
+    left-margin,~line-numbers,~resume,~show-spaces,~slim,~splittable~and~tab-size.\\
     If~you~go~on,~that~key~will~be~ignored.
   }
 \NewDocumentCommand \PitonOptions { } { \keys_set:nn { PitonOptions } }
@@ -284,7 +297,7 @@
       \ttfamily
       \cs_set_protected:Npn \__piton_begin_line: { }
       \cs_set_protected:Npn \__piton_end_line: { }
-      \lua_now:n { Parse(token.scan_argument()) } { #1 }
+      \lua_now:n { piton.Parse(token.scan_argument()) } { #1 }
     \group_end:
   }
 \cs_new_protected:Npn \__piton_piton:n #1
@@ -292,7 +305,7 @@
     \group_begin:
       \cs_set_protected:Npn \__piton_begin_line: { }
       \cs_set_protected:Npn \__piton_end_line: { }
-      \lua_now:e { Parse(token.scan_argument()) } { #1 }
+      \lua_now:n { piton.Parse(token.scan_argument()) } { #1 }
     \group_end:
   }
 \cs_new:Npn \__piton_pre_env:
@@ -299,8 +312,7 @@
   {
     \int_gincr:N \g__piton_env_int
     \tl_gclear:N \g__piton_aux_tl
-    \tl_if_exist:cT { c__piton _ \int_use:N \g__piton_env_int _ tl }
-      { \use:c { c__piton _ \int_use:N \g__piton_env_int _ tl } }
+    \cs_if_exist_use:c { c__piton _ \int_use:N \g__piton_env_int _ tl }
     \dim_compare:nNnT \l__piton_width_on_aux_dim = \c_zero_dim
       { \dim_set_eq:NN \l__piton_width_on_aux_dim \linewidth }
     \bool_if:NF \l__piton_resume_bool { \int_gzero:N \g__piton_visual_line_int }
@@ -309,16 +321,58 @@
     \dim_zero:N \parindent
     \dim_zero:N \lineskip
   }
-\NewDocumentCommand { \PitonInputFile } { m }
+\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 ,
+  }
+\NewDocumentCommand { \PitonInputFile } { O { } m }
+  {
     \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 } { #1 }
       \__piton_pre_env:
       \mode_if_vertical:TF \mode_leave_vertical: \newline
-      \lua_now:n { CountLinesFile(token.scan_argument()) } { #1 }
+      \lua_now:n { piton.CountLinesFile(token.scan_argument()) } { #2 }
+      \dim_compare:nNnT \l__piton_left_margin_dim < \c_zero_dim
+        {
+          \bool_if:NT \l__piton_line_numbers_bool
+            {
+             \hbox_set:Nn \l_tmpa_box
+               {
+                 \footnotesize
+                 \bool_if:NTF \l__piton_all_line_numbers_bool
+                   {
+                      \int_to_arabic:n
+                        { \g__piton_visual_line_int + \l__piton_nb_lines_int }
+                   }
+                   {
+                      \lua_now:n
+                        { piton.CountNonEmptyLinesFile(token.scan_argument()) }
+                        { #2 }
+                      \int_to_arabic:n
+                        {
+                          \g__piton_visual_line_int +
+                          \l__piton_nb_non_empty_lines_int
+                        }
+                    }
+                }
+              \dim_set:Nn \l__piton_left_margin_dim { \box_wd:N \l_tmpa_box + 0.5em }
+            }
+        }
       \ttfamily
       \bool_if:NT \c__piton_footnote_bool { \begin { savenotes } }
       \vtop \bgroup
-      \lua_now:n { ParseFile(token.scan_argument()) } { #1 }
+      \lua_now:e
+        { piton.ParseFile(token.scan_argument(),
+           \int_use:N \l__piton_first_line_int ,
+           \int_use:N \l__piton_last_line_int )
+        }
+        { #2 }
       \egroup
       \bool_if:NT \c__piton_footnote_bool { \end { savenotes } }
       \__piton_width_to_aux:
@@ -338,13 +392,44 @@
           {
             \group_end:
             \mode_if_vertical:TF \mode_leave_vertical: \newline
-            \lua_now:n { CountLines(token.scan_argument()) } { ##1 }
+            \lua_now:n { piton.CountLines(token.scan_argument()) } { ##1 }
+            \dim_compare:nNnT \l__piton_left_margin_dim < \c_zero_dim
+              {
+                \bool_if:NT \l__piton_line_numbers_bool
+                  {
+                    \bool_if:NTF \l__piton_all_line_numbers_bool
+                      {
+                        \hbox_set:Nn \l_tmpa_box
+                          {
+                            \footnotesize
+                            \int_to_arabic:n
+                              { \g__piton_visual_line_int + \l__piton_nb_lines_int }
+                          }
+                      }
+                      {
+                        \lua_now:n
+                          { piton.CountNonEmptyLines(token.scan_argument()) }
+                          { ##1 }
+                        \hbox_set:Nn \l_tmpa_box
+                          {
+                            \footnotesize
+                            \int_to_arabic:n
+                              {
+                                \g__piton_visual_line_int +
+                                \l__piton_nb_non_empty_lines_int
+                              }
+                          }
+                      }
+                    \dim_set:Nn \l__piton_left_margin_dim
+                      { \box_wd:N \l_tmpa_box + 0.5 em }
+                  }
+              }
             \ttfamily
             \bool_if:NT \c__piton_footnote_bool { \begin { savenotes } }
             \vtop \bgroup
             \lua_now:e
               {
-                GobbleParse
+                piton.GobbleParse
                   ( \int_use:N \l__piton_gobble_int , token.scan_argument() )
               }
               { ##1 }
@@ -478,6 +563,8 @@
     Interpol.Inside  = \color{black}\__piton_piton:n ,
     Post.Function    = \__piton_piton:n ,
   }
+\bool_if:NT \c__piton_math_comments_bool
+  { \SetPitonStyle { Comment.Math } }
 \AddToHook { env / piton / begin }
    { \msg_fatal:nn { piton } { No~environment~piton } }
 
@@ -491,7 +578,11 @@
 \ExplSyntaxOff
 \RequirePackage{luacode}
 \begin{luacode*}
-local P, S, V, C, Ct, Cc, Cf = lpeg.P, lpeg.S, lpeg.V, lpeg.C, lpeg.Ct, lpeg.Cc, lpeg.Cf
+piton = piton or { }
+if piton.comment_latex == nil then piton.comment_latex = ">" end
+piton.comment_latex = "#" .. piton.comment_latex
+local P, S, V, C, Ct, Cc = lpeg.P, lpeg.S, lpeg.V, lpeg.C, lpeg.Ct, lpeg.Cc
+local Cf, Cs = lpeg.Cf, lpeg.Cs
 local function Q(pattern)
   return Ct ( Cc ( luatexbase.catcodetables.CatcodeTableOther ) * C ( pattern ) )
 end
@@ -502,15 +593,20 @@
   return Cc ( { luatexbase.catcodetables.expl , string } )
 end
 local function K(pattern, style)
+  if style
+  then
   return
      Lc ( "{\\PitonStyle{" .. style .. "}{" )
      * Q ( pattern )
      * Lc ( "}}" )
+  else
+  return Q ( pattern )
+  end
 end
 local Escape =
-  P(begin_escape)
-  * L ( ( 1 - P(end_escape) ) ^ 1 )
-  * P(end_escape)
+  P(piton_begin_escape)
+  * L ( ( 1 - P(piton_end_escape) ) ^ 1 )
+  * P(piton_end_escape)
 lpeg.locale(lpeg)
 local alpha, digit, space = lpeg.alpha, lpeg.digit, lpeg.space
 local letter = alpha + P "_"
@@ -520,7 +616,7 @@
 
 local alphanum = letter + digit
 local identifier = letter * alphanum ^ 0
-local Identifier = Q ( identifier )
+local Identifier = K ( identifier )
 local Number =
   K (
       ( digit^1 * P "." * digit^0 + digit^0 * P "." * digit^1 + digit^1 )
@@ -528,16 +624,17 @@
       + digit^1 ,
       'Number'
     )
-if begin_escape ~= ''
-then Word = Q ( ( ( 1 - space - P(begin_escape) - P(end_escape) )
+local Word
+if piton_begin_escape ~= ''
+then Word = K ( ( ( 1 - space - P(piton_begin_escape) - P(piton_end_escape) )
                    - S "'\"\r[()]" - digit ) ^ 1 )
-else Word = Q ( ( ( 1 - space ) - S "'\"\r[()]" - digit ) ^ 1 )
+else Word = K ( ( ( 1 - space ) - S "'\"\r[()]" - digit ) ^ 1 )
 end
-local Space = Q ( ( space - P "\r" ) ^ 1 )
+local Space = K ( ( space - P "\r" ) ^ 1 )
 
-local SkipSpace = Q ( ( space - P "\r" ) ^ 0 )
+local SkipSpace = K ( ( space - P "\r" ) ^ 0 )
 
-local Punct = Q ( S ".,:;!" )
+local Punct = K ( S ".,:;!" )
 local Tab = P "\t" * Lc ( '\\l__piton_tab_tl' )
 local EOL =
   P "\r"
@@ -547,10 +644,13 @@
     +
     Lc ( '\\__piton_end_line: \\__piton_newline: \\__piton_begin_line:' )
   )
-local Delim = Q ( S "[()]" )
-
+local Delim = K ( S "[()]" )
 local Operator =
-  K ( P "!=" + P "==" + P "<<" + P ">>" + S "-~+/*%=<>&.@|" , 'Operator')
+  K ( P "!=" + P "<>" + P "==" + P "<<" + P ">>" + P "<=" + P ">=" + P ":="
+      + P "//" + P "**" + S "-~+/*%=<>&.@|"
+      ,
+      'Operator'
+    )
 
 local OperatorWord =
   K ( P "in" + P "is" + P "and" + P "or" + P "not" , 'Operator.Word')
@@ -602,9 +702,9 @@
    + P "StopAsyncIteration" + P "ModuleNotFoundError" + P "RecursionError" ,
   'Exception' )
 
-local RaiseException = K ( P "raise" , 'Keyword' ) * SkipSpace * Exception * Q ( P "(" )
+local RaiseException = K ( P "raise" , 'Keyword' ) * SkipSpace * Exception * K ( P "(" )
 
-local ExceptionInConsole = Exception *  Q ( ( 1 - P "\r" ) ^ 0 ) * EOL
+local ExceptionInConsole = Exception *  K ( ( 1 - P "\r" ) ^ 0 ) * EOL
 local Decorator = K ( P "@" * letter^1 , 'Name.Decorator' )
 local DefClass =
   K ( P "class" , 'Keyword' ) * Space * K ( identifier , 'Name.Class' )
@@ -617,7 +717,7 @@
    * (
        ( Space * K ( P "as" , 'Keyword' ) * Space * K ( identifier , 'Name.Namespace' ) )
        +
-       ( SkipSpace * Q ( P "," ) * SkipSpace * K ( identifier , 'Name.Namespace' ) ) ^ 0
+       ( SkipSpace * K ( P "," ) * SkipSpace * K ( identifier , 'Name.Namespace' ) ) ^ 0
      )
 local FromImport =
   K ( P "from" , 'Keyword' )
@@ -626,46 +726,62 @@
 local SingleShortInterpol =
     K ( P "{" , 'String.Interpol')
   * K ( ( 1 - S "}':" ) ^ 0 , 'Interpol.Inside' )
-  * Q ( P ":" * (1 - S "}:'") ^ 0 ) ^ -1
+  * K ( P ":" * (1 - S "}:'") ^ 0 ) ^ -1
   * K ( P "}" , 'String.Interpol' )
 
 local DoubleShortInterpol =
     K ( P "{" , 'String.Interpol' )
   * K ( ( 1 - S "}\":" ) ^ 0 , 'Interpol.Inside' )
-  * ( K ( P ":" , 'String.Interpol' ) * Q ( (1 - S "}:\"") ^ 0 ) ) ^ -1
+  * ( K ( P ":" , 'String.Interpol' ) * K ( (1 - S "}:\"") ^ 0 ) ) ^ -1
   * K ( P "}" , 'String.Interpol' )
 
 local SingleLongInterpol =
     K ( P "{" , 'String.Interpol' )
   * K ( ( 1 - S "}:\r" - P "'''" ) ^ 0 , 'Interpol.Inside' )
-  * Q ( P ":" * (1 - S "}:\r" - P "'''" ) ^ 0 ) ^ -1
+  * K ( P ":" * (1 - S "}:\r" - P "'''" ) ^ 0 ) ^ -1
   * K ( P "}" , 'String.Interpol' )
 
 local DoubleLongInterpol =
     K ( P "{" , 'String.Interpol' )
   * K ( ( 1 - S "}:\r" - P "\"\"\"" ) ^ 0 , 'Interpol.Inside' )
-  * Q ( P ":" * (1 - S "}:\r" - P "\"\"\"" ) ^ 0 ) ^ -1
+  * K ( P ":" * (1 - S "}:\r" - P "\"\"\"" ) ^ 0 ) ^ -1
   * K ( P "}" , 'String.Interpol' )
+local VisualSpace = P " " * Lc "\\l__piton_space_tl"
 local SingleShortPureString =
-  Q ( ( P "\\'" + P "{{" + P "}}" + 1 - S "{}'" ) ^ 1 )
+  ( K ( ( P "\\'" + P "{{" + P "}}" + 1 - S " {}'" ) ^ 1 ) + VisualSpace )  ^ 1
 
 local DoubleShortPureString =
-  Q ( ( P "\\\"" + P "{{" + P "}}" + 1 - S "{}\"" ) ^ 1 )
+  ( K ( ( P "\\\"" + P "{{" + P "}}" + 1 - S " {}\"" ) ^ 1 ) + VisualSpace ) ^ 1
 
 local SingleLongPureString =
-  Q ( ( 1 - P "'''" - S "{}'\r" ) ^ 1 )
+  K ( ( 1 - P "'''" - S "{}'\r" ) ^ 1 )
 
 local DoubleLongPureString =
-  Q ( ( 1 - P "\"\"\"" - S "{}\"\r" ) ^ 1 )
+  K ( ( 1 - P "\"\"\"" - S " {}\"\r" ) ^ 1 )
+local PercentInterpol =
+  K ( P "%"
+      * ( P "(" * alphanum ^ 1 * P ")" ) ^ -1
+      * ( S "-#0 +" ) ^ 0
+      * ( digit ^ 1 + P "*" ) ^ -1
+      * ( P "." * ( digit ^ 1 + P "*" ) ) ^ -1
+      * ( S "HlL" ) ^ -1
+      * S "sdfFeExXorgiGauc%" ,
+      'String.Interpol'
+    )
 local SingleShortString =
   Lc ( "{\\PitonStyle{String.Short}{" )
    * (
-         Q ( P "f'" + P "F'" )
+         K ( P "f'" + P "F'" )
          * ( SingleShortInterpol + SingleShortPureString ) ^ 0
-         * Q ( P "'" )
+         * K ( P "'" )
        +
-         Q ( ( P "'" + P "r'" + P "R'" )
-         * ( P "\\'" + 1 - S "'\r" ) ^ 0 * P "'" )
+         K ( P "'" + P "r'" + P "R'" )
+         * ( K ( ( P "\\'" + 1 - S " '\r%" ) ^ 1 )
+             + VisualSpace
+             + PercentInterpol
+             + K ( P "%" )
+           ) ^ 0
+         * K ( P "'" )
      )
    * Lc ( "}}" )
 
@@ -672,12 +788,17 @@
 local DoubleShortString =
   Lc ( "{\\PitonStyle{String.Short}{" )
    * (
-         Q ( P "f\"" + P "F\"" )
+         K ( P "f\"" + P "F\"" )
          * ( DoubleShortInterpol + DoubleShortPureString ) ^ 0
-         * Q ( P "\"" )
+         * K ( P "\"" )
        +
-         Q ( ( P "\"" + P "r\"" + P "R\"" )
-         * ( P "\\\"" + 1 - S "\"\r" ) ^ 0 * P "\"" )
+         K ( P "\"" + P "r\"" + P "R\"" )
+         * ( K ( ( P "\\\"" + 1 - S " \"\r%" ) ^ 1 )
+             + VisualSpace
+             + PercentInterpol
+             + K ( P "%" )
+           ) ^ 0
+         * K ( P "\"" )
      )
    * Lc ( "}}" )
 
@@ -685,7 +806,7 @@
 local SingleLongString =
   Lc "{\\PitonStyle{String.Long}{"
    * (
-         Q ( S "fF" * P "'''" )
+         K ( S "fF" * P "'''" )
          * ( SingleLongInterpol + SingleLongPureString ) ^ 0
          * Lc "}}"
          * (
@@ -699,25 +820,25 @@
          * Lc "{\\PitonStyle{String.Long}{"
          * ( SingleLongInterpol + SingleLongPureString ) ^ 0
        +
-         Q ( ( S "rR" ) ^ -1  * P "'''"
+         K ( ( S "rR" ) ^ -1  * P "'''"
              * ( 1 - P "'''" - P "\r" ) ^ 0 )
          * Lc "}}"
          * (
              Lc "{\\PitonStyle{String.Long}{"
-             * Q ( ( 1 - P "'''" - P "\r" ) ^ 0 )
+             * K ( ( 1 - P "'''" - P "\r" ) ^ 0 )
              * Lc "}}"
              * EOL
            ) ^ 0
          * Lc "{\\PitonStyle{String.Long}{"
-         * Q ( ( 1 - P "'''" - P "\r" ) ^ 0 )
+         * K ( ( 1 - P "'''" - P "\r" ) ^ 0 )
       )
-   * Q ( P "'''" )
+   * K ( P "'''" )
    * Lc "}}"
 
 local DoubleLongString =
   Lc "{\\PitonStyle{String.Long}{"
    * (
-         Q ( S "fF" * P "\"\"\"" )
+         K ( S "fF" * P "\"\"\"" )
          * ( DoubleLongInterpol + DoubleLongPureString ) ^ 0
          * Lc "}}"
          * (
@@ -731,19 +852,19 @@
          * Lc "{\\PitonStyle{String.Long}{"
          * ( DoubleLongInterpol + DoubleLongPureString ) ^ 0
        +
-         Q ( ( S "rR" ) ^ -1  * P "\"\"\""
+         K ( ( S "rR" ) ^ -1  * P "\"\"\""
               * ( 1 - P "\"\"\"" - P "\r" ) ^ 0 )
          * Lc "}}"
          * (
              Lc "{\\PitonStyle{String.Long}{"
-             * Q ( ( 1 - P "\"\"\"" - P "\r" ) ^ 0 )
+             * K ( ( 1 - P "\"\"\"" - P "\r" ) ^ 0 )
              * Lc "}}"
              * EOL
            ) ^ 0
          * Lc "{\\PitonStyle{String.Long}{"
-         * Q ( ( 1 - P "\"\"\"" - P "\r" ) ^ 0 )
+         * K ( ( 1 - P "\"\"\"" - P "\r" ) ^ 0 )
       )
-   * Q ( P "\"\"\"" )
+   * K ( P "\"\"\"" )
    * Lc "}}"
 local LongString = SingleLongString + DoubleLongString
 local StringDoc =
@@ -755,13 +876,12 @@
 
 local Comment =
   Lc ( "{\\PitonStyle{Comment}{" )
-  * Q ( P "#" )
-  * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0
+  * K ( P "#" )
+  * ( CommentMath + K ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0
   * Lc ( "}}" )
   * ( EOL + -1 )
-
 local CommentLaTeX =
-  P "##"
+  P(piton.comment_latex)
   * Lc "{\\PitonStyle{Comment.LaTeX}{\\ignorespaces"
   * L ( ( 1 - P "\r" ) ^ 0 )
   * Lc "}}"
@@ -787,18 +907,19 @@
   SkipSpace * Identifier * SkipSpace
    * (
          K ( P "=" * Expression , 'InitialValues' )
-       + Q ( P ":" ) * SkipSpace * K ( letter^1 , 'Name.Type' )
+       + K ( P ":" ) * SkipSpace * K ( letter^1 , 'Name.Type' )
      ) ^ -1
-local Params = ( Param * ( Q "," * Param ) ^ 0 ) ^ -1
+local Params = ( Param * ( K "," * Param ) ^ 0 ) ^ -1
 local DefFunction =
   K ( P "def" , 'Keyword' )
   * Space
   * K ( identifier , 'Name.Function' )
   * SkipSpace
-  * Q ( P "(" ) * Params * Q ( P ")" )
+  * K ( P "(" ) * Params * K ( P ")" )
   * SkipSpace
+  * ( K ( P "->" ) * SkipSpace * K ( identifier , 'Name.Type' ) ) ^ -1
   * K ( ( 1 - S ":\r" )^0 , 'Post.Function' )
-  * Q ( P ":" )
+  * K ( P ":" )
   * ( SkipSpace
       * ( EOL + CommentLaTeX + Comment ) -- in all cases, that contains an EOL
       * Tab ^ 0
@@ -806,15 +927,14 @@
       * StringDoc ^ 0 -- there may be additionnal docstrings
     ) ^ -1
 local ItemDict =
-  ShortString * SkipSpace * Q ( P ":" ) * K ( Expression , 'Dict.Value' )
+  ShortString * SkipSpace * K ( P ":" ) * K ( Expression , 'Dict.Value' )
 
 local ItemOfSet = SkipSpace * ( ItemDict + ShortString ) * SkipSpace
 
 local Set =
-  Q ( P "{" )
-  * ItemOfSet * ( Q ( P "," ) * ItemOfSet )  ^ 0
-  * Q ( P "}" )
-
+  K ( P "{" )
+  * ItemOfSet * ( K ( P "," ) * ItemOfSet )  ^ 0
+  * K ( P "}" )
 local SyntaxPythonAux =
       Lc ( '\\__piton_begin_line:' ) *
       ( ( space - P "\r" ) ^0 * P "\r" ) ^ -1 *
@@ -846,16 +966,23 @@
          + Word
       ) ^0 * -1 * Lc ( '\\__piton_end_line:' )
 local SyntaxPython = Ct ( SyntaxPythonAux )
-function Parse(code)
-  local t = SyntaxPython : match ( code )
+function piton.Parse(code)
+  local t = SyntaxPython : match ( code ) -- match is a method of the LPEG
   for _ , s in ipairs(t) do tex.tprint(s) end
 end
-function ParseFile(name)
+function piton.ParseFile(name,first_line,last_line)
   s = ''
-  for line in io.lines(name) do s = s .. '\r' .. line end
-  Parse(s)
+  local i = 0
+  for line in io.lines(name)
+  do i = i + 1
+     if i >= first_line
+     then s = s .. '\r' .. line
+     end
+     if i >= last_line then break end
+  end
+  piton.Parse(s)
 end
-function gobble(n,code)
+local function gobble(n,code)
   function concat(acc,new_value)
     return acc .. new_value
   end
@@ -873,19 +1000,10 @@
                  ) : match ( code )
   end
 end
-function GobbleParse(n,code)
-  if n==-1
-  then n = AutoGobbleLPEG : match(code)
-  else if n==-2
-       then n = EnvGobbleLPEG : match(code)
-       end
-  end
-  Parse(gobble(n,code))
-end
-function add(acc,new_value)
+local function add(acc,new_value)
   return acc + new_value
 end
-AutoGobbleLPEG =
+local AutoGobbleLPEG =
     ( space ^ 0 * P "\r" ) ^ -1
     * Cf (
            (
@@ -899,23 +1017,58 @@
            * ( 1 - P " " ) * ( 1 - P "\r" ) ^ 0 ) ^ -1 ,
            math.min
          )
-EnvGobbleLPEG =
+local EnvGobbleLPEG =
   ( ( 1 - P "\r" ) ^ 0 * P "\r" ) ^ 0
     * Cf ( Cc(0) * ( P " " * Cc(1) ) ^ 0 , add ) * -1
-function CountLines(code)
+function piton.GobbleParse(n,code)
+  if n==-1
+  then n = AutoGobbleLPEG : match(code)
+  else if n==-2
+       then n = EnvGobbleLPEG : match(code)
+       end
+  end
+  piton.Parse(gobble(n,code))
+end
+function piton.CountLines(code)
   local count = 0
-  for i in code:gmatch("\r") do count = count + 1 end
+  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 CountLinesFile(name)
+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



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