texlive[63841] Master: prettytok (8jul22)

commits+karl at tug.org commits+karl at tug.org
Fri Jul 8 23:51:18 CEST 2022


Revision: 63841
          http://tug.org/svn/texlive?view=revision&revision=63841
Author:   karl
Date:     2022-07-08 23:51:18 +0200 (Fri, 08 Jul 2022)
Log Message:
-----------
prettytok (8jul22)

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.sty
    trunk/Master/tlpkg/tlpsrc/prettytok.tlpsrc

Added Paths:
-----------
    trunk/Master/texmf-dist/doc/latex/prettytok/prettytok_template.html
    trunk/Master/texmf-dist/tex/latex/prettytok/prettytok.lua

Modified: trunk/Master/texmf-dist/doc/latex/prettytok/DEPENDS.txt
===================================================================
--- trunk/Master/texmf-dist/doc/latex/prettytok/DEPENDS.txt	2022-07-08 21:49:59 UTC (rev 63840)
+++ trunk/Master/texmf-dist/doc/latex/prettytok/DEPENDS.txt	2022-07-08 21:51:18 UTC (rev 63841)
@@ -1,2 +1 @@
-expl3
-filecontentsdef
+precattl

Modified: trunk/Master/texmf-dist/doc/latex/prettytok/README
===================================================================
--- trunk/Master/texmf-dist/doc/latex/prettytok/README	2022-07-08 21:49:59 UTC (rev 63840)
+++ trunk/Master/texmf-dist/doc/latex/prettytok/README	2022-07-08 21:51:18 UTC (rev 63841)
@@ -1,5 +1,9 @@
 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.
 
+Can be used to replace |\tl_analysis_show:n|.
+
 Released under the LaTeX Project Public License v1.3c or later
 See http://www.latex-project.org/lppl.txt
 
@@ -20,4 +24,4 @@
 
 The Current Maintainer of this work is user202729.
 
-This work consists of the files prettytok.sty.
+This work consists of the files prettytok.sty, prettytok.lua, prettytok_template.html.

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	2022-07-08 21:49:59 UTC (rev 63840)
+++ trunk/Master/texmf-dist/doc/latex/prettytok/prettytok.tex	2022-07-08 21:51:18 UTC (rev 63841)
@@ -1,10 +1,6 @@
 %! TEX program = lualatex
-\ProvidesFile{prettytok.tex} [2022/05/28 v0.0.0 Pretty-print token lists]
-% yes, this is not dtx
+\ProvidesFile{prettytok.tex} [2022/07/08 v0.0.1 ]
 \documentclass{l3doc}
-%\usepackage[a4paper,margin=25mm,left=50mm,nohead]{geometry}
-%\usepackage[numbered]{hypdoc}
-%\usepackage{\jobname}
 \EnableCrossrefs
 \CodelineIndex
 \RecordChanges
@@ -13,7 +9,7 @@
 \DoNotIndex{\newcommand,\newenvironment}
 
 \title{\textsf{prettytok} --- Pretty-print token lists\thanks{This file
-   describes version \fileversion, last revised \filedate.}
+	describes version \fileversion, last revised \filedate.}
 }
 \author{user202729%
 %\thanks{E-mail: (not set)}
@@ -25,7 +21,10 @@
 \changes{v0.0.0}{2022/05/18}{First public release}
 
 \begin{abstract}
-	Pretty-print token lists.
+Pretty-print token lists to HTML file for debugging purposes.
+Open the file in any browser to view the result.
+
+Can be used to replace |\tl_analysis_show:n|.
 \end{abstract}
 
 \section{Usage}
@@ -32,22 +31,66 @@
 
 \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}.
+	\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.
+	\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}
 
+\begin{function}{\prettyinit:}
+	\begin{syntax}
+		\cs{prettyinit:}
+	\end{syntax}
+	Do necessary initialization.
+
+	This should be called right after the package is loaded, after setting the configuration variables described below.
+\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{syntax}
+		\cs{prettye:n} \Arg{token list}
+	\end{syntax}
+	Print the token list, similar to \cs{pretty:n}, but is fully expandable.
+\end{function}
+
+\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.
+
+	Note that the input stream will be tokenized and has catcode frozen. Use with care.
+\end{function}
+
+\subsection{Lua programming interface}
+
+\cs{prettyinit:} must also be called before calling the functions in this section.
+
+\begin{function}{prettyprint}
+	\begin{syntax}
+		|prettyprint(|\meta{content}|)|
+	\end{syntax}
+	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{View result}
 
 The result is printed to a HTML file named |pretty-|\meta{jobname}|.html| by default.
@@ -58,24 +101,17 @@
 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.
+	\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.
+
+		(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}
 
-By default, the output refreshes whenever the TeX file is recompiled. The behavior
+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.
@@ -85,30 +121,82 @@
 		\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.
+	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}
+	\begin{syntax}
+		\cs{prettye:nn} \Arg{token list} \Arg{token list}
+		\cs{prettye:nnn} \Arg{token list} \Arg{token list} \Arg{token list}
+	\end{syntax}
+	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{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.
+	Print the content of \meta{token list}.
+
+	Same restriction applies -- the catcode is frozen.
+
+	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.
 \end{function}
 
-\begin{function}{\prettyshow:N}
+\begin{function}[EXP]{\prettystop}
 	\begin{syntax}
+		\cs{prettystop}
+	\end{syntax}
+	Only used as a delimiter for |:w| functions. For convenience, this function is defined to do nothing.
+\end{function}
+
+\begin{function}{\prettyshow:N,\prettyshow:c}
+	\begin{syntax}
 		\cs{prettyshow:N} \meta{token}
+		\cs{prettyshow:c} \Arg{control sequence name}
 	\end{syntax}
 	Show the meaning of a |N|-type argument.
 \end{function}
 
+\subsection{\LaTeXe\ interface}
+
+\begin{function}{\prettyN,\prettyX,\prettyO,\prettyV,\prettyinit,\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}
+		\tn{prettyshowN} \meta{token}
+		\tn{prettyshowC} \Arg{control sequence name}
+	\end{syntax}
+	Alias of the correspondingly-named commands.
+\end{function}
+
+\begin{function}[EXP]{\prettyeN,\prettyeW}
+	\begin{syntax}
+		\cs{prettyeN} \Arg{token list}
+		\cs{prettyeW} \meta{tokens} \cs{prettystop}
+	\end{syntax}
+	Alias of the correspondingly-named commands. Only available in \LuaTeX.
+\end{function}
+
+
 \subsection{Customization}
 
 These variables can be redefined before the
-first call to |\pretty:n| to customize the behavior.
+first call to \cs{pretty:n} or \cs{prettyinit:} to customize the behavior.
 
 \begin{variable}{\prettyfilename}
-	The output file name.  Defaults to |pretty-|\meta{jobname}|.html|, as mentioned above.
+	The output file name. Defaults to |pretty-|\meta{jobname}|.html|, as mentioned above.
 \end{variable}
 
 \begin{variable}{\prettyrefreshstrategy}
@@ -121,18 +209,13 @@
 	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
+	\PrintChanges
+	\PrintIndex
 }
 
 \Finale

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	2022-07-08 21:51:18 UTC (rev 63841)
@@ -0,0 +1,283 @@
+<!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-


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.lua
===================================================================
--- trunk/Master/texmf-dist/tex/latex/prettytok/prettytok.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/tex/latex/prettytok/prettytok.lua	2022-07-08 21:51:18 UTC (rev 63841)
@@ -0,0 +1,98 @@
+do
+local function looks_like_token(t)
+	return type(t)=="userdata" or (type(t)=="table" and t.cmdname~=nil and t.tok~=nil)
+end
+
+-- 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
+
+	local s=""
+
+	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
+				s=s.."token("..c..',"A"),'
+			else
+				s=s.."token("..c..',"C"),'
+			end
+		end
+	end
+
+	if type(tokenlist)~="table" then
+		-- user give a string (or something similar). Print it as detokenized characters
+		printstring(tokenlist)
+	
+	else
+
+		-- normal print of tokenlist
+		for i=1, #tokenlist do
+			local t=tokenlist[i]
+			if not looks_like_token(t) then
+				printstring(t)
+			elseif t.csname==nil then
+				s=s.."token("..t.mode..',"'..(({left_brace=1, right_brace=2, math_shift=3, tab_mark=4, mac_param=6, sup_mark=7, sub_mark=8, spacer="A", letter="B", other_char="C"})[t.cmdname])..'"),'
+			else
+				if t.active then
+					s=s.."token("..utf8.codepoint(t.csname)..',"D"),'
+				elseif t.tok==prettyprint_frozenrelaxtok then
+					s=s.."csfrozenrelax(),"
+				else
+					s=s.."cs("
+					for j=1, #t.csname do
+						s=s..t.csname:byte(j)..","
+					end
+					s=s.."),"
+				end
+			end
+		end
+		
+	end
+	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
+end
+
+local function get_file_number()
+	check_file_opened()
+	return token.get_mode(token.create("__prettyh_file"))
+end
+
+function prettyprint(...)
+	local prettyfilenumber=get_file_number()
+
+	local s="print_tl("
+	local args={...}
+	for i=1, select("#", ...) do
+		s=s..prettyprint_one_arg(args[i])
+	end
+
+	texio.write(prettyfilenumber, s..")//</script><script>\n")
+end
+
+function prettyprintw()
+	check_file_opened()
+	local extra=token.scan_toks()
+	local s={}
+	while true do
+		local n=token.get_next()
+		s[#s+1]=n
+		if n.csname=="prettystop" then break end
+	end
+
+	prettyprint(extra, s)
+	token.put_next(s)
+end
+end


Property changes on: trunk/Master/texmf-dist/tex/latex/prettytok/prettytok.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: trunk/Master/texmf-dist/tex/latex/prettytok/prettytok.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/prettytok/prettytok.sty	2022-07-08 21:49:59 UTC (rev 63840)
+++ trunk/Master/texmf-dist/tex/latex/prettytok/prettytok.sty	2022-07-08 21:51:18 UTC (rev 63841)
@@ -11,659 +11,204 @@
 % 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}
 
+\ProvidesExplPackage{prettytok}{2022/07/08}{0.0.1}{Pretty-print token list}
+\RequirePackage{precattl}
 
 
+% ======== 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.
+	}
 
-
-\@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}
-			}
+\ifdefined \prettyignoretlanalysisbug
+	\relax
+\else
+\begingroup
+	\tl_set:Nn \__test {}
+	\tl_analysis_map_inline:nn {ab} {
+		\tl_analysis_map_inline:nn {cd} {
+			\tl_put_right:Nx \__test {#1 ##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 {~}}
+	\tl_if_eq:NnF \__test {ac.ad.bc.bd.} {
+		\msg_error:nn {prettytok} {tl-analysis-bug}
 	}
-	\_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}}
-} }
+\fi
 
-
-
-\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
+% ======== load Lua module.
+\sys_if_engine_luatex:T{
+	\directlua{require("prettytok")}
+	\precattl_exec:n {
+		\directlua{prettyprint_frozenrelaxtok=token.get_next().tok}\cFrozenRelax
 	}
 }
 
-\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 }
+% ======== main code start.
 
-\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 \tl_if_eq:nnTF {o}
 \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
+\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}
 
+\msg_new:nnn {prettytok} {already-initialized} {Output~file~is~already~initialized!} 
 
-\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
-	}
+% See also Lua function: local function check_file_opened()
 
-	% ======== 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
-}
+\global\let \pretty_check_already_init: \relax
 
-\cs_new_protected:Npn \pretty:w #1 \prettystop {
-	\pretty:n {#1}
-}
+\precattl_exec:n {
+	\cs_new_protected:Npn \_prettyinit_unchecked: {
+		\global\protected\def \pretty_check_already_init: {\msg_error:nn {prettytok} {already-initialized}}
 
-\cs_generate_variant:Nn \pretty:n {x, o, V}
-\let \pretty:N \pretty:n
+		\iow_open:NV \_prettytok_file \prettyfilename
 
-% normal-catcode alias
-\let\prettyN\pretty:n
-\let\prettyX\pretty:x
-\let\prettyO\pretty:o
-\let\prettyV\pretty:V
+		% 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
 
-\cs_generate_variant:Nn \pretty:N {c}
+		% refresh strategy
+		\iow_now:Nx \_prettytok_file {set_refresh_strategy(\prettyrefreshstrategy,\prettyrefreshduration)}
+	}
 
-\cs_new_protected:Nn \pretty:nn {
-	\pretty:n {#1}
-	\pretty:n {#2}
+	\cs_new_protected:Npn \prettyinit: {
+		\pretty_check_already_init:
+		\_prettyinit_unchecked:
+	}
 }
 
-\cs_new_protected:Nn \pretty:nnn {
-	\pretty:n {#1}
-	\pretty:n {#2}
-	\pretty:n {#3}
-}
+\cs_new_eq:NN \prettyinit \prettyinit:
 
-\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
+\precattl_exec:n {
 
 
+	\cs_new_protected:Npn \pretty:n #1 {
 
+		% ======== first write out the preamble if it isn't written. Only do once.
+		\ifx \pretty_check_already_init: \relax \prettyinit: \fi
 
-
-\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;
+		% ======== 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
+	}
 }
 
-/* https://stackoverflow.com/questions/7011602/stretching-iframe-in-html5 */
-#wrap_all { display: none; position:fixed; width:100%; height:100%; top: 0px; left: 0px; }
+% ======== Lua expandable variant.
+\sys_if_engine_luatex:T {
+	\cs_new:Npn \prettye:n #1 {
+		\directlua{prettyprint(token.scan_toks())}{#1}
+	}
 
-
-iframe{
-	position: absolute;
-	width: 100%;
-	height: 100%;
-	display: none;
+	\cs_new:Npn \prettye:w {
+		\directlua{prettyprintw()} {}
+	}
+	\cs_new:Npn \prettye:nw #1 {
+		\directlua{prettyprintw()} {#1}
+	}
 }
-#status{
-	flex: 0 0 1.3em;
-}
 
-#display_wrap{
-	flex: 1 0 auto;
+\cs_new_protected:Npn \pretty:w #1 \prettystop {
+	\pretty:n {#1} #1 \prettystop
 }
-#controller{
-	flex: 0 0 50px;
-}
 
-.control-button{
-}
+\cs_new:Npn \prettystop {}
 
+\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
+\let\prettyeN\prettye:n
+\let\prettyeW\prettye:w
 
-.tokenlist, .fileline{
-	border: 1px solid gray;
-	height: 2em;
-	overflow: scroll;
-	white-space: nowrap;
-}
-.tokenlist::-webkit-scrollbar, .fileline::-webkit-scrollbar { width: 0 !important }
+\cs_generate_variant:Nn \pretty:N {c}
 
-.fileline{
-	background-color: #404040;
-}
 
-.explicit_char_target{
-	background-color: #FF8080;
-}
-.explicit_char{
-	background-color: #606060;
-}
+% ======== 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)
+		\cs_new_protected:Npn #1 ##1 ##2 { #2 {##1 ##2} }
+	}
+	\cs_generate_variant:Nn \__tmp:NN {cc}
 
-
-.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)
+	\def \__tmp {pretty:n}
+	\int_step_inline:nn {9} {
+		\__tmp:cc {\__tmp n} {\__tmp}
+		\tl_put_right:Nn \__tmp {n}
 	}
-	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}`
+	\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)
+			\cs_new:Npn #1 ##1 ##2 { #2 {##1 ##2} }
+		}
+		\def \__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}
+		}
 	}
-	return token_span
-}
+\endgroup
 
-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
+\cs_new_protected:Nn \prettyshow:N {
+	\exp_args:No \pretty:n {\meaning #1}
 }
+\cs_generate_variant:Nn \prettyshow:N {c}
+\let\prettyshowN\prettyshow:N
+\let\prettyshowC\prettyshow:c
 
-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

Modified: trunk/Master/tlpkg/tlpsrc/prettytok.tlpsrc
===================================================================
--- trunk/Master/tlpkg/tlpsrc/prettytok.tlpsrc	2022-07-08 21:49:59 UTC (rev 63840)
+++ trunk/Master/tlpkg/tlpsrc/prettytok.tlpsrc	2022-07-08 21:51:18 UTC (rev 63841)
@@ -1,2 +1,3 @@
 depend l3kernel
 depend filecontentsdef
+depend precattl



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