texlive[66763] Master/texmf-dist: piton (4apr23)

commits+karl at tug.org commits+karl at tug.org
Tue Apr 4 22:12:45 CEST 2023


Revision: 66763
          http://tug.org/svn/texlive?view=revision&revision=66763
Author:   karl
Date:     2023-04-04 22:12:45 +0200 (Tue, 04 Apr 2023)
Log Message:
-----------
piton (4apr23)

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

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

Modified: trunk/Master/texmf-dist/doc/lualatex/piton/piton-french.tex
===================================================================
--- trunk/Master/texmf-dist/doc/lualatex/piton/piton-french.tex	2023-04-04 20:12:31 UTC (rev 66762)
+++ trunk/Master/texmf-dist/doc/lualatex/piton/piton-french.tex	2023-04-04 20:12:45 UTC (rev 66763)
@@ -189,28 +189,31 @@
 points suivants doivent être remarqués :
 
 \begin{itemize}
-\item plusieurs espaces successifs sont remplacés par un unique espace ;
-\item il n'est pas possible d'utiliser le caractère |%| à l'intérieur ;
-\item les accolades doivent apparaître par paires correctement imbriquées;
-\item les commandes LaTeX (celles commençant par une contre-oblique |\| mais également les caractères actifs) sont
-complètement développées (mais non exécutées).  
-\end{itemize}
+\item plusieurs espaces successives sont remplacées par une unique espace, 
 
-Un mécanisme d'échappement est fourni : les commandes |\\|, |\%|, |\{| et |\}| insèrent les caractères
-correspondants |\|, |%|, 
-|{| et |}|. Ces deux dernières commandes ne sont nécessaires que si on a besoin d'insérer des accolades
-non équilibrées.
+{\color{cyan} mais la commande |\|␣ est fournie pour forcer l'insertion d'une espace} ;
 
-\smallskip
-La commande |\|␣ insère un espace. Elle peut être utilisée si on veut insérer plusieurs espaces successifs.
+\item il n'est pas possible d'utiliser le caractère |%| à l'intérieur, 
 
-\smallskip
+{\color{cyan} mais la commande |\%| est fournie pour insérer un |%|} ;
+
+\item les accolades doivent apparaître par paires correctement imbriquées, 
+
+{\color{cyan} mais les commandes |\{| et |\}| sont aussi fournies pour insérer des accolades individuelles} ;
+
+\item les commandes LaTeX\footnote{Cela s'applique aux commandes commençant par une contre-oblique |\| mais également aux caractères actifs.} sont
+complètement développées sans être exécutées 
+
+{\color{cyan} et on peut donc utiliser |\\| pour insérer une contre-oblique}.
+\end{itemize}
+
 Les autres caractères (y compris |#|, |^|, |_|, |&|, |$| % $
 et |@|) doivent être insérés sans contre-oblique.
 
-Exemples :
-
-\begin{tabular}{>{\color{gray}}l@{\hspace*{1cm}}l}
+\bigskip
+\begin{tabular}{>{\color{gray}}w{l}{75mm}@{\hspace*{1cm}}l}
+\omit Exemples : \hfil \\
+\noalign{\vskip1mm}
 \verb|\piton{ma_chaîne = '\\n'}| & 
 \piton{ma_chaîne = '\\n' } \\
 \verb|\piton{def pair(n): return n\%2==0}| & 
@@ -223,7 +226,7 @@
 \piton{my_dict = {'a': 3, 'b': 4}}
 \end{tabular}
 
-\smallskip
+\bigskip
 La commande |\piton| avec son argument entre accolades peut être utilisée dans les arguments des autres commandes LaTeX.\footnote{La commande
   |\piton| peut par exemple être
   utilisée dans une note de bas de page. Exemple : \piton{s = 'Une chaîne'}.}
@@ -236,9 +239,9 @@
 autre fonction.  
 
 \medskip
-Exemples :
-
-\begin{tabular}{>{\color{gray}}l@{\hspace*{1cm}}l}
+\begin{tabular}{>{\color{gray}}w{l}{75mm}@{\hspace*{1cm}}l}
+\omit Exemples : \hfil \\
+\noalign{\vskip1mm}
 \verb!\piton|ma_chaîne = '\n'|! & 
 \piton|ma_chaîne = '\n'| \\
 \verb|\piton!def pair(n): return n%2==0!| & 
@@ -285,6 +288,11 @@
 
 \item Avec la clé \Definition{all-line-numbers}, \emph{toutes} les lignes sont numérotées, y compris les lignes vides.
 
+\item \colorbox{yellow!50}{\textbf{Nouveau 1.5}}\par\nobreak
+
+La clé \Definition{numbers-sep} est la distance horizontale entre les numéros de lignes (insérés par |line-numbers|
+ou |all-line-numbers|) et les lignes du code informatique. La valeur initiale est 0.7~em.
+
 \item La clé \Definition{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.
@@ -326,7 +334,7 @@
 
 \smallskip
 Avec la clé \Definition{show-spaces}, tous les espaces sont matérialisés (et aucune coupure de ligne ne peut plus
-intervenir sur ces espaces matérialisés, même si la clé |break-lines| est active).
+intervenir sur ces espaces matérialisés, même si la clé |break-lines|\footnote{cf. \ref{line-breaks} p.~\pageref{line-breaks}.} est active).
 \end{itemize}
 
 \bigskip
@@ -407,8 +415,8 @@
 
 \bigskip
 Voici un exemple qui change le style utilisé pour le nom d'une fonction Python, au moment de sa définition
-(c'est-à-dire après le mot-clé |def|). Elle utilise la commande |\highLight| de \pkg{lua-ul} (qui nécessite aussi
-le chargement de \pkg{luacolor}).
+(c'est-à-dire après le mot-clé |def|). Elle utilise la commande |\highLight| de \pkg{lua-ul} (qui nécessite
+lui-même le chargement de \pkg{luacolor}).
 
 \begin{Verbatim}
 \SetPitonStyle
@@ -553,13 +561,13 @@
 \smallskip
 Cette clé prend en argument une valeur au format suivant : 
 
-\quad |{ noms = |\textsl{\ttfamily noms}|, style = |\textsl{\ttfamily instructions}| }|
+\quad |{ names = |\textsl{\ttfamily noms}|, style = |\textsl{\ttfamily instructions}| }|
 
 \begin{itemize}
 \item \textsl{\ttfamily noms} est une liste de noms d'identificateurs (séparés par des virgules) ; 
 
-\item \textsl{\ttfamily instructions} est une liste d'instructions LaTeX de formatage du même type que les styles
-précédemment définis (cf.~\ref{styles} p.~\pageref{styles}).
+\item \textsl{\ttfamily instructions} est une liste d'instructions LaTeX de formatage du même type que pour les
+styles précédemment définis (cf.~\ref{styles} p.~\pageref{styles}).
 \end{itemize}
 
 \emph{Attention} : Seuls les identifiants peuvent voir leur formatage affecté. Les mots-clés et les noms de
@@ -844,6 +852,14 @@
 
 \label{beamer}
 
+\emph{Première remarque}\par\nobreak
+Remarquons que, comme l'environnement |{Piton}| prend son argument selon un mode verbatim, il convient, ce qui
+n'est pas surprenant, de l'utiliser dans des environnements |{frame}| de Beamer protégés par la clé |fragile|.\footnote{On
+  rappelle que pour un environnement |{frame}| de Beamer qui utilise la clé |fragile|, l'instruction |\end{frame}|
+  doit être seule sur une ligne (à l'exception d'éventuels espaces en début de ligne).}
+
+
+\medskip
 Quand l'extension \pkg{piton} est utilisée dans la classe \cls{beamer}\footnote{L'extension \pkg{piton} détecte la
   classe \cls{beamer} mais il est aussi possible, si le besoin s'en faisait sentir, d'activer ce comportement avec
   la clé |beamer| au chargement de \pkg{piton} : |\usepackage[beamer]{piton}|}, le comportement de \pkg{piton} est
@@ -885,22 +901,11 @@
 \end{itemize}
 
 \medskip
-Néanmoins, il y a deux restrictions pour le contenu des arguments obligatoires de ces commandes.
-\begin{itemize}
-\item Les accolades dans les arguments obligatoires de ces commandes doivent être équilibrées (cependant, les
-accolades présentes dans des chaînes courtes\footnote{Les chaînes courtes de Python sont les chaînes (string)
-  délimitées par les caractères \texttt{'} ou \texttt{"} non triplés. En Python, les chaînes de caractères courtes
-  ne peuvent pas s'étendre sur plusieurs lignes de code.} de Python ne sont pas prises en compte).
-\item L'argument obligatoire ne doit contenir \textbf{aucun retour à la ligne} (s'il y en a, une erreur
-fatale est levée). Pour les éléments de plusieurs lignes, on pourra utiliser les environnements correspondants
-(voir ci-dessous).
-\end{itemize}
+Les accolades dans les arguments obligatoires de ces commandes doivent être équilibrées (cependant, les accolades
+présentes dans des chaînes courtes\footnote{Les chaînes courtes de Python sont les chaînes (string) délimitées par
+  les caractères \texttt{'} ou \texttt{"} non triplés. En Python, les chaînes de caractères courtes ne peuvent pas
+  s'étendre sur plusieurs lignes de code.} de Python ne sont pas prises en compte).
 
-\medskip
-Remarquons que, comme l'environnement |{Piton}| prend son argument selon un mode verbatim, il convient, ce qui
-n'est pas surprenant, de l'utiliser dans des environnements |{frame}| de Beamer protégés par la clé |fragile|.\footnote{On
-  rappelle que pour un environnement |{frame}| de Beamer qui utilise la clé |fragile|, l'instruction |\end{frame}|
-  doit être seule sur une ligne (à l'exception d'éventuels espaces en début de ligne).}
 
 \medskip
 Voici un exemple complet de fichier :
@@ -1028,12 +1033,14 @@
 
 \subsubsection{Coupure des lignes}
 
+\label{line-breaks}
+
 Par défaut, les éléments produits par \pkg{piton} ne peuvent pas être coupés par une fin de ligne. Il existe
 néanmoins des clés pour autoriser de telles coupures (les points de coupure possibles sont les espaces, y compris
 les espaces dans les chaînes Python).
 \begin{itemize}
 \item Avec la clé |break-lines-in-piton|, les coupures de ligne sont autorisées dans la commande |\piton{...}|
-(mais pas dans la commande \verb+|...|+, c'est-à-dire avec la syntaxe verbatim). 
+(mais pas dans la commande \verb+\piton|...|+, c'est-à-dire avec la syntaxe verbatim). 
 
 \item Avec la clé |break-lines-in-Piton|, les coupures de ligne sont autorisées dans l'environnement |{Piton}|
 (d'où la lettre |P| capitale dans le nom) et dans les listings produits par |\PitonInputFile|.
@@ -1548,7 +1555,7 @@
 \begin{~emphase#PitonExecute@}[background-color=gray!15]
 def square(x):
     return x*x
-print(f'The square of 12 is {square(12)}.')
+print(f'Le carré de 12 est {square(12)}.')
 \end{~emphase#PitonExecute@}
 \end{Verbatim}
 
@@ -1557,7 +1564,7 @@
 \begin{PitonExecute}[background-color=gray!15]
 def square(x):
     return x*x
-print(f'The square of 12 is {square(12)}.')
+print(f'Le carré de 12 est {square(12)}.')
 \end{PitonExecute}
 
 \bigskip

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

Modified: trunk/Master/texmf-dist/source/lualatex/piton/piton.dtx
===================================================================
--- trunk/Master/texmf-dist/source/lualatex/piton/piton.dtx	2023-04-04 20:12:31 UTC (rev 66762)
+++ trunk/Master/texmf-dist/source/lualatex/piton/piton.dtx	2023-04-04 20:12:45 UTC (rev 66763)
@@ -15,8 +15,8 @@
 %
 % \fi
 % \iffalse
-\def\myfileversion{1.4}
-\def\myfiledate{2023/02/14}
+\def\myfileversion{1.5}
+\def\myfiledate{2023/04/04}
 %
 %
 %<*batchfile> 
@@ -125,7 +125,6 @@
 % 
 %
 % \bigskip
-% 
 % The package \pkg{piton} is entirely contained in the file
 % |piton.sty|. This file may be put in the current directory or in a
 % |texmf| tree. However, the best is to install \pkg{piton} with a TeX
@@ -193,29 +192,33 @@
 % When its argument is given between curly braces, the command |\piton| does not
 % take its argument in verbatim mode. In particular:
 % \begin{itemize}
-% \item several consecutive spaces will be replaced by only one space;
-% \item it's not possible to use |%| inside the argument;
-% \item the braces must be appear by pairs correctly nested;
-% \item the LaTeX commands (those beginning with a backslash |\| but also the
-% active characters) are fully expanded (but not executed). 
+% \item several consecutive spaces will be replaced by only one space,
+% 
+% {\color{cyan} but the command |\|␣ is provided to force the insertion of a space};
+%
+% \item it's not possible to use |%| inside the argument,
+%
+% {\color{cyan} but the command |\%| is provided to insert a |%|};
+%
+% \item the braces must be appear by pairs correctly nested
+%
+% {\color{cyan} but the commands |\{| and |\}| are also provided for individual braces};
+%
+% \item the LaTeX commands\footnote{That concerns the commands beginning with a
+% backslash but also the active characters.} are fully expanded and not
+% executed,
+%
+% {\color{cyan} so it's possible to use |\\| to insert a backslash}.
 % \end{itemize}
 %
-% An escaping mechanism is provided: the commands |\\|, |\%|, |\{| and |\}|
-% insert the corresponding characters |\|, |%|, |{| and |}|. The last two
-% commands are necessary only if one need to insert braces which are not
-% balanced.
 %
-% \smallskip
-% The command |\|␣ inserts a space. It may be used in order to insert several
-% consecutive spaces. 
-%
-% \smallskip
 % The other characters (including |#|, |^|, |_|, |&|, |$| and |@|)
 % must be inserted without backslash.
 % 
-% Examples:
-%
-%\begin{tabular}{>{\color{gray}}l@{\hspace*{1cm}}l}
+% \bigskip
+%\begin{tabular}{>{\color{gray}}w{l}{75mm}@{\hspace*{1cm}}l}
+% \omit Examples : \hfil \\
+% \noalign{\vskip1mm}
 % \verb|\piton{MyString = '\\n'}| & 
 % \piton{MyString = '\\n'} \\
 % \verb|\piton{def even(n): return n\%2==0}| & 
@@ -228,7 +231,7 @@
 % \piton{MyDict = {'a': 3, 'b': 4 }}
 % \end{tabular}
 %
-% 
+% \bigskip
 % It's possible to use the command |\piton| in the arguments of a
 % LaTeX command.\footnote{For example, it's possible to use the command
 % \texttt{\textbackslash piton} in a footnote. Example :
@@ -243,9 +246,10 @@
 % command. 
 %
 % \medskip
-% Examples:
 %
-% \begin{tabular}{>{\color{gray}}l@{\hspace*{1cm}}l}
+% \begin{tabular}{>{\color{gray}}w{l}{75mm}@{\hspace*{1cm}}l}
+% \omit Examples : \hfil \\
+% \noalign{\vskip1mm}
 % \verb!\piton|MyString = '\n'|! & 
 % \piton|MyString = '\n'| \\
 % \verb|\piton!def even(n): return n%2==0!| & 
@@ -299,7 +303,13 @@
 % \item With the key \Definition{all-line-numbers}, \emph{all} the lines are numbered,
 % including the empty ones.
 %
-% \item With the key \Definition{resume} the counter of lines is not set to zero
+% \item \colorbox{yellow!50}{\bfseries{New 1.5}}\par\nobreak
+%
+% The key \Definition{numbers-sep} is the horizontal distance between the
+% numbers of lines (inserted by |line-numbers| of |all-line-numbers|) and the
+% beginning of the lines of code. The initial value is 0.7~em.
+%
+% \item With the key \Definition{resume}, the counter of lines is not set to zero
 % at the beginning of each environment |{Piton}| or use of |\PitonInputFile| as
 % it is otherwise. That allows a numbering of the lines across several
 % environments.
@@ -340,13 +350,14 @@
 % 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}.}\par\nobreak
+% \texttt{\textbackslash setmonofont} of the package \pkg{fontspec}.}\par\nobreak
 % \begingroup \PitonOptions{show-spaces-in-strings} Example : 
 % \piton|my_string = 'Very good answer'| \endgroup
 %
 % With the key \Definition{show-spaces}, all the spaces are replaced by U+2423
 % (and no line break can occur on those ``visible spaces'', even when the key
-% |break-lines| is in force).
+% |break-lines|\footnote{cf. \ref{line-breaks} p.~\pageref{line-breaks}} is in
+% force). 
 % \end{itemize}
 %
 % \bigskip
@@ -551,7 +562,7 @@
 %   {\end{tcolorbox}}
 % \end{verbatim}
 %
-\bigskip
+% \bigskip
 % With this new environment |{Python}|, it's possible to write:
 %
 % \begin{Verbatim}
@@ -597,7 +608,7 @@
 % \end{itemize}
 %
 % \emph{Caution}: Only the identifiers may be concerned by that key. The
-% keywords and the built-in functions won't be affected, even if their names is
+% keywords and the built-in functions won't be affected, even if their name is
 % in the list |\textsl{\ttfamily names}|.
 % 
 % \begin{Verbatim}
@@ -882,6 +893,16 @@
 %
 % \label{beamer}
 %
+% \emph{First remark}\par\nobreak
+% Since the environment |{Piton}| catches its body with a verbatim mode,
+% it's necessary to use the environments |{Piton}| within environments |{frame}|
+% of Beamer protected by the key |fragile|.\footnote{Remind that for an
+% environment \texttt{\{frame\}} of Beamer using the key |fragile|, the
+% instruction \texttt{\textbackslash end\{frame\}} must be alone on a single
+% line (except for any leading whitespace).}
+%
+%
+% \bigskip
 % When the package \pkg{piton} is used within the class
 % \cls{beamer}\footnote{The extension \pkg{piton} detects the class \cls{beamer}
 % but, if needed, it's also possible to activate that mechanism with the key
@@ -927,26 +948,11 @@
 % \end{itemize}
 
 % \medskip
-% However, there is two restrictions for the content of the mandatory arguments
-% of these commands.
-% \begin{itemize}
-% \item In the mandatory arguments of these commands, the braces must be
-% balanced. However, the braces includes in short strings\footnote{The
-% short strings of Python are the strings delimited by characters \texttt{'} or
-% the characters \texttt{"} and not \texttt{'''} nor \texttt{"""}. In Python,
-% the short strings can't extend on several lines.} of Python are not considered.
-% \item The must be \textbf{no carriage return} in the mandatory arguments of the
-% command (if there is, a fatal error will be raised). For multi-lines elements,
-% one should consider the corresponding environments (see below).
-% \end{itemize}
-% 
-% \medskip
-% Remark that, since the environment |{Piton}| catches its body with a verbatim
-% mode, it's necessary to use the environments |{Piton}| within environments
-% |{frame}| of Beamer protected by the key |fragile|.\footnote{Remind that for
-% an environment \texttt{\{frame\}} of Beamer using the key |fragile|, the
-% instruction \texttt{\textbackslash end\{frame\}} must be alone on a single
-% line (except for any leading whitespace).}
+% In the mandatory arguments of these commands, the braces must be balanced.
+% However, the braces included in short strings\footnote{The short strings of
+% Python are the strings delimited by characters \texttt{'} or the characters
+% \texttt{"} and not \texttt{'''} nor \texttt{"""}. In Python, the short strings
+% can't extend on several lines.} of Python are not considered. 
 %
 % \medskip
 % Here is a complete example of file:
@@ -984,7 +990,7 @@
 %
 % However, there is a restriction: these environments must contain only \emph{whole
 % lines of Python code} in their body.
-%%
+%
 %\medskip
 % Here is an example:
 %
@@ -1076,6 +1082,8 @@
 % 
 % \subsubsection{Line breaks}
 % 
+% \label{line-breaks}
+% 
 % By default, the elements produced by \pkg{piton} can't be broken by an end on
 % line. However, there are keys to allow such breaks (the possible breaking
 % points are the spaces, even the spaces in the Python strings).
@@ -1089,7 +1097,6 @@
 % \item The key |break-lines| is a conjonction of the two previous keys.
 % \end{itemize}
 % 
-
 % \bigskip 
 % The package \pkg{piton} provides also several keys to control the appearance
 % on the line breaks allowed by |break-lines-in-Piton|.
@@ -1385,8 +1392,8 @@
 % If an environment |{Piton}| is used in an environment |{minipage}| of LaTeX,
 % the notes are composed, of course, at the foot of the environment
 % |{minipage}|. Recall that such |{minipage}| can't be broken by a page break.
-
 %
+%
 % \begingroup
 % \fvset{commandchars=\~\&\@,formatcom=\small\color{gray}}
 % \begin{Verbatim}
@@ -1747,7 +1754,7 @@
 % \subsection{The L3 part of the implementation}
 %
 % \subsubsection{Declaration of the package}
-%     \begin{macrocode}
+%    \begin{macrocode}
 \NeedsTeXFormat{LaTeX2e}
 \RequirePackage{l3keys2e}
 \ProvidesExplPackage
@@ -1760,7 +1767,13 @@
 % \bigskip
 %    \begin{macrocode}
 \msg_new:nnn { piton } { LuaLaTeX~mandatory }
-  { The~package~'piton'~must~be~used~with~LuaLaTeX.\\ It~won't~be~loaded. }
+  { 
+    LuaLaTeX~is~mandatory.\\
+    The~package~'piton'~requires~the~engine~LuaLaTeX.\\
+    \str_if_eq:VnT \c_sys_jobname_str { output }
+      { If~you~use~Overleaf,~you~can~switch~to~LuaLaTeX~in~the~"Menu". \\}
+    If~you~go~on,~the~package~'piton'~won't~be~loaded.
+  }
 \sys_if_engine_luatex:F { \msg_critical:nn { piton } { LuaLaTeX~mandatory } }
 %    \end{macrocode}
 % 
@@ -2075,18 +2088,25 @@
 %    \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|. 
 %    \begin{macrocode}
 \dim_new:N \l_@@_left_margin_dim
 %    \end{macrocode}
 %
 % \medskip
-% The following boolean correspond will be set when the key |left-margin=auto|
+% The following boolean will be set when the key |left-margin=auto|
 % is used.
 %    \begin{macrocode}
 \bool_new:N \l_@@_left_margin_auto_bool
 %    \end{macrocode}
+%
+% \medskip
+% The following dimension corresponds to the key |numbers-sep| of
+% |\PitonOptions|.
+%    \begin{macrocode}
+\dim_new:N \l_@@_numbers_sep_dim 
+\dim_set:Nn \l_@@_numbers_sep_dim { 0.7 em }
+%    \end{macrocode}
 % 
 % \medskip
 % The tabulators will be replaced by the content of the following token list.
@@ -2170,8 +2190,18 @@
   }
 %    \end{macrocode}
 %
-%
+% 
 % \bigskip
+% The following commands are a easy way to insert safely braces (|{| and |}|) in
+% the TeX flow.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_open_brace:
+  { \directlua { piton.open_brace() } }
+\cs_new_protected:Npn \@@_close_brace:
+  { \directlua { piton.close_brace() } }
+%    \end{macrocode}
+% 
+% \bigskip
 % The following token list will be evaluated at the beginning of
 % |\@@_begin_line:|... |\@@_end_line:| and cleared at the end. It will be used
 % by LPEG acting between the lines of the Python code in order to add
@@ -2191,8 +2221,82 @@
       { \clist_set:NV \l_@@_bg_color_clist \l_@@_prompt_bg_color_tl } 
   }
 %    \end{macrocode}
+%
 % 
+% \bigskip
+% You will keep track of the current style for the treatment of EOL (for the
+% multi-line syntactic elements).
+%    \begin{macrocode}
+\clist_new:N \g_@@_current_style_clist
+\clist_set:Nn \g_@@_current_style_clist { __end }
+%    \end{macrocode}
+% The element |__end| is an arbitrary syntactic marker.
+% 
+% \medskip
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_close_current_styles:
+  { 
+    \int_set:Nn \l_tmpa_int { \clist_count:N \g_@@_current_style_clist - 1  } 
+    \exp_args:NV \@@_close_n_styles:n \l_tmpa_int
+  }
+%    \end{macrocode}
 %
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_close_n_styles:n #1
+  { 
+    \int_compare:nNnT { #1 } > 0 
+      { 
+        \@@_close_brace:
+        \@@_close_brace:
+        \@@_close_n_styles:n { #1 - 1 } 
+      }
+  }
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_open_current_styles:
+  { \exp_last_unbraced:NV \@@_open_styles:w \g_@@_current_style_clist , }
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_open_styles:w #1 , 
+  {
+    \tl_if_eq:nnF { #1 } { __end }
+      { \@@_open_brace: #1 \@@_open_brace: \@@_open_styles:w }
+  }
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_pop_style:
+  {
+    \clist_greverse:N \g_@@_current_style_clist
+    \clist_gpop:NN \g_@@_current_style_clist \l_tmpa_tl
+    \clist_gpop:NN \g_@@_current_style_clist \l_tmpa_tl
+    \clist_gpush:Nn \g_@@_current_style_clist { __end }
+    \clist_greverse:N \g_@@_current_style_clist
+  }
+%    \end{macrocode}
+% 
+% \medskip
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_push_style:n #1
+  {
+    \clist_greverse:N \g_@@_current_style_clist
+    \clist_gpop:NN \g_@@_current_style_clist \l_tmpa_tl
+    \clist_gpush:Nn \g_@@_current_style_clist { #1 }
+    \clist_gpush:Nn \g_@@_current_style_clist { __end }
+    \clist_greverse:N \g_@@_current_style_clist
+  }
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_push_and_exec:n #1
+  {
+    \@@_push_style:n { #1 }
+    \@@_open_brace: #1 \@@_open_brace:
+  }
+%    \end{macrocode}
+% 
 % \bigskip
 % \subsubsection{Treatment of a line of code}
 % 
@@ -2226,8 +2330,8 @@
 % \bigskip
 % In the contents provided by Lua, each line of the Python code will be
 % surrounded by |\@@_begin_line:| and |\@@_end_line:|. |\@@_begin_line:| is a
-% LaTeX that we will define now but |\@@_end_line:| is only a syntactic marker
-% that has no definition.
+% LaTeX command that we will define now but |\@@_end_line:| is only a syntactic
+% marker that has no definition.
 %
 %    \begin{macrocode}
 \cs_set_protected:Npn \@@_begin_line: #1 \@@_end_line:
@@ -2270,7 +2374,13 @@
               \@@_print_number:
           }
         \clist_if_empty:NF \l_@@_bg_color_clist 
-          { \skip_horizontal:n { 0.5 em } }
+          { 
+            \dim_compare:nNnT \l_@@_left_margin_dim = \c_zero_dim 
+               { 
+                 \bool_if:NF \l_@@_left_margin_auto_bool
+                   { \skip_horizontal:n { 0.5 em } }
+               }
+          }
         \coffin_typeset:Nnnnn \l_tmpa_coffin T l \c_zero_dim \c_zero_dim 
       }  
 %    \end{macrocode}
@@ -2448,6 +2558,8 @@
         }
         { \dim_set:Nn \l_@@_left_margin_dim { #1 } } ,
     left-margin      .value_required:n  = true ,
+    numbers-sep      .dim_set:N         = \l_@@_numbers_sep_dim ,
+    numbers-sep      .value_required:n  = true , 
     tab-size         .code:n            = \@@_set_tab_tl:n { #1 } ,
     tab-size         .value_required:n  = true , 
     show-spaces      .bool_set:N        = \l_@@_show_spaces_bool , 
@@ -2502,7 +2614,7 @@
     \hbox_overlap_left:n
       { 
         { \color { gray } \footnotesize \int_to_arabic:n \g_@@_visual_line_int }
-        \skip_horizontal:n { 0.4 em } 
+        \skip_horizontal:N \l_@@_numbers_sep_dim  
       }
   }
 %    \end{macrocode}
@@ -2774,7 +2886,8 @@
                     { \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 }
+          \dim_set:Nn \l_@@_left_margin_dim 
+            { \box_wd:N \l_tmpa_box + \l_@@_numbers_sep_dim + 0.1 em }
         }
 %    \end{macrocode}
 % Now, the main job.
@@ -2855,7 +2968,7 @@
                       }
                   }
                 \dim_set:Nn \l_@@_left_margin_dim
-                  { \box_wd:N \l_tmpa_box + 0.5 em }
+                  { \box_wd:N \l_tmpa_box + \l_@@_numbers_sep_dim + 0.1 em }
               }
 %    \end{macrocode}
 % Now, the main job.
@@ -2963,65 +3076,67 @@
 %    \begin{macrocode}
 \keys_define:nn { piton / Styles }
   {
-    String.Interpol  .tl_set:c = pitonStyle String.Interpol , 
-    String.Interpol  .value_required:n = true ,
-    FormattingType   .tl_set:c = pitonStyle FormattingType ,
-    FormattingType   .value_required:n = true ,
-    Dict.Value       .tl_set:c = pitonStyle Dict.Value ,
-    Dict.Value       .value_required:n = true ,
-    Name.Decorator   .tl_set:c = pitonStyle Name.Decorator ,
-    Name.Decorator   .value_required:n = true ,
-    Name.Function    .tl_set:c = pitonStyle Name.Function ,
-    Name.Function    .value_required:n = true ,
-    Keyword          .tl_set:c = pitonStyle Keyword ,
-    Keyword          .value_required:n = true ,
-    Keyword.Constant .tl_set:c = pitonStyle Keyword.Constant ,
-    Keyword.constant .value_required:n = true ,
-    String.Doc       .tl_set:c = pitonStyle String.Doc ,
-    String.Doc       .value_required:n = true ,
-    Interpol.Inside  .tl_set:c = pitonStyle Interpol.Inside ,
-    Interpol.Inside  .value_required:n = true ,
-    String.Long      .tl_set:c = pitonStyle String.Long ,
-    String.Long      .value_required:n = true ,
-    String.Short     .tl_set:c = pitonStyle String.Short ,
-    String.Short     .value_required:n = true ,
-    String           .meta:n = { String.Long = #1 , String.Short = #1 } ,
-    Comment.Math     .tl_set:c = pitonStyle Comment.Math , 
-    Comment.Math     .default:n = \@@_math_scantokens:n ,
-    Comment.Math     .initial:n = ,
-    Comment          .tl_set:c = pitonStyle Comment , 
-    Comment          .value_required:n = true ,
-    InitialValues    .tl_set:c = pitonStyle InitialValues ,
-    InitialValues    .value_required:n = true ,
-    Number           .tl_set:c = pitonStyle Number , 
-    Number           .value_required:n = true ,
-    Name.Namespace   .tl_set:c = pitonStyle Name.Namespace , 
-    Name.Namespace   .value_required:n = true ,
-    Name.Class       .tl_set:c = pitonStyle Name.Class , 
-    Name.Class       .value_required:n = true ,
-    Name.Builtin     .tl_set:c = pitonStyle Name.Builtin , 
-    Name.Builtin     .value_required:n = true ,
-    TypeParameter    .tl_set:c = pitonStyle TypeParameter , 
-    TypeParameter    .value_required:n = true ,
-    Name.Type        .tl_set:c = pitonStyle Name.Type , 
-    Name.Type        .value_required:n = true ,
-    Operator         .tl_set:c = pitonStyle Operator , 
-    Operator         .value_required:n = true ,
-    Operator.Word    .tl_set:c = pitonStyle Operator.Word , 
-    Operator.Word    .value_required:n = true ,
-    Exception        .tl_set:c = pitonStyle Exception ,
-    Exception        .value_required:n = true ,
-    Comment.LaTeX    .tl_set:c = pitonStyle Comment.LaTeX ,
-    Comment.LaTeX    .value_required:n = true ,
-    Identifier       .tl_set:c = pitonStyle Identifier ,
-    Comment.LaTeX    .value_required:n = true ,
-    ParseAgain.noCR  .tl_set:c = pitonStyle ParseAgain.noCR ,
-    ParseAgain.noCR  .value_required:n = true ,
-    ParseAgain       .tl_set:c = pitonStyle ParseAgain , 
-    ParseAgain       .value_required:n = true ,
-    Prompt           .tl_set:c = pitonStyle Prompt , 
-    Prompt           .value_required:n = true ,
-    unknown          .code:n = 
+    String.Interpol   .tl_set:c = pitonStyle String.Interpol , 
+    String.Interpol   .value_required:n = true ,
+    FormattingType    .tl_set:c = pitonStyle FormattingType ,
+    FormattingType    .value_required:n = true ,
+    Dict.Value        .tl_set:c = pitonStyle Dict.Value ,
+    Dict.Value        .value_required:n = true ,
+    Name.Decorator    .tl_set:c = pitonStyle Name.Decorator ,
+    Name.Decorator    .value_required:n = true ,
+    Name.Function     .tl_set:c = pitonStyle Name.Function ,
+    Name.Function     .value_required:n = true ,
+    Name.UserFunction .tl_set:c = pitonStyle Name.UserFunction ,
+    Name.UserFunction .value_required:n = true ,
+    Keyword           .tl_set:c = pitonStyle Keyword ,
+    Keyword           .value_required:n = true ,
+    Keyword.Constant  .tl_set:c = pitonStyle Keyword.Constant ,
+    Keyword.constant  .value_required:n = true ,
+    String.Doc        .tl_set:c = pitonStyle String.Doc ,
+    String.Doc        .value_required:n = true ,
+    Interpol.Inside   .tl_set:c = pitonStyle Interpol.Inside ,
+    Interpol.Inside   .value_required:n = true ,
+    String.Long       .tl_set:c = pitonStyle String.Long ,
+    String.Long       .value_required:n = true ,
+    String.Short      .tl_set:c = pitonStyle String.Short ,
+    String.Short      .value_required:n = true ,
+    String            .meta:n = { String.Long = #1 , String.Short = #1 } ,
+    Comment.Math      .tl_set:c = pitonStyle Comment.Math , 
+    Comment.Math      .default:n = \@@_math_scantokens:n ,
+    Comment.Math      .initial:n = ,
+    Comment           .tl_set:c = pitonStyle Comment , 
+    Comment           .value_required:n = true ,
+    InitialValues     .tl_set:c = pitonStyle InitialValues ,
+    InitialValues     .value_required:n = true ,
+    Number            .tl_set:c = pitonStyle Number , 
+    Number            .value_required:n = true ,
+    Name.Namespace    .tl_set:c = pitonStyle Name.Namespace , 
+    Name.Namespace    .value_required:n = true ,
+    Name.Class        .tl_set:c = pitonStyle Name.Class , 
+    Name.Class        .value_required:n = true ,
+    Name.Builtin      .tl_set:c = pitonStyle Name.Builtin , 
+    Name.Builtin      .value_required:n = true ,
+    TypeParameter     .tl_set:c = pitonStyle TypeParameter , 
+    TypeParameter     .value_required:n = true ,
+    Name.Type         .tl_set:c = pitonStyle Name.Type , 
+    Name.Type         .value_required:n = true ,
+    Operator          .tl_set:c = pitonStyle Operator , 
+    Operator          .value_required:n = true ,
+    Operator.Word     .tl_set:c = pitonStyle Operator.Word , 
+    Operator.Word     .value_required:n = true ,
+    Exception         .tl_set:c = pitonStyle Exception ,
+    Exception         .value_required:n = true ,
+    Comment.LaTeX     .tl_set:c = pitonStyle Comment.LaTeX ,
+    Comment.LaTeX     .value_required:n = true ,
+    Identifier        .tl_set:c = pitonStyle Identifier ,
+    Comment.LaTeX     .value_required:n = true ,
+    ParseAgain.noCR   .tl_set:c = pitonStyle ParseAgain.noCR ,
+    ParseAgain.noCR   .value_required:n = true ,
+    ParseAgain        .tl_set:c = pitonStyle ParseAgain , 
+    ParseAgain        .value_required:n = true ,
+    Prompt            .tl_set:c = pitonStyle Prompt , 
+    Prompt            .value_required:n = true ,
+    unknown           .code:n = 
       \msg_error:nn { piton } { Unknown~key~for~SetPitonStyle }
   }
 %    \end{macrocode}
@@ -3068,31 +3183,32 @@
 %    \begin{macrocode}
 \SetPitonStyle
   {                                                       
-    Comment          = \color[HTML]{0099FF} \itshape , 
-    Exception        = \color[HTML]{CC0000} ,
-    Keyword          = \color[HTML]{006699} \bfseries ,               
-    Keyword.Constant = \color[HTML]{006699} \bfseries ,               
-    Name.Builtin     = \color[HTML]{336666} ,
-    Name.Decorator   = \color[HTML]{9999FF}, 
-    Name.Class       = \color[HTML]{00AA88} \bfseries ,
-    Name.Function    = \color[HTML]{CC00FF} , 
-    Name.Namespace   = \color[HTML]{00CCFF} , 
-    Number           = \color[HTML]{FF6600} ,
-    Operator         = \color[HTML]{555555} ,
-    Operator.Word    = \bfseries ,
-    String           = \color[HTML]{CC3300} ,         
-    String.Doc       = \color[HTML]{CC3300} \itshape , 
-    String.Interpol  = \color[HTML]{AA0000} ,
-    Comment.LaTeX    = \normalfont \color[rgb]{.468,.532,.6} , 
-    Name.Type        = \color[HTML]{336666} ,
-    InitialValues    = \@@_piton:n ,
-    Dict.Value       = \@@_piton:n ,
-    Interpol.Inside  = \color{black}\@@_piton:n ,
-    TypeParameter    = \color[HTML]{008800} \itshape ,
-    Identifier       = \@@_identifier:n , 
-    Prompt           = , 
-    ParseAgain.noCR  = \@@_piton_no_cr:n , 
-    ParseAgain       = \@@_piton:n ,
+    Comment            = \color[HTML]{0099FF} \itshape , 
+    Exception          = \color[HTML]{CC0000} ,
+    Keyword            = \color[HTML]{006699} \bfseries ,               
+    Keyword.Constant   = \color[HTML]{006699} \bfseries ,               
+    Name.Builtin       = \color[HTML]{336666} ,
+    Name.Decorator     = \color[HTML]{9999FF}, 
+    Name.Class         = \color[HTML]{00AA88} \bfseries ,
+    Name.Function      = \color[HTML]{CC00FF} , 
+    Name.Namespace     = \color[HTML]{00CCFF} , 
+    Number             = \color[HTML]{FF6600} ,
+    Operator           = \color[HTML]{555555} ,
+    Operator.Word      = \bfseries ,
+    String             = \color[HTML]{CC3300} ,         
+    String.Doc         = \color[HTML]{CC3300} \itshape , 
+    String.Interpol    = \color[HTML]{AA0000} ,
+    Comment.LaTeX      = \normalfont \color[rgb]{.468,.532,.6} , 
+    Name.Type          = \color[HTML]{336666} ,
+    InitialValues      = \@@_piton:n ,
+    Dict.Value         = \@@_piton:n ,
+    Interpol.Inside    = \color{black}\@@_piton:n ,
+    TypeParameter      = \color[HTML]{008800} \itshape ,
+    Identifier         = \@@_identifier:n , 
+    Name.UserFunction  = , 
+    Prompt             = , 
+    ParseAgain.noCR    = \@@_piton_no_cr:n , 
+    ParseAgain         = \@@_piton:n ,
   }
 %    \end{macrocode}
 % The last styles |ParseAgain.noCR| and |ParseAgain| should be considered as 
@@ -3109,11 +3225,13 @@
 %    \end{macrocode}
 % 
 % \bigskip
+%
+% \bigskip
 % \subsubsection{Highlighting some identifiers}
 % 
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_identifier:n #1
-  { \cs_if_exist_use:c { PitonIdentifier #1 } { #1 } }
+  { \cs_if_exist_use:c { PitonIdentifier _ \l_@@_language_str _ #1 } { #1 } } 
 %    \end{macrocode}
 %
 % \bigskip
@@ -3141,11 +3259,58 @@
     \clist_map_inline:Nn \l_@@_identifiers_names_tl 
       {
         \tl_set_eq:cN 
-          { PitonIdentifier ##1 }
+          { PitonIdentifier _ \l_@@_language_str _ ##1 }
           \l_@@_style_tl
       }
   }
 %    \end{macrocode}
+%
+%
+% \bigskip
+% In particular, we have an hightlighting of the indentifiers which are the
+% names of Python functions previously defined by the user. Indeed, when a
+% Python function is defined, the style |Name.Function.Internal| is applied to
+% that name. We define now that style (you define it directly and you short-cut
+% the function |\SetPitonStyle|). 
+%    \begin{macrocode}
+\cs_new_protected:cpn { pitonStyle Name.Function.Internal } #1
+  {
+%    \end{macrocode}
+% First, the element is composed in the TeX flow with the style |Name.Function|
+% which is provided to the final user.
+%    \begin{macrocode}
+    { \PitonStyle { Name.Function } { #1 } }
+%    \end{macrocode}
+% Now, we specify that the name of the new Python function is a known identifier
+% that will be formated with the Piton style |Name.UserFunction|. Of course,
+% here the affectation is global because we have to exit many groups and even
+% the environments |{Piton}|).
+%    \begin{macrocode}
+    \cs_gset_protected:cpn { PitonIdentifier _ \l_@@_language_str _ #1 } 
+      { \PitonStyle{ Name.UserFunction } }
+%    \end{macrocode}
+% Now, we put the name of that new user function in the dedicated sequence
+% (specific of the current language). That sequence will be used only by 
+% |\PitonClearUserFunctions|.
+%    \begin{macrocode}
+    \seq_if_exist:cF { g_@@_functions _ \l_@@_language_str _ seq }
+      { \seq_new:c { g_@@_functions _ \l_@@_language_str _ seq } }
+    \seq_gput_right:cn { g_@@_functions _ \l_@@_language_str _ seq } { #1 }
+  }
+%    \end{macrocode}
+%
+% \bigskip
+%    \begin{macrocode}
+\NewDocumentCommand \PitonClearUserFunctions { ! O { \l_@@_language_str }  } 
+  {
+    \seq_if_exist:cT { g_@@_functions _ #1 _ seq }
+      {
+        \seq_map_inline:cn { g_@@_functions _ #1 _ seq }
+          { \cs_undefine:c { PitonIdentifier _ #1 _ ##1} }
+        \seq_gclear:c { g_@@_functions _ #1 _ seq }
+      }
+  }
+%    \end{macrocode}
 % 
 % \bigskip
 % \subsubsection{Security}
@@ -3164,7 +3329,7 @@
 %    \end{macrocode}
 % 
 % \bigskip
-% \subsubsection{The errors messages of the package}
+% \subsubsection{The error messages of the package}
 %
 %    \begin{macrocode}
 \msg_new:nnnn { piton } { Unknown~key~for~PitonOptions }
@@ -3237,6 +3402,12 @@
     If~you~go~on,~that~argument~will~be~ignored.
   }
 %    \end{macrocode}
+%
+% \bigskip
+%    \begin{macrocode}
+\msg_new:nnn { Piton } { Python~error }
+  { A~Python~error~has~been~detected. }
+%    \end{macrocode}
 % 
 % \bigskip
 % \subsection{The Lua part of the implementation}
@@ -3265,7 +3436,20 @@
 piton.comment_latex = "#" .. piton.comment_latex 
 %    \end{macrocode}
 %
+%
 % \bigskip
+% The following functions are an easy way to safely insert braces (|{| and |}|)
+% in the TeX flow.
+%    \begin{macrocode}
+function piton.open_brace () 
+   tex.sprint("{") 
+end 
+function piton.close_brace () 
+   tex.sprint("}") 
+end 
+%    \end{macrocode}
+%
+% \bigskip
 % \subsubsection{Special functions dealing with LPEG}
 %
 % \medskip
@@ -3276,6 +3460,7 @@
 local Cf, Cs , Cg , Cmt , Cb = lpeg.Cf, lpeg.Cs, lpeg.Cg , lpeg.Cmt , lpeg.Cb
 local R = lpeg.R
 %    \end{macrocode}
+%
 % 
 %
 % \bigskip
@@ -3318,24 +3503,18 @@
 %    \end{macrocode}
 % 
 % \bigskip
-% The function |K| creates a \textsc{lpeg} which will return as capture
-% the whole LaTeX code corresponding to a Python chunk (that is to say with the
+% 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. If the second argument is not present, the
-% function |K| behaves as the function |Q| does.
+% Python chunk). The first argument is a Lua string corresponding to the name of
+% a \pkg{piton} style and the second element is a pattern (that is to say a
+% \textsc{lpeg} without capture)
 %    \begin{macrocode}
-local function K(pattern, style)
-  if style 
-  then
-  return 
+local function K(style, pattern)
+  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|)
@@ -3344,7 +3523,18 @@
 % deal with both syntaxes, we have used two pairs of braces: 
 % |{\PitonStyle{Keyword}{|\texttt{\slshape text to format}|}}|.
 % 
+%
 % \bigskip
+%    \begin{macrocode}
+local function WithStyle(style,pattern)
+  return 
+       Ct ( Cc "Open" * Cc ( "{\\PitonStyle{" .. style .. "}{" ) * Cc "}}" ) 
+     * pattern 
+     * Ct ( Cc "Close" ) 
+end
+%    \end{macrocode}
+% 
+% \bigskip
 % The following \textsc{lpeg} catches the Python chunks which are in LaTeX
 % escapes (and that chunks will be considered as normal LaTeX constructions). We
 % recall that |piton.begin_espace| and |piton_end_escape| are Lua strings
@@ -3399,7 +3589,7 @@
 % On the other hand, the \textsc{lpeg} |Identifier| (with a capital) also returns
 % a \emph{capture}.
 %    \begin{macrocode}
-local Identifier = K ( identifier , 'Identifier' )
+local Identifier = K ( 'Identifier' , identifier)
 %    \end{macrocode}
 %
 % \bigskip
@@ -3417,11 +3607,10 @@
 % \pkg{piton} styles (but this is only a convention).
 %    \begin{macrocode}
 local Number =
-  K (
+  K ( 'Number' ,
       ( digit^1 * P "." * digit^0 + digit^0 * P "." * digit^1 + digit^1 )
       * ( S "eE" * S "+-" ^ -1 * digit^1 ) ^ -1
-      + digit^1 ,
-      'Number' 
+      + digit^1 
     ) 
 %    \end{macrocode}
 %
@@ -3433,19 +3622,19 @@
 %    \begin{macrocode}
 local Word
 if piton_begin_escape ~= ''
-then Word = K ( ( ( 1 - space - P(piton_begin_escape) - P(piton_end_escape) ) 
+then Word = Q ( ( ( 1 - space - P(piton_begin_escape) - P(piton_end_escape) ) 
                    - S "'\"\r[()]" - digit ) ^ 1 )
-else Word = K ( ( ( 1 - space ) - S "'\"\r[()]" - digit ) ^ 1 )
+else Word = Q ( ( ( 1 - space ) - S "'\"\r[()]" - digit ) ^ 1 )
 end
 %    \end{macrocode}
 %
 % \bigskip
 %    \begin{macrocode}
-local Space = ( K " " ) ^ 1
+local Space = ( Q " " ) ^ 1
 
-local SkipSpace = ( K " " ) ^ 0
+local SkipSpace = ( Q " " ) ^ 0
 
-local Punct = K ( S ".,:;!" )
+local Punct = Q ( S ".,:;!" )
 
 local Tab = P "\t" * Lc ( '\\l_@@_tab_tl' )
 %    \end{macrocode}
@@ -3452,13 +3641,13 @@
 % 
 % \bigskip
 %    \begin{macrocode}
-local SpaceIndentation = Lc ( '\\@@_an_indentation_space:' ) * ( K " " )
+local SpaceIndentation = Lc ( '\\@@_an_indentation_space:' ) * ( Q " " )
 %    \end{macrocode}
 %
 %
 % \bigskip
 %    \begin{macrocode}
-local Delim = K ( S "[()]" )
+local Delim = Q ( S "[()]" )
 %    \end{macrocode}
 % 
 % \bigskip
@@ -3480,26 +3669,26 @@
 % ligatures available in some fonts such as \emph{Fira Code} to be active.
 %    \begin{macrocode}
 local Operator = 
-  K ( P "!=" + P "<>" + P "==" + P "<<" + P ">>" + P "<=" + P ">=" + P ":=" 
+  K ( 'Operator' ,
+      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')
+  K ( 'Operator.Word' ,P "in" + P "is" + P "and" + P "or" + P "not" )
 
 local Keyword = 
-  K ( P "as" + P "assert" + P "break" + P "case" + P "class" + P "continue" 
+  K ( 'Keyword' ,
+      P "as" + P "assert" + P "break" + P "case" + P "class" + P "continue" 
       + P "def" + P "del" + P "elif" + P "else" + P "except" + P "exec" 
       + P "finally" + P "for" + P "from" + P "global" + P "if" + P "import" 
       + P "lambda" + P "non local" + P "pass" + P "return" + P "try" 
-      + P "while" + P "with" + P "yield" + P "yield from" ,
-  'Keyword' )
-  + K ( P "True" + P "False" + P "None" , 'Keyword.Constant' ) 
+      + P "while" + P "with" + P "yield" + P "yield from" )
+  + K ( 'Keyword.Constant' ,P "True" + P "False" + P "None" ) 
 
 local Builtin = 
-  K ( P "__import__" + P "abs" + P "all" + P "any" + P "bin" + P "bool" 
+  K ( 'Name.Builtin' ,
+      P "__import__" + P "abs" + P "all" + P "any" + P "bin" + P "bool" 
     + P "bytearray" + P "bytes" + P "chr" + P "classmethod" + P "compile" 
     + P "complex" + P "delattr" + P "dict" + P "dir" + P "divmod" 
     + P "enumerate" + P "eval" + P "filter" + P "float" + P "format" 
@@ -3510,11 +3699,12 @@
     + P "ord" + P "pow" + P "print" + P "property" + P "range" + P "repr" 
     + P "reversed" + P "round" + P "set" + P "setattr" + P "slice" + P "sorted" 
     + P "staticmethod" + P "str" + P "sum" + P "super" + P "tuple" + P "type"
-    + P "vars" + P "zip" ,
-  'Name.Builtin' )
+    + P "vars" + P "zip" )
 
+
 local Exception =
-  K ( P "ArithmeticError" + P "AssertionError" + P "AttributeError"
+  K ( 'Exception' ,
+      P "ArithmeticError" + P "AssertionError" + P "AttributeError"
    + P "BaseException" + P "BufferError" + P "BytesWarning" + P "DeprecationWarning"
    + P "EOFError" + P "EnvironmentError" + P "Exception" + P "FloatingPointError"
    + P "FutureWarning" + P "GeneratorExit" + P "IOError" + P "ImportError"
@@ -3533,11 +3723,11 @@
    + P "ConnectionResetError" + P "FileExistsError" + P "FileNotFoundError"
    + P "InterruptedError" + P "IsADirectoryError" + P "NotADirectoryError"
    + P "PermissionError" + P "ProcessLookupError" + P "TimeoutError"
-   + P "StopAsyncIteration" + P "ModuleNotFoundError" + P "RecursionError" ,
-  'Exception' )
+   + P "StopAsyncIteration" + P "ModuleNotFoundError" + P "RecursionError" )
 
-local RaiseException = K ( P "raise" , 'Keyword' ) * SkipSpace * Exception * K ( P "(" ) 
 
+local RaiseException = K ( 'Keyword' , P "raise" ) * SkipSpace * Exception * Q ( P "(" ) 
+
 %    \end{macrocode}
 %
 % \bigskip
@@ -3544,7 +3734,7 @@
 % In Python, a ``decorator'' is a statement whose begins by |@| which patches
 % the function defined in the following statement.
 %    \begin{macrocode}
-local Decorator = K ( P "@" * letter^1 , 'Name.Decorator' ) 
+local Decorator = K ( 'Name.Decorator' , P "@" * letter^1  ) 
 %    \end{macrocode}
 % 
 % \bigskip
@@ -3556,7 +3746,7 @@
 % Example:\enskip \piton{class myclass:}
 %    \begin{macrocode}
 local DefClass = 
-  K ( P "class" , 'Keyword' ) * Space * K ( identifier , 'Name.Class' ) 
+  K ( 'Keyword' , P "class" ) * Space * K ( 'Name.Class' , identifier ) 
 %    \end{macrocode}
 % 
 % If the word |class| is not followed by a identifier, it will be catched as
@@ -3580,17 +3770,16 @@
 % Example:\enskip \piton{import math, numpy}
 %    \begin{macrocode}
 local ImportAs = 
-  K ( P "import" , 'Keyword' )
+  K ( 'Keyword' , P "import" )
    * Space 
-   * K ( identifier * ( P "." * identifier ) ^ 0 , 
-         'Name.Namespace' 
-       )
+   * K ( 'Name.Namespace' , 
+         identifier * ( P "." * identifier ) ^ 0 )
    * ( 
-       ( Space * K ( P "as" , 'Keyword' ) * Space 
-          * K ( identifier , 'Name.Namespace' ) )
+       ( Space * K ( 'Keyword' , P "as" ) * Space 
+          * K ( 'Name.Namespace' , identifier ) )
        + 
-       ( SkipSpace * K ( P "," ) * SkipSpace 
-          * K ( identifier , 'Name.Namespace' ) ) ^ 0 
+       ( SkipSpace * Q ( P "," ) * SkipSpace 
+          * K ( 'Name.Namespace' , identifier ) ) ^ 0 
      ) 
 %    \end{macrocode}
 % Be careful: there is no commutativity of |+| in the previous expression.
@@ -3608,9 +3797,9 @@
 % \smallskip
 %    \begin{macrocode}
 local FromImport =
-  K ( P "from" , 'Keyword' ) 
-    * Space * K ( identifier , 'Name.Namespace' )
-    * Space * K ( P "import" , 'Keyword' ) 
+  K ( 'Keyword' , P "from" ) 
+    * Space * K ( 'Name.Namespace' , identifier )
+    * Space * K ( 'Keyword' , P "import" ) 
 %    \end{macrocode}
 %
 % \bigskip
@@ -3648,14 +3837,14 @@
 % technics now in Python).
 %    \begin{macrocode}
 local PercentInterpol =  
-  K ( P "%" 
+  K ( 'String.Interpol' , 
+      P "%" 
       * ( P "(" * alphanum ^ 1 * P ")" ) ^ -1 
       * ( S "-#0 +" ) ^ 0 
       * ( digit ^ 1 + P "*" ) ^ -1 
       * ( P "." * ( digit ^ 1 + P "*" ) ) ^ -1 
       * ( S "HlL" ) ^ -1
-      * S "sdfFeExXorgiGauc%" ,
-      'String.Interpol' 
+      * S "sdfFeExXorgiGauc%" 
     ) 
 %    \end{macrocode}
 % 
@@ -3668,62 +3857,57 @@
 % @@\_piton:n} wich means that the interpolations are parsed once again by \pkg{piton}.}
 %    \begin{macrocode}
 local SingleShortString =
-  Lc ( "{\\PitonStyle{String.Short}{" )
-   * (
+  WithStyle ( 'String.Short' ,
 %    \end{macrocode}
 % First, we deal with the f-strings of Python, which are prefixed by |f| or |F|.
 %    \begin{macrocode}
-         K ( P "f'" + P "F'" ) 
+         Q ( P "f'" + P "F'" ) 
          * ( 
-             K ( P "{" , 'String.Interpol')
-              * K ( ( 1 - S "}':" ) ^ 0 , 'Interpol.Inside' )
-              * K ( P ":" * (1 - S "}:'") ^ 0 ) ^ -1
-              * K ( P "}" , 'String.Interpol' )
+             K ( 'String.Interpol' , P "{" )
+              * K ( 'Interpol.Inside' , ( 1 - S "}':" ) ^ 0  )
+              * Q ( P ":" * (1 - S "}:'") ^ 0 ) ^ -1
+              * K ( 'String.Interpol' , P "}" )
              + 
              VisualSpace 
              + 
-             K ( ( P "\\'" + P "{{" + P "}}" + 1 - S " {}'" ) ^ 1 )
+             Q ( ( P "\\'" + P "{{" + P "}}" + 1 - S " {}'" ) ^ 1 )
            ) ^ 0 
-         * K ( P "'" )
+         * Q ( P "'" )
        + 
 %    \end{macrocode}
 % Now, we deal with the standard strings of Python, but also the ``raw strings''.
 %    \begin{macrocode}
-         K ( P "'" + P "r'" + P "R'" ) 
-         * ( K ( ( P "\\'" + 1 - S " '\r%" ) ^ 1 ) 
+         Q ( P "'" + P "r'" + P "R'" ) 
+         * ( Q ( ( P "\\'" + 1 - S " '\r%" ) ^ 1 ) 
              + VisualSpace 
              + PercentInterpol 
-             + K ( P "%" ) 
+             + Q ( P "%" ) 
            ) ^ 0 
-         * K ( P "'" )
-     )
-   * Lc ( "}}" ) 
+         * Q ( P "'" ) )
 
+
 local DoubleShortString =
-  Lc ( "{\\PitonStyle{String.Short}{" )
-   * (
-         K ( P "f\"" + P "F\"" ) 
+  WithStyle ( 'String.Short' , 
+         Q ( P "f\"" + P "F\"" ) 
          * ( 
-             K ( P "{" , 'String.Interpol' )
-               * K ( ( 1 - S "}\":" ) ^ 0 , 'Interpol.Inside' )
-               * ( K ( P ":" , 'String.Interpol' ) * K ( (1 - S "}:\"") ^ 0 ) ) ^ -1
-               * K ( P "}" , 'String.Interpol' )
+             K ( 'String.Interpol' , P "{" )
+               * Q ( ( 1 - S "}\":" ) ^ 0 , 'Interpol.Inside' )
+               * ( K ( 'String.Interpol' , P ":" ) * Q ( (1 - S "}:\"") ^ 0 ) ) ^ -1
+               * K ( 'String.Interpol' , P "}" )
              + 
              VisualSpace 
              + 
-             K ( ( P "\\\"" + P "{{" + P "}}" + 1 - S " {}\"" ) ^ 1 ) 
+             Q ( ( P "\\\"" + P "{{" + P "}}" + 1 - S " {}\"" ) ^ 1 ) 
             ) ^ 0
-         * K ( P "\"" )
+         * Q ( P "\"" )
        +
-         K ( P "\"" + P "r\"" + P "R\"" ) 
-         * ( K ( ( P "\\\"" + 1 - S " \"\r%" ) ^ 1 ) 
+         Q ( P "\"" + P "r\"" + P "R\"" ) 
+         * ( Q ( ( P "\\\"" + 1 - S " \"\r%" ) ^ 1 ) 
              + VisualSpace 
              + PercentInterpol 
-             + K ( P "%" ) 
+             + Q ( P "%" ) 
            ) ^ 0 
-         * K ( P "\"" )
-     )
-   * Lc ( "}}" ) 
+         * Q ( P "\"" ) )
 
 local ShortString = SingleShortString + DoubleShortString
 %    \end{macrocode}
@@ -3749,6 +3933,7 @@
            ) ^ 0 
     }
 %    \end{macrocode}
+% 
 %
 % \bigskip 
 % If Beamer is used (or if the key |beamer| is used at load-time), the following
@@ -3757,12 +3942,38 @@
 local Beamer = P ( false ) 
 local BeamerBeginEnvironments = P ( true ) 
 local BeamerEndEnvironments = P ( true ) 
-local BeamerNamesEnvironments =
+local BeamerNamesEnvironments =  
   P "uncoverenv" + P "onlyenv" + P "visibleenv" + P "invisibleenv" 
   + P "alertenv" + P "actionenv"
 
 %    \end{macrocode}
+%
+%    \begin{macrocode}
+UserCommands = 
+       Ct ( Cc "Open" * C ( "\\emph{" ) * Cc "}" ) 
+     * ( C ( BalancedBraces ) / (function (s) return MainLoopPython:match(s) end ) )
+     * P "}" * Ct ( Cc "Close" ) 
+%    \end{macrocode}
 % 
+%    \begin{macrocode}
+function OneBeamerEnvironment(name)
+  return 
+      Ct ( Cc "Open" 
+            * C ( 
+                  P ( "\\begin{" .. name ..   "}" )
+                  * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1 
+                ) 
+           * Cc ( "\\end{" .. name ..  "}" )
+          ) 
+     * ( 
+         C ( ( 1 - P ( "\\end{" .. name .. "}" ) ) ^ 0 ) 
+         / (function (s) return MainLoopPython:match(s) end ) 
+       )
+     * P ( "\\end{" .. name ..  "}" ) * Ct ( Cc "Close" ) 
+end 
+%    \end{macrocode}
+% 
+%
 % \bigskip
 %    \begin{macrocode}
 if piton_beamer 
@@ -3770,24 +3981,27 @@
   Beamer =
       L  ( P "\\pause" * ( P "[" * (1 - P "]") ^ 0 * P "]" ) ^ -1 ) 
     + 
-%    \end{macrocode}
-% We recall that the command |\@@_beamer_command:n| executes the argument
-% corresponding to its argument but also stores it in |\l_@@_beamer_command_str|.
-% That string is used only in the error message ``|cr~not~allowed|'' raised when
-% there is a carriage return in the mandatory argument of that command.
-%    \begin{macrocode}
-      (   P "\\uncover"   * Lc ( '\\@@_beamer_command:n{uncover}' ) 
-        + P "\\only"      * Lc ( '\\@@_beamer_command:n{only}' ) 
-        + P "\\alert"     * Lc ( '\\@@_beamer_command:n{alert}' ) 
-        + P "\\visible"   * Lc ( '\\@@_beamer_command:n{visible}' ) 
-        + P "\\invisible" * Lc ( '\\@@_beamer_command:n{invisible}' ) 
-        + P "\\action"    * Lc ( '\\@@_beamer_command:n{action}' ) 
-      ) 
-      *
-      L ( ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1 * P "{" )
-      * K ( BalancedBraces , 'ParseAgain.noCR' ) 
-      * L ( P "}" )
-    +  
+      Ct ( Cc "Open" 
+            * C ( 
+                  ( 
+                    P "\\uncover" + P "\\only" + P "\\alert" + P "\\visible"
+                    + P "\\invisible" + P "\\action" 
+                  ) 
+                  * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1 
+                  * P "{" 
+                ) 
+            * Cc "}" 
+         ) 
+       * ( C ( BalancedBraces ) / (function (s) return MainLoopPython:match(s) end ) )
+       * P "}" * Ct ( Cc "Close" ) 
+    + 
+      OneBeamerEnvironment "uncoverenv" 
+    + OneBeamerEnvironment "onlyenv" 
+    + OneBeamerEnvironment "visibleenv" 
+    + OneBeamerEnvironment "invisibleenv" 
+    + OneBeamerEnvironment "alertenv" 
+    + OneBeamerEnvironment "actionenv" 
+    +
       L ( 
 %    \end{macrocode}
 % For |\\alt|, the specification of the overlays (between angular brackets) is mandatory.
@@ -3796,9 +4010,9 @@
           * P "<" * (1 - P ">") ^ 0 * P ">" 
           * P "{" 
         )
-      * K ( BalancedBraces , 'ParseAgain.noCR' ) 
+      * K ( 'ParseAgain.noCR' , BalancedBraces ) 
       * L ( P "}{" )
-      * K ( BalancedBraces , 'ParseAgain.noCR' ) 
+      * K ( 'ParseAgain.noCR' , BalancedBraces ) 
       * L ( P "}" )
     +  
       L ( 
@@ -3809,11 +4023,11 @@
           * P "<" * (1 - P ">") ^ 0 * P ">" 
           * P "{" 
         )
-      * K ( BalancedBraces , 'ParseAgain.noCR' ) 
+      * K ( 'ParseAgain.noCR' , BalancedBraces ) 
       * L ( P "}{" )
-      * K ( BalancedBraces , 'ParseAgain.noCR' ) 
+      * K ( 'ParseAgain.noCR' , BalancedBraces ) 
       * L ( P "}{" )
-      * K ( BalancedBraces , 'ParseAgain.noCR' ) 
+      * K ( 'ParseAgain.noCR' , BalancedBraces ) 
       * L ( P "}" )
 %    \end{macrocode}
 % Now for the environemnts.
@@ -3841,24 +4055,29 @@
 % \bigskip
 % The following LPEG will detect the Python prompts when the user is typesetting
 % an interactive session of Python (directly or through |{pyconsole}| of
-% \pkg{pyluatex}). 
+% \pkg{pyluatex}). We have to detect that prompt twice. The first detection
+% (called \emph{hasty detection}) will be before the |\@@_begin_line:| because
+% you want to trigger a special background color for that row (and, after the
+% |\@@_begin_line:|, it's too late to change de background).
 %    \begin{macrocode}
 local PromptHastyDetection = ( # ( P ">>>" + P "..." ) * Lc ( '\\@@_prompt:' ) ) ^ -1 
 %    \end{macrocode}
-% We remind that the marker |#| of LPEG specifies that the pattern will be
+% We remind that the marker |#| of \textsc{lpeg} specifies that the pattern will be
 % detected but won't consume any character.
 %
+% \medskip
+% With the following \textsc{lpeg}, a style will actually be applied to the
+% prompt (for instance, it's possible to decide to discard these prompts).
 %    \begin{macrocode}
-local Prompt = K ( ( ( P ">>>" + P "..." ) * P " " ^ -1 ) ^ -1 , 'Prompt' ) 
+local Prompt = K ( 'Prompt' , ( ( P ">>>" + P "..." ) * P " " ^ -1 ) ^ -1  ) 
 %    \end{macrocode}
 %    
+%
+%
 % \bigskip
 % The following \textsc{lpeg} |EOL| is for the end of lines.
 %    \begin{macrocode}
-local EOL
-if piton_beamer 
-then
-EOL = 
+local EOL = 
   P "\r" 
   *
   (
@@ -3871,45 +4090,23 @@
 % @@\_end\_line:} must be explicit because it will be used as marker in order to
 % delimit the argument of the command \texttt{\textbackslash @@\_begin\_line:}}.
 %    \begin{macrocode}
-    Lc ( '\\@@_end_line:' ) 
-    * BeamerEndEnvironments 
-    * BeamerBeginEnvironments 
-    * PromptHastyDetection
-    * Lc ( '\\@@_newline: \\@@_begin_line:' )
-    * Prompt
+    Ct ( 
+         Cc "EOL"
+         * 
+         Ct (
+              Lc "\\@@_end_line:"
+              * BeamerEndEnvironments 
+              * BeamerBeginEnvironments 
+              * PromptHastyDetection
+              * Lc "\\@@_newline: \\@@_begin_line:"
+              * Prompt
+            )
+       )
   ) 
   *
   SpaceIndentation ^ 0
-else
-EOL = 
-  P "\r" 
-  *
-  (
-    ( space ^ 0 * -1 )
-    + 
 %    \end{macrocode}
-% We recall that each line in the Python code we have to parse will be sent
-% back to LaTeX between a pair |\@@_begin_line:| --
-% |\@@_end_line:|\footnote{Remember that the \texttt{\textbackslash
-% @@\_end\_line:} must be explicit because it will be used as marker in order to
-% delimit the argument of the command \texttt{\textbackslash @@\_begin\_line:}}.
-%    \begin{macrocode}
-    Lc ( '\\@@_end_line:' )  
-    * PromptHastyDetection
-    * Lc ( '\\@@_newline: \\@@_begin_line:' )
-    * Prompt 
-  ) 
-  *
-  SpaceIndentation ^ 0
-end 
-%    \end{macrocode}
 %
-% \bigskip
-%    \begin{macrocode}
-function EOL_for_style ( s ) 
-   return Lc "}}" * EOL * Lc ( "{\\PitonStyle{" .. s .. "}{" ) 
-end 
-%    \end{macrocode}
 % 
 % \bigskip
 % \paragraph{The long strings}
@@ -3917,63 +4114,61 @@
 % 
 %    \begin{macrocode}
 local SingleLongString =
-  Lc "{\\PitonStyle{String.Long}{" 
-   * (
-         K ( S "fF" * P "'''" )
+  WithStyle ( 'String.Long' , 
+     ( Q ( S "fF" * P "'''" )
          * (
-             K ( P "{" , 'String.Interpol' )
-               * K ( ( 1 - S "}:\r" - P "'''" ) ^ 0 , 'Interpol.Inside' )
-               * K ( P ":" * (1 - S "}:\r" - P "'''" ) ^ 0 ) ^ -1
-               * K ( P "}" , 'String.Interpol' )
+             K ( 'String.Interpol' , P "{"  )
+               * K ( 'Interpol.Inside' , ( 1 - S "}:\r" - P "'''" ) ^ 0  )
+               * Q ( P ":" * (1 - S "}:\r" - P "'''" ) ^ 0 ) ^ -1
+               * K ( 'String.Interpol' , P "}"  )
              + 
-             K ( ( 1 - P "'''" - S "{}'\r" ) ^ 1 )
+             Q ( ( 1 - P "'''" - S "{}'\r" ) ^ 1 )
              + 
-             EOL_for_style 'String.Long'
+             EOL
            ) ^ 0 
        +
-         K ( ( S "rR" ) ^ -1  * P "'''" )
+         Q ( ( S "rR" ) ^ -1  * P "'''" )
          * (
-             K ( ( 1 - P "'''" - S "\r%" ) ^ 1 )  
+             Q ( ( 1 - P "'''" - S "\r%" ) ^ 1 )  
              + 
              PercentInterpol
              +
              P "%"
              +
-             EOL_for_style 'String.Long'
+             EOL
            ) ^ 0 
       )
-   * K ( P "'''" )
-   * Lc "}}" 
+      * Q ( P "'''" ) ) 
 
 
 local DoubleLongString =
-  Lc "{\\PitonStyle{String.Long}{" 
-   * (
-         K ( S "fF" * P "\"\"\"" )
-         * (
-             K ( P "{" , 'String.Interpol' )
-               * K ( ( 1 - S "}:\r" - P "\"\"\"" ) ^ 0 , 'Interpol.Inside' )
-               * K ( P ":" * (1 - S "}:\r" - P "\"\"\"" ) ^ 0 ) ^ -1
-               * K ( P "}" , 'String.Interpol' )
-             + 
-             K ( ( 1 - P "\"\"\"" - S "{}\"\r" ) ^ 1 ) 
-             + 
-             EOL_for_style 'String.Long'
-           ) ^ 0 
-       +
-         K ( ( S "rR" ) ^ -1  * P "\"\"\"" )
-         * (
-             K ( ( 1 - P "\"\"\"" - S "%\r" ) ^ 1 )  
-             + 
-             PercentInterpol 
-             + 
-             P "%"
-             + 
-             EOL_for_style 'String.Long'
-           ) ^ 0 
-      )
-   * K ( P "\"\"\"" )
-   * Lc "}}" 
+  WithStyle ( 'String.Long' ,
+     (
+        Q ( S "fF" * P "\"\"\"" )
+        * (
+            K ( 'String.Interpol', P "{"  )
+              * K ( 'Interpol.Inside' , ( 1 - S "}:\r" - P "\"\"\"" ) ^ 0 )
+              * Q ( P ":" * (1 - S "}:\r" - P "\"\"\"" ) ^ 0 ) ^ -1
+              * K ( 'String.Interpol' , P "}"  )
+            + 
+            Q ( ( 1 - P "\"\"\"" - S "{}\"\r" ) ^ 1 ) 
+            + 
+            EOL
+          ) ^ 0 
+      +
+        Q ( ( S "rR" ) ^ -1  * P "\"\"\"" )
+        * (
+            Q ( ( 1 - P "\"\"\"" - S "%\r" ) ^ 1 )  
+            + 
+            PercentInterpol 
+            + 
+            P "%"
+            + 
+            EOL
+          ) ^ 0 
+     )
+     * Q ( P "\"\"\"" ) 
+  ) 
 %    \end{macrocode}
 %
 %    \begin{macrocode}
@@ -3986,11 +4181,11 @@
 % of a function definition (which begins with |def|).
 %    \begin{macrocode}
 local StringDoc = 
-    K ( P "\"\"\"" , 'String.Doc' )
-      * ( K ( (1 - P "\"\"\"" - P "\r" ) ^ 0 , 'String.Doc' ) * EOL 
+    K ( 'String.Doc' , P "\"\"\"" )
+      * ( K ( 'String.Doc' , (1 - P "\"\"\"" - P "\r" ) ^ 0  ) * EOL
           * Tab ^ 0 
         ) ^ 0
-      * K ( ( 1 - P "\"\"\"" - P "\r" ) ^ 0 * P "\"\"\"" , 'String.Doc' )
+      * K ( 'String.Doc' , ( 1 - P "\"\"\"" - P "\r" ) ^ 0 * P "\"\"\"" )
 %    \end{macrocode}
 %
 % \bigskip
@@ -4000,13 +4195,12 @@
 % listings.
 %    \begin{macrocode}
 local CommentMath = 
-  P "$" * K ( ( 1 - S "$\r" ) ^ 1 , 'Comment.Math' ) * P "$"
+  P "$" * K ( 'Comment.Math' , ( 1 - S "$\r" ) ^ 1  ) * P "$"
 
 local Comment = 
-  Lc ( "{\\PitonStyle{Comment}{" ) 
-  * K ( P "#" ) 
-  * ( CommentMath + K ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0
-  * Lc ( "}}" )
+  WithStyle ( 'Comment' ,
+     Q ( P "#" ) 
+     * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0 ) 
   * ( EOL + -1 )
 %    \end{macrocode}
 % 
@@ -4023,7 +4217,7 @@
   * Lc "{\\PitonStyle{Comment.LaTeX}{\\ignorespaces" 
   * L ( ( 1 - P "\r" ) ^ 0 ) 
   * Lc "}}" 
-  * ( EOL + -1 ) 
+  * ( EOL + -1 )  -- you could put EOL instead of EOL
 %    \end{macrocode}
 % 
 % \bigskip
@@ -4071,14 +4265,14 @@
 local Param = 
   SkipSpace * Identifier * SkipSpace
    * ( 
-         K ( P "=" * Expression , 'InitialValues' )
-       + K ( P ":" ) * SkipSpace * K ( letter^1 , 'Name.Type' ) 
+         K ( 'InitialValues' , P "=" * Expression )
+       + Q ( P ":" ) * SkipSpace * K ( 'Name.Type' , letter^1  ) 
      ) ^ -1
 %    \end{macrocode}
 % 
 % \medskip
 %    \begin{macrocode}
-local Params = ( Param * ( K "," * Param ) ^ 0 ) ^ -1
+local Params = ( Param * ( Q "," * Param ) ^ 0 ) ^ -1
 %    \end{macrocode}
 % 
 % \bigskip
@@ -4089,13 +4283,13 @@
 % |Comment|, |CommentLaTeX|, |Params|, |StringDoc|...
 %    \begin{macrocode}
 local DefFunction =
-  K ( P "def" , 'Keyword' )
+  K ( 'Keyword' , P "def" )
   * Space
-  * K ( identifier , 'Name.Function' ) 
+  * K ( 'Name.Function.Internal' , identifier ) 
   * SkipSpace 
-  * K ( P "(" ) * Params * K ( P ")" ) 
+  * Q ( P "(" ) * Params * Q ( P ")" ) 
   * SkipSpace
-  * ( K ( P "->" ) * SkipSpace * K ( identifier , 'Name.Type' ) ) ^ -1
+  * ( Q ( P "->" ) * SkipSpace * K ( 'Name.Type' , identifier  ) ) ^ -1
 %    \end{macrocode}
 % Here, we need a \pkg{piton} style |ParseAgain| which will be linked to
 % |\@@_piton:n| (that means that the capture will be parsed once again by
@@ -4102,8 +4296,8 @@
 % \pkg{piton}). We could avoid that kind of trick by using a non-terminal of a
 % grammar but we have probably here a better legibility.
 %    \begin{macrocode}
-  * K ( ( 1 - S ":\r" )^0 , 'ParseAgain' ) 
-  * K ( P ":" )
+  * K ( 'ParseAgain' , ( 1 - S ":\r" )^0  ) 
+  * Q ( P ":" )
   * ( SkipSpace
       * ( EOL + CommentLaTeX + Comment ) -- in all cases, that contains an EOL
       * Tab ^ 0 
@@ -4144,20 +4338,20 @@
 %
 %    \begin{macrocode}
 local ItemDict = 
-  ShortString * SkipSpace * K ( P ":" ) * K ( Expression , 'Dict.Value' ) 
+  ShortString * SkipSpace * Q ( P ":" ) * K ( 'Dict.Value' , Expression  ) 
 
 local ItemOfSet = SkipSpace * ( ItemDict + ShortString ) * SkipSpace 
 
 local Set = 
-  K ( P "{" ) 
-  * ItemOfSet * ( K ( P "," ) * ItemOfSet )  ^ 0 
-  * K ( P "}" )
+  Q ( P "{" ) 
+  * ItemOfSet * ( Q ( P "," ) * ItemOfSet )  ^ 0 
+  * Q ( P "}" )
 %    \end{macrocode}
 %
 % \paragraph{Miscellaneous}
 % 
 %    \begin{macrocode}
-local ExceptionInConsole = Exception *  K ( ( 1 - P "\r" ) ^ 0 ) * EOL  
+local ExceptionInConsole = Exception *  Q ( ( 1 - P "\r" ) ^ 0 ) * EOL 
 %    \end{macrocode}
 % 
 % 
@@ -4166,7 +4360,7 @@
 %
 % First, the main loop :
 %    \begin{macrocode}
-MainLoop = 
+MainLoopPython = 
   (  ( space^1 * -1 ) 
      + EOL
      + Space 
@@ -4173,7 +4367,8 @@
      + Tab
      + Escape 
      + CommentLaTeX
-     + Beamer 
+     + Beamer
+     + UserCommands 
      + LongString 
      + Comment
      + ExceptionInConsole
@@ -4189,10 +4384,10 @@
      + RaiseException 
      + DefFunction
      + DefClass 
-     + Keyword * ( Space + Punct + Delim + EOL + -1 ) 
+     + Keyword * ( Space + Punct + Delim + EOL+ -1 ) 
      + Decorator
-     + OperatorWord * ( Space + Punct + Delim + EOL + -1 ) 
-     + Builtin * ( Space + Punct + Delim + EOL + -1 ) 
+     + OperatorWord * ( Space + Punct + Delim + EOL+ -1 ) 
+     + Builtin * ( Space + Punct + Delim + EOL+ -1 ) 
      + Identifier 
      + Number
      + Word
@@ -4213,12 +4408,12 @@
        ( ( space - P "\r" ) ^0 * P "\r" ) ^ -1 
        * BeamerBeginEnvironments 
        * PromptHastyDetection
-       * Lc ( '\\@@_begin_line:' ) 
+       * Lc '\\@@_begin_line:'
        * Prompt 
        * SpaceIndentation ^ 0 
-       * MainLoop
+       * MainLoopPython
        * -1 
-       * Lc ( '\\@@_end_line:' )
+       * Lc '\\@@_end_line:' 
      )
 %    \end{macrocode}
 %
@@ -4231,31 +4426,35 @@
 % \subsubsection{The LPEG ocaml}
 % 
 %    \begin{macrocode}
-local Punct = K ( S ",:;!" )
+local Delim = Q ( P "[|" + P "|]" + S "[()]" )
 %    \end{macrocode}
+%
+%    \begin{macrocode}
+local Punct = Q ( S ",:;!" )
+%    \end{macrocode}
 % 
 %    \begin{macrocode}
 local identifier = 
   ( R "az" + R "AZ" + P "_") * ( R "az" + R "AZ" + S "_'" + digit ) ^ 0 
 
-local Identifier = K ( identifier )
+local Identifier = K ( 'Identifier' , identifier )
 
 local Operator = 
-  K ( P "!=" + P "<>" + P "==" + P "<<" + P ">>" + P "<=" + P ">=" + P ":=" 
+  K ( 'Operator' ,
+      P "!=" + P "<>" + P "==" + P "<<" + P ">>" + P "<=" + P ">=" + P ":=" 
       + P "||" + P "&&" + P "//" + P "**" + P ";;" + P "::" + P "->" 
       + P "+." + P "-." + P "*." + P "/." 
       + S "-~+/*%=<>&@|" 
-      , 
-      'Operator'
     )
 
 local OperatorWord = 
-  K ( P "and" + P "asr" + P "land" + P "lor" + P "lsl" + P "lxor" 
-      + P "mod" + P "or" , 
-      'Operator.Word') 
+  K ( 'Operator.Word' ,
+      P "and" + P "asr" + P "land" + P "lor" + P "lsl" + P "lxor" 
+      + P "mod" + P "or" )
 
 local Keyword = 
-  K ( P "as" + P "assert" + P "begin" + P "class" + P "constraint" + P "done" 
+  K ( 'Keyword' ,
+      P "as" + P "assert" + P "begin" + P "class" + P "constraint" + P "done" 
   + P "do" + P "downto" + P "else" + P "end" + P "exception" + P "external" 
   + P "false" + P "for" + P "function" + P "fun" + P "functor" + P "if" 
   + P "in" + P "include" + P "inherit" + P "initializer" + P "lazy" + P "let" 
@@ -4262,13 +4461,13 @@
   + P "match" + P "method" + P "module" + P "mutable" + P "new" + P "object" 
   + P "of" + P "open" + P "private" + P "raise" + P "rec" + P "sig" 
   + P "struct" + P "then" + P "to" + P "true" + P "try" + P "type" 
-  + P "value" + P "val" + P "virtual" + P "when" + P "while" + P "with" ,
-  'Keyword' ) 
-  + K ( P "true" + P "false" , 'Keyword.Constant' )  
+  + P "value" + P "val" + P "virtual" + P "when" + P "while" + P "with" )
+  + K ( 'Keyword.Constant' , P "true" + P "false" )  
 
 
 local Builtin = 
-  K (   P "not" + P "incr" + P "decr" + P "fst" + P "snd" 
+  K ( 'Name.Builtin' ,
+        P "not" + P "incr" + P "decr" + P "fst" + P "snd" 
       + P "String.length" 
       + P "List.tl" + P "List.hd" + P "List.mem" + P "List.exists" 
       + P "List.for_all" + P "List.filter" + P "List.length" + P "List.map" 
@@ -4280,8 +4479,7 @@
       + P "Stack.create" + P "Stack.is_empty" + P "Stack.push" + P "Stack.pop" 
       + P "Hashtbl.create" + P "Hashtbl.add" + P "Hashtbl.remove" 
       + P "Hashtbl.mem" + P "Hashtbl.find" + P "Hashtbl.find_opt" 
-      + P "Hashtbl.iter"  
-      , 'Name.Builtin' )
+      + P "Hashtbl.iter" )
 %    \end{macrocode}
 % 
 % \bigskip
@@ -4288,19 +4486,19 @@
 % The following exceptions are exceptions in the standard library of OCaml (Stdlib).
 %    \begin{macrocode}
 local Exception =
-  K ( P "Division_by_zero" + P "End_of_File" + P "Failure" 
+  K (   'Exception' ,
+       P "Division_by_zero" + P "End_of_File" + P "Failure" 
      + P "Invalid_argument" + P "Match_failure" + P "Not_found" 
      + P "Out_of_memory" + P "Stack_overflow" + P "Sys_blocked_io" 
-     + P "Sys_error" + P "Undefined_recursive_module" ,
-  'Exception' )
+     + P "Sys_error" + P "Undefined_recursive_module" )
 %    \end{macrocode}
 %
-% 
+% \bigskip
 % \paragraph{The characters in OCaml}
 %
 %    \begin{macrocode}
 local Char = 
-  K ( P "'" * ( ( 1 - P "'" ) ^ 0 + P "\\'" ) * P "'" , 'String.Short' ) 
+  K ( 'String.Short' , P "'" * ( ( 1 - P "'" ) ^ 0 + P "\\'" ) * P "'" ) 
 %    \end{macrocode}
 % 
 %
@@ -4337,7 +4535,7 @@
       ) 
       *
       L ( ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1 * P "{" )
-      * K ( BalancedBraces , 'ParseAgain.noCR' ) 
+      * K ( 'ParseAgain.noCR' , BalancedBraces ) 
       * L ( P "}" )
     +  
       L ( 
@@ -4345,9 +4543,9 @@
           * P "<" * (1 - P ">") ^ 0 * P ">" 
           * P "{" 
         )
-      * K ( BalancedBraces , 'ParseAgain.noCR' ) 
+      * K ( 'ParseAgain.noCR' , BalancedBraces ) 
       * L ( P "}{" )
-      * K ( BalancedBraces , 'ParseAgain.noCR' ) 
+      * K ( 'ParseAgain.noCR' , BalancedBraces ) 
       * L ( P "}" )
     +  
       L ( 
@@ -4355,11 +4553,11 @@
           * P "<" * (1 - P ">") ^ 0 * P ">" 
           * P "{" 
         )
-      * K ( BalancedBraces , 'ParseAgain.noCR' ) 
+      * K ( 'ParseAgain.noCR' , BalancedBraces ) 
       * L ( P "}{" )
-      * K ( BalancedBraces , 'ParseAgain.noCR' ) 
+      * K ( 'ParseAgain.noCR' , BalancedBraces ) 
       * L ( P "}{" )
-      * K ( BalancedBraces , 'ParseAgain.noCR' ) 
+      * K ( 'ParseAgain.noCR' , BalancedBraces ) 
       * L ( P "}" )
   BeamerBeginEnvironments = 
       ( space ^ 0 * 
@@ -4380,62 +4578,53 @@
 %
 % \bigskip
 % \paragraph{EOL}
-%
 %    \begin{macrocode}
-local EOL
-if piton_beamer 
-then
-EOL = 
+local EOL = 
   P "\r" 
   *
   (
     ( space^0 * -1 )
     + 
-    Lc ( '\\@@_end_line:' ) 
-    * BeamerEndEnvironments 
-    * BeamerBeginEnvironments 
-    * Lc ( '\\@@_newline: \\@@_begin_line:' )
+    Ct ( 
+         Cc "EOL"
+         * 
+         Ct (
+              Lc "\\@@_end_line:"
+              * BeamerEndEnvironments 
+              * BeamerBeginEnvironments 
+              * PromptHastyDetection
+              * Lc "\\@@_newline: \\@@_begin_line:"
+              * Prompt
+            )
+       )
   ) 
   *
   SpaceIndentation ^ 0
-else
-EOL = 
-  P "\r" 
-  *
-  (
-    ( space ^ 0 * -1 )
-    + 
-    Lc ( '\\@@_end_line:' )  
-    * Lc ( '\\@@_newline: \\@@_begin_line:' )
-  ) 
-  *
-  SpaceIndentation ^ 0
-end 
 %    \end{macrocode}
 %
+%
 %    \begin{macrocode}
-function EOL_for_style ( s ) 
-   return Lc "}}" * EOL * Lc ( "{\\PitonStyle{" .. s .. "}{" ) 
-end 
-%    \end{macrocode}
 % 
-% 
 % \paragraph{The strings}
 % 
+% We need a pattern |string| without captures because it will be used within the
+% comments of OCaml.
 %    \begin{macrocode}
-local String =
-  Lc "{\\PitonStyle{String.Long}{" 
-   * K ( P "\"" )
-   * ( 
-       VisualSpace
-       + 
-       K ( ( 1 - S " \"\r" ) ^ 1 ) 
-       +  
-       EOL_for_style 'String.Long' 
-     ) ^ 0 
-   * K ( P "\"" )
-   * Lc "}}" 
+local string =
+       Q ( P "\"" )
+     * ( 
+         VisualSpace
+         + 
+         Q ( ( 1 - S " \"\r" ) ^ 1 ) 
+         +  
+         EOL
+       ) ^ 0 
+     * Q ( P "\"" ) 
 %    \end{macrocode}
+% 
+%    \begin{macrocode}
+local String = WithStyle ( 'String.Long' , string ) 
+%    \end{macrocode}
 %
 % 
 % \bigskip
@@ -4461,16 +4650,15 @@
 % The \textsc{lpeg} |QuotedStringBis| will do the second analysis. 
 %    \begin{macrocode}
 local QuotedStringBis = 
-   Lc "{\\PitonStyle{String.Long}{"  
-   *
-     (  
+  WithStyle ( 'String.Long' ,
+      (  
         VisualSpace
         +
-        K ( ( 1 - S " \r" ) ^ 1 ) 
+        Q ( ( 1 - S " \r" ) ^ 1 ) 
         +  
-        EOL_for_style 'String.Long' 
-     ) ^ 0 
-   * Lc "}}" 
+        EOL
+      ) ^ 0  ) 
+
 %    \end{macrocode}
 % 
 % \medskip
@@ -4486,7 +4674,7 @@
 % \bigskip
 % \paragraph{The comments in the OCaml listings}
 %
-% In OCaml, the delimiters for the comments are |(*| and |*)|. There
+% In OCaml, the delimiters for the comments are |(*| and |*)|. There are
 % unsymmetrical and, therefore, the comments may be nested. That's why we need a
 % grammar.
 % 
@@ -4495,20 +4683,18 @@
 % 
 %    \begin{macrocode}
 local Comment =
-  Lc "{\\PitonStyle{Comment}{" 
-  *
-  P {
-      "A" ,
-      A = K "(*"
-          * ( V "A" 
-              + K ( ( 1 - P "(*" - P "*)" - S "\r$" ) ^ 1 ) -- $
-              + P "$" * K ( ( 1 - S "$\r" ) ^ 1 , 'Comment.Math' ) * P "$" -- $
-              + EOL_for_style 'Comment'
-            ) ^ 0 
-          * K "*)" 
-    }
-  *
-  Lc "}}" 
+  WithStyle ( 'Comment' ,
+     P {
+         "A" ,
+         A = Q "(*"
+             * ( V "A" 
+                 + Q ( ( 1 - P "(*" - P "*)" - S "\r$\"" ) ^ 1 ) -- $
+                 + string 
+                 + P "$" * K ( 'Comment.Math' , ( 1 - S "$\r" ) ^ 1 ) * P "$" -- $
+                 + EOL
+               ) ^ 0 
+             * Q "*)" 
+       }   )
 %    \end{macrocode}
 % 
 % \bigskip
@@ -4516,11 +4702,11 @@
 %
 %    \begin{macrocode}
 local DefFunction = 
-  ( K ( P "let rec" + P "let" + P "and" , 'Keyword' ) ) 
+  K ( 'Keyword' , P "let rec" + P "let" + P "and" ) 
   * Space
-  * K ( identifier , 'Name.Function' ) 
+  * K ( 'Name.Function.Internal' , identifier ) 
   * Space 
-  * # ( 1 - P "=" ) 
+  * # ( P "=" * space * P "function" + ( 1 - P "=" ) )
 %    \end{macrocode}
 % 
 % \bigskip
@@ -4527,7 +4713,7 @@
 % \paragraph{The parameters of the types}
 % 
 %    \begin{macrocode}
-local TypeParameter = K ( P "'" * alpha * # ( 1 - P "'") , 'TypeParameter' ) 
+local TypeParameter = K ( 'TypeParameter' , P "'" * alpha * # ( 1 - P "'" ) ) 
 %    \end{macrocode}
 % 
 % \bigskip
@@ -4535,7 +4721,7 @@
 %
 % First, the main loop :
 %    \begin{macrocode}
-MainLoop = 
+MainLoopOCaml = 
   (  ( space^1 * -1 ) 
      + EOL
      + Space 
@@ -4576,7 +4762,7 @@
        * BeamerBeginEnvironments 
        * Lc ( '\\@@_begin_line:' ) 
        * SpaceIndentation ^ 0 
-       * MainLoop
+       * MainLoopOCaml
        * -1 
        * Lc ( '\\@@_end_line:' )
      )
@@ -4589,9 +4775,6 @@
 % \bigskip
 % \subsubsection{The function Parse}
 %
-%    \begin{macrocode}
-local MinimalSyntax = Ct ( ( (1 - P "\r" ) ^ 1 + EOL ) ^ 0 )
-%    \end{macrocode}
 %
 % The function |Parse| is the main function of the package \pkg{piton}.
 % It parses its argument and sends back to LaTeX the code with interlaced
@@ -4603,8 +4786,39 @@
 %    \begin{macrocode}
 function piton.Parse(language,code)
   local t = languages[language] : match ( code ) 
-  if t == nil then t = MinimalSyntax : match ( code ) end
-  for _ , s in ipairs(t) do tex.tprint(s) end 
+  local left_stack = {}
+  local right_stack = {}
+  for _ , one_item in ipairs(t) 
+  do 
+     if one_item[1] == "EOL"
+     then 
+          for _ , s in ipairs(right_stack) 
+            do tex.sprint( s ) 
+            end
+          for _ , s in ipairs(one_item[2]) 
+            do tex.tprint(s)
+            end
+          for _ , s in ipairs(left_stack) 
+            do tex.sprint( s ) 
+            end
+     else 
+          if one_item[1] == "Open"
+          then
+               tex.sprint( one_item[2] ) 
+               table.insert(left_stack,one_item[2])
+               table.insert(right_stack,one_item[3])
+          else 
+               if one_item[1] == "Close"
+               then
+                    tex.sprint( right_stack[#right_stack] ) 
+                    left_stack[#left_stack] = nil
+                    right_stack[#right_stack] = nil
+               else 
+                    tex.tprint(one_item)  
+               end 
+          end 
+     end 
+  end 
 end
 %    \end{macrocode}
 %
@@ -4843,6 +5057,11 @@
 % \vspace{1cm}
 % \section{History}
 %
+% % \subsection*{Changes between versions 1.4 and 1.5}
+%
+% New key |numbers-sep|.
+%
+%
 % \subsection*{Changes between versions 1.3 and 1.4}
 %
 % New key |identifiers| in |\PitonOptions|.

Modified: trunk/Master/texmf-dist/tex/lualatex/piton/piton.sty
===================================================================
--- trunk/Master/texmf-dist/tex/lualatex/piton/piton.sty	2023-04-04 20:12:31 UTC (rev 66762)
+++ trunk/Master/texmf-dist/tex/lualatex/piton/piton.sty	2023-04-04 20:12:45 UTC (rev 66763)
@@ -18,14 +18,10 @@
 %% and version 1.3 or later is part of all distributions of
 %% LaTeX version 2005/12/01 or later.
 %% 
-\def\myfileversion{1.4}
-\def\myfiledate{2023/02/14}
+\def\myfileversion{1.5}
+\def\myfiledate{2023/04/04}
 
-\bigskip
 
-%%
-
-
 \NeedsTeXFormat{LaTeX2e}
 \RequirePackage{l3keys2e}
 \ProvidesExplPackage
@@ -34,7 +30,13 @@
   {\myfileversion}
   {Highlight Python codes with LPEG on LuaLaTeX}
 \msg_new:nnn { piton } { LuaLaTeX~mandatory }
-  { The~package~'piton'~must~be~used~with~LuaLaTeX.\\ It~won't~be~loaded. }
+  {
+    LuaLaTeX~is~mandatory.\\
+    The~package~'piton'~requires~the~engine~LuaLaTeX.\\
+    \str_if_eq:VnT \c_sys_jobname_str { output }
+      { If~you~use~Overleaf,~you~can~switch~to~LuaLaTeX~in~the~"Menu". \\}
+    If~you~go~on,~the~package~'piton'~won't~be~loaded.
+  }
 \sys_if_engine_luatex:F { \msg_critical:nn { piton } { LuaLaTeX~mandatory } }
 \RequirePackage { luatexbase }
 \bool_new:N \c__piton_footnotehyper_bool
@@ -155,6 +157,8 @@
 \bool_new:N \l__piton_slim_bool
 \dim_new:N \l__piton_left_margin_dim
 \bool_new:N \l__piton_left_margin_auto_bool
+\dim_new:N \l__piton_numbers_sep_dim
+\dim_set:Nn \l__piton_numbers_sep_dim { 0.7 em }
 \tl_new:N \l__piton_tab_tl
 \cs_new_protected:Npn \__piton_set_tab_tl:n #1
   {
@@ -191,6 +195,10 @@
      }
      { \msg_error:nn { piton } { label~with~lines~numbers } }
   }
+\cs_new_protected:Npn \__piton_open_brace:
+  { \directlua { piton.open_brace() } }
+\cs_new_protected:Npn \__piton_close_brace:
+  { \directlua { piton.close_brace() } }
 \tl_new:N \g__piton_begin_line_hook_tl
 \cs_new_protected:Npn \__piton_prompt:
   {
@@ -197,6 +205,50 @@
     \tl_gset:Nn \g__piton_begin_line_hook_tl
       { \clist_set:NV \l__piton_bg_color_clist \l__piton_prompt_bg_color_tl }
   }
+\clist_new:N \g__piton_current_style_clist
+\clist_set:Nn \g__piton_current_style_clist { __end }
+\cs_new_protected:Npn \__piton_close_current_styles:
+  {
+    \int_set:Nn \l_tmpa_int { \clist_count:N \g__piton_current_style_clist - 1  }
+    \exp_args:NV \__piton_close_n_styles:n \l_tmpa_int
+  }
+\cs_new_protected:Npn \__piton_close_n_styles:n #1
+  {
+    \int_compare:nNnT { #1 } > 0
+      {
+        \__piton_close_brace:
+        \__piton_close_brace:
+        \__piton_close_n_styles:n { #1 - 1 }
+      }
+  }
+\cs_new_protected:Npn \__piton_open_current_styles:
+  { \exp_last_unbraced:NV \__piton_open_styles:w \g__piton_current_style_clist , }
+\cs_new_protected:Npn \__piton_open_styles:w #1 ,
+  {
+    \tl_if_eq:nnF { #1 } { __end }
+      { \__piton_open_brace: #1 \__piton_open_brace: \__piton_open_styles:w }
+  }
+\cs_new_protected:Npn \__piton_pop_style:
+  {
+    \clist_greverse:N \g__piton_current_style_clist
+    \clist_gpop:NN \g__piton_current_style_clist \l_tmpa_tl
+    \clist_gpop:NN \g__piton_current_style_clist \l_tmpa_tl
+    \clist_gpush:Nn \g__piton_current_style_clist { __end }
+    \clist_greverse:N \g__piton_current_style_clist
+  }
+\cs_new_protected:Npn \__piton_push_style:n #1
+  {
+    \clist_greverse:N \g__piton_current_style_clist
+    \clist_gpop:NN \g__piton_current_style_clist \l_tmpa_tl
+    \clist_gpush:Nn \g__piton_current_style_clist { #1 }
+    \clist_gpush:Nn \g__piton_current_style_clist { __end }
+    \clist_greverse:N \g__piton_current_style_clist
+  }
+\cs_new_protected:Npn \__piton_push_and_exec:n #1
+  {
+    \__piton_push_style:n { #1 }
+    \__piton_open_brace: #1 \__piton_open_brace:
+  }
 \cs_new_protected:Npn \__piton_replace_spaces:n #1
   {
     \tl_set:Nn \l_tmpa_tl { #1 }
@@ -249,7 +301,13 @@
               \__piton_print_number:
           }
         \clist_if_empty:NF \l__piton_bg_color_clist
-          { \skip_horizontal:n { 0.5 em } }
+          {
+            \dim_compare:nNnT \l__piton_left_margin_dim = \c_zero_dim
+               {
+                 \bool_if:NF \l__piton_left_margin_auto_bool
+                   { \skip_horizontal:n { 0.5 em } }
+               }
+          }
         \coffin_typeset:Nnnnn \l_tmpa_coffin T l \c_zero_dim \c_zero_dim
       }
     \dim_compare:nNnT { \box_wd:N \l_tmpa_box } > \g__piton_width_dim
@@ -378,6 +436,8 @@
         }
         { \dim_set:Nn \l__piton_left_margin_dim { #1 } } ,
     left-margin      .value_required:n  = true ,
+    numbers-sep      .dim_set:N         = \l__piton_numbers_sep_dim ,
+    numbers-sep      .value_required:n  = true ,
     tab-size         .code:n            = \__piton_set_tab_tl:n { #1 } ,
     tab-size         .value_required:n  = true ,
     show-spaces      .bool_set:N        = \l__piton_show_spaces_bool ,
@@ -409,7 +469,7 @@
     \hbox_overlap_left:n
       {
         { \color { gray } \footnotesize \int_to_arabic:n \g__piton_visual_line_int }
-        \skip_horizontal:n { 0.4 em }
+        \skip_horizontal:N \l__piton_numbers_sep_dim
       }
   }
 \cs_new_protected:Npn \__piton_write_aux:
@@ -606,7 +666,8 @@
                     { \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 }
+          \dim_set:Nn \l__piton_left_margin_dim
+            { \box_wd:N \l_tmpa_box + \l__piton_numbers_sep_dim + 0.1 em }
         }
       \ttfamily
       \bool_if:NT \c__piton_footnote_bool { \begin { savenotes } }
@@ -662,7 +723,7 @@
                       }
                   }
                 \dim_set:Nn \l__piton_left_margin_dim
-                  { \box_wd:N \l_tmpa_box + 0.5 em }
+                  { \box_wd:N \l_tmpa_box + \l__piton_numbers_sep_dim + 0.1 em }
               }
             \ttfamily
             \bool_if:NT \c__piton_footnote_bool { \begin { savenotes } }
@@ -714,65 +775,67 @@
   { \normalfont \scantextokens { $#1$ } }
 \keys_define:nn { piton / Styles }
   {
-    String.Interpol  .tl_set:c = pitonStyle String.Interpol ,
-    String.Interpol  .value_required:n = true ,
-    FormattingType   .tl_set:c = pitonStyle FormattingType ,
-    FormattingType   .value_required:n = true ,
-    Dict.Value       .tl_set:c = pitonStyle Dict.Value ,
-    Dict.Value       .value_required:n = true ,
-    Name.Decorator   .tl_set:c = pitonStyle Name.Decorator ,
-    Name.Decorator   .value_required:n = true ,
-    Name.Function    .tl_set:c = pitonStyle Name.Function ,
-    Name.Function    .value_required:n = true ,
-    Keyword          .tl_set:c = pitonStyle Keyword ,
-    Keyword          .value_required:n = true ,
-    Keyword.Constant .tl_set:c = pitonStyle Keyword.Constant ,
-    Keyword.constant .value_required:n = true ,
-    String.Doc       .tl_set:c = pitonStyle String.Doc ,
-    String.Doc       .value_required:n = true ,
-    Interpol.Inside  .tl_set:c = pitonStyle Interpol.Inside ,
-    Interpol.Inside  .value_required:n = true ,
-    String.Long      .tl_set:c = pitonStyle String.Long ,
-    String.Long      .value_required:n = true ,
-    String.Short     .tl_set:c = pitonStyle String.Short ,
-    String.Short     .value_required:n = true ,
-    String           .meta:n = { String.Long = #1 , String.Short = #1 } ,
-    Comment.Math     .tl_set:c = pitonStyle Comment.Math ,
-    Comment.Math     .default:n = \__piton_math_scantokens:n ,
-    Comment.Math     .initial:n = ,
-    Comment          .tl_set:c = pitonStyle Comment ,
-    Comment          .value_required:n = true ,
-    InitialValues    .tl_set:c = pitonStyle InitialValues ,
-    InitialValues    .value_required:n = true ,
-    Number           .tl_set:c = pitonStyle Number ,
-    Number           .value_required:n = true ,
-    Name.Namespace   .tl_set:c = pitonStyle Name.Namespace ,
-    Name.Namespace   .value_required:n = true ,
-    Name.Class       .tl_set:c = pitonStyle Name.Class ,
-    Name.Class       .value_required:n = true ,
-    Name.Builtin     .tl_set:c = pitonStyle Name.Builtin ,
-    Name.Builtin     .value_required:n = true ,
-    TypeParameter    .tl_set:c = pitonStyle TypeParameter ,
-    TypeParameter    .value_required:n = true ,
-    Name.Type        .tl_set:c = pitonStyle Name.Type ,
-    Name.Type        .value_required:n = true ,
-    Operator         .tl_set:c = pitonStyle Operator ,
-    Operator         .value_required:n = true ,
-    Operator.Word    .tl_set:c = pitonStyle Operator.Word ,
-    Operator.Word    .value_required:n = true ,
-    Exception        .tl_set:c = pitonStyle Exception ,
-    Exception        .value_required:n = true ,
-    Comment.LaTeX    .tl_set:c = pitonStyle Comment.LaTeX ,
-    Comment.LaTeX    .value_required:n = true ,
-    Identifier       .tl_set:c = pitonStyle Identifier ,
-    Comment.LaTeX    .value_required:n = true ,
-    ParseAgain.noCR  .tl_set:c = pitonStyle ParseAgain.noCR ,
-    ParseAgain.noCR  .value_required:n = true ,
-    ParseAgain       .tl_set:c = pitonStyle ParseAgain ,
-    ParseAgain       .value_required:n = true ,
-    Prompt           .tl_set:c = pitonStyle Prompt ,
-    Prompt           .value_required:n = true ,
-    unknown          .code:n =
+    String.Interpol   .tl_set:c = pitonStyle String.Interpol ,
+    String.Interpol   .value_required:n = true ,
+    FormattingType    .tl_set:c = pitonStyle FormattingType ,
+    FormattingType    .value_required:n = true ,
+    Dict.Value        .tl_set:c = pitonStyle Dict.Value ,
+    Dict.Value        .value_required:n = true ,
+    Name.Decorator    .tl_set:c = pitonStyle Name.Decorator ,
+    Name.Decorator    .value_required:n = true ,
+    Name.Function     .tl_set:c = pitonStyle Name.Function ,
+    Name.Function     .value_required:n = true ,
+    Name.UserFunction .tl_set:c = pitonStyle Name.UserFunction ,
+    Name.UserFunction .value_required:n = true ,
+    Keyword           .tl_set:c = pitonStyle Keyword ,
+    Keyword           .value_required:n = true ,
+    Keyword.Constant  .tl_set:c = pitonStyle Keyword.Constant ,
+    Keyword.constant  .value_required:n = true ,
+    String.Doc        .tl_set:c = pitonStyle String.Doc ,
+    String.Doc        .value_required:n = true ,
+    Interpol.Inside   .tl_set:c = pitonStyle Interpol.Inside ,
+    Interpol.Inside   .value_required:n = true ,
+    String.Long       .tl_set:c = pitonStyle String.Long ,
+    String.Long       .value_required:n = true ,
+    String.Short      .tl_set:c = pitonStyle String.Short ,
+    String.Short      .value_required:n = true ,
+    String            .meta:n = { String.Long = #1 , String.Short = #1 } ,
+    Comment.Math      .tl_set:c = pitonStyle Comment.Math ,
+    Comment.Math      .default:n = \__piton_math_scantokens:n ,
+    Comment.Math      .initial:n = ,
+    Comment           .tl_set:c = pitonStyle Comment ,
+    Comment           .value_required:n = true ,
+    InitialValues     .tl_set:c = pitonStyle InitialValues ,
+    InitialValues     .value_required:n = true ,
+    Number            .tl_set:c = pitonStyle Number ,
+    Number            .value_required:n = true ,
+    Name.Namespace    .tl_set:c = pitonStyle Name.Namespace ,
+    Name.Namespace    .value_required:n = true ,
+    Name.Class        .tl_set:c = pitonStyle Name.Class ,
+    Name.Class        .value_required:n = true ,
+    Name.Builtin      .tl_set:c = pitonStyle Name.Builtin ,
+    Name.Builtin      .value_required:n = true ,
+    TypeParameter     .tl_set:c = pitonStyle TypeParameter ,
+    TypeParameter     .value_required:n = true ,
+    Name.Type         .tl_set:c = pitonStyle Name.Type ,
+    Name.Type         .value_required:n = true ,
+    Operator          .tl_set:c = pitonStyle Operator ,
+    Operator          .value_required:n = true ,
+    Operator.Word     .tl_set:c = pitonStyle Operator.Word ,
+    Operator.Word     .value_required:n = true ,
+    Exception         .tl_set:c = pitonStyle Exception ,
+    Exception         .value_required:n = true ,
+    Comment.LaTeX     .tl_set:c = pitonStyle Comment.LaTeX ,
+    Comment.LaTeX     .value_required:n = true ,
+    Identifier        .tl_set:c = pitonStyle Identifier ,
+    Comment.LaTeX     .value_required:n = true ,
+    ParseAgain.noCR   .tl_set:c = pitonStyle ParseAgain.noCR ,
+    ParseAgain.noCR   .value_required:n = true ,
+    ParseAgain        .tl_set:c = pitonStyle ParseAgain ,
+    ParseAgain        .value_required:n = true ,
+    Prompt            .tl_set:c = pitonStyle Prompt ,
+    Prompt            .value_required:n = true ,
+    unknown           .code:n =
       \msg_error:nn { piton } { Unknown~key~for~SetPitonStyle }
   }
 \msg_new:nnn { piton } { Unknown~key~for~SetPitonStyle }
@@ -805,35 +868,36 @@
   }
 \SetPitonStyle
   {
-    Comment          = \color[HTML]{0099FF} \itshape ,
-    Exception        = \color[HTML]{CC0000} ,
-    Keyword          = \color[HTML]{006699} \bfseries ,
-    Keyword.Constant = \color[HTML]{006699} \bfseries ,
-    Name.Builtin     = \color[HTML]{336666} ,
-    Name.Decorator   = \color[HTML]{9999FF},
-    Name.Class       = \color[HTML]{00AA88} \bfseries ,
-    Name.Function    = \color[HTML]{CC00FF} ,
-    Name.Namespace   = \color[HTML]{00CCFF} ,
-    Number           = \color[HTML]{FF6600} ,
-    Operator         = \color[HTML]{555555} ,
-    Operator.Word    = \bfseries ,
-    String           = \color[HTML]{CC3300} ,
-    String.Doc       = \color[HTML]{CC3300} \itshape ,
-    String.Interpol  = \color[HTML]{AA0000} ,
-    Comment.LaTeX    = \normalfont \color[rgb]{.468,.532,.6} ,
-    Name.Type        = \color[HTML]{336666} ,
-    InitialValues    = \__piton_piton:n ,
-    Dict.Value       = \__piton_piton:n ,
-    Interpol.Inside  = \color{black}\__piton_piton:n ,
-    TypeParameter    = \color[HTML]{008800} \itshape ,
-    Identifier       = \__piton_identifier:n ,
-    Prompt           = ,
-    ParseAgain.noCR  = \__piton_piton_no_cr:n ,
-    ParseAgain       = \__piton_piton:n ,
+    Comment            = \color[HTML]{0099FF} \itshape ,
+    Exception          = \color[HTML]{CC0000} ,
+    Keyword            = \color[HTML]{006699} \bfseries ,
+    Keyword.Constant   = \color[HTML]{006699} \bfseries ,
+    Name.Builtin       = \color[HTML]{336666} ,
+    Name.Decorator     = \color[HTML]{9999FF},
+    Name.Class         = \color[HTML]{00AA88} \bfseries ,
+    Name.Function      = \color[HTML]{CC00FF} ,
+    Name.Namespace     = \color[HTML]{00CCFF} ,
+    Number             = \color[HTML]{FF6600} ,
+    Operator           = \color[HTML]{555555} ,
+    Operator.Word      = \bfseries ,
+    String             = \color[HTML]{CC3300} ,
+    String.Doc         = \color[HTML]{CC3300} \itshape ,
+    String.Interpol    = \color[HTML]{AA0000} ,
+    Comment.LaTeX      = \normalfont \color[rgb]{.468,.532,.6} ,
+    Name.Type          = \color[HTML]{336666} ,
+    InitialValues      = \__piton_piton:n ,
+    Dict.Value         = \__piton_piton:n ,
+    Interpol.Inside    = \color{black}\__piton_piton:n ,
+    TypeParameter      = \color[HTML]{008800} \itshape ,
+    Identifier         = \__piton_identifier:n ,
+    Name.UserFunction  = ,
+    Prompt             = ,
+    ParseAgain.noCR    = \__piton_piton_no_cr:n ,
+    ParseAgain         = \__piton_piton:n ,
   }
 \bool_if:NT \c__piton_math_comments_bool { \SetPitonStyle { Comment.Math } }
 \cs_new_protected:Npn \__piton_identifier:n #1
-  { \cs_if_exist_use:c { PitonIdentifier #1 } { #1 } }
+  { \cs_if_exist_use:c { PitonIdentifier _ \l__piton_language_str _ #1 } { #1 } }
 \keys_define:nn { PitonOptions }
   { identifiers .code:n = \__piton_set_identifiers:n { #1 } }
 \keys_define:nn { Piton / identifiers }
@@ -849,10 +913,28 @@
     \clist_map_inline:Nn \l__piton_identifiers_names_tl
       {
         \tl_set_eq:cN
-          { PitonIdentifier ##1 }
+          { PitonIdentifier _ \l__piton_language_str _ ##1 }
           \l__piton_style_tl
       }
   }
+\cs_new_protected:cpn { pitonStyle Name.Function.Internal } #1
+  {
+    { \PitonStyle { Name.Function } { #1 } }
+    \cs_gset_protected:cpn { PitonIdentifier _ \l__piton_language_str _ #1 }
+      { \PitonStyle{ Name.UserFunction } }
+    \seq_if_exist:cF { g__piton_functions _ \l__piton_language_str _ seq }
+      { \seq_new:c { g__piton_functions _ \l__piton_language_str _ seq } }
+    \seq_gput_right:cn { g__piton_functions _ \l__piton_language_str _ seq } { #1 }
+  }
+\NewDocumentCommand \PitonClearUserFunctions { ! O { \l__piton_language_str }  }
+  {
+    \seq_if_exist:cT { g__piton_functions _ #1 _ seq }
+      {
+        \seq_map_inline:cn { g__piton_functions _ #1 _ seq }
+          { \cs_undefine:c { PitonIdentifier _ #1 _ ##1} }
+        \seq_gclear:c { g__piton_functions _ #1 _ seq }
+      }
+  }
 \AddToHook { env / piton / begin }
    { \msg_fatal:nn { piton } { No~environment~piton } }
 
@@ -920,6 +1002,8 @@
     in~Beamer.\\
     If~you~go~on,~that~argument~will~be~ignored.
   }
+\msg_new:nnn { Piton } { Python~error }
+  { A~Python~error~has~been~detected. }
 \ExplSyntaxOff
 \RequirePackage{luacode}
 \begin{luacode*}
@@ -926,6 +1010,12 @@
 piton = piton or { }
 if piton.comment_latex == nil then piton.comment_latex = ">" end
 piton.comment_latex = "#" .. piton.comment_latex
+function piton.open_brace ()
+   tex.sprint("{")
+end
+function piton.close_brace ()
+   tex.sprint("}")
+end
 local P, S, V, C, Ct, Cc = lpeg.P, lpeg.S, lpeg.V, lpeg.C, lpeg.Ct, lpeg.Cc
 local Cf, Cs , Cg , Cmt , Cb = lpeg.Cf, lpeg.Cs, lpeg.Cg , lpeg.Cmt , lpeg.Cb
 local R = lpeg.R
@@ -938,17 +1028,18 @@
 local function Lc(string)
   return Cc ( { luatexbase.catcodetables.expl , string } )
 end
-local function K(pattern, style)
-  if style
-  then
+local function K(style, pattern)
   return
      Lc ( "{\\PitonStyle{" .. style .. "}{" )
      * Q ( pattern )
      * Lc ( "}}" )
-  else
-  return Q ( pattern )
-  end
 end
+local function WithStyle(style,pattern)
+  return
+       Ct ( Cc "Open" * Cc ( "{\\PitonStyle{" .. style .. "}{" ) * Cc "}}" )
+     * pattern
+     * Ct ( Cc "Close" )
+end
 local Escape =
   P(piton_begin_escape)
   * L ( ( 1 - P(piton_end_escape) ) ^ 1 )
@@ -963,51 +1054,50 @@
 
 local alphanum = letter + digit
 local identifier = letter * alphanum ^ 0
-local Identifier = K ( identifier , 'Identifier' )
+local Identifier = K ( 'Identifier' , identifier)
 local Number =
-  K (
+  K ( 'Number' ,
       ( digit^1 * P "." * digit^0 + digit^0 * P "." * digit^1 + digit^1 )
       * ( S "eE" * S "+-" ^ -1 * digit^1 ) ^ -1
-      + digit^1 ,
-      'Number'
+      + digit^1
     )
 local Word
 if piton_begin_escape ~= ''
-then Word = K ( ( ( 1 - space - P(piton_begin_escape) - P(piton_end_escape) )
+then Word = Q ( ( ( 1 - space - P(piton_begin_escape) - P(piton_end_escape) )
                    - S "'\"\r[()]" - digit ) ^ 1 )
-else Word = K ( ( ( 1 - space ) - S "'\"\r[()]" - digit ) ^ 1 )
+else Word = Q ( ( ( 1 - space ) - S "'\"\r[()]" - digit ) ^ 1 )
 end
-local Space = ( K " " ) ^ 1
+local Space = ( Q " " ) ^ 1
 
-local SkipSpace = ( K " " ) ^ 0
+local SkipSpace = ( Q " " ) ^ 0
 
-local Punct = K ( S ".,:;!" )
+local Punct = Q ( S ".,:;!" )
 
 local Tab = P "\t" * Lc ( '\\l__piton_tab_tl' )
-local SpaceIndentation = Lc ( '\\__piton_an_indentation_space:' ) * ( K " " )
-local Delim = K ( S "[()]" )
+local SpaceIndentation = Lc ( '\\__piton_an_indentation_space:' ) * ( Q " " )
+local Delim = Q ( S "[()]" )
 local VisualSpace = space * Lc "\\l__piton_space_tl"
 local Operator =
-  K ( P "!=" + P "<>" + P "==" + P "<<" + P ">>" + P "<=" + P ">=" + P ":="
+  K ( 'Operator' ,
+      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')
+  K ( 'Operator.Word' ,P "in" + P "is" + P "and" + P "or" + P "not" )
 
 local Keyword =
-  K ( P "as" + P "assert" + P "break" + P "case" + P "class" + P "continue"
+  K ( 'Keyword' ,
+      P "as" + P "assert" + P "break" + P "case" + P "class" + P "continue"
       + P "def" + P "del" + P "elif" + P "else" + P "except" + P "exec"
       + P "finally" + P "for" + P "from" + P "global" + P "if" + P "import"
       + P "lambda" + P "non local" + P "pass" + P "return" + P "try"
-      + P "while" + P "with" + P "yield" + P "yield from" ,
-  'Keyword' )
-  + K ( P "True" + P "False" + P "None" , 'Keyword.Constant' )
+      + P "while" + P "with" + P "yield" + P "yield from" )
+  + K ( 'Keyword.Constant' ,P "True" + P "False" + P "None" )
 
 local Builtin =
-  K ( P "__import__" + P "abs" + P "all" + P "any" + P "bin" + P "bool"
+  K ( 'Name.Builtin' ,
+      P "__import__" + P "abs" + P "all" + P "any" + P "bin" + P "bool"
     + P "bytearray" + P "bytes" + P "chr" + P "classmethod" + P "compile"
     + P "complex" + P "delattr" + P "dict" + P "dir" + P "divmod"
     + P "enumerate" + P "eval" + P "filter" + P "float" + P "format"
@@ -1018,11 +1108,11 @@
     + P "ord" + P "pow" + P "print" + P "property" + P "range" + P "repr"
     + P "reversed" + P "round" + P "set" + P "setattr" + P "slice" + P "sorted"
     + P "staticmethod" + P "str" + P "sum" + P "super" + P "tuple" + P "type"
-    + P "vars" + P "zip" ,
-  'Name.Builtin' )
+    + P "vars" + P "zip" )
 
 local Exception =
-  K ( P "ArithmeticError" + P "AssertionError" + P "AttributeError"
+  K ( 'Exception' ,
+      P "ArithmeticError" + P "AssertionError" + P "AttributeError"
    + P "BaseException" + P "BufferError" + P "BytesWarning" + P "DeprecationWarning"
    + P "EOFError" + P "EnvironmentError" + P "Exception" + P "FloatingPointError"
    + P "FutureWarning" + P "GeneratorExit" + P "IOError" + P "ImportError"
@@ -1041,92 +1131,84 @@
    + P "ConnectionResetError" + P "FileExistsError" + P "FileNotFoundError"
    + P "InterruptedError" + P "IsADirectoryError" + P "NotADirectoryError"
    + P "PermissionError" + P "ProcessLookupError" + P "TimeoutError"
-   + P "StopAsyncIteration" + P "ModuleNotFoundError" + P "RecursionError" ,
-  'Exception' )
+   + P "StopAsyncIteration" + P "ModuleNotFoundError" + P "RecursionError" )
 
-local RaiseException = K ( P "raise" , 'Keyword' ) * SkipSpace * Exception * K ( P "(" )
+local RaiseException = K ( 'Keyword' , P "raise" ) * SkipSpace * Exception * Q ( P "(" )
 
-local Decorator = K ( P "@" * letter^1 , 'Name.Decorator' )
+local Decorator = K ( 'Name.Decorator' , P "@" * letter^1  )
 local DefClass =
-  K ( P "class" , 'Keyword' ) * Space * K ( identifier , 'Name.Class' )
+  K ( 'Keyword' , P "class" ) * Space * K ( 'Name.Class' , identifier )
 local ImportAs =
-  K ( P "import" , 'Keyword' )
+  K ( 'Keyword' , P "import" )
    * Space
-   * K ( identifier * ( P "." * identifier ) ^ 0 ,
-         'Name.Namespace'
-       )
+   * K ( 'Name.Namespace' ,
+         identifier * ( P "." * identifier ) ^ 0 )
    * (
-       ( Space * K ( P "as" , 'Keyword' ) * Space
-          * K ( identifier , 'Name.Namespace' ) )
+       ( Space * K ( 'Keyword' , P "as" ) * Space
+          * K ( 'Name.Namespace' , identifier ) )
        +
-       ( SkipSpace * K ( P "," ) * SkipSpace
-          * K ( identifier , 'Name.Namespace' ) ) ^ 0
+       ( SkipSpace * Q ( P "," ) * SkipSpace
+          * K ( 'Name.Namespace' , identifier ) ) ^ 0
      )
 local FromImport =
-  K ( P "from" , 'Keyword' )
-    * Space * K ( identifier , 'Name.Namespace' )
-    * Space * K ( P "import" , 'Keyword' )
+  K ( 'Keyword' , P "from" )
+    * Space * K ( 'Name.Namespace' , identifier )
+    * Space * K ( 'Keyword' , P "import" )
 local PercentInterpol =
-  K ( P "%"
+  K ( 'String.Interpol' ,
+      P "%"
       * ( P "(" * alphanum ^ 1 * P ")" ) ^ -1
       * ( S "-#0 +" ) ^ 0
       * ( digit ^ 1 + P "*" ) ^ -1
       * ( P "." * ( digit ^ 1 + P "*" ) ) ^ -1
       * ( S "HlL" ) ^ -1
-      * S "sdfFeExXorgiGauc%" ,
-      'String.Interpol'
+      * S "sdfFeExXorgiGauc%"
     )
 local SingleShortString =
-  Lc ( "{\\PitonStyle{String.Short}{" )
-   * (
-         K ( P "f'" + P "F'" )
+  WithStyle ( 'String.Short' ,
+         Q ( P "f'" + P "F'" )
          * (
-             K ( P "{" , 'String.Interpol')
-              * K ( ( 1 - S "}':" ) ^ 0 , 'Interpol.Inside' )
-              * K ( P ":" * (1 - S "}:'") ^ 0 ) ^ -1
-              * K ( P "}" , 'String.Interpol' )
+             K ( 'String.Interpol' , P "{" )
+              * K ( 'Interpol.Inside' , ( 1 - S "}':" ) ^ 0  )
+              * Q ( P ":" * (1 - S "}:'") ^ 0 ) ^ -1
+              * K ( 'String.Interpol' , P "}" )
              +
              VisualSpace
              +
-             K ( ( P "\\'" + P "{{" + P "}}" + 1 - S " {}'" ) ^ 1 )
+             Q ( ( P "\\'" + P "{{" + P "}}" + 1 - S " {}'" ) ^ 1 )
            ) ^ 0
-         * K ( P "'" )
+         * Q ( P "'" )
        +
-         K ( P "'" + P "r'" + P "R'" )
-         * ( K ( ( P "\\'" + 1 - S " '\r%" ) ^ 1 )
+         Q ( P "'" + P "r'" + P "R'" )
+         * ( Q ( ( P "\\'" + 1 - S " '\r%" ) ^ 1 )
              + VisualSpace
              + PercentInterpol
-             + K ( P "%" )
+             + Q ( P "%" )
            ) ^ 0
-         * K ( P "'" )
-     )
-   * Lc ( "}}" )
+         * Q ( P "'" ) )
 
 local DoubleShortString =
-  Lc ( "{\\PitonStyle{String.Short}{" )
-   * (
-         K ( P "f\"" + P "F\"" )
+  WithStyle ( 'String.Short' ,
+         Q ( P "f\"" + P "F\"" )
          * (
-             K ( P "{" , 'String.Interpol' )
-               * K ( ( 1 - S "}\":" ) ^ 0 , 'Interpol.Inside' )
-               * ( K ( P ":" , 'String.Interpol' ) * K ( (1 - S "}:\"") ^ 0 ) ) ^ -1
-               * K ( P "}" , 'String.Interpol' )
+             K ( 'String.Interpol' , P "{" )
+               * Q ( ( 1 - S "}\":" ) ^ 0 , 'Interpol.Inside' )
+               * ( K ( 'String.Interpol' , P ":" ) * Q ( (1 - S "}:\"") ^ 0 ) ) ^ -1
+               * K ( 'String.Interpol' , P "}" )
              +
              VisualSpace
              +
-             K ( ( P "\\\"" + P "{{" + P "}}" + 1 - S " {}\"" ) ^ 1 )
+             Q ( ( P "\\\"" + P "{{" + P "}}" + 1 - S " {}\"" ) ^ 1 )
             ) ^ 0
-         * K ( P "\"" )
+         * Q ( P "\"" )
        +
-         K ( P "\"" + P "r\"" + P "R\"" )
-         * ( K ( ( P "\\\"" + 1 - S " \"\r%" ) ^ 1 )
+         Q ( P "\"" + P "r\"" + P "R\"" )
+         * ( Q ( ( P "\\\"" + 1 - S " \"\r%" ) ^ 1 )
              + VisualSpace
              + PercentInterpol
-             + K ( P "%" )
+             + Q ( P "%" )
            ) ^ 0
-         * K ( P "\"" )
-     )
-   * Lc ( "}}" )
+         * Q ( P "\"" ) )
 
 local ShortString = SingleShortString + DoubleShortString
 local BalancedBraces =
@@ -1147,31 +1229,59 @@
   P "uncoverenv" + P "onlyenv" + P "visibleenv" + P "invisibleenv"
   + P "alertenv" + P "actionenv"
 
+UserCommands =
+       Ct ( Cc "Open" * C ( "\\emph{" ) * Cc "}" )
+     * ( C ( BalancedBraces ) / (function (s) return MainLoopPython:match(s) end ) )
+     * P "}" * Ct ( Cc "Close" )
+function OneBeamerEnvironment(name)
+  return
+      Ct ( Cc "Open"
+            * C (
+                  P ( "\\begin{" .. name ..   "}" )
+                  * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1
+                )
+           * Cc ( "\\end{" .. name ..  "}" )
+          )
+     * (
+         C ( ( 1 - P ( "\\end{" .. name .. "}" ) ) ^ 0 )
+         / (function (s) return MainLoopPython:match(s) end )
+       )
+     * P ( "\\end{" .. name ..  "}" ) * Ct ( Cc "Close" )
+end
 if piton_beamer
 then
   Beamer =
       L  ( P "\\pause" * ( P "[" * (1 - P "]") ^ 0 * P "]" ) ^ -1 )
     +
-      (   P "\\uncover"   * Lc ( '\\__piton_beamer_command:n{uncover}' )
-        + P "\\only"      * Lc ( '\\__piton_beamer_command:n{only}' )
-        + P "\\alert"     * Lc ( '\\__piton_beamer_command:n{alert}' )
-        + P "\\visible"   * Lc ( '\\__piton_beamer_command:n{visible}' )
-        + P "\\invisible" * Lc ( '\\__piton_beamer_command:n{invisible}' )
-        + P "\\action"    * Lc ( '\\__piton_beamer_command:n{action}' )
-      )
-      *
-      L ( ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1 * P "{" )
-      * K ( BalancedBraces , 'ParseAgain.noCR' )
-      * L ( P "}" )
+      Ct ( Cc "Open"
+            * C (
+                  (
+                    P "\\uncover" + P "\\only" + P "\\alert" + P "\\visible"
+                    + P "\\invisible" + P "\\action"
+                  )
+                  * ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1
+                  * P "{"
+                )
+            * Cc "}"
+         )
+       * ( C ( BalancedBraces ) / (function (s) return MainLoopPython:match(s) end ) )
+       * P "}" * Ct ( Cc "Close" )
     +
+      OneBeamerEnvironment "uncoverenv"
+    + OneBeamerEnvironment "onlyenv"
+    + OneBeamerEnvironment "visibleenv"
+    + OneBeamerEnvironment "invisibleenv"
+    + OneBeamerEnvironment "alertenv"
+    + OneBeamerEnvironment "actionenv"
+    +
       L (
           ( P "\\alt" )
           * P "<" * (1 - P ">") ^ 0 * P ">"
           * P "{"
         )
-      * K ( BalancedBraces , 'ParseAgain.noCR' )
+      * K ( 'ParseAgain.noCR' , BalancedBraces )
       * L ( P "}{" )
-      * K ( BalancedBraces , 'ParseAgain.noCR' )
+      * K ( 'ParseAgain.noCR' , BalancedBraces )
       * L ( P "}" )
     +
       L (
@@ -1179,11 +1289,11 @@
           * P "<" * (1 - P ">") ^ 0 * P ">"
           * P "{"
         )
-      * K ( BalancedBraces , 'ParseAgain.noCR' )
+      * K ( 'ParseAgain.noCR' , BalancedBraces )
       * L ( P "}{" )
-      * K ( BalancedBraces , 'ParseAgain.noCR' )
+      * K ( 'ParseAgain.noCR' , BalancedBraces )
       * L ( P "}{" )
-      * K ( BalancedBraces , 'ParseAgain.noCR' )
+      * K ( 'ParseAgain.noCR' , BalancedBraces )
       * L ( P "}" )
   BeamerBeginEnvironments =
       ( space ^ 0 *
@@ -1201,115 +1311,97 @@
       ) ^ 0
 end
 local PromptHastyDetection = ( # ( P ">>>" + P "..." ) * Lc ( '\\__piton_prompt:' ) ) ^ -1
-local Prompt = K ( ( ( P ">>>" + P "..." ) * P " " ^ -1 ) ^ -1 , 'Prompt' )
-local EOL
-if piton_beamer
-then
-EOL =
+local Prompt = K ( 'Prompt' , ( ( P ">>>" + P "..." ) * P " " ^ -1 ) ^ -1  )
+local EOL =
   P "\r"
   *
   (
     ( space^0 * -1 )
     +
-    Lc ( '\\__piton_end_line:' )
-    * BeamerEndEnvironments
-    * BeamerBeginEnvironments
-    * PromptHastyDetection
-    * Lc ( '\\__piton_newline: \\__piton_begin_line:' )
-    * Prompt
+    Ct (
+         Cc "EOL"
+         *
+         Ct (
+              Lc "\\__piton_end_line:"
+              * BeamerEndEnvironments
+              * BeamerBeginEnvironments
+              * PromptHastyDetection
+              * Lc "\\__piton_newline: \\__piton_begin_line:"
+              * Prompt
+            )
+       )
   )
   *
   SpaceIndentation ^ 0
-else
-EOL =
-  P "\r"
-  *
-  (
-    ( space ^ 0 * -1 )
-    +
-    Lc ( '\\__piton_end_line:' )
-    * PromptHastyDetection
-    * Lc ( '\\__piton_newline: \\__piton_begin_line:' )
-    * Prompt
-  )
-  *
-  SpaceIndentation ^ 0
-end
-function EOL_for_style ( s )
-   return Lc "}}" * EOL * Lc ( "{\\PitonStyle{" .. s .. "}{" )
-end
 local SingleLongString =
-  Lc "{\\PitonStyle{String.Long}{"
-   * (
-         K ( S "fF" * P "'''" )
+  WithStyle ( 'String.Long' ,
+     ( Q ( S "fF" * P "'''" )
          * (
-             K ( P "{" , 'String.Interpol' )
-               * K ( ( 1 - S "}:\r" - P "'''" ) ^ 0 , 'Interpol.Inside' )
-               * K ( P ":" * (1 - S "}:\r" - P "'''" ) ^ 0 ) ^ -1
-               * K ( P "}" , 'String.Interpol' )
+             K ( 'String.Interpol' , P "{"  )
+               * K ( 'Interpol.Inside' , ( 1 - S "}:\r" - P "'''" ) ^ 0  )
+               * Q ( P ":" * (1 - S "}:\r" - P "'''" ) ^ 0 ) ^ -1
+               * K ( 'String.Interpol' , P "}"  )
              +
-             K ( ( 1 - P "'''" - S "{}'\r" ) ^ 1 )
+             Q ( ( 1 - P "'''" - S "{}'\r" ) ^ 1 )
              +
-             EOL_for_style 'String.Long'
+             EOL
            ) ^ 0
        +
-         K ( ( S "rR" ) ^ -1  * P "'''" )
+         Q ( ( S "rR" ) ^ -1  * P "'''" )
          * (
-             K ( ( 1 - P "'''" - S "\r%" ) ^ 1 )
+             Q ( ( 1 - P "'''" - S "\r%" ) ^ 1 )
              +
              PercentInterpol
              +
              P "%"
              +
-             EOL_for_style 'String.Long'
+             EOL
            ) ^ 0
       )
-   * K ( P "'''" )
-   * Lc "}}"
+      * Q ( P "'''" ) )
 
 local DoubleLongString =
-  Lc "{\\PitonStyle{String.Long}{"
-   * (
-         K ( S "fF" * P "\"\"\"" )
-         * (
-             K ( P "{" , 'String.Interpol' )
-               * K ( ( 1 - S "}:\r" - P "\"\"\"" ) ^ 0 , 'Interpol.Inside' )
-               * K ( P ":" * (1 - S "}:\r" - P "\"\"\"" ) ^ 0 ) ^ -1
-               * K ( P "}" , 'String.Interpol' )
-             +
-             K ( ( 1 - P "\"\"\"" - S "{}\"\r" ) ^ 1 )
-             +
-             EOL_for_style 'String.Long'
-           ) ^ 0
-       +
-         K ( ( S "rR" ) ^ -1  * P "\"\"\"" )
-         * (
-             K ( ( 1 - P "\"\"\"" - S "%\r" ) ^ 1 )
-             +
-             PercentInterpol
-             +
-             P "%"
-             +
-             EOL_for_style 'String.Long'
-           ) ^ 0
-      )
-   * K ( P "\"\"\"" )
-   * Lc "}}"
+  WithStyle ( 'String.Long' ,
+     (
+        Q ( S "fF" * P "\"\"\"" )
+        * (
+            K ( 'String.Interpol', P "{"  )
+              * K ( 'Interpol.Inside' , ( 1 - S "}:\r" - P "\"\"\"" ) ^ 0 )
+              * Q ( P ":" * (1 - S "}:\r" - P "\"\"\"" ) ^ 0 ) ^ -1
+              * K ( 'String.Interpol' , P "}"  )
+            +
+            Q ( ( 1 - P "\"\"\"" - S "{}\"\r" ) ^ 1 )
+            +
+            EOL
+          ) ^ 0
+      +
+        Q ( ( S "rR" ) ^ -1  * P "\"\"\"" )
+        * (
+            Q ( ( 1 - P "\"\"\"" - S "%\r" ) ^ 1 )
+            +
+            PercentInterpol
+            +
+            P "%"
+            +
+            EOL
+          ) ^ 0
+     )
+     * Q ( P "\"\"\"" )
+  )
 local LongString = SingleLongString + DoubleLongString
 local StringDoc =
-    K ( P "\"\"\"" , 'String.Doc' )
-      * ( K ( (1 - P "\"\"\"" - P "\r" ) ^ 0 , 'String.Doc' ) * EOL
+    K ( 'String.Doc' , P "\"\"\"" )
+      * ( K ( 'String.Doc' , (1 - P "\"\"\"" - P "\r" ) ^ 0  ) * EOL
           * Tab ^ 0
         ) ^ 0
-      * K ( ( 1 - P "\"\"\"" - P "\r" ) ^ 0 * P "\"\"\"" , 'String.Doc' )
+      * K ( 'String.Doc' , ( 1 - P "\"\"\"" - P "\r" ) ^ 0 * P "\"\"\"" )
 local CommentMath =
-  P "$" * K ( ( 1 - S "$\r" ) ^ 1 , 'Comment.Math' ) * P "$"
+  P "$" * K ( 'Comment.Math' , ( 1 - S "$\r" ) ^ 1  ) * P "$"
 
 local Comment =
-  Lc ( "{\\PitonStyle{Comment}{" )
-  * K ( P "#" )
-  * ( CommentMath + K ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0
-  * Lc ( "}}" )
+  WithStyle ( 'Comment' ,
+     Q ( P "#" )
+     * ( CommentMath + Q ( ( 1 - S "$\r" ) ^ 1 ) ) ^ 0 )
   * ( EOL + -1 )
 local CommentLaTeX =
   P(piton.comment_latex)
@@ -1316,7 +1408,7 @@
   * Lc "{\\PitonStyle{Comment.LaTeX}{\\ignorespaces"
   * L ( ( 1 - P "\r" ) ^ 0 )
   * Lc "}}"
-  * ( EOL + -1 )
+  * ( EOL + -1 )  -- you could put EOL instead of EOL
 local Expression =
   P { "E" ,
        E = ( 1 - S "{}()[]\r," ) ^ 0
@@ -1337,20 +1429,20 @@
 local Param =
   SkipSpace * Identifier * SkipSpace
    * (
-         K ( P "=" * Expression , 'InitialValues' )
-       + K ( P ":" ) * SkipSpace * K ( letter^1 , 'Name.Type' )
+         K ( 'InitialValues' , P "=" * Expression )
+       + Q ( P ":" ) * SkipSpace * K ( 'Name.Type' , letter^1  )
      ) ^ -1
-local Params = ( Param * ( K "," * Param ) ^ 0 ) ^ -1
+local Params = ( Param * ( Q "," * Param ) ^ 0 ) ^ -1
 local DefFunction =
-  K ( P "def" , 'Keyword' )
+  K ( 'Keyword' , P "def" )
   * Space
-  * K ( identifier , 'Name.Function' )
+  * K ( 'Name.Function.Internal' , identifier )
   * SkipSpace
-  * K ( P "(" ) * Params * K ( P ")" )
+  * Q ( P "(" ) * Params * Q ( P ")" )
   * SkipSpace
-  * ( K ( P "->" ) * SkipSpace * K ( identifier , 'Name.Type' ) ) ^ -1
-  * K ( ( 1 - S ":\r" )^0 , 'ParseAgain' )
-  * K ( P ":" )
+  * ( Q ( P "->" ) * SkipSpace * K ( 'Name.Type' , identifier  ) ) ^ -1
+  * K ( 'ParseAgain' , ( 1 - S ":\r" )^0  )
+  * Q ( P ":" )
   * ( SkipSpace
       * ( EOL + CommentLaTeX + Comment ) -- in all cases, that contains an EOL
       * Tab ^ 0
@@ -1358,16 +1450,16 @@
       * StringDoc ^ 0 -- there may be additionnal docstrings
     ) ^ -1
 local ItemDict =
-  ShortString * SkipSpace * K ( P ":" ) * K ( Expression , 'Dict.Value' )
+  ShortString * SkipSpace * Q ( P ":" ) * K ( 'Dict.Value' , Expression  )
 
 local ItemOfSet = SkipSpace * ( ItemDict + ShortString ) * SkipSpace
 
 local Set =
-  K ( P "{" )
-  * ItemOfSet * ( K ( P "," ) * ItemOfSet )  ^ 0
-  * K ( P "}" )
-local ExceptionInConsole = Exception *  K ( ( 1 - P "\r" ) ^ 0 ) * EOL
-MainLoop =
+  Q ( P "{" )
+  * ItemOfSet * ( Q ( P "," ) * ItemOfSet )  ^ 0
+  * Q ( P "}" )
+local ExceptionInConsole = Exception *  Q ( ( 1 - P "\r" ) ^ 0 ) * EOL
+MainLoopPython =
   (  ( space^1 * -1 )
      + EOL
      + Space
@@ -1375,6 +1467,7 @@
      + Escape
      + CommentLaTeX
      + Beamer
+     + UserCommands
      + LongString
      + Comment
      + ExceptionInConsole
@@ -1387,10 +1480,10 @@
      + RaiseException
      + DefFunction
      + DefClass
-     + Keyword * ( Space + Punct + Delim + EOL + -1 )
+     + Keyword * ( Space + Punct + Delim + EOL+ -1 )
      + Decorator
-     + OperatorWord * ( Space + Punct + Delim + EOL + -1 )
-     + Builtin * ( Space + Punct + Delim + EOL + -1 )
+     + OperatorWord * ( Space + Punct + Delim + EOL+ -1 )
+     + Builtin * ( Space + Punct + Delim + EOL+ -1 )
      + Identifier
      + Number
      + Word
@@ -1402,37 +1495,38 @@
        ( ( space - P "\r" ) ^0 * P "\r" ) ^ -1
        * BeamerBeginEnvironments
        * PromptHastyDetection
-       * Lc ( '\\__piton_begin_line:' )
+       * Lc '\\__piton_begin_line:'
        * Prompt
        * SpaceIndentation ^ 0
-       * MainLoop
+       * MainLoopPython
        * -1
-       * Lc ( '\\__piton_end_line:' )
+       * Lc '\\__piton_end_line:'
      )
 local languages = { }
 languages['python'] = python
-local Punct = K ( S ",:;!" )
+local Delim = Q ( P "[|" + P "|]" + S "[()]" )
+local Punct = Q ( S ",:;!" )
 local identifier =
   ( R "az" + R "AZ" + P "_") * ( R "az" + R "AZ" + S "_'" + digit ) ^ 0
 
-local Identifier = K ( identifier )
+local Identifier = K ( 'Identifier' , identifier )
 
 local Operator =
-  K ( P "!=" + P "<>" + P "==" + P "<<" + P ">>" + P "<=" + P ">=" + P ":="
+  K ( 'Operator' ,
+      P "!=" + P "<>" + P "==" + P "<<" + P ">>" + P "<=" + P ">=" + P ":="
       + P "||" + P "&&" + P "//" + P "**" + P ";;" + P "::" + P "->"
       + P "+." + P "-." + P "*." + P "/."
       + S "-~+/*%=<>&@|"
-      ,
-      'Operator'
     )
 
 local OperatorWord =
-  K ( P "and" + P "asr" + P "land" + P "lor" + P "lsl" + P "lxor"
-      + P "mod" + P "or" ,
-      'Operator.Word')
+  K ( 'Operator.Word' ,
+      P "and" + P "asr" + P "land" + P "lor" + P "lsl" + P "lxor"
+      + P "mod" + P "or" )
 
 local Keyword =
-  K ( P "as" + P "assert" + P "begin" + P "class" + P "constraint" + P "done"
+  K ( 'Keyword' ,
+      P "as" + P "assert" + P "begin" + P "class" + P "constraint" + P "done"
   + P "do" + P "downto" + P "else" + P "end" + P "exception" + P "external"
   + P "false" + P "for" + P "function" + P "fun" + P "functor" + P "if"
   + P "in" + P "include" + P "inherit" + P "initializer" + P "lazy" + P "let"
@@ -1439,12 +1533,12 @@
   + P "match" + P "method" + P "module" + P "mutable" + P "new" + P "object"
   + P "of" + P "open" + P "private" + P "raise" + P "rec" + P "sig"
   + P "struct" + P "then" + P "to" + P "true" + P "try" + P "type"
-  + P "value" + P "val" + P "virtual" + P "when" + P "while" + P "with" ,
-  'Keyword' )
-  + K ( P "true" + P "false" , 'Keyword.Constant' )
+  + P "value" + P "val" + P "virtual" + P "when" + P "while" + P "with" )
+  + K ( 'Keyword.Constant' , P "true" + P "false" )
 
 local Builtin =
-  K (   P "not" + P "incr" + P "decr" + P "fst" + P "snd"
+  K ( 'Name.Builtin' ,
+        P "not" + P "incr" + P "decr" + P "fst" + P "snd"
       + P "String.length"
       + P "List.tl" + P "List.hd" + P "List.mem" + P "List.exists"
       + P "List.for_all" + P "List.filter" + P "List.length" + P "List.map"
@@ -1456,16 +1550,15 @@
       + P "Stack.create" + P "Stack.is_empty" + P "Stack.push" + P "Stack.pop"
       + P "Hashtbl.create" + P "Hashtbl.add" + P "Hashtbl.remove"
       + P "Hashtbl.mem" + P "Hashtbl.find" + P "Hashtbl.find_opt"
-      + P "Hashtbl.iter"
-      , 'Name.Builtin' )
+      + P "Hashtbl.iter" )
 local Exception =
-  K ( P "Division_by_zero" + P "End_of_File" + P "Failure"
+  K (   'Exception' ,
+       P "Division_by_zero" + P "End_of_File" + P "Failure"
      + P "Invalid_argument" + P "Match_failure" + P "Not_found"
      + P "Out_of_memory" + P "Stack_overflow" + P "Sys_blocked_io"
-     + P "Sys_error" + P "Undefined_recursive_module" ,
-  'Exception' )
+     + P "Sys_error" + P "Undefined_recursive_module" )
 local Char =
-  K ( P "'" * ( ( 1 - P "'" ) ^ 0 + P "\\'" ) * P "'" , 'String.Short' )
+  K ( 'String.Short' , P "'" * ( ( 1 - P "'" ) ^ 0 + P "\\'" ) * P "'" )
 local BalancedBraces =
   P { "E" ,
        E =
@@ -1491,7 +1584,7 @@
       )
       *
       L ( ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1 * P "{" )
-      * K ( BalancedBraces , 'ParseAgain.noCR' )
+      * K ( 'ParseAgain.noCR' , BalancedBraces )
       * L ( P "}" )
     +
       L (
@@ -1499,9 +1592,9 @@
           * P "<" * (1 - P ">") ^ 0 * P ">"
           * P "{"
         )
-      * K ( BalancedBraces , 'ParseAgain.noCR' )
+      * K ( 'ParseAgain.noCR' , BalancedBraces )
       * L ( P "}{" )
-      * K ( BalancedBraces , 'ParseAgain.noCR' )
+      * K ( 'ParseAgain.noCR' , BalancedBraces )
       * L ( P "}" )
     +
       L (
@@ -1509,11 +1602,11 @@
           * P "<" * (1 - P ">") ^ 0 * P ">"
           * P "{"
         )
-      * K ( BalancedBraces , 'ParseAgain.noCR' )
+      * K ( 'ParseAgain.noCR' , BalancedBraces )
       * L ( P "}{" )
-      * K ( BalancedBraces , 'ParseAgain.noCR' )
+      * K ( 'ParseAgain.noCR' , BalancedBraces )
       * L ( P "}{" )
-      * K ( BalancedBraces , 'ParseAgain.noCR' )
+      * K ( 'ParseAgain.noCR' , BalancedBraces )
       * L ( P "}" )
   BeamerBeginEnvironments =
       ( space ^ 0 *
@@ -1530,50 +1623,38 @@
         * P "\r"
       ) ^ 0
 end
-local EOL
-if piton_beamer
-then
-EOL =
+local EOL =
   P "\r"
   *
   (
     ( space^0 * -1 )
     +
-    Lc ( '\\__piton_end_line:' )
-    * BeamerEndEnvironments
-    * BeamerBeginEnvironments
-    * Lc ( '\\__piton_newline: \\__piton_begin_line:' )
+    Ct (
+         Cc "EOL"
+         *
+         Ct (
+              Lc "\\__piton_end_line:"
+              * BeamerEndEnvironments
+              * BeamerBeginEnvironments
+              * PromptHastyDetection
+              * Lc "\\__piton_newline: \\__piton_begin_line:"
+              * Prompt
+            )
+       )
   )
   *
   SpaceIndentation ^ 0
-else
-EOL =
-  P "\r"
-  *
-  (
-    ( space ^ 0 * -1 )
-    +
-    Lc ( '\\__piton_end_line:' )
-    * Lc ( '\\__piton_newline: \\__piton_begin_line:' )
-  )
-  *
-  SpaceIndentation ^ 0
-end
-function EOL_for_style ( s )
-   return Lc "}}" * EOL * Lc ( "{\\PitonStyle{" .. s .. "}{" )
-end
-local String =
-  Lc "{\\PitonStyle{String.Long}{"
-   * K ( P "\"" )
-   * (
-       VisualSpace
-       +
-       K ( ( 1 - S " \"\r" ) ^ 1 )
-       +
-       EOL_for_style 'String.Long'
-     ) ^ 0
-   * K ( P "\"" )
-   * Lc "}}"
+local string =
+       Q ( P "\"" )
+     * (
+         VisualSpace
+         +
+         Q ( ( 1 - S " \"\r" ) ^ 1 )
+         +
+         EOL
+       ) ^ 0
+     * Q ( P "\"" )
+local String = WithStyle ( 'String.Long' , string )
 local ext = ( R "az" + P "_" ) ^ 0
 local open = "{" * Cg(ext, 'init') * "|"
 local close = "|" * C(ext) * "}"
@@ -1581,42 +1662,39 @@
   Cmt ( close * Cb('init'),
         function (s, i, a, b) return a==b end )
 local QuotedStringBis =
-   Lc "{\\PitonStyle{String.Long}{"
-   *
-     (
+  WithStyle ( 'String.Long' ,
+      (
         VisualSpace
         +
-        K ( ( 1 - S " \r" ) ^ 1 )
+        Q ( ( 1 - S " \r" ) ^ 1 )
         +
-        EOL_for_style 'String.Long'
-     ) ^ 0
-   * Lc "}}"
+        EOL
+      ) ^ 0  )
+
 local QuotedString =
    C ( open * ( 1 - closeeq ) ^ 0  * close ) /
   ( function (s) return QuotedStringBis : match(s) end )
 local Comment =
-  Lc "{\\PitonStyle{Comment}{"
-  *
-  P {
-      "A" ,
-      A = K "(*"
-          * ( V "A"
-              + K ( ( 1 - P "(*" - P "*)" - S "\r$" ) ^ 1 ) -- $
-              + P "$" * K ( ( 1 - S "$\r" ) ^ 1 , 'Comment.Math' ) * P "$" -- $
-              + EOL_for_style 'Comment'
-            ) ^ 0
-          * K "*)"
-    }
-  *
-  Lc "}}"
+  WithStyle ( 'Comment' ,
+     P {
+         "A" ,
+         A = Q "(*"
+             * ( V "A"
+                 + Q ( ( 1 - P "(*" - P "*)" - S "\r$\"" ) ^ 1 ) -- $
+                 + string
+                 + P "$" * K ( 'Comment.Math' , ( 1 - S "$\r" ) ^ 1 ) * P "$" -- $
+                 + EOL
+               ) ^ 0
+             * Q "*)"
+       }   )
 local DefFunction =
-  ( K ( P "let rec" + P "let" + P "and" , 'Keyword' ) )
+  K ( 'Keyword' , P "let rec" + P "let" + P "and" )
   * Space
-  * K ( identifier , 'Name.Function' )
+  * K ( 'Name.Function.Internal' , identifier )
   * Space
-  * # ( 1 - P "=" )
-local TypeParameter = K ( P "'" * alpha * # ( 1 - P "'") , 'TypeParameter' )
-MainLoop =
+  * # ( P "=" * space * P "function" + ( 1 - P "=" ) )
+local TypeParameter = K ( 'TypeParameter' , P "'" * alpha * # ( 1 - P "'" ) )
+MainLoopOCaml =
   (  ( space^1 * -1 )
      + EOL
      + Space
@@ -1648,16 +1726,46 @@
        * BeamerBeginEnvironments
        * Lc ( '\\__piton_begin_line:' )
        * SpaceIndentation ^ 0
-       * MainLoop
+       * MainLoopOCaml
        * -1
        * Lc ( '\\__piton_end_line:' )
      )
 languages['ocaml'] = ocaml
-local MinimalSyntax = Ct ( ( (1 - P "\r" ) ^ 1 + EOL ) ^ 0 )
 function piton.Parse(language,code)
   local t = languages[language] : match ( code )
-  if t == nil then t = MinimalSyntax : match ( code ) end
-  for _ , s in ipairs(t) do tex.tprint(s) end
+  local left_stack = {}
+  local right_stack = {}
+  for _ , one_item in ipairs(t)
+  do
+     if one_item[1] == "EOL"
+     then
+          for _ , s in ipairs(right_stack)
+            do tex.sprint( s )
+            end
+          for _ , s in ipairs(one_item[2])
+            do tex.tprint(s)
+            end
+          for _ , s in ipairs(left_stack)
+            do tex.sprint( s )
+            end
+     else
+          if one_item[1] == "Open"
+          then
+               tex.sprint( one_item[2] )
+               table.insert(left_stack,one_item[2])
+               table.insert(right_stack,one_item[3])
+          else
+               if one_item[1] == "Close"
+               then
+                    tex.sprint( right_stack[#right_stack] )
+                    left_stack[#left_stack] = nil
+                    right_stack[#right_stack] = nil
+               else
+                    tex.tprint(one_item)
+               end
+          end
+     end
+  end
 end
 function piton.ParseFile(language,name,first_line,last_line)
   s = ''



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