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.