texlive[66884] Master/texmf-dist: prettytok (18apr23)

commits+karl at tug.org commits+karl at tug.org
Tue Apr 18 21:40:32 CEST 2023


Revision: 66884
          http://tug.org/svn/texlive?view=revision&revision=66884
Author:   karl
Date:     2023-04-18 21:40:32 +0200 (Tue, 18 Apr 2023)
Log Message:
-----------
prettytok (18apr23)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/latex/prettytok/DEPENDS.txt
    trunk/Master/texmf-dist/doc/latex/prettytok/README
    trunk/Master/texmf-dist/doc/latex/prettytok/prettytok.pdf
    trunk/Master/texmf-dist/doc/latex/prettytok/prettytok.tex
    trunk/Master/texmf-dist/tex/latex/prettytok/prettytok.lua
    trunk/Master/texmf-dist/tex/latex/prettytok/prettytok.sty

Added Paths:
-----------
    trunk/Master/texmf-dist/doc/latex/prettytok/prettytok-test.tex
    trunk/Master/texmf-dist/doc/latex/prettytok/prettytok_template.html
    trunk/Master/texmf-dist/tex/latex/prettytok/prettytok-decode-8bit.py

Removed Paths:
-------------
    trunk/Master/texmf-dist/tex/latex/prettytok/prettytok_template.html

Modified: trunk/Master/texmf-dist/doc/latex/prettytok/DEPENDS.txt
===================================================================
--- trunk/Master/texmf-dist/doc/latex/prettytok/DEPENDS.txt	2023-04-18 19:40:07 UTC (rev 66883)
+++ trunk/Master/texmf-dist/doc/latex/prettytok/DEPENDS.txt	2023-04-18 19:40:32 UTC (rev 66884)
@@ -1 +1,2 @@
 precattl
+l3keys2e

Modified: trunk/Master/texmf-dist/doc/latex/prettytok/README
===================================================================
--- trunk/Master/texmf-dist/doc/latex/prettytok/README	2023-04-18 19:40:07 UTC (rev 66883)
+++ trunk/Master/texmf-dist/doc/latex/prettytok/README	2023-04-18 19:40:32 UTC (rev 66884)
@@ -1,6 +1,5 @@
 prettytok -- Pretty-print token list
-Pretty-print token lists to HTML file for debugging purposes.
-Open the file in any browser to view the result.
+Pretty-print token lists for debugging purposes.
 
 Can be used to replace |\tl_analysis_show:n|.
 
@@ -11,7 +10,7 @@
 
 ========
 
-Copyright 2022 user202729
+Copyright 2022-2023 user202729
 
 This work  may be  distributed and/or  modified under  the conditions  of the
 LaTeX Project Public License (LPPL),  either version 1.3c  of this license or
@@ -24,4 +23,4 @@
 
 The Current Maintainer of this work is user202729.
 
-This work consists of the files prettytok.sty, prettytok.lua, prettytok_template.html.
+This work consists of the files prettytok.sty, prettytok.lua, prettytok_template.html, prettytok-decode-8bit.py, prettytok-test.tex.

Added: trunk/Master/texmf-dist/doc/latex/prettytok/prettytok-test.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/prettytok/prettytok-test.tex	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/prettytok/prettytok-test.tex	2023-04-18 19:40:32 UTC (rev 66884)
@@ -0,0 +1,17 @@
+\documentclass{article}
+\usepackage{prettytok}
+
+\prettyN{123{4 5}\6}
+\prettyN{#&^_:}
+\edef\mytest{\prettyeN{\error}}
+
+\prettyN {very long long long long long long long long long long long long long long argument \argument\argument\test123456}
+\prettyeN {very long long long long long long long long long long long long long long argument \argument\argument\test123456}
+
+\ExplSyntaxOn
+\pretty:n {#&^_:}
+\ExplSyntaxOff
+
+\begin {document}
+\prettyW abc \prettystop
+\end {document}


Property changes on: trunk/Master/texmf-dist/doc/latex/prettytok/prettytok-test.tex
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: trunk/Master/texmf-dist/doc/latex/prettytok/prettytok.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/prettytok/prettytok.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/prettytok/prettytok.tex	2023-04-18 19:40:07 UTC (rev 66883)
+++ trunk/Master/texmf-dist/doc/latex/prettytok/prettytok.tex	2023-04-18 19:40:32 UTC (rev 66884)
@@ -1,14 +1,19 @@
 %! TEX program = lualatex
-\ProvidesFile{prettytok.tex} [2022/07/08 v0.0.1 ]
+\ProvidesFile{prettytok.tex} [2023/04/18 v0.2.0 ]
+\RequirePackage{fvextra}
 \documentclass{l3doc}
+\usepackage[svgnames]{xcolor}
 \EnableCrossrefs
 \CodelineIndex
-\RecordChanges
+\fvset{breaklines=true,gobble=0,tabsize=4,frame=single,numbers=left,numbersep=3pt}
+\AtBeginDocument{\DeleteShortVerb\"}
+\MakeOuterQuote{"}
+\usepackage{cleveref}
 \begin{document}
+\hfuzz=1pt
 \GetFileInfo{\jobname.tex}
-\DoNotIndex{\newcommand,\newenvironment}
 
-\title{\textsf{prettytok} --- Pretty-print token lists\thanks{This file
+\title{\pkg{prettytok} --- Pretty-print token lists\thanks{This file
 	describes version \fileversion, last revised \filedate.}
 }
 \author{user202729%
@@ -18,17 +23,205 @@
 
 \maketitle
 
-\changes{v0.0.0}{2022/05/18}{First public release}
-
 \begin{abstract}
-Pretty-print token lists to HTML file for debugging purposes.
-Open the file in any browser to view the result.
+Pretty-print token lists for debugging purposes.
 
 Can be used to replace |\tl_analysis_show:n|.
 \end{abstract}
 
+\section{Motivation}
+
+\TeX/\LaTeX's default mechanism for debug-printing -- that is, the following:
+\begin{itemize}
+	\item |\showtokens{...}|,
+	\item |\show...|,
+	\item |\typeout{\unexpanded{...}}|,
+	\item |\tl_show:n|,
+	\item etc.
+\end{itemize}
+has a few limitations:
+
+\begin{itemize}
+	\item |\show| and similar is considered an error and stops the \TeX\ run. (this point is partially fixable, see the package writer's question \url{https://tex.stackexchange.com/q/621919/250119})
+	\item If there's some unprintable character in the output (for example, |^^J|, |^^M|, |^^I| -- literal tab character), it's not easy to distinguish between them.
+	\item If some token has unexpected catcode (most commonly, letter versus other), it's not easy to distinguish as well.
+	\item They does not work in expansion-only context.
+
+		(apart from |\msg_expandable_error:nn|, but this one suffers from the first problem as well)
+\end{itemize}
+
+|\tl_analysis_show:n| attempts to fix the third problem, but is very, very verbose and does not fix the other problems.
+
+This package aims to fix all of them.
+
+(although the expandable debug printing functions are \LuaTeX-only.)
+
+And some more additional (expandable in \LuaTeX) functions to inspect the content of the input stream at a particular moment in time.
+
+
 \section{Usage}
 
+\subsection{A complete example}
+
+For a full example, the following code, which prints several things, both using the \LaTeXe\ interface
+and using the \pkg{expl3}-style interface, using both expandable and unexpandable command (the former requires \LuaTeX, as mentioned in \ref{subsec:expandable-interface}):
+\VerbatimInput{prettytok-test.tex}
+The corresponding output (in the current version) is:
+\begingroup%
+\ExplSyntaxOn
+
+\definecolor{myyellow}{RGB}{173, 174, 0}
+\definecolor{mygreen}{RGB}{52, 174, 0}
+
+\let \\ \textbackslash
+\def \cmd#1{\textcolor{myyellow}{\textbf{\textbackslash}#1}}
+\def \spec#1 {\textcolor{red}{#1}}
+\def \letr#1 {\textcolor{mygreen}{#1}}
+\setlength{\parindent}{0pt}
+\frenchspacing   %  no double space after dot
+
+\catcode`␣\active    \def␣{\textbf{\textcolor{gray!60}{\char32}}}
+
+\ExplSyntaxOff
+\small%
+\obeylines%
+\texttt{
+> 123\spec\{4␣5\spec\}\cmd{6}
+> \spec{\#\&\textasciicircum\_}:
+> \cmd{error}
+> \letr{very␣long␣long␣long␣long␣long␣long␣long␣long␣long␣long␣long␣long␣long}
+> .. \letr{␣long␣argument}␣\cmd{argument} \cmd{argument} \cmd{test} 123456
+> \letr{very␣long␣long␣long␣long␣long␣long␣long␣long␣long␣long␣long␣long␣long}
+> .. \letr{␣long␣argument}␣\cmd{argument} \cmd{argument} \cmd{test} 123456
+> \spec{\#\&\textasciicircum}\letr{\_:}
+> \letr{abc}␣
+}\endgroup
+
+\subsection{Loading the package}
+
+\begin{verbatim}
+\usepackage{prettytok}
+\end{verbatim}
+
+\subsection{Options}
+
+There are several options that can be passed to the package.
+
+Usage example: |\usepackage[mode=term-shell]{prettytok}|.
+
+\begin{variable}{mode=}
+	Specify the working mode of the package, that is, where the output is displayed. It can either be:
+\begin{itemize}
+	\item |term-8bit|: this is the default.
+
+		Assume XTerm-compatible system, output to the terminal.
+
+		Requires |-8bit| option on engines other than \LuaTeX, see the following link: \\
+		\url{https://tex.stackexchange.com/q/168460/250119}.
+
+		Besides, this drops the distinction between the catcode of some tokens (for example \verb|{}$#&^_| are all shown as the same color as "special catcode"),
+		which is available in the tooltip in the HTML version.
+
+		This might work on Windows, although the package writer have not tested it.
+		Refer to \url{https://stackoverflow.com/q/2048509/5267751}
+		and \url{https://superuser.com/q/413073/577463}.
+
+	\item |term-shell|: 
+		To output colored text to the terminal, |--8bit| flag is needed otherwise the terminal escape codes will be
+		changed to |^^[| etc.
+		A workaround, using \TeX\ Live's behavior when the file name has the form \verb+|...+,
+		is provided with this option.
+
+		Requires |--shell-escape| flag. May not be very reliable.
+
+		Refer to \url{https://tex.stackexchange.com/a/670572/250119} for more details.
+
+	\item |html|: output to a HTML file named for example |pretty-abc.html| (although this can be customized,
+		refer to \hyperref[opt:html-file-name]{|html-file-name=|}%
+		) if the main \TeX\ file is named |abc.tex|.
+
+		Open the file in any browser to view the result.
+
+		Using this option, the output will not be cluttered with the traceback/other \TeX\ default output.
+
+By default, the output refreshes whenever the \TeX\ file is recompiled. The behavior
+can be customized with \hyperref[opt:html-refresh-strategy]{|html-refresh-strategy=|} and \hyperref[opt:html-refresh-duration]{|html-refresh-duration=|}.
+
+\end{itemize}
+\end{variable}
+
+Currently, it's not supported to print the debug output to the PDF itself,
+because if the \TeX\ program stops with error / has some error that corrupts the PDF output, the output will even with corrupted more by the debug print.
+
+\subsubsection{HTML configuration}
+
+These options are only meaningful if |mode=html|.
+
+\begin{variable}{html-file-name=}\label{opt:html-file-name}
+	The output file name. Defaults to |pretty-|\meta{jobname}|.html|, as mentioned above.
+\end{variable}
+
+\begin{variable}{html-refresh-strategy=}\label{opt:html-refresh-strategy}
+	The auto-refresh strategy. Allowed values are 0-4. 0 is no refresh. \\
+	Which value works best depends on the particular browser. \\
+	If you're using Google Chrome to view the output HTML,
+	invoking the browser from the command-line with |--allow-file-access-from-files| flag may be useful.
+\end{variable}
+
+\begin{variable}{html-refresh-duration=}\label{opt:html-refresh-duration}
+	The duration between two consecutive refresh check, in milliseconds. Defaults to 1000.
+\end{variable}
+
+\subsubsection{Terminal configuration}
+
+These options are only meaningful if |mode=term-8bit| or |mode=term-shell|.
+
+\begin{variable}{term-prefix=,term-prefix-more=}
+	Strings consist of prefixes to be output before each terminal line.
+
+	This might be useful for log-filtering/output-filtering tools such as |texfot| to recognize the output line.
+
+	Defaults to \verb*|> | and \verb*|> .. | respectively.
+\end{variable}
+
+\begin{variable}{term-wrap-limit=}
+	Estimated line length limit. Set this to a little smaller than your terminal width.
+
+	Defaults to 70.
+\end{variable}
+
+\begin{variable}{term-shell-decode-cmd=}
+	Only meaningful with |mode=term-shell|.
+
+	Normally you would not need to explicitly pass this option, unless something does not work.
+
+	By default, a file named \file{prettytok-decode-8bit.py}
+	should be included in your \TeX\ distribution, and
+	the package runs |kpsewhich prettytok-decode-8bit.py| to find the location
+	of that file in order to execute it.
+	However, if by any reason this does not work, you can specify an explicit command such as
+	|python3 /full/path/to/prettytok-decode-8bit.py| to override it.
+
+	Passing blank value invokes the default behavior (runs |kpsewhich|).
+
+	Alternatively, you can also choose to explicitly pass the path in order to save a call to |kpsewhich|
+	to make the program a bit faster.
+
+	If you \emph{really} want to, special characters may be passed by prefixing them with |\|.
+	\DisableQuotes
+	But |\"| won't work anyway (as far as the package writer know, this is impossible in non-\LuaTeX\ engines).
+	\EnableQuotes
+	\begin{texnote} The path is interpreted by detokenizing the value in |escapechar=-1|. \end{texnote}
+\end{variable}
+
+\begin{variable}{term-shell-decode-cmd-print=}
+	If |mode=term-shell|, print out the command correspond to |term-shell-decode-cmd| on the console, for debugging purpose.
+
+	Example output: 
+	|The value of term-shell-decode-cmd is: [[[./prettytok-decode-8bit.py]]]|
+\end{variable}
+
+
 \subsection{Main function}
 \begin{function}{\pretty:n,\pretty:x,\pretty:o,\pretty:V}
 	\begin{syntax}
@@ -35,93 +228,95 @@
 		\cs{pretty:n} \Arg{token list}
 	\end{syntax}
 	Print the content of \meta{token list}.
+
+	This is a simple replacement of the functions above. (|\tl_analysis_show:n|, etc.)
 \end{function}
 
-\begin{function}{\pretty:N,\pretty:c}
+\begin{function}{\pretty:w}
 	\begin{syntax}
-		\cs{pretty:N} \meta{token}
-		\cs{pretty:c} \Arg{control sequence name}
+		\cs{pretty:w} \meta{token list} \cs{prettystop}
 	\end{syntax}
-	Print \meta{token}.
+	Print the content of \meta{token list}.
+	
+The purpose of this function is that
+it can be inserted "anywhere" in order to \emph{inspect the input stream}
+without affecting how the function works.
 
-	This function is not very useful. Usually it's preferable to use |\pretty:V| to print a token list variable's value,
-	or |\prettyshow:N| to print a control sequence's meaning.
+Note that the input stream will be tokenized and has catcode frozen.
+
+For example
+\begin{verbatim}
+\ExplSyntaxOn
+\def \f #1 {\prettye:w 789}
+\f 123456 \prettystop
+\end{verbatim}
+will print out |78923456|.
+
+For now, it must be brace-balanced.  Use \cs{prettye:w} instead if this is a problem.
 \end{function}
 
-\begin{function}{\prettyinit:}
+\begin{function}[EXP]{\prettystop}
 	\begin{syntax}
-		\cs{prettyinit:}
+		\cs{prettystop}
 	\end{syntax}
-	Do necessary initialization.
-
-	This should be called right after the package is loaded, after setting the configuration variables described below.
+	Only used as a delimiter for |:w| functions. For convenience, this function is defined to do nothing.
 \end{function}
 
-\subsection{Expandable interface (\LuaTeX\ only)}
-
-\cs{prettyinit:} must be called before calling the functions in this section.
-
-\begin{function}[EXP]{\prettye:n}
+\begin{function}{\prettyshow:N,\prettyshow:c}
 	\begin{syntax}
-		\cs{prettye:n} \Arg{token list}
+		\cs{prettyshow:N} \meta{token}
+		\cs{prettyshow:c} \Arg{control sequence name}
 	\end{syntax}
-	Print the token list, similar to \cs{pretty:n}, but is fully expandable.
+	Show the meaning of a |N|-type argument.
 \end{function}
 
-\begin{function}[EXP]{\prettye:w}
+\begin{function}{\pretty:N,\pretty:c}
 	\begin{syntax}
-		\cs{prettye:w} \meta{tokens} \cs{prettystop}
+		\cs{pretty:N} \meta{token}
+		\cs{pretty:c} \Arg{control sequence name}
 	\end{syntax}
-	Print the tokens until \cs{prettystop} is seen. Useful for inspecting the content of the input stream.
+	Print \meta{token}.
 
-	Note that the input stream will be tokenized and has catcode frozen. Use with care.
+	It may also be useful to use |\pretty:V| to print a token list variable's value,
+	or |\prettyshow:N| to print a control sequence's meaning.
 \end{function}
 
-\subsection{Lua programming interface}
-
-\cs{prettyinit:} must also be called before calling the functions in this section.
-
-\begin{function}{prettyprint}
+\begin{function}{\pretty:nn, \pretty:nnn}
 	\begin{syntax}
-		|prettyprint(|\meta{content}|)|
+		\cs{pretty:nn} \Arg{token list} \Arg{token list}
+		\cs{pretty:nnn} \Arg{token list} \Arg{token list} \Arg{token list}
 	\end{syntax}
-	Print the content, which should be a table of token objects.
-
-	For convenience, you can pass multiple arguments. Strings are also supported.
+	Print multiple token lists. Its effect is similar to multiple consecutive calls to \cs{pretty:n}.
 \end{function}
 
 
-\subsection{View result}
 
-The result is printed to a HTML file named |pretty-|\meta{jobname}|.html| by default.
-Open the file in any browser to view the result.
 
-Note that the HTML file will not be touched if nothing is printed, as such it's encouraged to add a line such as |\pretty:n {start}| right after loading the file.
 
-Why HTML file?
 
-\begin{itemize}
-	\item If the \TeX\ program stops with error / has some error that corrupts the PDF output, the output will even with corrupted more by the debug print.
-	\item Printing to the console is extremely limited (difficult syntax highlighting/scrolling/line wrapping), and most likely cluttered with the traceback/other \TeX\ default output.
+\subsection{Expandable interface (\LuaTeX\ only)}
+\label{subsec:expandable-interface}
 
-		(nevertheless, there might be plan to support output to console with syntax highlighting later.)
-	\item Output to another \TeX\ file to be compiled works as well; however it's necessary to run another instance of |latexmk| (or other tool used to compile \TeX\ code)
-		and compiling \TeX\ file takes longer than loading a HTML file.
-\end{itemize}
+\begin{function}[EXP]{\prettye:n}
+	\begin{syntax}
+		\cs{prettye:n} \Arg{token list}
+	\end{syntax}
+	Print the token list, similar to \cs{pretty:n}, but is fully expandable.
+\end{function}
 
-By default, the output refreshes whenever the \TeX\ file is recompiled. The behavior
-can be customized with \cs{prettyrefreshstrategy} and \cs{prettyrefreshduration}.
+\begin{function}[EXP]{\prettye:w}
+	\begin{syntax}
+		\cs{prettye:w} \meta{tokens} \cs{prettystop}
+	\end{syntax}
+	Print the tokens until \cs{prettystop} is seen. Useful for inspecting the content of the input stream.
 
-\subsection{Additional functions}
+	As a debugging tool, it's possible to execute |\everyeof{\prettystop}| to avoid runaway printing in weird catcode environments.
 
-There are also these functions, for convenience.
+	Currently some implementation details (it can be fixed, but the package writer does not
+have an immediate need for it, see \url{https://tex.stackexchange.com/q/335994/250119}) means control sequences not
+in the hash table will be destroyed.
+Use with care.
 
-\begin{function}{\pretty:nn, \pretty:nnn}
-	\begin{syntax}
-		\cs{pretty:nn} \Arg{token list} \Arg{token list}
-		\cs{pretty:nnn} \Arg{token list} \Arg{token list} \Arg{token list}
-	\end{syntax}
-	Print multiple token lists. Its effect is similar to multiple consecutive calls to \cs{pretty:n}.
 \end{function}
 
 \begin{function}[EXP]{\prettye:nn, \prettye:nnn}
@@ -132,49 +327,63 @@
 	Similar to multiple consecutive calls to \cs{prettye:n}.
 \end{function}
 
-\begin{function}[EXP]{\prettye:nw, \prettye:nnw}
-	\begin{syntax}
-		\cs{prettye:nw} \Arg{token list} \meta{tokens} \cs{prettystop}
-		\cs{prettye:nnw} \Arg{token list} \Arg{token list} \meta{tokens} \cs{prettystop}
-	\end{syntax}
-	Similar to call(s) to \cs{prettye:n} followed by a call to \cs{prettye:w}.
-\end{function}
 
-\begin{function}{\pretty:w}
+
+\begin{function}[EXP]{\prettye:nw}
 	\begin{syntax}
-		\cs{pretty:w} \meta{token list} \cs{prettystop}
+		\cs{prettye:nw} \Arg{callback} \meta{tokens} \cs{prettystop}
 	\end{syntax}
-	Print the content of \meta{token list}.
+	Same as above, but has a callback, that is, code that is put in the input stream after the content is printed.
 
-	Same restriction applies -- the catcode is frozen.
+	Useful if you want to fine-tune what is printed exactly.
+	(\texttt{\cs{prettye:w} \meta{callback} \meta{tokens}} is functionally the same, but the callback
+	is also printed, which will clutter the debug output)
 
-	In addition -- for now, it must be brace-balanced and if \meta{token list} has a surrounding brace group it will be removed. Use \cs{prettye:w} instead if possible.
+	For example
+\begin{verbatim}
+\prettye:nw {\somecode ...} 123 \prettystop
+\end{verbatim}
+will print |123|, then after some expansion steps results in the input stream contain
+|\somecode ... 123 \prettystop|.
 \end{function}
 
-\begin{function}[EXP]{\prettystop}
+\begin{function}[EXP]{\prettye:nnw, \prettye:nnnw}
 	\begin{syntax}
-		\cs{prettystop}
+		\cs{prettye:nnw}  \Arg{callback} \Arg{token list} \meta{tokens} \cs{prettystop}
+		\cs{prettye:nnnw} \Arg{callback} \Arg{token list} \Arg{token list} \meta{tokens} \cs{prettystop}
 	\end{syntax}
-	Only used as a delimiter for |:w| functions. For convenience, this function is defined to do nothing.
+	Similar to call(s) to \cs{prettye:n} followed by a call to \cs{prettye:nw}.
+
+	For example
+\begin{verbatim}
+\prettye:nnw {\somecode ...} {123} 456 \prettystop
+\end{verbatim}
+will print |123456|, then, after some expansion steps, |\somecode ... 456 \prettystop| remains in the input stream.
 \end{function}
 
-\begin{function}{\prettyshow:N,\prettyshow:c}
+\subsection{Lua programming interface}
+
+\begin{function}{prettyprint}
 	\begin{syntax}
-		\cs{prettyshow:N} \meta{token}
-		\cs{prettyshow:c} \Arg{control sequence name}
+		|prettyprint(|\meta{content}|)|
 	\end{syntax}
-	Show the meaning of a |N|-type argument.
+	Print the content, which should be a table of token objects.
+
+	For convenience, you can pass multiple arguments. Strings are also supported.
 \end{function}
 
+
+
+
 \subsection{\LaTeXe\ interface}
 
-\begin{function}{\prettyN,\prettyX,\prettyO,\prettyV,\prettyinit,\prettyshowN,\prettyshowC}
+\begin{function}{\prettyN,\prettyX,\prettyO,\prettyV,\prettyW,\prettyshowN,\prettyshowC}
 	\begin{syntax}
 		\tn{prettyN} \Arg{token list}
 		\tn{prettyX} \Arg{token list}
 		\tn{prettyO} \Arg{token list}
 		\tn{prettyV} \meta{tl var}
-		\tn{prettyinit}
+		\cs{prettyW} \meta{token list} \cs{prettystop}
 		\tn{prettyshowN} \meta{token}
 		\tn{prettyshowC} \Arg{control sequence name}
 	\end{syntax}
@@ -190,33 +399,19 @@
 \end{function}
 
 
-\subsection{Customization}
+\section{Implementation}
 
-These variables can be redefined before the
-first call to \cs{pretty:n} or \cs{prettyinit:} to customize the behavior.
+Unfortunately, the implementation is not typesetted in \TeX. Read the |.sty| file.
 
-\begin{variable}{\prettyfilename}
-	The output file name. Defaults to |pretty-|\meta{jobname}|.html|, as mentioned above.
-\end{variable}
+Remark: it's possible to do expandable printing in other engines as well by, for example, turning on |\tracingmacros|, parse the token list somehow
+(and use some not-always-exact logic to distinguish normal character and active character with same meaning;
+then grep the resulting log file for special markers.
 
-\begin{variable}{\prettyrefreshstrategy}
-	The auto-refresh strategy. Allowed values are 0-4. 0 is no refresh. \\
-	Which value works best depends on the particular browser. \\
-	On Google Chrome, passing |--allow-file-access-from-files| may be useful.
-\end{variable}
+But that would be very, very slow and slows down everything else by turning on logging. Just use \LuaTeX\ for debugging.
 
-\begin{variable}{\prettyrefreshduration}
-	The duration between two consecutive refresh check, in milliseconds. Defaults to 1000.
-\end{variable}
+There's another option of recompiling the engine and adding some expandable primitive for debug logging...
 
-\section{Implementation}
-
-Unfortunately, the implementation is not typesetted in \TeX. Read the |.sty| file.
-
-\StopEventually{^^A
-	\PrintChanges
-	\PrintIndex
-}
-
+\PrintChanges
+\PrintIndex
 \Finale
 \end{document}

Added: trunk/Master/texmf-dist/doc/latex/prettytok/prettytok_template.html
===================================================================
--- trunk/Master/texmf-dist/doc/latex/prettytok/prettytok_template.html	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/prettytok/prettytok_template.html	2023-04-18 19:40:32 UTC (rev 66884)
@@ -0,0 +1,317 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<link rel="icon" href="data:,">
+<style>
+body{
+	background-color: black;
+	color: white;
+}
+
+/* https://stackoverflow.com/questions/7011602/stretching-iframe-in-html5 */
+#wrap_all { display: none; position:fixed; width:100%; height:100%; top: 0px; left: 0px; }
+
+
+iframe{
+	position: absolute;
+	width: 100%;
+	height: 100%;
+	display: none;
+}
+#status{
+	flex: 0 0 1.3em;
+}
+
+#display_wrap{
+	flex: 1 0 auto;
+}
+#controller{
+	flex: 0 0 50px;
+}
+
+.control-button{
+}
+
+
+
+.tokenlist, .fileline{
+	border: 1px solid gray;
+  padding: 2px;
+  line-height: 1.5em;
+}
+
+.fileline{
+	background-color: #404040;
+}
+
+.explicit_char_target{
+	background-color: #FF8080;
+}
+.explicit_char{
+	background-color: #606060;
+}
+
+
+.cs, .active_char{
+	color: #FFFF00;
+}
+
+#popup{
+	display: none;
+	position: absolute;
+	border: 1px solid gray;
+	background-color: #000080ff;
+}
+
+.cmd__left_brace_cmd, .cmd__right_brace_cmd, .cmd__mac_param_cmd, .frozenrelax{
+	color: #FFAAAA;
+}
+.cmd__out_param_cmd{
+	border: 1px solid #FFAAAA;
+}
+.out_param_expansion{
+	border: 1px solid #FFAAAA;
+	background-color: #000080;
+}
+.cmd__out_param_cmd::before{
+	content: "#";
+}
+
+.cmd__letter_cmd{
+	color: #AAFFAA;
+}
+
+.cmd__spacer_cmd{
+	color: #606060;
+}
+
+
+input[type=button]{
+	color: white;
+	background-color: #0000ff;
+	border: 0;
+}
+
+#log{
+	display: flex;
+	flex-direction: column-reverse;
+	flex: 0 0 30%;
+	overflow: scroll;
+}
+
+/*
+   hack to make it display as ␣ but copy-paste (or search) as space
+*/
+.space_charcode{
+  font-size: 0pt;
+}
+
+.space_charcode::before{
+  font-size: medium;
+  content: "␣";
+}
+</style>
+</head>
+<body>
+
+	<div id=output></div>
+	<div id=wrap_all>
+		<iframe id=iframe src="about:blank" frameborder=0></iframe>
+		<iframe id=iframe2 src="about:blank" frameborder=0></iframe>
+	</div>
+	<script>
+"use strict"
+
+function show_html_except_space(s){
+	return s
+		.replace(/\r|\n/g, "↵")
+		.replace(/\t/g, "⇥")
+}
+
+function show_html(s){
+	return show_html_except_space(s).replace(/ /g, "␣")
+}
+
+output.innerHTML=""
+
+function print_tl(...tokens){
+	const tl_div=document.createElement("div")
+	tl_div.classList.add("tokenlist")
+	for(let token of tokens){
+		tl_div.appendChild(token)
+		if({13: true, 10: true}[token.data_charcode]){
+			tl_div.appendChild(document.createElement("br"))
+    }else{
+      tl_div.appendChild(document.createElement("wbr"))
+    }
+	}
+	output.appendChild(tl_div)
+}
+
+function token(charcode /* int */, catcode /* single character string in hex */){
+	const token_span=document.createElement("span")
+	const ch=String.fromCodePoint(charcode)
+	token_span.innerText=show_html_except_space(ch)
+	token_span.data_charcode=charcode
+  if(charcode==32){  // special handle space here
+    token_span.classList.add("space_charcode")
+  }
+	if(catcode==='D'){
+		token_span.classList.add("active_char")
+		token_span.title=`active ${ch} # ${charcode}`
+	}else{
+		const cls={
+			1: 'cmd__left_brace_cmd',
+			2: 'cmd__right_brace_cmd',
+			3: 'cmd__math_shift_cmd',
+			4: 'cmd__tab_mark_cmd',
+			6: 'cmd__mac_param_cmd',
+			7: 'cmd__sup_mark_cmd',
+			8: 'cmd__sub_mark_cmd',
+			A: 'cmd__spacer_cmd',
+			B: 'cmd__letter_cmd',
+			C: 'cmd__other_char_cmd',
+		}[catcode]
+		token_span.classList.add("token", cls)
+		token_span.title=`${cls} ${ch} # ${charcode}`
+	}
+	return token_span
+}
+
+function cs(...codepoints){
+	const token_span=document.createElement("span")
+
+	const control_sequence_name=String.fromCodePoint(...codepoints)
+	//const meaning_str=readstr()
+
+  /*
+	token_span.innerText='\\' + show_html(control_sequence_name) + ' '
+  */
+
+  var items=control_sequence_name.split(' ')
+  items[0]="\\"+items[0]
+  items[items.length-1]+=' '
+  for(var i=0; i<items.length; i++){
+    if(i!=0){  // append a '␣' span that copy-paste as a space
+      var space_span=document.createElement("span")
+      space_span.innerText=' '
+      space_span.classList.add("space_charcode")
+      token_span.appendChild(space_span)
+    }
+
+    // append the text itself
+    if(items[i]!="")
+      token_span.appendChild(new Text(show_html_except_space(items[i])))
+  }
+
+  //token_span.title=`cs '${control_sequence_name}' → ${meaning_str}`
+	token_span.classList.add("cs")
+
+	return token_span
+}
+
+function csfrozenrelax(){
+	const token_span=document.createElement("span")
+	token_span.innerText="\\relax"
+	token_span.title="frozen relax"
+	token_span.classList.add("cs", "frozenrelax")
+	return token_span
+}
+
+var refresh_strategy_already_set=false
+function set_refresh_strategy(strategy, duration){
+	if(refresh_strategy_already_set) return
+	refresh_strategy_already_set=true
+
+	switch(strategy){
+		case 0: // do nothing
+			return
+
+		case 1: // refresh the sub-iframe
+			if(window.parent===window){
+				print_tl=function(...x) {}
+				//output.style.display="none"
+				iframe.src=location.href
+				iframe.style.display="block"
+				wrap_all.style.display="block"
+				setInterval(function(){
+					iframe.src=iframe.src
+				}, duration)
+			}
+			return
+
+		case 2: // refresh two sub-iframes
+			if(window.parent===window){
+				print_tl=function(...x) {}
+				//output.style.display="none"
+				iframe.src=iframe2.src=location.href
+				iframe.style.display="block"
+				iframe2.style.display="block"
+				wrap_all.style.display="block"
+				async function sleep(ms){
+					await new Promise(resolve=>setTimeout(resolve, ms))
+				}
+				(async function(){
+					while(true){
+						await sleep(duration/2)
+						iframe.src=iframe.src
+
+						await sleep(duration/2)
+						iframe2.style.zIndex=1
+						iframe.style.zIndex=2
+
+						await sleep(duration/2)
+						iframe2.src=iframe2.src
+
+						await sleep(duration/2)
+						iframe.style.zIndex=1
+						iframe2.style.zIndex=2
+					}
+				})()
+			}
+			return
+
+		case 3: // refresh whole page
+			setTimeout(function(){
+				location.reload()
+			}, duration)
+			return
+
+		case 4: // request own file
+			window.addEventListener("load", async function(){
+				async function get_code(){
+					//let text=await (await fetch(location.href)).text()
+					let text=await new Promise(function(resolve){
+						let request = new XMLHttpRequest();
+						request.responseType = "text"
+						request.onload = function() {
+							resolve(request.responseText) 
+						}
+						request.onerror = function() {
+							console.log("Error happened. Read documentation for more details.")
+						}
+						request.open("GET", location.href, true)
+						request.send()
+					})
+					return text.replace(/.*?-end-template()-/s, "")
+				}
+				let text=await get_code()
+				output.innerHTML=""
+				try{ eval(text) }catch(e) {}
+				setInterval(async function(){
+					let text2=await get_code()
+					if(text2!==text){
+						output.innerHTML=""
+						try{ eval(text2) }catch(e) {}
+						text=text2
+					}
+				}, duration)
+			})
+			return
+	}
+}
+	</script>
+
+<script>
+// -end-template-


Property changes on: trunk/Master/texmf-dist/doc/latex/prettytok/prettytok_template.html
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/tex/latex/prettytok/prettytok-decode-8bit.py
===================================================================
--- trunk/Master/texmf-dist/tex/latex/prettytok/prettytok-decode-8bit.py	                        (rev 0)
+++ trunk/Master/texmf-dist/tex/latex/prettytok/prettytok-decode-8bit.py	2023-04-18 19:40:32 UTC (rev 66884)
@@ -0,0 +1,12 @@
+#!/bin/python3
+"""
+A hack to allow decoding for example ^^[ to the proper escape sequence.
+"""
+
+import sys
+import re
+def replace_8bit(match_: re.Match) -> str:
+	return chr(ord(match_.group(1))^0x40)
+if __name__ == '__main__':
+	for line in sys.stdin:
+		sys.stdout.write(re.sub(r"\^\^(.)", replace_8bit, line))


Property changes on: trunk/Master/texmf-dist/tex/latex/prettytok/prettytok-decode-8bit.py
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Modified: trunk/Master/texmf-dist/tex/latex/prettytok/prettytok.lua
===================================================================
--- trunk/Master/texmf-dist/tex/latex/prettytok/prettytok.lua	2023-04-18 19:40:07 UTC (rev 66883)
+++ trunk/Master/texmf-dist/tex/latex/prettytok/prettytok.lua	2023-04-18 19:40:32 UTC (rev 66884)
@@ -6,8 +6,8 @@
 -- public API :: once the package is loaded, this holds the .tok value of the frozen relax token
 prettyprint_frozenrelaxtok=nil
 
+
 local function prettyprint_one_arg(tokenlist)
-
 	if looks_like_token(tokenlist) then
 		return prettyprint_one_arg({tokenlist})
 	end
@@ -46,8 +46,9 @@
 					s=s.."csfrozenrelax(),"
 				else
 					s=s.."cs("
-					for j=1, #t.csname do
-						s=s..t.csname:byte(j)..","
+					-- TODO
+					for _, c in utf8.codes(t.csname) do
+						s=s..c..","
 					end
 					s=s.."),"
 				end
@@ -58,41 +59,192 @@
 	return s
 end
 
-local function check_file_opened()
-	-- if it's \relax then get_macro() also returns nil
-	if token.get_macro("pretty_check_already_init:") == nil then
-		error("Output file not initialized!")
-	end
+local function get_output_format()
+	return token.get_macro "_prettytok_mode"
 end
 
 local function get_file_number()
-	check_file_opened()
-	return token.get_mode(token.create("__prettyh_file"))
+	return token.get_mode(token.create("_prettytok_file"))
 end
 
 function prettyprint(...)
-	local prettyfilenumber=get_file_number()
+	local output_format=get_output_format()
+	local args={...}
+	if output_format=="html" then
+		local prettyfilenumber=get_file_number()
 
-	local s="print_tl("
-	local args={...}
-	for i=1, select("#", ...) do
-		s=s..prettyprint_one_arg(args[i])
+		local s="print_tl("
+		for i=1, select("#", ...) do
+			s=s..prettyprint_one_arg(args[i])
+		end
+
+		texio.write(prettyfilenumber, s..")//</script><script>\n")
+	else
+		assert(output_format=="term-8bit" or output_format=="term-shell")
+		texio.write_nl("")
+
+		local content=""
+		local content_len=0  -- only count visible content
+
+		local function typeout_content()
+			print(content)
+			content=""
+			content_len=0
+		end
+
+		local function append_content(s)  -- only call this on content that takes visible width. For example don't use this to set color
+			assert(type(s)=="string")
+			content=content..s
+			content_len=content_len+utf8.len(s)
+		end
+
+		append_content(token.get_macro "prettytermprefix")
+		local wraplimit=tonumber(token.get_macro "prettytermwraplimit")
+
+		---- color
+
+		--[[
+		local gray  ='\x1b[90m'
+		local red   ='\x1b[31m'
+		local green ='\x1b[38;5;121m'
+		local yellow='\x1b[93m'
+		local white ='\x1b[0m'
+		]]
+
+		local gray  =token.get_macro "_prettytok_gray"
+		local red   =token.get_macro "_prettytok_red"
+		local green =token.get_macro "_prettytok_green"
+		local yellow=token.get_macro "_prettytok_yellow"
+		local white =token.get_macro "_prettytok_white"
+
+		local current_color=white
+		local function setcolor(c)
+			if current_color~=c then
+				current_color=c
+				content=content..c
+			end
+		end
+
+		local prettytermprefixmore=token.get_macro "prettytermprefixmore"
+
+		local function check_wrap()
+			if content_len>wraplimit then
+				if current_color~=white then
+					content=content..white
+				end
+				print(content)
+				
+				content=""
+				content_len=0
+				append_content(prettytermprefixmore)
+				if current_color~=white then
+					content=content..current_color
+				end
+			end
+		end
+
+		local function prettyprint_term_one_arg(tokenlist)
+			if looks_like_token(tokenlist) then
+				return prettyprint_term_one_arg({tokenlist})
+			end
+
+
+			local function print_term_char(code)
+				if code<27 then
+					if code==9 then
+						append_content("⇥")
+					else
+						append_content("^^"..string.char(code+64))
+						if code==13 or code==10 then
+							typeout_content()
+							append_content(prettytermprefixmore)  -- color the prefix with the same color
+						end
+					end
+				elseif code==32 then
+					append_content("␣")
+				else
+					append_content(utf8.char(code))  -- unlike TeX implementation currently this does not show ^^⟨hex digits⟩ representation
+				end
+			end
+
+
+			local function printstring(t)
+				-- this is just for debugging/convenience purpose. If the item is a string instead of a token...
+				t=tostring(t)
+				for _, c in utf8.codes(t) do
+					if c==32 then
+						setcolor(gray)
+						append_content("␣")
+					else
+						setcolor(white)
+						append_content(utf8.char(c))
+					end
+				end
+			end
+
+			if type(tokenlist)~="table" then
+				-- user give a string (or something similar). Print it as detokenized characters
+				printstring(tokenlist)
+				check_wrap()
+			
+			else
+
+				-- normal print of tokenlist
+				for i=1, #tokenlist do
+					local t=tokenlist[i]
+					if not looks_like_token(t) then
+						printstring(t)
+						check_wrap()
+					elseif t.csname==nil then
+						setcolor(({left_brace=red, right_brace=red, math_shift=red, tab_mark=red, mac_param=red, sup_mark=red, sub_mark=red, spacer=gray, letter=green, other_char=white})[t.cmdname])
+						print_term_char(t.mode)
+						check_wrap()
+					else
+						if t.active then
+							setcolor(yellow)
+							print_term_char(utf8.codepoint(t.csname))
+						elseif t.tok==prettyprint_frozenrelaxtok then
+							setcolor(red)
+							append_content("\\relax ")
+						else
+							setcolor(yellow)
+							append_content("\\")
+							for _, c in utf8.codes(t.csname) do
+								print_term_char(c)
+							end
+							append_content(" ")
+						end
+						check_wrap()
+					end
+				end
+				
+			end
+		end
+
+		for i=1, select("#", ...) do
+			prettyprint_term_one_arg(args[i])
+		end
+
+		setcolor(white)
+
+		typeout_content()
 	end
-
-	texio.write(prettyfilenumber, s..")//</script><script>\n")
 end
 
 function prettyprintw()
-	check_file_opened()
+	local callback=token.scan_toks()
 	local extra=token.scan_toks()
 	local s={}
+	local last_token
 	while true do
-		local n=token.get_next()
-		s[#s+1]=n
-		if n.csname=="prettystop" then break end
+		last_token=token.get_next()
+		if last_token.csname=="prettystop" then break end
+		s[#s+1]=last_token
+		callback[#callback+1]=last_token
 	end
 
-	prettyprint(extra, s)
-	token.put_next(s)
+	prettyprint(extra, s)  -- exclude the \prettystop token
+	callback[#callback+1]=last_token
+	token.put_next(callback)
 end
 end

Modified: trunk/Master/texmf-dist/tex/latex/prettytok/prettytok.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/prettytok/prettytok.sty	2023-04-18 19:40:07 UTC (rev 66883)
+++ trunk/Master/texmf-dist/tex/latex/prettytok/prettytok.sty	2023-04-18 19:40:32 UTC (rev 66884)
@@ -1,5 +1,5 @@
 % File: prettytok.sty
-% Copyright 2022 user202729
+% Copyright 2022-2023 user202729
 %
 % This work  may be  distributed and/or  modified under  the conditions  of the
 % LaTeX Project Public License (LPPL),  either version 1.3c  of this license or
@@ -12,33 +12,60 @@
 % 
 % The Current Maintainer of this work is user202729.
 
-\ProvidesExplPackage{prettytok}{2022/07/08}{0.0.1}{Pretty-print token list}
+\ProvidesExplPackage{prettytok}{2023-04-18}{0.2.0}{Pretty-print token list}
 \RequirePackage{precattl}
+\RequirePackage{l3keys2e}
 
 
+\keys_define:nn{prettytok}{
+	mode.choices:nn={ term-8bit, term-shell, html }{
+		\str_set:Nx \_prettytok_mode {\l_keys_choice_tl}
+	},
+	mode.initial:n = { term-8bit },
+
+	ignore-tlanalysis-bug.bool_set:N=\_prettytok_ignore_tlanalysis_bug,
+
+	term-shell-decode-cmd.tl_set:N=\_prettytok_term_shell_decode_cmd,
+	term-shell-decode-cmd.initial:n={},
+	term-shell-decode-cmd-print.bool_set:N=\_prettytok_term_shell_decode_cmd_print,
+
+	html-file-name.tl_set:N=\_prettytok_html_file_name,
+	html-file-name.initial:x={pretty-\jobname.html},
+	html-refresh-strategy.tl_set:N=\_prettytok_html_refresh_strategy,
+	html-refresh-strategy.initial:n=4,
+	html-refresh-duration.tl_set:N=\_prettytok_html_refresh_duration,
+	html-refresh-duration.initial:n=1000,
+
+	term-prefix.tl_set:N=\prettytermprefix,
+	term-prefix.initial:n={>~},
+	term-prefix-more.tl_set:N=\prettytermprefixmore,
+	term-prefix-more.initial:n={>~ ..~},
+	term-wrap-limit.tl_set:N=\prettytermwraplimit,
+	term-wrap-limit.initial:n=70,
+
+}
+\ProcessKeysOptions{prettytok}
+
+
 % ======== check tl_analysis bug.
-\msg_new:nnn {prettytok} {tl-analysis-bug}
-	{
-		Because~of~an~tl-analysis~bug~(see~https://github.com/latex3/latex3/issues/1073),~functions~will~not~be~usable~inside~tl-analysis~functions!~
-		Upgrade~your~LaTeX~version,~or~
-		define~macro~"prettyignoretlanalysisbug"~before~loading~the~package~to~ignore~this~error.
-	}
-
-\ifdefined \prettyignoretlanalysisbug
-	\relax
-\else
-\begingroup
-	\tl_set:Nn \__test {}
+\bool_if:NF \_prettytok_ignore_tlanalysis_bug {
+	\tl_set:Nn \_prettytok_test {}
 	\tl_analysis_map_inline:nn {ab} {
 		\tl_analysis_map_inline:nn {cd} {
-			\tl_put_right:Nx \__test {#1 ##1 .}
+			\tl_put_right:Nx \_prettytok_test {#1 ##1 .}
 		}
 	}
-	\tl_if_eq:NnF \__test {ac.ad.bc.bd.} {
+	\tl_if_eq:NnF \_prettytok_test {ac.ad.bc.bd.} {
+		\msg_new:nnn {prettytok} {tl-analysis-bug}
+		{
+			Because~of~an~tl-analysis~bug~(see~https://github.com/latex3/latex3/issues/1073),~
+			functions~will~not~be~usable~inside~tl-analysis~functions!~
+			Upgrade~your~LaTeX~version,~or~
+			pass-option~"ignore-tlanalysis-bug"~to~ignore~this~error.
+		}
 		\msg_error:nn {prettytok} {tl-analysis-bug}
 	}
-\endgroup
-\fi
+}
 
 % ======== load Lua module.
 \sys_if_engine_luatex:T{
@@ -49,7 +76,6 @@
 }
 
 % ======== main code start.
-
 \cs_generate_variant:Nn \exp_args:NNn {NNx}
 \cs_generate_variant:Nn \iow_open:Nn {NV}
 \cs_generate_variant:Nn \exp_args:NNn {NNV}
@@ -59,90 +85,241 @@
 \cs_generate_variant:Nn \use:N {c}
 \cs_generate_variant:Nn \str_map_inline:nn {xn}
 \cs_generate_variant:Nn \tl_build_put_right:Nn {Nx}
+\cs_generate_variant:Nn \tl_build_put_right:Nn {NV}
 \cs_generate_variant:Nn \iow_now:Nn {NV}
 
-\iow_new:N \_prettytok_file
-\ior_new:N \_prettytok_input_template_file
 
+\str_if_eq:VnTF \_prettytok_mode {html} {
+	\iow_new:N \_prettytok_file
+	\ior_new:N \_prettytok_input_template_file
 
-\exp_args:NNx \providecommand \prettyfilename {pretty-\jobname.html}
-\providecommand \prettyrefreshstrategy {4}
-\providecommand \prettyrefreshduration {1000}
+	\iow_open:NV \_prettytok_file \_prettytok_html_file_name
 
-\msg_new:nnn {prettytok} {already-initialized} {Output~file~is~already~initialized!} 
+	\precattl_exec:n{
+	% write the template
+	\ior_open:Nn \_prettytok_input_template_file {prettytok_template.html}
+	\ior_str_map_variable:NNn \_prettytok_input_template_file \_prettytok_line {
+		\str_replace_all:Nnn \_prettytok_line {\cO\^^I} {~}  % workaround: XeTeX prints literal tab character as ^^I which obviously breaks JavaScript
+		\iow_now:NV \_prettytok_file \_prettytok_line
+	}
+	\ior_close:N \_prettytok_input_template_file
 
+	% refresh strategy
+	\iow_now:Nx \_prettytok_file {set_refresh_strategy(\_prettytok_html_refresh_strategy,\_prettytok_html_refresh_duration)}
 
-% See also Lua function: local function check_file_opened()
+	\cs_new_protected:Npn \pretty:n #1 {
 
-\global\let \pretty_check_already_init: \relax
+		% ======== the actual content. Collect to one \write to put them on the same line (also maybe for efficiency???)
+		\tl_build_begin:N \_prettytok_content
+		\tl_build_put_right:Nn \_prettytok_content {print_tl(}
+		\tl_analysis_map_inline:nn {#1} {
+			% by documentation of \tl_analysis_map_inline:nn: #1=token, #2=char code, #3=catcode
+			\int_compare:nNnTF {##2} = {-1} {
+				% token is control sequence
+				\tl_if_eq:onTF {##1} {\cFrozenRelax} {
+					\tl_build_put_right:Nn \_prettytok_content {csfrozenrelax(),}
+				} {
+					\tl_build_put_right:Nn \_prettytok_content {cs(}
+					\tl_if_eq:xoF {\use:c {}} {##1} {
+						\str_map_inline:xn {\exp_after:wN \cs_to_str:N ##1} {  % side note, must use str here to preserve spaces
+							\tl_build_put_right:Nx \_prettytok_content {\int_eval:n {`####1},}
+						}
+					}
+					\tl_build_put_right:Nn \_prettytok_content {),}
+				}
+			}
+			{
+				% token is not control sequence
+				\tl_build_put_right:Nn \_prettytok_content {token(##2, "##3"),}
+			}
+		}
+		\tl_build_put_right:Nn \_prettytok_content {)//</script><script>}
+		\tl_build_end:N \_prettytok_content
+		\iow_now:NV \_prettytok_file \_prettytok_content
+	}
+	}
 
-\precattl_exec:n {
-	\cs_new_protected:Npn \_prettyinit_unchecked: {
-		\global\protected\def \pretty_check_already_init: {\msg_error:nn {prettytok} {already-initialized}}
+} {
+	\str_if_eq:VnTF \_prettytok_mode {term-shell} {
+		\newwrite \_prettytok_typeout_stream
+		\tl_if_empty:NTF \_prettytok_term_shell_decode_cmd {
+			\sys_get_shell:nnN {kpsewhich~ prettytok-decode-8bit.py} {\cctab_select:N \c_other_cctab} \_prettytok_term_shell_decode_cmd
+		} {
+			\begingroup
+				\escapechar=-1~
+				\str_gset:NV \_prettytok_term_shell_decode_cmd \_prettytok_term_shell_decode_cmd
+			\endgroup
+		}
+		\bool_if:NT \_prettytok_term_shell_decode_cmd_print {
+			\typeout{^^JThe~ value~ of~ term-shell-decode-cmd~ is:~ [[[\_prettytok_term_shell_decode_cmd]]]^^J}
+		}
+		\immediate \openout \_prettytok_typeout_stream = {|\_prettytok_term_shell_decode_cmd}
+	} {
+		\int_const:Nn \_prettytok_typeout_stream {128}  % 16 works except on LuaLaTeX
+	}
 
-		\iow_open:NV \_prettytok_file \prettyfilename
 
-		% write the template
-		\begingroup
-			\ior_open:Nn \_prettytok_input_template_file {prettytok_template.html}
-			\ior_str_map_variable:NNn \_prettytok_input_template_file \_prettytok_line {
-				\str_replace_all:Nnn \_prettytok_line {\cO\^^I} {~}  % workaround: XeTeX prints literal tab character as ^^I which obviously breaks JavaScript
-				\iow_now:NV \_prettytok_file \_prettytok_line
-			}
-			\ior_close:N \_prettytok_input_template_file
-		\endgroup
+	\precattl_exec:n{
+	\str_gset:Nn \_prettytok_gray {\cO\^^[[90m}
+	\str_gset:Nn \_prettytok_red {\cO\^^[[31m}
+	\str_gset:Nn \_prettytok_green {\cO\^^[[38;5;121m}  % this is the color vim use for green on my machine. Anyway~
+	%\str_gset:Nn \_prettytok_green {\cO\^^[[92m}
+	\str_gset:Nn \_prettytok_yellow {\cO\^^[[93m}
+	%\str_gset:Nn \_prettytok_white {\cO\^^[[0m}  % i.e. the default
+	\str_gset:Nn \_prettytok_white {\cO\^^[[97m}  % vim terminal has a quirk that if a line wraps, the status at the start of the line is considered "default" for that line, so need to explicitly specify color as white
 
-		% refresh strategy
-		\iow_now:Nx \_prettytok_file {set_refresh_strategy(\prettyrefreshstrategy,\prettyrefreshduration)}
+	% https://stackoverflow.com/q/4842424/5267751
+
+	\cs_new_protected:Npn \_prettytok_setcolor:N #1 {
+		\ifx \_prettytok_current_color #1
+		\else
+			\let \_prettytok_current_color #1
+			\tl_build_put_right:NV \_prettytok_content #1
+		\fi
 	}
 
-	\cs_new_protected:Npn \prettyinit: {
-		\pretty_check_already_init:
-		\_prettyinit_unchecked:
+	% caller should call \_prettytok_check_wrap: when useful.
+	\cs_new_protected:Npn \_prettytok_term_prepare_print_char:n #1 {
+		\_prettytok_append_content:x {
+			\ifnum #1 < 27 ~
+				\ifnum #1 = 9 ~  % tab
+					\cO{⇥}
+				\else
+					\cO{\^\^} \char_generate:nn {#1+64} {12}
+					\bool_if:nT {\int_compare_p:nNn {#1} = {13} || \int_compare_p:nNn {#1} = {10}} {
+						\cO{^^J} \prettytermprefixmore
+					}
+				\fi
+			\else
+				\ifnum #1 = 32 ~
+					\cO{␣}
+				\else
+					\bool_if:nTF {\int_compare_p:nNn {#1} > {32} && \int_compare_p:nNn {#1} < {127}} {  % printable ASCII character
+						\char_generate:nn {#1} {12}
+					} {
+						\ifnum #1 < "100 ~
+							^ ^
+							\expandafter \@gobble \exp:w \exp_end_continue_f:w \int_to_hex:n {"100+#1}  % convert to hex, exactly 2 digits (by adding 100 then delete first '1')
+						\else
+							\ifnum #1 < "10000 ~
+								^ ^ ^ ^
+								\expandafter \@gobble \exp:w \exp_end_continue_f:w \int_to_hex:n {"10000+#1}  % convert to hex, exactly 4 digits
+							\else
+								^ ^ ^ ^ ^ ^
+								\expandafter \@gobble \exp:w \exp_end_continue_f:w \int_to_hex:n {"1000000+#1}  % convert to hex, exactly 6 digits
+							\fi
+						\fi
+					}
+				\fi
+			\fi
+		}
 	}
-}
+	\cs_generate_variant:Nn \_prettytok_term_prepare_print_char:n {x}
 
-\cs_new_eq:NN \prettyinit \prettyinit:
+	\int_new:N \_prettytok_content_len
 
+	% only call this on content that takes visible width. For example don't use this to set color
+	\cs_new_protected:Npn \_prettytok_append_content:n #1 {
+		\tl_build_put_right:Nn \_prettytok_content {#1}
+		\int_add:Nn \_prettytok_content_len {\str_count:n {#1}}
+	}
 
-\precattl_exec:n {
+	\cs_generate_variant:Nn \_prettytok_append_content:n {V,x}
 
+	\cs_new_protected:Npn \_prettytok_check_wrap: {
+		\int_compare:nNnT {\_prettytok_content_len} > {\prettytermwraplimit} {
+			% be careful to not color the \prettytermprefixmore part
+			\ifx \_prettytok_current_color \_prettytok_white
+			\else
+				\tl_build_put_right:NV \_prettytok_content \_prettytok_white
+			\fi
+			\tl_build_end:N \_prettytok_content
+			\_prettytok_typeout_content:
 
+			\tl_build_begin:N \_prettytok_content
+			\int_zero:N \_prettytok_content_len
+			\_prettytok_append_content:V \prettytermprefixmore
+			\ifx \_prettytok_current_color \_prettytok_white
+			\else
+				\tl_build_put_right:NV \_prettytok_content \_prettytok_current_color
+			\fi
+		}
+	}
+
+	% \_prettytok_content must have been called \tl_build_end:N on before this function is called
+	\sys_if_engine_luatex:TF {
+		\cs_new_protected:Npn \_prettytok_typeout_content: {
+			\directlua{
+				texio.write_nl("") 
+				print(token.get_macro("_prettytok_content"))
+			} % https://tex.stackexchange.com/questions/64462/lualatex-print-directlua-env-and-newlinehttps://tex.stackexchange.com/questions/64462/lualatex-print-directlua-env-and-newline
+		}
+	} {
+		\cs_new_protected:Npn \_prettytok_typeout_content: {
+			\immediate\write\_prettytok_typeout_stream{\_prettytok_content}
+		}
+	}
+
 	\cs_new_protected:Npn \pretty:n #1 {
+		\tl_build_begin:N \_prettytok_content
+		\int_zero:N \_prettytok_content_len
+		\_prettytok_append_content:V \prettytermprefix
 
-		% ======== first write out the preamble if it isn't written. Only do once.
-		\ifx \pretty_check_already_init: \relax \prettyinit: \fi
+		\let \_prettytok_current_color \_prettytok_white
 
-		% ======== the actual content. Collect to one \write to put them on the same line (also maybe for efficiency???)
-		\tl_build_begin:N \_prettytok_content
-		\tl_build_put_right:Nn \_prettytok_content {print_tl(}
 		\tl_analysis_map_inline:nn {#1} {
 			% by documentation of \tl_analysis_map_inline:nn: #1=token, #2=char code, #3=catcode
 			\int_compare:nNnTF {##2} = {-1} {
 				% token is control sequence
 				\tl_if_eq:onTF {##1} {\cFrozenRelax} {
-					\tl_build_put_right:Nn \_prettytok_content {csfrozenrelax(),}
+					\_prettytok_setcolor:N \_prettytok_red
+					\_prettytok_append_content:n { \cO\\relax~ }
 				} {
-					\tl_build_put_right:Nn \_prettytok_content {cs(}
+					\_prettytok_setcolor:N \_prettytok_yellow
+					\_prettytok_append_content:n { \cO\\ }
 					\tl_if_eq:xoF {\use:c {}} {##1} {
 						\str_map_inline:xn {\exp_after:wN \cs_to_str:N ##1} {  % side note, must use str here to preserve spaces
-							\tl_build_put_right:Nx \_prettytok_content {\int_eval:n {`####1},}
+							\_prettytok_term_prepare_print_char:x {\int_eval:n {`####1}}
 						}
 					}
-					\tl_build_put_right:Nn \_prettytok_content {),}
+					\_prettytok_append_content:n {~}
+					\_prettytok_check_wrap:  % here we do not wrap in the middle of a csname
 				}
 			}
 			{
 				% token is not control sequence
-				\tl_build_put_right:Nn \_prettytok_content {token(##2, "##3"),}
+				\if ##3 B   % letter
+					\_prettytok_setcolor:N \_prettytok_green
+				\else
+					\if ##3 A   % spacer
+						\_prettytok_setcolor:N \_prettytok_gray
+					\else
+						\if ##3 D  % active
+							\_prettytok_setcolor:N \_prettytok_yellow
+						\else
+							\if ##3 C   % other cat
+								\_prettytok_setcolor:N \_prettytok_white
+							\else  % something else.
+								\_prettytok_setcolor:N \_prettytok_red
+							\fi
+						\fi
+					\fi
+				\fi
+
+				\_prettytok_term_prepare_print_char:n {##2}
+				\_prettytok_check_wrap:
 			}
 		}
-		\tl_build_put_right:Nn \_prettytok_content {)//</script><script>}
+		\_prettytok_setcolor:N \_prettytok_white
 		\tl_build_end:N \_prettytok_content
-		\iow_now:NV \_prettytok_file \_prettytok_content
+
+		\_prettytok_typeout_content:
 	}
+	}
+
 }
 
+
 % ======== Lua expandable variant.
 \sys_if_engine_luatex:T {
 	\cs_new:Npn \prettye:n #1 {
@@ -150,65 +327,84 @@
 	}
 
 	\cs_new:Npn \prettye:w {
-		\directlua{prettyprintw()} {}
+		\directlua{prettyprintw()} {} {}
 	}
 	\cs_new:Npn \prettye:nw #1 {
-		\directlua{prettyprintw()} {#1}
+		\directlua{prettyprintw()} {#1} {}
 	}
+	\cs_new:Npn \prettye:nnw #1 #2 {
+		\directlua{prettyprintw()} {#1} {#2}
+	}
 }
 
-\cs_new_protected:Npn \pretty:w #1 \prettystop {
-	\pretty:n {#1} #1 \prettystop
+% ======== w variant.
+
+\cs_new_protected:Npn \pretty:w { \pretty_aux:w \empty }
+\cs_new_protected:Npn \pretty_aux:w #1 \prettystop {
+	\pretty:o { #1 }  % use o-expansion to remove the \empty
+	#1 \prettystop
 }
-
 \cs_new:Npn \prettystop {}
 
+% ======== other variants.
 \cs_generate_variant:Nn \pretty:n {x, o, V}
-\let \pretty:N \pretty:n
+\cs_new_eq:NN \pretty:N \pretty:n
+\cs_generate_variant:Nn \pretty:N {c}
 
-% ======== normal-catcode alias
-\let\prettyN\pretty:n
-\let\prettyX\pretty:x
-\let\prettyO\pretty:o
-\let\prettyV\pretty:V
-\let\prettyeN\prettye:n
-\let\prettyeW\prettye:w
+\cs_new_protected:Npn \prettythenrun:n #1 {
+	\pretty:n {running~#1}
+	#1
+	\pretty:n {done}
+}
+\cs_new_protected:Npn \prettythenrun:w #1 \prettythenrunstop {
+	\prettythenrun:n {#1}
+}
 
-\cs_generate_variant:Nn \pretty:N {c}
+\cs_new_protected:Nn \prettyshow:N { \pretty:o {\meaning #1} }
+\cs_generate_variant:Nn \prettyshow:N {c}
 
 
 % ======== generate \pretty:nn, \pretty:nnn, etc.
 \begingroup
-	\def \__tmp:NN #1 #2 {   % #1: example \pretty:nn, #2: example \pretty:n (the latter has one more n than the former)
+	\def \_prettytok_tmp:NN #1 #2 {   % #1: example \pretty:nn, #2: example \pretty:n (the latter has one more n than the former)
 		\cs_new_protected:Npn #1 ##1 ##2 { #2 {##1 ##2} }
 	}
-	\cs_generate_variant:Nn \__tmp:NN {cc}
+	\cs_generate_variant:Nn \_prettytok_tmp:NN {cc}
 
-	\def \__tmp {pretty:n}
+	\def \_prettytok_tmp {pretty:n}
 	\int_step_inline:nn {9} {
-		\__tmp:cc {\__tmp n} {\__tmp}
-		\tl_put_right:Nn \__tmp {n}
+		\_prettytok_tmp:cc {\_prettytok_tmp n} {\_prettytok_tmp}
+		\tl_put_right:Nn \_prettytok_tmp {n}
 	}
 
 	\sys_if_engine_luatex:T {
-		\def \__tmp:NN #1 #2 {   % #1: example \prettye:nn, #2: example \prettye:n (the latter has one more n than the former)
+		\def \_prettytok_tmp:NN #1 #2 {   % #1: example \prettye:nn, #2: example \prettye:n (the latter has one more n than the former)
 			\cs_new:Npn #1 ##1 ##2 { #2 {##1 ##2} }
 		}
-		\def \__tmp {prettye:n}
+		\def \_prettytok_tmp {prettye:n}
 		\int_step_inline:nn {9} {
-			\__tmp:cc {\__tmp n} {\__tmp}
-			\__tmp:cc {\__tmp nw} {\__tmp w}
-			\tl_put_right:Nn \__tmp {n}
+			\_prettytok_tmp:cc {\_prettytok_tmp n} {\_prettytok_tmp}
+			\tl_put_right:Nn \_prettytok_tmp {n}
 		}
+
+		\def \_prettytok_tmp:NN #1 #2 {   % #1: example \prettye:nnnw, #2: example \prettye:nnw (the latter has one more n than the former)
+			\cs_new:Npn #1 ##1 ##2 ##3 { #2 {##1} {##2 ##3} }  % here ##1 is the callback (first ⟨n⟩), ##2 etc. are the additional-print things
+		}
+		\def \_prettytok_tmp {prettye:nn}
+		\int_step_inline:nn {9} {
+			\_prettytok_tmp:cc {\_prettytok_tmp nw} {\_prettytok_tmp w}
+			\tl_put_right:Nn \_prettytok_tmp {n}
+		}
 	}
 \endgroup
 
-
-\cs_new_protected:Nn \prettyshow:N {
-	\exp_args:No \pretty:n {\meaning #1}
-}
-\cs_generate_variant:Nn \prettyshow:N {c}
+% ======== normal-catcode alias
+\let\prettyN\pretty:n
+\let\prettyX\pretty:x
+\let\prettyO\pretty:o
+\let\prettyV\pretty:V
+\let\prettyW\pretty:w
+\let\prettyeN\prettye:n
+\let\prettyeW\prettye:w
 \let\prettyshowN\prettyshow:N
 \let\prettyshowC\prettyshow:c
-
-

Deleted: trunk/Master/texmf-dist/tex/latex/prettytok/prettytok_template.html
===================================================================
--- trunk/Master/texmf-dist/tex/latex/prettytok/prettytok_template.html	2023-04-18 19:40:07 UTC (rev 66883)
+++ trunk/Master/texmf-dist/tex/latex/prettytok/prettytok_template.html	2023-04-18 19:40:32 UTC (rev 66884)
@@ -1,283 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<link rel="icon" href="data:,">
-<style>
-body{
-	background-color: black;
-	color: white;
-}
-
-/* https://stackoverflow.com/questions/7011602/stretching-iframe-in-html5 */
-#wrap_all { display: none; position:fixed; width:100%; height:100%; top: 0px; left: 0px; }
-
-
-iframe{
-	position: absolute;
-	width: 100%;
-	height: 100%;
-	display: none;
-}
-#status{
-	flex: 0 0 1.3em;
-}
-
-#display_wrap{
-	flex: 1 0 auto;
-}
-#controller{
-	flex: 0 0 50px;
-}
-
-.control-button{
-}
-
-
-
-.tokenlist, .fileline{
-	border: 1px solid gray;
-	overflow: scroll;
-	white-space: nowrap;
-}
-.tokenlist::-webkit-scrollbar, .fileline::-webkit-scrollbar { width: 0 !important }
-
-.fileline{
-	background-color: #404040;
-}
-
-.explicit_char_target{
-	background-color: #FF8080;
-}
-.explicit_char{
-	background-color: #606060;
-}
-
-
-.cs, .active_char{
-	color: #FFFF00;
-}
-.cs::before{
-	content: "\\";
-}
-.cs::after{
-	content: " ";
-}
-
-#popup{
-	display: none;
-	position: absolute;
-	border: 1px solid gray;
-	background-color: #000080ff;
-}
-
-.cmd__left_brace_cmd, .cmd__right_brace_cmd, .cmd__mac_param_cmd, .frozenrelax{
-	color: #FFAAAA;
-}
-.cmd__out_param_cmd{
-	border: 1px solid #FFAAAA;
-}
-.out_param_expansion{
-	border: 1px solid #FFAAAA;
-	background-color: #000080;
-}
-.cmd__out_param_cmd::before{
-	content: "#";
-}
-
-.cmd__letter_cmd{
-	color: #AAFFAA;
-}
-
-.cmd__spacer_cmd{
-	color: #606060;
-}
-
-
-input[type=button]{
-	color: white;
-	background-color: #0000ff;
-	border: 0;
-}
-
-#log{
-	display: flex;
-	flex-direction: column-reverse;
-	flex: 0 0 30%;
-	overflow: scroll;
-}
-</style>
-</head>
-<body>
-
-	<div id=output></div>
-	<div id=wrap_all>
-		<iframe id=iframe src="about:blank" frameborder=0></iframe>
-		<iframe id=iframe2 src="about:blank" frameborder=0></iframe>
-	</div>
-	<script>
-"use strict"
-function show_html(s){
-	return s.replace(/ /g, "␣")
-		.replace(/\r|\n/g, "↵")
-		.replace(/\t/g, "⇥")
-}
-
-output.innerHTML=""
-
-function print_tl(...tokens){
-	const tl_div=document.createElement("div")
-	tl_div.className="tokenlist"
-	for(let token of tokens){
-		tl_div.appendChild(token)
-		if({13: true, 10: true}[token.data_charcode]){
-			tl_div.appendChild(document.createElement("br"))
-		}
-	}
-	output.appendChild(tl_div)
-}
-
-function token(charcode /* int */, catcode /* single character string in hex */){
-	const token_span=document.createElement("span")
-	const ch=String.fromCodePoint(charcode)
-	token_span.innerText=show_html(ch)
-	token_span.data_charcode=charcode
-	if(catcode==='D'){
-		token_span.className="active_char"
-		token_span.title=`active ${ch} # ${charcode}`
-	}else{
-		const cls={
-			1: 'cmd__left_brace_cmd',
-			2: 'cmd__right_brace_cmd',
-			3: 'cmd__math_shift_cmd',
-			4: 'cmd__tab_mark_cmd',
-			6: 'cmd__mac_param_cmd',
-			7: 'cmd__sup_mark_cmd',
-			8: 'cmd__sub_mark_cmd',
-			A: 'cmd__spacer_cmd',
-			B: 'cmd__letter_cmd',
-			C: 'cmd__other_char_cmd',
-		}[catcode]
-		token_span.className="token "+cls
-		token_span.title=`${cls} ${ch} # ${charcode}`
-	}
-	return token_span
-}
-
-function cs(...codepoints){
-	const token_span=document.createElement("span")
-
-	const control_sequence_name=String.fromCodePoint(...codepoints)
-	//const meaning_str=readstr()
-
-	token_span.innerText=show_html(control_sequence_name)
-	//token_span.title=`cs '${control_sequence_name}' → ${meaning_str}`
-	token_span.className="cs"
-
-	return token_span
-}
-
-function csfrozenrelax(){
-	const token_span=document.createElement("span")
-	token_span.innerText="relax"
-	token_span.title="frozen relax"
-	token_span.className="cs frozenrelax"
-	return token_span
-}
-
-var refresh_strategy_already_set=false
-function set_refresh_strategy(strategy, duration){
-	if(refresh_strategy_already_set) return
-	refresh_strategy_already_set=true
-
-	switch(strategy){
-		case 0: // do nothing
-			return
-
-		case 1: // refresh the sub-iframe
-			if(window.parent===window){
-				print_tl=function(...x) {}
-				//output.style.display="none"
-				iframe.src=location.href
-				iframe.style.display="block"
-				wrap_all.style.display="block"
-				setInterval(function(){
-					iframe.src=iframe.src
-				}, duration)
-			}
-			return
-
-		case 2: // refresh two sub-iframes
-			if(window.parent===window){
-				print_tl=function(...x) {}
-				//output.style.display="none"
-				iframe.src=iframe2.src=location.href
-				iframe.style.display="block"
-				iframe2.style.display="block"
-				wrap_all.style.display="block"
-				async function sleep(ms){
-					await new Promise(resolve=>setTimeout(resolve, ms))
-				}
-				(async function(){
-					while(true){
-						await sleep(duration/2)
-						iframe.src=iframe.src
-
-						await sleep(duration/2)
-						iframe2.style.zIndex=1
-						iframe.style.zIndex=2
-
-						await sleep(duration/2)
-						iframe2.src=iframe2.src
-
-						await sleep(duration/2)
-						iframe.style.zIndex=1
-						iframe2.style.zIndex=2
-					}
-				})()
-			}
-			return
-
-		case 3: // refresh whole page
-			setTimeout(function(){
-				location.reload()
-			}, duration)
-			return
-
-		case 4: // request own file
-			window.addEventListener("load", async function(){
-				async function get_code(){
-					//let text=await (await fetch(location.href)).text()
-					let text=await new Promise(function(resolve){
-						let request = new XMLHttpRequest();
-						request.responseType = "text"
-						request.onload = function() {
-							resolve(request.responseText) 
-						}
-						request.onerror = function() {
-							console.log("Error happened. Read documentation for more details.")
-						}
-						request.open("GET", location.href, true)
-						request.send()
-					})
-					return text.replace(/.*?-end-template()-/s, "")
-				}
-				let text=await get_code()
-				output.innerHTML=""
-				try{ eval(text) }catch(e) {}
-				setInterval(async function(){
-					let text2=await get_code()
-					if(text2!==text){
-						output.innerHTML=""
-						try{ eval(text2) }catch(e) {}
-						text=text2
-					}
-				}, duration)
-			})
-			return
-	}
-}
-	</script>
-
-<script>
-// -end-template-



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