summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2022-05-28 20:23:06 +0000
committerKarl Berry <karl@freefriends.org>2022-05-28 20:23:06 +0000
commit9ddf4513815730b922a72693349b23b6262cf038 (patch)
treeb8d2d88ccc8e2aa6ab4490688ea8550ce79e543b
parentcfcd43f33b17b5eb32ebb5a917f144700c9c1ef1 (diff)
prettytok (28may22)
git-svn-id: svn://tug.org/texlive/trunk@63430 c570f23f-e606-0410-a88d-b1316a301751
-rw-r--r--Master/texmf-dist/doc/latex/prettytok/DEPENDS.txt2
-rw-r--r--Master/texmf-dist/doc/latex/prettytok/README23
-rw-r--r--Master/texmf-dist/doc/latex/prettytok/prettytok.pdfbin0 -> 335928 bytes
-rw-r--r--Master/texmf-dist/doc/latex/prettytok/prettytok.tex139
-rw-r--r--Master/texmf-dist/tex/latex/prettytok/prettytok.sty669
-rwxr-xr-xMaster/tlpkg/bin/tlpkg-ctan-check2
-rw-r--r--Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc1
-rw-r--r--Master/tlpkg/tlpsrc/prettytok.tlpsrc2
8 files changed, 837 insertions, 1 deletions
diff --git a/Master/texmf-dist/doc/latex/prettytok/DEPENDS.txt b/Master/texmf-dist/doc/latex/prettytok/DEPENDS.txt
new file mode 100644
index 00000000000..5e0ae3b076f
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/prettytok/DEPENDS.txt
@@ -0,0 +1,2 @@
+expl3
+filecontentsdef
diff --git a/Master/texmf-dist/doc/latex/prettytok/README b/Master/texmf-dist/doc/latex/prettytok/README
new file mode 100644
index 00000000000..cefd81b493c
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/prettytok/README
@@ -0,0 +1,23 @@
+prettytok -- Pretty-print token list
+
+Released under the LaTeX Project Public License v1.3c or later
+See http://www.latex-project.org/lppl.txt
+
+Report bugs at https://github.com/user202729/TeXlib
+
+========
+
+Copyright 2022 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
+(at your option) any later version. The latest version of this license is in
+the file:
+
+ http://www.latex-project.org/lppl.txt
+
+This work has the LPPL maintenance status `maintained'.
+
+The Current Maintainer of this work is user202729.
+
+This work consists of the files prettytok.sty.
diff --git a/Master/texmf-dist/doc/latex/prettytok/prettytok.pdf b/Master/texmf-dist/doc/latex/prettytok/prettytok.pdf
new file mode 100644
index 00000000000..76ca759f676
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/prettytok/prettytok.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/prettytok/prettytok.tex b/Master/texmf-dist/doc/latex/prettytok/prettytok.tex
new file mode 100644
index 00000000000..d21af2d0fe2
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/prettytok/prettytok.tex
@@ -0,0 +1,139 @@
+%! TEX program = lualatex
+\ProvidesFile{prettytok.tex} [2022/05/28 v0.0.0 Pretty-print token lists]
+% yes, this is not dtx
+\documentclass{l3doc}
+%\usepackage[a4paper,margin=25mm,left=50mm,nohead]{geometry}
+%\usepackage[numbered]{hypdoc}
+%\usepackage{\jobname}
+\EnableCrossrefs
+\CodelineIndex
+\RecordChanges
+\begin{document}
+\GetFileInfo{\jobname.tex}
+\DoNotIndex{\newcommand,\newenvironment}
+
+\title{\textsf{prettytok} --- Pretty-print token lists\thanks{This file
+ describes version \fileversion, last revised \filedate.}
+}
+\author{user202729%
+%\thanks{E-mail: (not set)}
+}
+\date{Released \filedate}
+
+\maketitle
+
+\changes{v0.0.0}{2022/05/18}{First public release}
+
+\begin{abstract}
+ Pretty-print token lists.
+\end{abstract}
+
+\section{Usage}
+
+\subsection{Main function}
+\begin{function}{\pretty:n,\pretty:x,\pretty:o,\pretty:V}
+ \begin{syntax}
+ \cs{pretty:n} \Arg{token list} \\
+ \end{syntax}
+ Print the content of \meta{token list}.
+\end{function}
+
+\begin{function}{\pretty:N,\pretty:c}
+ \begin{syntax}
+ \cs{pretty:N} \meta{token} \\
+ \cs{pretty:c} \Arg{control sequence name} \\
+ \end{syntax}
+ Print \meta{token}. \\
+ 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.
+\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 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.
+ \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.
+ \item Output to another \TeX\ file to be compiled is a bit absurd, and compiling \TeX\ file takes longer than loading a HTML file.
+\end{itemize}
+
+By default, the output refreshes whenever the TeX file is recompiled. The behavior
+can be customized with \cs{prettyrefreshstrategy} and \cs{prettyrefreshduration}.
+
+\subsection{\LaTeX2 interface}
+
+
+\begin{function}{\prettyN,\prettyX,\prettyO,\prettyV}
+ \begin{syntax}
+ \cs{prettyN} \Arg{token list} \\
+ \end{syntax}
+ Alias of the correspondingly-named commands.
+\end{function}
+
+\subsection{Additional functions}
+
+There are also these functions, for convenience.
+
+\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.
+\end{function}
+
+\begin{function}{\pretty:w}
+ \begin{syntax}
+ \cs{pretty:w} \meta{token list} \cs{prettystop}
+ \end{syntax}
+ Print the content of \meta{token list}. For now, it must be brace-balanced.
+\end{function}
+
+\begin{function}{\prettyshow:N}
+ \begin{syntax}
+ \cs{prettyshow:N} \meta{token}
+ \end{syntax}
+ Show the meaning of a |N|-type argument.
+\end{function}
+
+\subsection{Customization}
+
+These variables can be redefined before the
+first call to |\pretty:n| to customize the behavior.
+
+\begin{variable}{\prettyfilename}
+ The output file name. Defaults to |pretty-|\meta{jobname}|.html|, as mentioned above.
+\end{variable}
+
+\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}
+
+\begin{variable}{\prettyrefreshduration}
+ The duration between two consecutive refresh check, in milliseconds. Defaults to 1000.
+\end{variable}
+
+\begin{variable}{\prettypreamble}
+ The HTML source code preamble. This can be redefined to change styles, but the
+ behavior is not guaranteed.
+\end{variable}
+
+\section{Implementation}
+
+Unfortunately, the implementation is not typesetted in \TeX. Read the |.sty| file.
+
+\StopEventually{^^A
+ \PrintChanges
+ \PrintIndex
+}
+
+\Finale
+\end{document}
diff --git a/Master/texmf-dist/tex/latex/prettytok/prettytok.sty b/Master/texmf-dist/tex/latex/prettytok/prettytok.sty
new file mode 100644
index 00000000000..e17eb204c68
--- /dev/null
+++ b/Master/texmf-dist/tex/latex/prettytok/prettytok.sty
@@ -0,0 +1,669 @@
+% File: prettytok.sty
+% Copyright 2022 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
+% (at your option) any later version. The latest version of this license is in
+% the file:
+%
+% http://www.latex-project.org/lppl.txt
+%
+% This work has the LPPL maintenance status `maintained'.
+%
+% The Current Maintainer of this work is user202729.
+\RequirePackage{expl3}
+\ProvidesExplPackage{prettytok}{2022/05/28}{0.0.0}{Pretty-print token list}
+
+
+
+
+
+\@ifpackagelater{expl3}{2022/04/10} % https://github.com/latex3/latex3/blob/main/l3kernel/CHANGELOG.md#2022-04-10
+ {
+ }
+
+ {
+
+\cs_set_protected:Npn \tl_analysis_map_inline:Nn #1
+ { \exp_args:No \tl_analysis_map_inline:nn #1 }
+\cs_set_protected:Npn \tl_analysis_map_inline:nn #1
+ {
+ \__tl_analysis:n {#1}
+ \int_gincr:N \g__kernel_prg_map_int
+ \exp_args:Nc \__tl_analysis_map:Nn
+ { _tl_analysis_map_inline_ \int_use:N \g__kernel_prg_map_int :wNw }
+ }
+\cs_set_protected:Npn \__tl_analysis_map:Nn #1#2
+ {
+ \cs_gset_protected:Npn #1 ##1##2##3 {#2}
+ \exp_after:wN \__tl_analysis_map:NwNw \exp_after:wN #1
+ \g__tl_analysis_result_tl
+ \s__tl { ? \tl_map_break: } \s__tl
+ \prg_break_point:Nn \tl_map_break:
+ { \int_gdecr:N \g__kernel_prg_map_int }
+ }
+\cs_set_protected:Npn \__tl_analysis_map:NwNw #1 #2 \s__tl #3 #4 \s__tl
+ {
+ \use_none:n #3
+ #1 {#2} {#4} {#3}
+ \__tl_analysis_map:NwNw #1
+ }
+
+ }
+
+\cs_generate_variant:Nn \EI_append:n {x}
+\cs_generate_variant:Nn \int_compare:nNnTF {VNnTF}
+\cs_generate_variant:Nn \tl_set:Nn {Nx}
+\cs_generate_variant:Nn \int_compare:nNnT {VNnT}
+\cs_generate_variant:Nn \cs_if_exist_use:NT {cT}
+
+% ======== define handler functions.
+% a few things it can do:
+% • \tl_build_gput_right:Nn to \_EIresult (content being put there must be wrapped in \unexpanded i.e. x-expand to the desired result
+
+\cs_set_protected:Npn \EI_append_raw:n #1 {
+ \tl_build_gput_right:Nn \_EIresult {#1}
+}
+
+\cs_set_protected:Npn \EI_append:n #1 {
+ \EI_append_raw:n {\exp_not:n {#1}}
+}
+
+
+% handler can call this to collect following tokens in the input stream as argument.
+% #1: the function to pass argument in. (arguments are passed as brace-hack-included)
+% #2: number of arguments
+\cs_set_protected:Npn \EI_collect_arg:Nn #1 #2 {
+ \def \_EIcollecting_balanced {#2}
+ \def \_EIbalance_level {0}
+ \tl_build_gbegin:N \_EIbalanced_content
+ \tl_build_gput_right:Nn \_EIbalanced_content {\noexpand #1}
+}
+
+\cs_set_protected:Npn \EIhandler_EIexpand {
+ \EI_collect_arg:Nn \EI_append:x {1}
+}
+
+\cs_set_protected:Npn \EIhandler_EIexecute {
+ \EI_collect_arg:Nn \use:n {1}
+}
+
+\cs_set_protected:Npn \execinsideprepare:n #1 {
+ \tl_build_gbegin:N \_EIresult
+ \def \_EIcollecting_balanced {0}
+
+ \tl_analysis_map_inline:nn {#1} {
+ % reminder: ##1: token, ##2: char code (int), ##3: cat code (hex digit)
+
+ \int_compare:VNnTF \_EIcollecting_balanced > 0 {
+ % collecting content.
+
+ \tl_build_gput_right:Nn \_EIbalanced_content {##1}
+ \str_case:nn {##3} {
+ {1} { \tl_set:Nx \_EIbalance_level {\_EIbalance_level+1} }
+ {2} { \tl_set:Nx \_EIbalance_level {\_EIbalance_level-1} }
+ }
+
+ % we check this every time instead of only after egroup tokens...
+ % so that if there's exactly one token to be collected it's still correctly passed through
+ \int_compare:nNnT {\_EIbalance_level} = {0} {
+
+ % done, call handler function and revert to normal mode.
+
+ \tl_set:Nx \_EIcollecting_balanced {\int_eval:n{\_EIcollecting_balanced-1}}
+ \int_compare:VNnT \_EIcollecting_balanced = 0 {
+ \tl_build_gend:N \_EIbalanced_content
+ \tl_set:Nx \_EIbalanced_content {\_EIbalanced_content}
+ %\pretty:V \_EIbalanced_content
+ \_EIbalanced_content % ← the handler function is embedded in here
+ %\pretty:n {done}
+ }
+ }
+ } {
+ \let \_EIprocessed \c_false_bool
+
+ % check for \EIexecute etc. and handle accordingly.
+ \int_compare:nNnT {##2} = {-1} {
+ \cs_if_exist_use:cT {
+ EIhandler_ \expandafter \cs_to_str:N ##1
+ } {
+ \let \_EIprocessed \c_true_bool
+ }
+ }
+
+ % if not, just append to result.
+ \bool_if:NF \_EIprocessed {
+ \tl_build_gput_right:Nn \_EIresult {##1}
+ }
+ }
+ }
+
+ \tl_build_gend:N \_EIresult
+ \tl_set:Nx \_EIresult {\_EIresult}
+}
+
+\cs_set_protected:Npn \execinside:n #1 {
+ \execinsideprepare:n {#1}
+ \_EIresult
+}
+\let\execinside\execinside:n % normal-catcode alias
+
+\cs_set_protected:Npn \execinside_set:Nn #1 #2 {
+ \execinsideprepare:n {#2}
+ \let #1 \_EIresult
+}
+\let\execinsideSet\execinside_set:Nn
+
+\cs_set_protected:Npn \execinside_gset:Nn #1 #2 {
+ \execinsideprepare:n {#2}
+ \global \let #1 \_EIresult
+}
+\let\execinsideGset\execinside_gset:Nn
+
+\cs_generate_variant:Nn \exp_args:NN {Nc}
+\cs_generate_variant:Nn \EI_append:n {x}
+\cs_generate_variant:Nn \exp_args:Nn {No}
+\cs_generate_variant:Nn \EI_append:n {o}
+\cs_generate_variant:Nn \tl_put_right:Nn {Nx}
+\cs_generate_variant:Nn \use:nn {nV}
+\cs_generate_variant:Nn \execinside_set:Nn {NV}
+
+
+\def \_precattlappend_space #1 {
+ \begingroup
+ \lccode `\ =#1
+ \lowercase{
+ \def\_precattltmp{\endgroup \EI_append:n {~}}
+ }
+ \_precattltmp
+}
+
+\begingroup
+
+
+\global\def \_precattlappend_begin #1 {
+ \begingroup
+ \lccode `\{=#1
+ \lowercase{\endgroup \EI_append_raw:n { \iftrue { \else } \fi }}
+}
+\global\def \_precattlappend_end #1 {
+ \begingroup
+ \lccode `\}=#1
+ \lowercase{\endgroup \EI_append_raw:n { \iffalse { \else } \fi }}
+}
+\endgroup
+
+\def \_precattldo_special_cC #1 { \exp_args:Nc \EI_append:n {#1} }
+\def \_precattldo_special_cB #1 { \str_map_inline:nn {#1} { \_precattlappend_begin {`##1} } }
+\def \_precattldo_special_cE #1 { \str_map_inline:nn {#1} { \_precattlappend_end {`##1} } }
+\def \_precattldo_special_cM #1 { \str_map_inline:nn {#1} { \EI_append:x {\char_generate:nn {`##1} {3}} } }
+\def \_precattldo_special_cT #1 { \str_map_inline:nn {#1} { \EI_append:x {\char_generate:nn {`##1} {4}} } }
+\def \_precattldo_special_cP #1 { \str_map_inline:nn {#1} { \exp_args:No \EI_append:o {\char_generate:nn {`##1} {6}} } }
+\def \_precattldo_special_cU #1 { \str_map_inline:nn {#1} { \EI_append:x {\char_generate:nn {`##1} {7}} } }
+\def \_precattldo_special_cD #1 { \str_map_inline:nn {#1} { \EI_append:x {\char_generate:nn {`##1} {8}} } }
+\def \_precattldo_special_cS #1 { \str_map_inline:nn {#1} { \_precattlappend_space {`##1} } }
+\def \_precattldo_special_cL #1 { \str_map_inline:nn {#1} { \EI_append:x {\char_generate:nn {`##1} {11}} } }
+\def \_precattldo_special_cO #1 { \str_map_inline:nn {#1} { \EI_append:x {\char_generate:nn {`##1} {12}} } }
+\def \_precattldo_special_cA #1 { \str_map_inline:nn {#1} {
+ \exp_args:No \EI_append:o {\char_generate:nn {`##1} {13}}
+} }
+
+
+
+\def \_precattldo_special #1 #2 {
+ % given #1 e.g. \cO, #2 e.g. {abc}, append <abc> in OTHER catcode to EI.
+ {
+ \escapechar=-1
+
+ % let \_precattltmp be the concatenation of \string of all tokens within #2.
+ \def \_precattltmp {}
+ \tl_analysis_map_inline:nn {#2} {
+ \tl_put_right:Nx \_precattltmp {\exp_after:wN \string ##1}
+ }
+
+ % then pass it to the specific handler.
+ \exp_args:Nc \exp_args:NV {_precattldo_special_\string #1} \_precattltmp
+ }
+}
+
+\def \_precattldo_special_cC_outer { \_precattldo_special\cC }
+\def \_precattldo_special_cB_outer { \_precattldo_special\cB }
+\def \_precattldo_special_cE_outer { \_precattldo_special\cE }
+\def \_precattldo_special_cM_outer { \_precattldo_special\cM }
+\def \_precattldo_special_cT_outer { \_precattldo_special\cT }
+\def \_precattldo_special_cP_outer { \_precattldo_special\cP }
+\def \_precattldo_special_cU_outer { \_precattldo_special\cU }
+\def \_precattldo_special_cD_outer { \_precattldo_special\cD }
+\def \_precattldo_special_cS_outer { \_precattldo_special\cS }
+\def \_precattldo_special_cL_outer { \_precattldo_special\cL }
+\def \_precattldo_special_cO_outer { \_precattldo_special\cO }
+\def \_precattldo_special_cA_outer { \_precattldo_special\cA }
+
+\def \_precattl_tmp_help #1 {
+ \def \_precattl_do_frozen_relax { \EI_append:n {#1} }
+ % #1 here will be substituted by the frozen relax
+}
+\expandafter \_precattl_tmp_help \ifnum0=0\fi
+\let \_precattl_tmp_help \undefined
+
+
+
+\def \precattl_prepare:n #1 {
+ \begingroup
+ \let \EIhandler_EIexpand \undefined
+ \let \EIhandler_EIexecute \undefined
+ \def \EIhandler_cC { \EI_collect_arg:Nn \_precattldo_special_cC_outer 1 }
+ \def \EIhandler_cB { \EI_collect_arg:Nn \_precattldo_special_cB_outer 1 }
+ \def \EIhandler_cE { \EI_collect_arg:Nn \_precattldo_special_cE_outer 1 }
+ \def \EIhandler_cM { \EI_collect_arg:Nn \_precattldo_special_cM_outer 1 }
+ \def \EIhandler_cT { \EI_collect_arg:Nn \_precattldo_special_cT_outer 1 }
+ \def \EIhandler_cP { \EI_collect_arg:Nn \_precattldo_special_cP_outer 1 }
+ \def \EIhandler_cU { \EI_collect_arg:Nn \_precattldo_special_cU_outer 1 }
+ \def \EIhandler_cD { \EI_collect_arg:Nn \_precattldo_special_cD_outer 1 }
+ \def \EIhandler_cS { \EI_collect_arg:Nn \_precattldo_special_cS_outer 1 }
+ \def \EIhandler_cL { \EI_collect_arg:Nn \_precattldo_special_cL_outer 1 }
+ \def \EIhandler_cO { \EI_collect_arg:Nn \_precattldo_special_cO_outer 1 }
+ \def \EIhandler_cA { \EI_collect_arg:Nn \_precattldo_special_cA_outer 1 }
+ \let \EIhandler_cFrozenRelax \_precattl_do_frozen_relax
+ \execinside_gset:Nn \_precattlvalueg {#1}
+ \endgroup
+ \let \_precattlvalue \_precattlvalueg
+}
+
+\def \precattl_set:Nn #1 #2 {
+ \precattl_prepare:n {#2}
+ \tl_set_eq:NN #1 \_precattlvalue
+}
+\let\precattlSet\precattl_set:Nn
+
+\def \precattl_exec:n #1 {
+ \precattl_prepare:n {#1}
+ \_precattlvalue
+}
+\let\precattlExec\precattl_exec:n
+
+
+
+
+
+\RequirePackage{filecontentsdef}
+
+%\sys_if_engine_luatex:T{\directlua{require("prettytok")}}
+
+% usage: \pretty:n, etc.
+
+\cs_generate_variant:Nn \exp_args:NNn {NNx}
+\cs_generate_variant:Nn \iow_open:Nn {NV}
+\cs_generate_variant:Nn \exp_args:NNn {NNV}
+\cs_generate_variant:Nn \iow_now:Nn {Nx}
+\cs_generate_variant:Nn \tl_if_eq:nnF {xoF}
+\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 \iow_now:Nn {NV}
+
+\iow_new:N \__prettyh_file
+\exp_args:NNx \providecommand \prettyfilename {pretty-\jobname.html}
+\providecommand \prettyrefreshstrategy {4}
+\providecommand \prettyrefreshduration {1000}
+
+
+\cs_new_protected:Npn \pretty:n #1 {
+
+ % ======== first write out the preamble if it isn't written. Only do once. Delete the preamble macro if it's already written.
+ \cs_if_exist:NT \prettypreamble {
+ \iow_open:NV \__prettyh_file \prettyfilename
+ {
+ \str_set:NV \prettypreamble \prettypreamble
+ \precattl_exec:n {
+ \str_replace_all:Nnn \prettypreamble {\cO\^^M} {\cO\^^J}
+ }
+ \iow_now:NV \__prettyh_file \prettypreamble
+ \iow_now:Nx \__prettyh_file {set_refresh_strategy(\prettyrefreshstrategy,\prettyrefreshduration)}
+ }
+ \cs_undefine:N \prettypreamble
+ }
+
+ % ======== the actual content. Collect to one \write to put them on the same line (also maybe for efficiency???)
+ \tl_build_begin:N \__prettyh_content
+ \tl_build_put_right:Nn \__prettyh_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_build_put_right:Nn \__prettyh_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 \__prettyh_content {\int_eval:n {`####1},}
+ }
+ }
+ \tl_build_put_right:Nn \__prettyh_content {),}
+ }
+ {
+ % token is not control sequence
+ \tl_build_put_right:Nn \__prettyh_content {token(##2, "##3"),}
+ }
+ }
+ \tl_build_put_right:Nn \__prettyh_content {)//</script><script>}
+ \tl_build_end:N \__prettyh_content
+ \iow_now:NV \__prettyh_file \__prettyh_content
+}
+
+\cs_new_protected:Npn \pretty:w #1 \prettystop {
+ \pretty:n {#1}
+}
+
+\cs_generate_variant:Nn \pretty:n {x, o, V}
+\let \pretty:N \pretty:n
+
+% normal-catcode alias
+\let\prettyN\pretty:n
+\let\prettyX\pretty:x
+\let\prettyO\pretty:o
+\let\prettyV\pretty:V
+
+\cs_generate_variant:Nn \pretty:N {c}
+
+\cs_new_protected:Nn \pretty:nn {
+ \pretty:n {#1}
+ \pretty:n {#2}
+}
+
+\cs_new_protected:Nn \pretty:nnn {
+ \pretty:n {#1}
+ \pretty:n {#2}
+ \pretty:n {#3}
+}
+
+\cs_new_protected:Nn \pretty:nnnn {
+ \pretty:n {#1}
+ \pretty:n {#2}
+ \pretty:n {#3}
+ \pretty:n {#4}
+}
+
+\cs_new_protected:Nn \prettyshow:N {
+ \exp_args:No \pretty:n {\meaning #1}
+}
+\let\prettyshowN\prettyshow:N
+
+
+
+
+
+\ExplSyntaxOff
+\begin{filecontentsdefmacro}{\prettypreamble}
+<!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;
+ height: 2em;
+ 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{
+ 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: #808080;
+}
+
+
+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)
+ }
+ output.appendChild(tl_div)
+}
+
+function token(charcode /* single character string in hex */, catcode /* integer */){
+ const token_span=document.createElement("span")
+ const ch=String.fromCodePoint(charcode)
+ token_span.innerText=show_html(ch)
+ 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
+}
+
+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-
+\end{filecontentsdefmacro}
+\ExplSyntaxOn
diff --git a/Master/tlpkg/bin/tlpkg-ctan-check b/Master/tlpkg/bin/tlpkg-ctan-check
index 60049711624..c19e2724f64 100755
--- a/Master/tlpkg/bin/tlpkg-ctan-check
+++ b/Master/tlpkg/bin/tlpkg-ctan-check
@@ -636,7 +636,7 @@ my @TLP_working = qw(
powerdot powerdot-fuberlin powerdot-tuliplab
ppr-prv pracjourn practicalreports
prelim2e preprint prerex present
- pressrelease prettyref preview prftree
+ pressrelease prettyref prettytok preview prftree
principia printlen proba probsoln prociagssymp
prodint productbox profcollege proflabo proflycee program
progress progressbar projlib
diff --git a/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc b/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc
index 983a248d7ba..92c58df1af1 100644
--- a/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc
+++ b/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc
@@ -1036,6 +1036,7 @@ depend prelim2e
depend preprint
depend pressrelease
depend prettyref
+depend prettytok
depend preview
depend printlen
depend probsoln
diff --git a/Master/tlpkg/tlpsrc/prettytok.tlpsrc b/Master/tlpkg/tlpsrc/prettytok.tlpsrc
new file mode 100644
index 00000000000..e820daab37b
--- /dev/null
+++ b/Master/tlpkg/tlpsrc/prettytok.tlpsrc
@@ -0,0 +1,2 @@
+depend l3kernel
+depend filecontentsdef