diff options
author | Norbert Preining <norbert@preining.info> | 2023-02-15 03:01:49 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2023-02-15 03:01:49 +0000 |
commit | a7d99429152acee049db679dc26a92e01faf4992 (patch) | |
tree | c12bd699dd6c10d6efea6d36cfb71493181d98f5 /macros/luatex/latex/piton/piton.dtx | |
parent | dc5dafdd7c01d469b556bc5bef745a6f1c84a5cb (diff) |
CTAN sync 202302150301
Diffstat (limited to 'macros/luatex/latex/piton/piton.dtx')
-rw-r--r-- | macros/luatex/latex/piton/piton.dtx | 1202 |
1 files changed, 938 insertions, 264 deletions
diff --git a/macros/luatex/latex/piton/piton.dtx b/macros/luatex/latex/piton/piton.dtx index 3bf162d38e..126c19dc10 100644 --- a/macros/luatex/latex/piton/piton.dtx +++ b/macros/luatex/latex/piton/piton.dtx @@ -15,8 +15,8 @@ % % \fi % \iffalse -\def\myfileversion{1.3} -\def\myfiledate{2023/01/29} +\def\myfileversion{1.4} +\def\myfiledate{2023/02/14} % % %<*batchfile> @@ -26,7 +26,7 @@ \usedir{tex/latex/cascade} \preamble -Copyright (C) 2023 by F. Pantigny +Copyright (C) 2022-2023 by F. Pantigny ----------------------------------- This file may be distributed and/or modified under the @@ -51,7 +51,7 @@ version 2005/12/01 or later. \geometry{left=2.8cm,right=2.8cm,top=2.5cm,bottom=2.5cm,papersize={21cm,29.7cm}} \usepackage{fontspec} \usepackage[dvipsnames]{xcolor} -\usepackage{caption,tabularx,tcolorbox} +\usepackage{caption,tabularx,tcolorbox,luacolor,lua-ul} \def\emphase{\bgroup\color{RoyalPurple}\let\next=} \fvset{commandchars=\~\#\@,formatcom=\color{gray}} \captionsetup{labelfont = bf} @@ -206,8 +206,8 @@ version 2005/12/01 or later. % balanced. % % \smallskip -% \colorbox{yellow!50}{\textbf{New 1.3}}\enskip The command |\|␣ inserts a -% space. It may be used in order to insert several consecutive spaces. +% The command |\|␣ inserts a space. It may be used in order to insert several +% consecutive spaces. % % \smallskip % The other characters (including |#|, |^|, |_|, |&|, |$| and |@|) @@ -318,28 +318,35 @@ version 2005/12/01 or later. % environments |{Piton}| and the listings produced by |\PitonInputFile| (that % background has a width of |\linewidth|). % -% \colorbox{yellow!50}{\textbf{New 1.3}}\enskip The key |background-color| -% accepts a color defined «on the fly». For example, it's possible to write -% |background-color = [cmyk]{0.1,0.05,0,0}|. -% -% \item \colorbox{yellow!50}{\textbf{New 1.3}}\enskip With the key -% \Definition{prompt-background-color}, \pkg{piton} adds a color background to -% the lines beginning with the prompt ``|>>>|'' (and its continuation ``|...|'') -% charactéristic of the Python consoles with \textsc{repl} (\emph{read-eval-print loop}). -% -% \item \colorbox{yellow!50}{\textbf{Modified 1.2}}\enskip When the key -% \Definition{show-spaces-in-strings} is activated, the spaces in the short strings (that -% is to say those delimited by |'| or |"|) are replaced by the character~␣ -% (U+2423 : \textsc{open box}). Of course, that character~U+2423 must be present -% in the monospaced font which is used.\footnote{The package \pkg{piton} simply -% uses the current monospaced font. The best way to change that font is to use -% the command \texttt{\textbackslash setmonofont} of -% \pkg{fontspec}.}\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). +% \smallskip +% \colorbox{yellow!50}{\textbf{New 1.4}}\enskip The key |background-color| +% supports also as value a \emph{list} of colors. In this case, the successive +% rows are colored by using the colors of the list in a cyclic way. +% +% \emph{Example} : |\PitonOptions{background-color = {gray!5,white}}| +% +% +% The key |background-color| accepts a color defined «on the fly». For example, +% it's possible to write |background-color = [cmyk]{0.1,0.05,0,0}|. +% +% \item With the key \Definition{prompt-background-color}, \pkg{piton} adds a +% color background to the lines beginning with the prompt ``|>>>|'' (and its +% continuation ``|...|'') characteristic of the Python consoles with +% \textsc{repl} (\emph{read-eval-print loop}). +% +% \item When the key \Definition{show-spaces-in-strings} is activated, the +% spaces in the short strings (that is to say those delimited by |'| or |"|) are +% replaced by the character~␣ (U+2423 : \textsc{open box}). Of course, that +% character~U+2423 must be present in the monospaced font which is +% used.\footnote{The package \pkg{piton} simply uses the current monospaced +% font. The best way to change that font is to use the command +% \texttt{\textbackslash setmonofont} of \pkg{fontspec}.}\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). % \end{itemize} % % \bigskip @@ -420,21 +427,22 @@ version 2005/12/01 or later. % % \bigskip % Here an example which changes the style used to highlight, in the definition -% of a Python function, the name of the function which is defined. +% of a Python function, the name of the function which is defined. That code +% uses the command |\highLight| of \pkg{lua-ul} (that package requires also the +% package \pkg{luacolor}). % % \begin{verbatim} -% \SetPitonStyle -% { Name.Function = \bfseries \setlength{\fboxsep}{1pt}\colorbox{yellow!50} } +% \SetPitonStyle{ Name.Function = \bfseries \highLight[red!50] } % \end{verbatim} % -% In that example, |\colorbox{yellow!50}| must be considered as the name of a +% In that example, |\highLight[red!50]| must be considered as the name of a % LaTeX command which takes in exactly one argument, since, usually, it is used -% with the syntax |\colorbox{yellow!50}{...}|. +% with |\highLight[red!50]{...}|. % % \medskip % \begingroup % \SetPitonStyle -% { Name.Function = \bfseries \setlength{\fboxsep}{1pt}\colorbox{yellow!50} } +% { Name.Function = \bfseries \highLight[red!50] } % With that setting, we will have : \piton{def cube(x) : return x * x * x } % \endgroup % @@ -444,7 +452,20 @@ version 2005/12/01 or later. % \pkg{manni} de Pygments.\footnote{See: % \url{https://pygments.org/styles/}. Remark that, by default, Pygments provides for its style \pkg{manni} a colored background whose color is the HTML color \texttt{\#F0F3F3}. It's possible to have the same color in \texttt{\{Pion\}} with the instruction \texttt{\textbackslash PitonOptions\{background-color = [HTML]\{F0F3F3\}\}}.} % +% \bigskip +% \colorbox{yellow!50}{\textbf{New 1.4}}\enskip The command |\PitonStyle| takes +% in as argument the name of a style and allows to retrieve the value (as a list +% of LaTeX instructions) of that style. +% +% \smallskip +% For example, it's possible to write |{\PitonStyle{Keyword}{function}}| and we +% will have the word {\PitonStyle{Keyword}{function}} formatted as a keyword. % +% \smallskip +% The syntax |{\PitonStyle{|\textsl{\texttt{style}}|}{...}}| is mandatory in +% order to be able to deal both with the semi-global commands and the commands +% with arguments which may be present in the definition of the style +% \texttt{\textsl{style}}. % % \begin{table}[b] % \centering @@ -521,7 +542,8 @@ version 2005/12/01 or later. % % \bigskip % If one wishes to format Python code in a box of \pkg{tcolorbox}, it's possible -% to define an environment |{Python}| with the following code: +% to define an environment |{Python}| with the following code (of course, the +% package \pkg{tcolorbox} must be loaded). % %\begin{verbatim} % \NewPitonEnvironment{Python}{} @@ -553,6 +575,129 @@ version 2005/12/01 or later. % % \section{Advanced features} % +% \subsection{Highlighting some identifiers} +% +% \colorbox{yellow!50}{\textbf{New 1.4}} It's possible to require a changement +% of formating for some identifiers with the key |identifiers| of +% |\PitonOptions|. +% +% \smallskip +% That key takes in as argument a value of the following format: +% +% \quad |{ names = |\textsl{\ttfamily names}|, style = |\textsl{\ttfamily +% instructions}| }| +% +% \begin{itemize} +% \item \textsl{\ttfamily names} is a (comma-separated) list of identifiers +% names; +% +% \item \textsl{\ttfamily instructions} is a list of LaTeX instructions of the +% same type that \pkg{piton} ``styles'' previously presented (cf~\ref{styles} +% p.~\pageref{styles}). +% \end{itemize} +% +% \emph{Caution}: Only the identifiers may be concerned by that key. The +% keywords and the built-in functions won't be affected, even if their names is +% in the list |\textsl{\ttfamily names}|. +% +% \begin{Verbatim} +% \PitonOptions +% { +% ~emphase#identifiers@ = +% { +% ~emphase#names@ = { l1 , l2 } , +% ~emphase#style@ = \color{red} +% } +% } +% +% \begin{Piton} +% def tri(l): +% """Segmentation sort""" +% if len(l) <= 1: +% return l +% else: +% a = l[0] +% l1 = [ x for x in l[1:] if x < a ] +% l2 = [ x for x in l[1:] if x >= a ] +% return tri(l1) + [a] + tri(l2) +% \end{Piton} +% \end{Verbatim} +% +% +% \bigskip +% +% \begingroup +% +% \PitonOptions +% { +% identifiers = +% { +% names = { l1 , l2 } , +% style = \color{red} +% } +% } +% +% \begin{Piton} +% def tri(l): +% """Segmentation sort""" +% if len(l) <= 1: +% return l +% else: +% a = l[0] +% l1 = [ x for x in l[1:] if x < a ] +% l2 = [ x for x in l[1:] if x >= a ] +% return tri(l1) + [a] + tri(l2) +% \end{Piton} +% +% \endgroup +% +% \bigskip +% By using the key |identifier|, it's possible to add other built-in functions +% (or other new keywords, etc.) that will be detected by \pkg{piton}. +% +% +% \begin{Verbatim} +% \PitonOptions +% { +% ~emphase#identifiers@ = +% { +% names = { cos, sin, tan, floor, ceil, trunc, pow, exp, ln, factorial } , +% style = \PitonStyle{Name.Builtin} +% } +% } +% +% \begin{Piton} +% from math import * +% cos(pi/2) +% factorial(5) +% ceil(-2.3) +% floor(5.4) +% \end{Piton} +% \end{Verbatim} +% +% \begingroup +% +% \PitonOptions +% { +% identifiers = +% { +% names = { cos, sin, tan, floor, ceil, trunc, pow, exp, ln, factorial } , +% style = \PitonStyle{Name.Builtin} +% } +% } +% +% \begin{Piton} +% from math import * +% cos(pi/2) +% factorial(5) +% ceil(-2.3) +% floor(5.4) +% \end{Piton} +% +% +% \endgroup +% +% % \subsection{Mechanisms to escape to LaTeX} % % The package \pkg{piton} provides several mechanisms for escaping to LaTeX: @@ -608,15 +753,14 @@ version 2005/12/01 or later. % \end{itemize} % % \bigskip -% \colorbox{yellow!50}{\textbf{New 1.3}}\enskip If the user has required line -% numbers in the left margin (with the key |line-numbers| or the key -% |all-line-numbers| of |\PitonOptions|), it's possible to refer to a number of -% line with the command |\label| used in a LaTeX comment.\footnote{That feature -% is implemented by using a redefinition of the standard command -% \texttt{\textbackslash label} in the environments \texttt{\{Piton\}}. -% Therefore, incompatibilities may occur with extensions which redefine -% (globally) that command \texttt{\textbackslash label} (for example: \pkg{varioref}, -% \pkg{refcheck}, \pkg{showlabels}, etc.)} +% If the user has required line numbers in the left margin (with the +% key |line-numbers| or the key |all-line-numbers| of |\PitonOptions|), it's +% possible to refer to a number of line with the command |\label| used in a +% LaTeX comment.\footnote{That feature is implemented by using a redefinition of +% the standard command \texttt{\textbackslash label} in the environments +% \texttt{\{Piton\}}. Therefore, incompatibilities may occur with extensions +% which redefine (globally) that command \texttt{\textbackslash label} (for +% example: \pkg{varioref}, \pkg{refcheck}, \pkg{showlabels}, etc.)} % % \subsubsection{The key ``math-comments''} % @@ -666,14 +810,15 @@ version 2005/12/01 or later. % \medskip % In the following code, which is a recursive programmation of the mathematical % factorial, we decide to highlight in yellow the instruction which contains the -% recursive call. +% recursive call. That example uses the command |\highLight| of \pkg{lua-ul} +% (that package requires itself the package \pkg{luacolor}). % \begin{Verbatim} % \begin{Piton} % def fact(n): % if n==0: % return 1 % else: -% ~emphase#$\colorbox{yellow!50}{$@return n*fact(n-1)~emphase#$}$@ +% ~emphase#$\highLight{$@return n*fact(n-1)~emphase#$}$@ % \end{Piton} % \end{Verbatim} % @@ -682,11 +827,50 @@ version 2005/12/01 or later. % if n==0: % return 1 % else: -% $\colorbox{yellow!50}{$return n*fact(n-1)$}$ +% $\highLight{$return n*fact(n-1)$}$ % \end{Piton} % % \bigskip +% In fact, in that case, it's probably easier to use the command |\@highLight| +% of \pkg{lua-ul}: that command sets a yellow background until the end of the +% current TeX group. Since the name of that command contains the character |@|, +% it's necessary to define a synonym without |@| in order to be able to use it +% directly in |{Piton}|. +% \begingroup +% \fvset{commandchars=\~\#\+,formatcom=\color{gray}} +% \begin{Verbatim} +% \makeatletter +% ~emphase#\let\Yellow\@highLight+ +% \makeatother +% \end{Verbatim} +% \endgroup +% +% \begin{Verbatim} +% \begin{Piton} +% def fact(n): +% if n==0: +% return 1 +% else: +% ~emphase#$\Yellow$@return n*fact(n-1) +% \end{Piton} +% \end{Verbatim} % +% \makeatletter +% \let\Yellow\@highLight +% \makeatother +% +% +% \begin{Piton} +% def fact(n): +% if n==0: +% return 1 +% else: +% $\Yellow$return n*fact(n-1) +% \end{Piton} +% +% +% +% \bigskip % \emph{Caution} : The escape to LaTeX allowed by the characters of % |escape-inside| is not active in the strings nor in the Python comments % (however, it's possible to have a whole Python comment composed in LaTeX by @@ -752,7 +936,8 @@ version 2005/12/01 or later. % 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). +% 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 @@ -786,13 +971,16 @@ version 2005/12/01 or later. % In the previous example, the braces in the Python strings |"{"| and |"}"| are % correctly interpreted (without any escape character). % +% +% +% % \bigskip % \subsubsection{Environments of Beamer allowed in \{Piton\} and \textbackslash PitonInputFile} % % When \pkg{piton} is used in the class \pkg{beamer}, the following environments % of Beamer are directly detected in the environments |{Piton}| (and in the -% listings processed by |\PitonInputFile|): |{uncoverenv}|, |{onlyenv}|, -% |{visibleenv}| and |{invisibleenv}|. +% listings processed by |\PitonInputFile|): |{actionenv}|, |{alertenv}|, +% |{invisibleenv}|, |{onlyenv}|, |{uncoverenv}| and |{visibleenv}|. % % However, there is a restriction: these environments must contain only \emph{whole % lines of Python code} in their body. @@ -817,6 +1005,45 @@ version 2005/12/01 or later. % \end{Verbatim} % % +% \vspace{1cm} +% \textbf{Remark concerning the command \textbackslash alert and the environment +% \{alertenv\} of Beamer}\par\nobreak +% +% \smallskip +% Beamer provides an easy way to change the color used by the environment +% |{alertenv}| (and by the command |\alert| which relies upon it) to highlight +% its argument. Here is an example: +% +% \begin{Verbatim} +% \setbeamercolor{~emphase#alerted text@}{fg=blue} +% \end{Verbatim} +% +% However, when used inside an environment |{Piton}|, such tuning will probably +% not be the best choice because \pkg{piton} will, by design, change (most of +% the time) the color the different elements of text. One may prefer an environment +% |{alertenv}| that will change the background color for the elements to be +% hightlighted. +% +% \smallskip +% Here is a code that will do that job and add a yellow background. That code +% uses the command |\@highLight| of \pkg{lua-ul} (that extension requires also +% the package \pkg{luacolor}). +% +% \begingroup +% \fvset{commandchars=\~\#\+,formatcom=\color{gray}} +% \begin{Verbatim} +% \setbeamercolor{alerted text}{bg=yellow!50} +% \makeatletter +% \AddToHook{env/Piton/begin} +% {\renewenvironment<>{alertenv}{\only~#1{~emphase#\@highLight+[alerted text.bg]}}{}} +% \makeatother +% \end{Verbatim} +% \endgroup +% +% That code redefines locally the environment |{alertenv}| within the +% environments |{Piton}| (we recall that the command |\alert| relies upon that +% environment |{alertenv}|). +% % \subsection{Page breaks and line breaks} % % \label{breakable} @@ -862,10 +1089,6 @@ version 2005/12/01 or later. % \item The key |break-lines| is a conjonction of the two previous keys. % \end{itemize} % -% \medskip -% \colorbox{yellow!50}{\textbf{Nouveau 1.2}}\enskip Depuis la version 1.2, la -% clé |break-lines| autorise les coupures de lignes dans |\piton{...}| et pas -% seulement dans |{Piton}|. % \bigskip % The package \pkg{piton} provides also several keys to control the appearance @@ -889,8 +1112,8 @@ version 2005/12/01 or later. % % % \bigskip -% The following code has been composed in a |{minipage}| of width 12~cm with the -% following tuning: +% The following code has been composed in a standard LaTeX |{minipage}| of width +% 12~cm with the following tuning: % % \begin{Verbatim} % \PitonOptions{break-lines,indent-broken-lines,background-color=gray!15} @@ -1255,6 +1478,8 @@ version 2005/12/01 or later. % \url{https://dejavu-fonts.github.io}} specified by the command |\setmonofont| of % \pkg{fontspec}. % +% That tuning uses the command |\highLight| of \pkg{lua-ul} (that package +% requires itself the package \pkg{luacolor}). % % \begin{Verbatim} % \setmonofont[Scale=0.85]{DejaVu Sans Mono} @@ -1267,7 +1492,7 @@ version 2005/12/01 or later. % Operator = , % Operator.Word = \bfseries , % Name.Builtin = , -% Name.Function = \bfseries \colorbox{gray!20} , +% Name.Function = \bfseries \highLight[gray!20] , % Comment = \color{gray} , % Comment.LaTeX = \normalfont \color{gray}, % Keyword = \bfseries , @@ -1293,7 +1518,7 @@ version 2005/12/01 or later. % Operator.Word = \bfseries , % Operator = , % Name.Builtin = , -% Name.Function = \bfseries \colorbox{gray!20} , +% Name.Function = \bfseries \highLight[gray!20] , % Comment = \color{gray} , % Comment.LaTeX = \normalfont \color{gray} , % Keyword = \bfseries , @@ -1336,12 +1561,13 @@ version 2005/12/01 or later. % % Here is, for example, an environment |{PitonExecute}| which formats a Python % listing (with \pkg{piton}) but display also the output of the execution of the -% code with Python. +% code with Python (for technical reasons, the |!| is mandatory in the signature +% of the environment). % % % \begin{Verbatim} % \ExplSyntaxOn -% \NewDocumentEnvironment { ~emphase#PitonExecute@ } { ! O { } } +% \NewDocumentEnvironment { ~emphase#PitonExecute@ } { ! O { } } % the ! is mandatory % { % \PyLTVerbatimEnv % \begin{pythonq} @@ -1373,7 +1599,7 @@ version 2005/12/01 or later. % \end{pythonq} % \directlua % { -% tex.print("\\PitonOptions{~#1}") +% tex.print("\\PitonOptions{#1}") % tex.print("\\begin{Piton}") % tex.print(pyluatex.get_last_code()) % tex.print("\\end{Piton}") @@ -1400,7 +1626,7 @@ version 2005/12/01 or later. % listing and to send back to LaTeX as output that code \emph{with interlaced LaTeX % instructions of formatting}. % -% In fact, all that job is done by a \textsc{lpeg} called |SyntaxPython|. That +% In fact, all that job is done by a \textsc{lpeg} called |python|. That % \textsc{lpeg}, when matched against the string of a Python listing, % returns as capture a Lua table containing data to send to LaTeX. % The only thing to do after will be to apply |tex.tprint| to each element of @@ -1418,7 +1644,7 @@ version 2005/12/01 or later. % return x%2 % \end{Piton} % -% The capture returned by the \pkg{lpeg} |SyntaxPython| against that code is the +% The capture returned by the \pkg{lpeg} |python| against that code is the % Lua table containing the following elements : % % \bigskip @@ -1714,6 +1940,14 @@ version 2005/12/01 or later. % \bigskip % \subsubsection{Parameters and technical definitions} % +% The following string will contain the name of the informatic language +% considered (the initial value is |python|). +% +% \begin{macrocode} +\str_new:N \l_@@_language_str +\str_set:Nn \l_@@_language_str { python } +% \end{macrocode} +% % We will compute (with Lua) the numbers of lines of the Python code and store % it in the following counter. % \begin{macrocode} @@ -1757,7 +1991,7 @@ version 2005/12/01 or later. % \medskip % The following string corresponds to the key |background-color| of |\PitonOptions|. % \begin{macrocode} -\str_new:N \l_@@_bg_color_tl +\clist_new:N \l_@@_bg_color_clist % \end{macrocode} % % \medskip @@ -1767,7 +2001,7 @@ version 2005/12/01 or later. % to require a background for these lines of code (and the other lines of code % will have the standard background color specified by |background-color|). % \begin{macrocode} -\str_new:N \l_@@_prompt_bg_color_tl +\tl_new:N \l_@@_prompt_bg_color_tl % \end{macrocode} % % \medskip @@ -1954,7 +2188,7 @@ version 2005/12/01 or later. \cs_new_protected:Npn \@@_prompt: { \tl_gset:Nn \g_@@_begin_line_hook_tl - { \tl_set:NV \l_@@_bg_color_tl \l_@@_prompt_bg_color_tl } + { \clist_set:NV \l_@@_bg_color_clist \l_@@_prompt_bg_color_tl } } % \end{macrocode} % @@ -2009,7 +2243,7 @@ version 2005/12/01 or later. \bool_if:NTF \l_@@_slim_bool { \hcoffin_set:Nn \l_tmpa_coffin } { - \str_if_empty:NTF \l_@@_bg_color_tl + \clist_if_empty:NTF \l_@@_bg_color_clist { \vcoffin_set:Nnn \l_tmpa_coffin { \dim_eval:n { \linewidth - \l_@@_left_margin_dim } } @@ -2035,7 +2269,7 @@ version 2005/12/01 or later. { \tl_if_empty:nF { #1 } } \@@_print_number: } - \tl_if_empty:NF \l_@@_bg_color_tl + \clist_if_empty:NF \l_@@_bg_color_clist { \skip_horizontal:n { 0.5 em } } \coffin_typeset:Nnnnn \l_tmpa_coffin T l \c_zero_dim \c_zero_dim } @@ -2047,14 +2281,14 @@ version 2005/12/01 or later. { \dim_gset:Nn \g_@@_width_dim { \box_wd:N \l_tmpa_box } } \box_set_dp:Nn \l_tmpa_box { \box_dp:N \l_tmpa_box + 1.25 pt } \box_set_ht:Nn \l_tmpa_box { \box_ht:N \l_tmpa_box + 1.25 pt } - \str_if_empty:NTF \l_@@_bg_color_tl + \clist_if_empty:NTF \l_@@_bg_color_clist { \box_use_drop:N \l_tmpa_box } { \vbox_top:n { \hbox:n { - \@@_color:V \l_@@_bg_color_tl + \@@_color:N \l_@@_bg_color_clist \vrule height \box_ht:N \l_tmpa_box depth \box_dp:N \l_tmpa_box width \l_@@_width_on_aux_dim @@ -2071,10 +2305,29 @@ version 2005/12/01 or later. % \end{macrocode} % % \bigskip -% The following command |\@@_color:n| will accept both |\@@_color:n { red!15 }| -% and |\@@_color:n { [rgb]{0.9,0.9,0}}|. +% The command |\@@_color:N| will take in as argument a reference to a +% comma-separated list of colors. A color will be picked by using the value of +% |\g_@@_line_int| (modulo the number of colors in the list). +% \begin{macrocode} +\cs_set_protected:Npn \@@_color:N #1 + { + \int_set:Nn \l_tmpa_int { \clist_count:N #1 } + \int_set:Nn \l_tmpb_int { \int_mod:nn \g_@@_line_int \l_tmpa_int + 1 } + \tl_set:Nx \l_tmpa_tl { \clist_item:Nn #1 \l_tmpb_int } + \tl_if_eq:NnTF \l_tmpa_tl { none } +% \end{macrocode} +% By setting |\l_@@_width_on_aux_dim| to zero, the colored rectangle will be +% drawn with zero width and, thus, it will be a mere strut (and we need that strut). +% \begin{macrocode} + { \dim_zero:N \l_@@_width_on_aux_dim } + { \exp_args:NV \@@_color_i:n \l_tmpa_tl } + } +% \end{macrocode} +% +% The following command |\@@_color:n| will accept both the instruction +% |\@@_color:n { red!15 }| and the instruction |\@@_color:n { [rgb]{0.9,0.9,0} }|. % \begin{macrocode} -\cs_set_protected:Npn \@@_color:n #1 +\cs_set_protected:Npn \@@_color_i:n #1 { \tl_if_head_eq_meaning:nNTF { #1 } [ { @@ -2121,7 +2374,7 @@ version 2005/12/01 or later. \l_@@_continuation_symbol_tl } \skip_horizontal:n { 0.3 em } - \tl_if_empty:NF \l_@@_bg_color_tl + \clist_if_empty:NF \l_@@_bg_color_clist { \skip_horizontal:n { 0.5 em } } } \bool_if:NT \l_@@_indent_broken_lines_bool @@ -2161,6 +2414,8 @@ version 2005/12/01 or later. % \begin{macrocode} \keys_define:nn { PitonOptions } { + language .str_set:N = \l_@@_language_str , + language .value_required:n = true , gobble .int_set:N = \l_@@_gobble_int , gobble .value_required:n = true , auto-gobble .code:n = \int_set:Nn \l_@@_gobble_int { -1 } , @@ -2179,10 +2434,10 @@ version 2005/12/01 or later. resume .value_forbidden:n = true , splittable .int_set:N = \l_@@_splittable_int , splittable .default:n = 1 , - background-color .str_set:N = \l_@@_bg_color_tl , + background-color .clist_set:N = \l_@@_bg_color_clist , background-color .value_required:n = true , - prompt-background-color .str_set:N = \l_@@_prompt_bg_color_tl , - prompt-background-color .value_required:n = true , + prompt-background-color .tl_set:N = \l_@@_prompt_bg_color_tl , + prompt-background-color .value_required:n = true , slim .bool_set:N = \l_@@_slim_bool , slim .default:n = true , left-margin .code:n = @@ -2279,7 +2534,7 @@ version 2005/12/01 or later. { \bool_if:NT \l_@@_slim_bool { - \tl_if_empty:NF \l_@@_bg_color_tl + \clist_if_empty:NF \l_@@_bg_color_clist { \tl_gput_right:Nx \g_@@_aux_tl { @@ -2319,7 +2574,11 @@ version 2005/12/01 or later. \cs_set_protected:Npn \@@_begin_line: { } \cs_set_protected:Npn \@@_end_line: { } \tl_set:Nx \l_tmpa_tl - { \lua_now:n { piton.ParseBis(token.scan_string()) } { #1 } } + { + \lua_now:e + { piton.ParseBis('\l_@@_language_str',token.scan_string()) } + { #1 } + } \bool_if:NTF \l_@@_show_spaces_bool { \regex_replace_all:nnN { \x20 } { ␣ } \l_tmpa_tl } % U+2423 % \end{macrocode} @@ -2345,7 +2604,11 @@ version 2005/12/01 or later. \cs_set_protected:Npn \@@_begin_line: { } \cs_set_protected:Npn \@@_end_line: { } \tl_set:Nx \l_tmpa_tl - { \lua_now:n { piton.Parse(token.scan_string()) } { #1 } } + { + \lua_now:e + { piton.Parse('\l_@@_language_str',token.scan_string()) } + { #1 } + } \bool_if:NT \l_@@_show_spaces_bool { \regex_replace_all:nnN { \x20 } { ␣ } \l_tmpa_tl } % U+2423 \l_tmpa_tl @@ -2373,11 +2636,19 @@ version 2005/12/01 or later. \l_@@_break_lines_in_Piton_bool { \tl_set:Nx \l_tmpa_tl - { \lua_now:n { piton.ParseTer(token.scan_string()) } { #1 } } + { + \lua_now:e + { piton.ParseTer('\l_@@_language_str',token.scan_string()) } + { #1 } + } } { \tl_set:Nx \l_tmpa_tl - { \lua_now:n { piton.Parse(token.scan_string()) } { #1 } } + { + \lua_now:e + { piton.Parse('\l_@@_language_str',token.scan_string()) } + { #1 } + } } \bool_if:NT \l_@@_show_spaces_bool { \regex_replace_all:nnN { \x20 } { ␣ } \l_tmpa_tl } % U+2423 @@ -2402,11 +2673,19 @@ version 2005/12/01 or later. \l_@@_break_lines_in_Piton_bool { \tl_set:Nx \l_tmpa_tl - { \lua_now:n { piton.ParseTer(token.scan_string()) } { #1 } } + { + \lua_now:e + { piton.ParseTer('\l_@@_language_str',token.scan_string()) } + { #1 } + } } { \tl_set:Nx \l_tmpa_tl - { \lua_now:n { piton.Parse(token.scan_string()) } { #1 } } + { + \lua_now:e + { piton.Parse('\l_@@_language_str',token.scan_string()) } + { #1 } + } } \bool_if:NT \l_@@_show_spaces_bool { \regex_replace_all:nnN { \x20 } { ␣ } \l_tmpa_tl } % U+2423 @@ -2505,7 +2784,7 @@ version 2005/12/01 or later. \vtop \bgroup \lua_now:e { - piton.ParseFile(token.scan_argument() , + piton.ParseFile('\l_@@_language_str',token.scan_argument() , \int_use:N \l_@@_first_line_int , \int_use:N \l_@@_last_line_int ) } @@ -2587,7 +2866,11 @@ version 2005/12/01 or later. \lua_now:e { piton.GobbleParse - ( \int_use:N \l_@@_gobble_int , token.scan_argument() ) + ( + '\l_@@_language_str' , + \int_use:N \l_@@_gobble_int , + token.scan_argument() + ) } { ##1 } \vspace { 2.5 pt } @@ -2718,20 +3001,26 @@ version 2005/12/01 or later. 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 , - Post.Function .tl_set:c = pitonStyle Post.Function , - Post.Function .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 , - Beamer .tl_set:c = pitonStyle Beamer , - Beamer .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 } } @@ -2749,6 +3038,7 @@ version 2005/12/01 or later. Comment.LaTeX,~ Dict.Value,~ Exception,~ + Identifier,~ InitialValues,~ Keyword,~ Keyword.Constant,~ @@ -2760,6 +3050,7 @@ version 2005/12/01 or later. Number,~ Operator,~ Operator.Word,~ + Prompt,~ String,~ String.Doc,~ String.Long,~ @@ -2797,12 +3088,16 @@ version 2005/12/01 or later. InitialValues = \@@_piton:n , Dict.Value = \@@_piton:n , Interpol.Inside = \color{black}\@@_piton:n , - Beamer = \@@_piton_no_cr:n , - Post.Function = \@@_piton:n , + TypeParameter = \color[HTML]{008800} \itshape , + Identifier = \@@_identifier:n , + Prompt = , + ParseAgain.noCR = \@@_piton_no_cr:n , + ParseAgain = \@@_piton:n , } % \end{macrocode} -% The last styles |Beamer| and |Post.Function| should be considered as -% ``internal style'' (not available for the final user). +% The last styles |ParseAgain.noCR| and |ParseAgain| should be considered as +% ``internal style'' (not available for the final user). However, maybe we will +% change that and document these styles for the final user (why not?). % % \medskip % If the key |math-comments| has been used at load-time, we change the style @@ -2810,8 +3105,46 @@ version 2005/12/01 or later. % However, maybe we will document in a future version the possibility to write % change the style \emph{locally} in a document)]. % \begin{macrocode} -\bool_if:NT \c_@@_math_comments_bool - { \SetPitonStyle { Comment.Math } } +\bool_if:NT \c_@@_math_comments_bool { \SetPitonStyle { Comment.Math } } +% \end{macrocode} +% +% \bigskip +% \subsubsection{Highlighting some identifiers} +% +% \begin{macrocode} +\cs_new_protected:Npn \@@_identifier:n #1 + { \cs_if_exist_use:c { PitonIdentifier #1 } { #1 } } +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\keys_define:nn { PitonOptions } + { identifiers .code:n = \@@_set_identifiers:n { #1 } } +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\keys_define:nn { Piton / identifiers } + { + names .clist_set:N = \l_@@_identifiers_names_tl , + style .tl_set:N = \l_@@_style_tl , + } +% \end{macrocode} +% +% \bigskip +% \begin{macrocode} +\cs_new_protected:Npn \@@_set_identifiers:n #1 + { + \clist_clear_new:N \l_@@_identifiers_names_tl + \tl_clear_new:N \l_@@_style_tl + \keys_set:nn { Piton / identifiers } { #1 } + \clist_map_inline:Nn \l_@@_identifiers_names_tl + { + \tl_set_eq:cN + { PitonIdentifier ##1 } + \l_@@_style_tl + } + } % \end{macrocode} % % \bigskip @@ -2854,7 +3187,9 @@ version 2005/12/01 or later. end-of-broken-line,~ env-gobble,~ gobble,~ + identifiers,~ indent-broken-lines,~ + language,~ left-margin,~ line-numbers,~ prompt-background-color,~ @@ -2914,7 +3249,7 @@ version 2005/12/01 or later. % % % \bigskip -% The Lua code will be loaded via a |{luacode*}| environment. Thei environment +% The Lua code will be loaded via a |{luacode*}| environment. The environment % is by itself a Lua block and the local declarations will be local to that % block. All the global functions (used by the L3 parts of the implementation) % will be put in a Lua table |piton|. @@ -2929,18 +3264,17 @@ piton = piton or { } if piton.comment_latex == nil then piton.comment_latex = ">" end piton.comment_latex = "#" .. piton.comment_latex % \end{macrocode} -% -% +% % \bigskip % \subsubsection{Special functions dealing with LPEG} % -% % \medskip % We will use the Lua library \pkg{lpeg} which is built in LuaTeX. That's why we % define first aliases for several functions of that library. % \begin{macrocode} local P, S, V, C, Ct, Cc = lpeg.P, lpeg.S, lpeg.V, lpeg.C, lpeg.Ct, lpeg.Cc -local Cf, Cs = lpeg.Cf, lpeg.Cs +local Cf, Cs , Cg , Cmt , Cb = lpeg.Cf, lpeg.Cs, lpeg.Cg , lpeg.Cmt , lpeg.Cb +local R = lpeg.R % \end{macrocode} % % @@ -3034,13 +3368,6 @@ lpeg.locale(lpeg) % \end{macrocode} % % \bigskip -% \subsubsection{The LPEG SyntaxPython} -% -% -% \bigskip -% -% -% \bigskip % \paragraph{The basic syntactic LPEG} % % \begin{macrocode} @@ -3072,7 +3399,7 @@ local identifier = letter * alphanum ^ 0 % On the other hand, the \textsc{lpeg} |Identifier| (with a capital) also returns % a \emph{capture}. % \begin{macrocode} -local Identifier = K ( identifier ) +local Identifier = K ( identifier , 'Identifier' ) % \end{macrocode} % % \bigskip @@ -3135,6 +3462,20 @@ local Delim = K ( S "[()]" ) % \end{macrocode} % % \bigskip +% The following \textsc{lpeg} catches a space (U+0020) and replace it by +% |\l_@@_space_tl|. It will be used in the strings. Usually, +% |\l_@@_space_tl| will contain a space and therefore there won't be difference. +% However, when the key |show-spaces-in-strings| is in force, |\\l_@@_space_tl| will +% contain ␣ (U+2423) in order to visualize the spaces. +% \begin{macrocode} +local VisualSpace = space * Lc "\\l_@@_space_tl" +% \end{macrocode} +% +% +% \bigskip +% \subsubsection{The LPEG python} +% +% \bigskip % Some strings of length 2 are explicit because we want the corresponding % ligatures available in some fonts such as \emph{Fira Code} to be active. % \begin{macrocode} @@ -3173,7 +3514,7 @@ local Builtin = 'Name.Builtin' ) local Exception = - K ( "ArithmeticError" + P "AssertionError" + P "AttributeError" + K ( 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" @@ -3292,7 +3633,7 @@ local FromImport = % % % \bigskip -% First, we define \textsc{lpeg} for the interpolations in the f-strings. Here +% We have also to deal with the interpolations in the f-strings. Here % is an example of a f-string with an interpolation and a format % instruction\footnote{There is no special \pkg{piton} style for the formatting % instruction (after the colon): the style which will be applied will be the @@ -3301,66 +3642,6 @@ local FromImport = % % \piton{f'Total price: {total+1:.2f} €'} % -% \medskip -% The following \textsc{lpeg} |SingleShortInterpol| (and the three variants) -% will catch the whole interpolation, included the braces, that is to say, in -% the previous example:\enskip |{total+1:.2f}| -% -% \medskip -% \begin{macrocode} -local SingleShortInterpol = - K ( P "{" , 'String.Interpol') - * K ( ( 1 - S "}':" ) ^ 0 , 'Interpol.Inside' ) - * K ( P ":" * (1 - S "}:'") ^ 0 ) ^ -1 - * K ( P "}" , 'String.Interpol' ) - -local DoubleShortInterpol = - K ( P "{" , 'String.Interpol' ) - * K ( ( 1 - S "}\":" ) ^ 0 , 'Interpol.Inside' ) - * ( K ( P ":" , 'String.Interpol' ) * K ( (1 - S "}:\"") ^ 0 ) ) ^ -1 - * K ( P "}" , 'String.Interpol' ) - -local SingleLongInterpol = - K ( P "{" , 'String.Interpol' ) - * K ( ( 1 - S "}:\r" - P "'''" ) ^ 0 , 'Interpol.Inside' ) - * K ( P ":" * (1 - S "}:\r" - P "'''" ) ^ 0 ) ^ -1 - * K ( P "}" , 'String.Interpol' ) - -local DoubleLongInterpol = - K ( P "{" , 'String.Interpol' ) - * K ( ( 1 - S "}:\r" - P "\"\"\"" ) ^ 0 , 'Interpol.Inside' ) - * K ( P ":" * (1 - S "}:\r" - P "\"\"\"" ) ^ 0 ) ^ -1 - * K ( P "}" , 'String.Interpol' ) -% \end{macrocode} -% -% -% \bigskip -% The following \textsc{lpeg} catches a space (U+0020) and replace it by -% |\l_@@_space_tl|. It will be used in the short strings. Usually, -% |\l_@@_space_tl| will contain a space and therefore there won't be difference. -% However, when the key |show-spaces-in-strings| is in force, |\\l_@@_space_tl| will -% contain ␣ (U+2423) in order to visualize the spaces. -% \begin{macrocode} -local VisualSpace = space * Lc "\\l_@@_space_tl" -% \end{macrocode} -% -% \bigskip -% Now, we define \textsc{lpeg} for the parts of the strings which are \emph{not} -% in the interpolations. -% -% \begin{macrocode} -local SingleShortPureString = - ( VisualSpace + K ( ( P "\\'" + P "{{" + P "}}" + 1 - S " {}'" ) ^ 1 ) ) ^ 1 - -local DoubleShortPureString = - ( VisualSpace + K ( ( P "\\\"" + P "{{" + P "}}" + 1 - S " {}\"" ) ^ 1 ) ) ^ 1 - -local SingleLongPureString = - K ( ( 1 - P "'''" - S "{}'\r" ) ^ 1 ) - -local DoubleLongPureString = - K ( ( 1 - P "\"\"\"" - S " {}\"\r" ) ^ 1 ) -% \end{macrocode} % % \bigskip % The interpolations beginning by |%| (even though there is more modern @@ -3393,7 +3674,16 @@ local SingleShortString = % First, we deal with the f-strings of Python, which are prefixed by |f| or |F|. % \begin{macrocode} K ( P "f'" + P "F'" ) - * ( SingleShortInterpol + SingleShortPureString ) ^ 0 + * ( + K ( P "{" , 'String.Interpol') + * K ( ( 1 - S "}':" ) ^ 0 , 'Interpol.Inside' ) + * K ( P ":" * (1 - S "}:'") ^ 0 ) ^ -1 + * K ( P "}" , 'String.Interpol' ) + + + VisualSpace + + + K ( ( P "\\'" + P "{{" + P "}}" + 1 - S " {}'" ) ^ 1 ) + ) ^ 0 * K ( P "'" ) + % \end{macrocode} @@ -3413,7 +3703,16 @@ local DoubleShortString = Lc ( "{\\PitonStyle{String.Short}{" ) * ( K ( P "f\"" + P "F\"" ) - * ( DoubleShortInterpol + DoubleShortPureString ) ^ 0 + * ( + K ( P "{" , 'String.Interpol' ) + * K ( ( 1 - S "}\":" ) ^ 0 , 'Interpol.Inside' ) + * ( K ( P ":" , 'String.Interpol' ) * K ( (1 - S "}:\"") ^ 0 ) ) ^ -1 + * K ( P "}" , 'String.Interpol' ) + + + VisualSpace + + + K ( ( P "\\\"" + P "{{" + P "}}" + 1 - S " {}\"" ) ^ 1 ) + ) ^ 0 * K ( P "\"" ) + K ( P "\"" + P "r\"" + P "R\"" ) @@ -3440,11 +3739,13 @@ local ShortString = SingleShortString + DoubleShortString % \begin{macrocode} local BalancedBraces = P { "E" , - E = ( ShortString + ( 1 - S "{}" ) ) ^ 0 - * - ( - P "{" * V "E" * P "}" - * ( ShortString + ( 1 - S "{}" ) ) ^ 0 + E = + ( + P "{" * V "E" * P "}" + + + ShortString + + + ( 1 - S "{}" ) ) ^ 0 } % \end{macrocode} @@ -3458,6 +3759,7 @@ local BeamerBeginEnvironments = P ( true ) local BeamerEndEnvironments = P ( true ) local BeamerNamesEnvironments = P "uncoverenv" + P "onlyenv" + P "visibleenv" + P "invisibleenv" + + P "alertenv" + P "actionenv" % \end{macrocode} % @@ -3483,7 +3785,7 @@ then ) * L ( ( P "<" * (1 - P ">") ^ 0 * P ">" ) ^ -1 * P "{" ) - * K ( BalancedBraces , 'Beamer' ) + * K ( BalancedBraces , 'ParseAgain.noCR' ) * L ( P "}" ) + L ( @@ -3494,9 +3796,9 @@ then * P "<" * (1 - P ">") ^ 0 * P ">" * P "{" ) - * K ( BalancedBraces , 'Beamer' ) + * K ( BalancedBraces , 'ParseAgain.noCR' ) * L ( P "}{" ) - * K ( BalancedBraces , 'Beamer' ) + * K ( BalancedBraces , 'ParseAgain.noCR' ) * L ( P "}" ) + L ( @@ -3507,11 +3809,11 @@ then * P "<" * (1 - P ">") ^ 0 * P ">" * P "{" ) - * K ( BalancedBraces , 'Beamer' ) + * K ( BalancedBraces , 'ParseAgain.noCR' ) * L ( P "}{" ) - * K ( BalancedBraces , 'Beamer' ) + * K ( BalancedBraces , 'ParseAgain.noCR' ) * L ( P "}{" ) - * K ( BalancedBraces , 'Beamer' ) + * K ( BalancedBraces , 'ParseAgain.noCR' ) * L ( P "}" ) % \end{macrocode} % Now for the environemnts. @@ -3538,15 +3840,18 @@ end % % \bigskip % The following LPEG will detect the Python prompts when the user is typesetting -% an interactive session of Python (directly or throught |{pyconsole}| of +% an interactive session of Python (directly or through |{pyconsole}| of % \pkg{pyluatex}). % \begin{macrocode} -local Prompt = ( # ( P ">>>" + P "..." ) * Lc ( '\\@@_prompt:' ) ) ^ -1 +local PromptHastyDetection = ( # ( P ">>>" + P "..." ) * Lc ( '\\@@_prompt:' ) ) ^ -1 % \end{macrocode} % We remind that the marker |#| of LPEG specifies that the pattern will be % detected but won't consume any character. % -% +% \begin{macrocode} +local Prompt = K ( ( ( P ">>>" + P "..." ) * P " " ^ -1 ) ^ -1 , 'Prompt' ) +% \end{macrocode} +% % \bigskip % The following \textsc{lpeg} |EOL| is for the end of lines. % \begin{macrocode} @@ -3569,8 +3874,9 @@ EOL = Lc ( '\\@@_end_line:' ) * BeamerEndEnvironments * BeamerBeginEnvironments - * Prompt + * PromptHastyDetection * Lc ( '\\@@_newline: \\@@_begin_line:' ) + * Prompt ) * SpaceIndentation ^ 0 @@ -3589,52 +3895,52 @@ EOL = % delimit the argument of the command \texttt{\textbackslash @@\_begin\_line:}}. % \begin{macrocode} Lc ( '\\@@_end_line:' ) - * Prompt + * 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} % % -% \bigskip -% Of course, it's more complicated for ``longs strings'' because, by definition, -% in Python, those strings may be broken by an end on line (which is catched by -% the \textsc{lpeg} |EOL|). % \begin{macrocode} local SingleLongString = Lc "{\\PitonStyle{String.Long}{" * ( K ( S "fF" * P "'''" ) - * ( SingleLongInterpol + SingleLongPureString ) ^ 0 - * Lc "}}" * ( - EOL + 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 ) + - Lc "{\\PitonStyle{String.Long}{" - * ( SingleLongInterpol + SingleLongPureString ) ^ 0 - * Lc "}}" - * EOL + EOL_for_style 'String.Long' ) ^ 0 - * Lc "{\\PitonStyle{String.Long}{" - * ( SingleLongInterpol + SingleLongPureString ) ^ 0 + - K ( ( S "rR" ) ^ -1 * P "'''" - * ( 1 - P "'''" - P "\r" ) ^ 0 ) - * Lc "}}" + K ( ( S "rR" ) ^ -1 * P "'''" ) * ( - Lc "{\\PitonStyle{String.Long}{" - * K ( ( 1 - P "'''" - P "\r" ) ^ 0 ) - * Lc "}}" - * EOL + K ( ( 1 - P "'''" - S "\r%" ) ^ 1 ) + + + PercentInterpol + + + P "%" + + + EOL_for_style 'String.Long' ) ^ 0 - * Lc "{\\PitonStyle{String.Long}{" - * K ( ( 1 - P "'''" - P "\r" ) ^ 0 ) ) * K ( P "'''" ) * Lc "}}" @@ -3644,30 +3950,27 @@ local DoubleLongString = Lc "{\\PitonStyle{String.Long}{" * ( K ( S "fF" * P "\"\"\"" ) - * ( DoubleLongInterpol + DoubleLongPureString ) ^ 0 - * Lc "}}" * ( - EOL + 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 ) + - Lc "{\\PitonStyle{String.Long}{" - * ( DoubleLongInterpol + DoubleLongPureString ) ^ 0 - * Lc "}}" - * EOL + EOL_for_style 'String.Long' ) ^ 0 - * Lc "{\\PitonStyle{String.Long}{" - * ( DoubleLongInterpol + DoubleLongPureString ) ^ 0 + - K ( ( S "rR" ) ^ -1 * P "\"\"\"" - * ( 1 - P "\"\"\"" - P "\r" ) ^ 0 ) - * Lc "}}" + K ( ( S "rR" ) ^ -1 * P "\"\"\"" ) * ( - Lc "{\\PitonStyle{String.Long}{" - * K ( ( 1 - P "\"\"\"" - P "\r" ) ^ 0 ) - * Lc "}}" - * EOL + K ( ( 1 - P "\"\"\"" - S "%\r" ) ^ 1 ) + + + PercentInterpol + + + P "%" + + + EOL_for_style 'String.Long' ) ^ 0 - * Lc "{\\PitonStyle{String.Long}{" - * K ( ( 1 - P "\"\"\"" - P "\r" ) ^ 0 ) ) * K ( P "\"\"\"" ) * Lc "}}" @@ -3794,12 +4097,12 @@ local DefFunction = * SkipSpace * ( K ( P "->" ) * SkipSpace * K ( identifier , 'Name.Type' ) ) ^ -1 % \end{macrocode} -% Here, we need a \pkg{piton} style |Post.Function| which will be linked to +% 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 % \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 , 'Post.Function' ) + * K ( ( 1 - S ":\r" )^0 , 'ParseAgain' ) * K ( P ":" ) * ( SkipSpace * ( EOL + CommentLaTeX + Comment ) -- in all cases, that contains an EOL @@ -3851,8 +4154,6 @@ local Set = * K ( P "}" ) % \end{macrocode} % -% -% \bigskip % \paragraph{Miscellaneous} % % \begin{macrocode} @@ -3885,7 +4186,6 @@ MainLoop = + ShortString + Punct + FromImport - + ImportAs + RaiseException + DefFunction + DefClass @@ -3906,49 +4206,416 @@ MainLoop = % will be used as marker in order to delimit the argument of the command % \texttt{\textbackslash @@\_begin\_line:}}. % \begin{macrocode} -local SyntaxPython = P ( true ) +local python = P ( true ) -function piton.defSyntaxPython() - SyntaxPython = - Ct ( - ( ( space - P "\r" ) ^0 * P "\r" ) ^ -1 - * BeamerBeginEnvironments - * Prompt - * Lc ( '\\@@_begin_line:' ) - * SpaceIndentation ^ 0 - * MainLoop - * -1 - * Lc ( '\\@@_end_line:' ) - ) +python = + Ct ( + ( ( space - P "\r" ) ^0 * P "\r" ) ^ -1 + * BeamerBeginEnvironments + * PromptHastyDetection + * Lc ( '\\@@_begin_line:' ) + * Prompt + * SpaceIndentation ^ 0 + * MainLoop + * -1 + * Lc ( '\\@@_end_line:' ) + ) +% \end{macrocode} +% +% \begin{macrocode} +local languages = { } +languages['python'] = python +% \end{macrocode} +% +% % \bigskip +% \subsubsection{The LPEG ocaml} +% +% \begin{macrocode} +local Punct = K ( S ",:;!" ) +% \end{macrocode} +% +% \begin{macrocode} +local identifier = + ( R "az" + R "AZ" + P "_") * ( R "az" + R "AZ" + S "_'" + digit ) ^ 0 + +local Identifier = K ( identifier ) + +local Operator = + K ( 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') + +local Keyword = + K ( 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" + + 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' ) + + +local Builtin = + K ( 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" + + P "List.iter" + + P "Array.length" + P "Array.make" + P "Array.make_matrix" + + P "Array.init" + P "Array.copy" + P "Array.copy" + P "Array.mem" + + P "Array.exists" + P "Array.for_all" + P "Array.map" + P "Array.iter" + + P "Queue.create" + P "Queue.is_empty" + P "Queue.push" + P "Queue.pop" + + 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' ) +% \end{macrocode} +% +% \bigskip +% 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" + + 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' ) +% \end{macrocode} +% +% +% \paragraph{The characters in OCaml} +% +% \begin{macrocode} +local Char = + K ( P "'" * ( ( 1 - P "'" ) ^ 0 + P "\\'" ) * P "'" , 'String.Short' ) +% \end{macrocode} +% +% +% \bigskip +% \paragraph{Beamer} +% +% \begin{macrocode} +local BalancedBraces = + P { "E" , + E = + ( + P "{" * V "E" * P "}" + + + P "\"" * ( 1 - S "\"" ) ^ 0 * P "\"" -- OCaml strings + + + ( 1 - S "{}" ) + ) ^ 0 + } +% \end{macrocode} +% +% +% \begin{macrocode} +if piton_beamer +then + Beamer = + L ( P "\\pause" * ( P "[" * (1 - P "]") ^ 0 * P "]" ) ^ -1 ) + + + ( 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 "}" ) + + + L ( + ( P "\\alt" ) + * P "<" * (1 - P ">") ^ 0 * P ">" + * P "{" + ) + * K ( BalancedBraces , 'ParseAgain.noCR' ) + * L ( P "}{" ) + * K ( BalancedBraces , 'ParseAgain.noCR' ) + * L ( P "}" ) + + + L ( + ( P "\\temporal" ) + * P "<" * (1 - P ">") ^ 0 * P ">" + * P "{" + ) + * K ( BalancedBraces , 'ParseAgain.noCR' ) + * L ( P "}{" ) + * K ( BalancedBraces , 'ParseAgain.noCR' ) + * L ( P "}{" ) + * K ( BalancedBraces , 'ParseAgain.noCR' ) + * L ( P "}" ) + BeamerBeginEnvironments = + ( space ^ 0 * + L + ( + P "\\begin{" * BeamerNamesEnvironments * "}" + * ( P "<" * ( 1 - P ">") ^ 0 * P ">" ) ^ -1 + ) + * P "\r" + ) ^ 0 + BeamerEndEnvironments = + ( space ^ 0 * + L ( P "\\end{" * BeamerNamesEnvironments * P "}" ) + * P "\r" + ) ^ 0 end +% \end{macrocode} +% +% \bigskip +% \paragraph{EOL} +% +% \begin{macrocode} +local EOL +if piton_beamer +then +EOL = + P "\r" + * + ( + ( space^0 * -1 ) + + + Lc ( '\\@@_end_line:' ) + * BeamerEndEnvironments + * BeamerBeginEnvironments + * Lc ( '\\@@_newline: \\@@_begin_line:' ) + ) + * + 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} +% +% \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 "}}" +% \end{macrocode} +% +% +% \bigskip +% Now, the ``quoted strings'' of OCaml (for example \verb+{ext|Essai|ext}+). +% +% For those strings, we will do two consecutive analysis. First an analysis to +% determine the whole string and, then, an analysis for the potential visual +% spaces and the EOL in the string. +% +% The first analysis require a match-time capture. For explanations about that +% programmation, see the paragraphe \emph{Lua's long % strings} in +% |www.inf.puc-rio.br/~roberto/lpeg|. +% \begin{macrocode} +local ext = ( R "az" + P "_" ) ^ 0 +local open = "{" * Cg(ext, 'init') * "|" +local close = "|" * C(ext) * "}" +local closeeq = + Cmt ( close * Cb('init'), + function (s, i, a, b) return a==b end ) +% \end{macrocode} +% +% \medskip +% The \textsc{lpeg} |QuotedStringBis| will do the second analysis. +% \begin{macrocode} +local QuotedStringBis = + Lc "{\\PitonStyle{String.Long}{" + * + ( + VisualSpace + + + K ( ( 1 - S " \r" ) ^ 1 ) + + + EOL_for_style 'String.Long' + ) ^ 0 + * Lc "}}" +% \end{macrocode} +% +% \medskip +% We use a ``function capture'' (as called in the official documentation of the +% \textsc{lpeg}) in order to do the second analysis on the result of the first one. +% \begin{macrocode} +local QuotedString = + C ( open * ( 1 - closeeq ) ^ 0 * close ) / + ( function (s) return QuotedStringBis : match(s) end ) +% \end{macrocode} +% +% +% \bigskip +% \paragraph{The comments in the OCaml listings} +% +% In OCaml, the delimiters for the comments are |(*| and |*)|. There +% unsymmetrical and, therefore, the comments may be nested. That's why we need a +% grammar. +% +% In these comments, we embed the math comments (between |$| and |$|) and we +% embed also a treatment for the end of lines (since the comments may be multi-lines). +% +% \begin{macrocode} +local 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 "}}" +% \end{macrocode} +% +% \bigskip +% \paragraph{The DefFunction} +% +% \begin{macrocode} +local DefFunction = + ( K ( P "let rec" + P "let" + P "and" , 'Keyword' ) ) + * Space + * K ( identifier , 'Name.Function' ) + * Space + * # ( 1 - P "=" ) +% \end{macrocode} +% +% \bigskip +% \paragraph{The parameters of the types} +% +% \begin{macrocode} +local TypeParameter = K ( P "'" * alpha * # ( 1 - P "'") , 'TypeParameter' ) +% \end{macrocode} +% +% \bigskip +% \paragraph{The main LPEG} +% +% First, the main loop : +% \begin{macrocode} +MainLoop = + ( ( space^1 * -1 ) + + EOL + + Space + + Tab + + Escape + + Beamer + + TypeParameter + + String + QuotedString + Char + + Comment + + Delim + + Operator + + Punct + + FromImport + + ImportAs + + Exception + + DefFunction + + Keyword * ( Space + Punct + Delim + EOL + -1 ) + + OperatorWord * ( Space + Punct + Delim + EOL + -1 ) + + Builtin * ( Space + Punct + Delim + EOL + -1 ) + + Identifier + + Number + + Word + ) ^ 0 +% \end{macrocode} +% +% \bigskip +% We recall that each line in the Python code to parse will be sent back to +% LaTeX between a pair |\@@_begin_line:| -- |\@@_end_line:|\footnote{Remember +% that the \texttt{\textbackslash @@\_end\_line:} must be explicit because it +% will be used as marker in order to delimit the argument of the command +% \texttt{\textbackslash @@\_begin\_line:}}. +% \begin{macrocode} +local ocaml = P ( true ) -piton.defSyntaxPython() +ocaml = + Ct ( + ( ( space - P "\r" ) ^0 * P "\r" ) ^ -1 + * BeamerBeginEnvironments + * Lc ( '\\@@_begin_line:' ) + * SpaceIndentation ^ 0 + * MainLoop + * -1 + * Lc ( '\\@@_end_line:' ) + ) % \end{macrocode} % +% \begin{macrocode} +languages['ocaml'] = ocaml +% \end{macrocode} % % \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 % formatting LaTeX instructions. In fact, everything is done by the -% \textsc{lpeg} |SyntaxPython| which returns as capture a Lua table containing +% \textsc{lpeg} |python| which returns as capture a Lua table containing % data to send to LaTeX. % % \bigskip % \begin{macrocode} -function piton.Parse(code) - local t = SyntaxPython : match ( code ) +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 end % \end{macrocode} % +% +% % \bigskip % The function |ParseFile| will be used by the LaTeX command |\PitonInputFile|. % That function merely reads the whole file (that is to say all its lines) and % then apply the function~|Parse| to the resulting Lua string. % \begin{macrocode} -function piton.ParseFile(name,first_line,last_line) +function piton.ParseFile(language,name,first_line,last_line) s = '' local i = 0 for line in io.lines(name) @@ -3958,19 +4625,19 @@ function piton.ParseFile(name,first_line,last_line) end if i >= last_line then break end end - piton.Parse(s) + piton.Parse(language,s) end % \end{macrocode} % % \bigskip -% \subsubsection{Two vairants of the function Parse with integrated preprocessors} +% \subsubsection{Two variants of the function Parse with integrated preprocessors} % % The following command will be used by the user command |\piton|. % For that command, we have to undo the duplication of the symbols |#|. % \begin{macrocode} -function piton.ParseBis(code) +function piton.ParseBis(language,code) local s = ( Cs ( ( P '##' / '#' + 1 ) ^ 0 ) ) : match ( code ) - return piton.Parse(s) + return piton.Parse(language,s) end % \end{macrocode} % @@ -3981,16 +4648,16 @@ end % element. In that case, you have to remove the potential |\@@_breakable_space:| % that have been inserted when the key |break-lines| is in force. % \begin{macrocode} -function piton.ParseTer(code) +function piton.ParseTer(language,code) local s = ( Cs ( ( P '\\@@_breakable_space:' / ' ' + 1 ) ^ 0 ) ) : match ( code ) - return piton.Parse(s) + return piton.Parse(language,s) end % \end{macrocode} % % % \bigskip -% \subsubsection{The preprocessors of the function Parse} +% \subsubsection{Preprocessors of the function Parse for gobble} % % We deal now with preprocessors of the function |Parse| which are needed when % the ``gobble mechanism'' is used. @@ -4095,7 +4762,7 @@ local EnvGobbleLPEG = % % \bigskip % \begin{macrocode} -function piton.GobbleParse(n,code) +function piton.GobbleParse(language,n,code) if n==-1 then n = AutoGobbleLPEG : match(code) else if n==-2 @@ -4105,7 +4772,7 @@ function piton.GobbleParse(n,code) end end end - piton.Parse(gobble(n,code)) + piton.Parse(language,gobble(n,code)) end % \end{macrocode} % @@ -4168,7 +4835,6 @@ function piton.CountNonEmptyLinesFile(name) end % \end{macrocode} % -% \bigskip % \begin{macrocode} \end{luacode*} % \end{macrocode} @@ -4177,6 +4843,14 @@ end % \vspace{1cm} % \section{History} % +% \subsection*{Changes between versions 1.3 and 1.4} +% +% New key |identifiers| in |\PitonOptions|. +% +% New command |\PitonStyle|. +% +% |background-color| now accepts as value a \emph{list} of colors. +% % \subsection*{Changes between versions 1.2 and 1.3} % % When the class Beamer is used, the environment |{Piton}| and the command @@ -4194,7 +4868,7 @@ end % \subsection*{Changes between versions 1.1 and 1.2} % % New keys |break-lines-in-piton| and |break-lines-in-Piton|. -% +% % New key |show-spaces-in-string| and modification of the key |show-spaces|. % % When the class \cls{beamer} is used, the environements |{uncoverenv}|, @@ -4249,7 +4923,7 @@ end % % % -% +% \tableofcontents % % \end{document} % |