diff options
author | Norbert Preining <norbert@preining.info> | 2022-07-09 03:01:16 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2022-07-09 03:01:16 +0000 |
commit | 7891283a2f2fb8a8a884bb212c36da8082764a9b (patch) | |
tree | 98a050dec8439492144177997c6f66e4f9543d62 /macros/latex/contrib/prettytok | |
parent | c600912bde983d6a04c7ce42321d50d4c7c1a50b (diff) |
CTAN sync 202207090301
Diffstat (limited to 'macros/latex/contrib/prettytok')
-rw-r--r-- | macros/latex/contrib/prettytok/DEPENDS.txt | 3 | ||||
-rw-r--r-- | macros/latex/contrib/prettytok/README | 6 | ||||
-rw-r--r-- | macros/latex/contrib/prettytok/prettytok.lua | 98 | ||||
-rw-r--r-- | macros/latex/contrib/prettytok/prettytok.pdf | bin | 335928 -> 369580 bytes | |||
-rw-r--r-- | macros/latex/contrib/prettytok/prettytok.sty | 729 | ||||
-rw-r--r-- | macros/latex/contrib/prettytok/prettytok.tex | 171 | ||||
-rw-r--r-- | macros/latex/contrib/prettytok/prettytok_template.html | 283 |
7 files changed, 651 insertions, 639 deletions
diff --git a/macros/latex/contrib/prettytok/DEPENDS.txt b/macros/latex/contrib/prettytok/DEPENDS.txt index 5e0ae3b076..dd4fa25323 100644 --- a/macros/latex/contrib/prettytok/DEPENDS.txt +++ b/macros/latex/contrib/prettytok/DEPENDS.txt @@ -1,2 +1 @@ -expl3 -filecontentsdef +precattl diff --git a/macros/latex/contrib/prettytok/README b/macros/latex/contrib/prettytok/README index cefd81b493..531d9833dd 100644 --- a/macros/latex/contrib/prettytok/README +++ b/macros/latex/contrib/prettytok/README @@ -1,4 +1,8 @@ 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 @@ This work has the LPPL maintenance status `maintained'. 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. diff --git a/macros/latex/contrib/prettytok/prettytok.lua b/macros/latex/contrib/prettytok/prettytok.lua new file mode 100644 index 0000000000..a0aba07243 --- /dev/null +++ b/macros/latex/contrib/prettytok/prettytok.lua @@ -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 diff --git a/macros/latex/contrib/prettytok/prettytok.pdf b/macros/latex/contrib/prettytok/prettytok.pdf Binary files differindex 76ca759f67..5b10ffaf19 100644 --- a/macros/latex/contrib/prettytok/prettytok.pdf +++ b/macros/latex/contrib/prettytok/prettytok.pdf diff --git a/macros/latex/contrib/prettytok/prettytok.sty b/macros/latex/contrib/prettytok/prettytok.sty index e17eb204c6..3acea38c62 100644 --- a/macros/latex/contrib/prettytok/prettytok.sty +++ b/macros/latex/contrib/prettytok/prettytok.sty @@ -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} - - - - - -\@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) +\ProvidesExplPackage{prettytok}{2022/07/08}{0.0.1}{Pretty-print token list} +\RequirePackage{precattl} - \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 - } - } +% ======== 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. + } - % 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}} -} } - - - -\def \_precattldo_special #1 #2 { - % given #1 e.g. \cO, #2 e.g. {abc}, append <abc> in OTHER catcode to EI. - { - \escapechar=-1 +\fi - % 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 } - -\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. +% ======== 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} \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 - } - - % ======== 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 +% See also Lua function: local function check_file_opened() -% normal-catcode alias -\let\prettyN\pretty:n -\let\prettyX\pretty:x -\let\prettyO\pretty:o -\let\prettyV\pretty:V +\global\let \pretty_check_already_init: \relax -\cs_generate_variant:Nn \pretty:N {c} +\precattl_exec:n { + \cs_new_protected:Npn \_prettyinit_unchecked: { + \global\protected\def \pretty_check_already_init: {\msg_error:nn {prettytok} {already-initialized}} -\cs_new_protected:Nn \pretty:nn { - \pretty:n {#1} - \pretty:n {#2} -} + \iow_open:NV \_prettytok_file \prettyfilename -\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; -} + % 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 -#display_wrap{ - flex: 1 0 auto; -} -#controller{ - flex: 0 0 50px; -} + % refresh strategy + \iow_now:Nx \_prettytok_file {set_refresh_strategy(\prettyrefreshstrategy,\prettyrefreshduration)} + } -.control-button{ + \cs_new_protected:Npn \prettyinit: { + \pretty_check_already_init: + \_prettyinit_unchecked: + } } +\cs_new_eq:NN \prettyinit \prettyinit: -.tokenlist, .fileline{ - border: 1px solid gray; - height: 2em; - overflow: scroll; - white-space: nowrap; -} -.tokenlist::-webkit-scrollbar, .fileline::-webkit-scrollbar { width: 0 !important } +\precattl_exec:n { -.fileline{ - background-color: #404040; -} -.explicit_char_target{ - background-color: #FF8080; -} -.explicit_char{ - background-color: #606060; -} + \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 -.cs, .active_char{ - color: #FFFF00; -} -.cs::before{ - content: "\\"; -} -.cs::after{ - content: " "; + % ======== 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 + } } -#popup{ - display: none; - position: absolute; - border: 1px solid gray; - background-color: #000080ff; -} +% ======== Lua expandable variant. +\sys_if_engine_luatex:T { + \cs_new:Npn \prettye:n #1 { + \directlua{prettyprint(token.scan_toks())}{#1} + } -.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: "#"; + \cs_new:Npn \prettye:w { + \directlua{prettyprintw()} {} + } + \cs_new:Npn \prettye:nw #1 { + \directlua{prettyprintw()} {#1} + } } -.cmd__letter_cmd{ - color: #AAFFAA; +\cs_new_protected:Npn \pretty:w #1 \prettystop { + \pretty:n {#1} #1 \prettystop } -.cmd__spacer_cmd{ - color: #808080; -} +\cs_new:Npn \prettystop {} +\cs_generate_variant:Nn \pretty:n {x, o, V} +\let \pretty:N \pretty:n -input[type=button]{ - color: white; - background-color: #0000ff; - border: 0; -} +% ======== 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 -#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, "⇥") -} +\cs_generate_variant:Nn \pretty:N {c} -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) +% ======== 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} } } - output.appendChild(tl_div) -} + \cs_generate_variant:Nn \__tmp:NN {cc} -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}` + \def \__tmp {pretty:n} + \int_step_inline:nn {9} { + \__tmp:cc {\__tmp n} {\__tmp} + \tl_put_right:Nn \__tmp {n} } - return token_span -} - -function cs(...codepoints){ - const token_span=document.createElement("span") - const control_sequence_name=String.fromCodePoint(...codepoints) - //const meaning_str=readstr() + \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} + } + } +\endgroup - 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 diff --git a/macros/latex/contrib/prettytok/prettytok.tex b/macros/latex/contrib/prettytok/prettytok.tex index d21af2d0fe..96878ec457 100644 --- a/macros/latex/contrib/prettytok/prettytok.tex +++ b/macros/latex/contrib/prettytok/prettytok.tex @@ -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,29 +21,76 @@ \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} \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 @@ Note that the HTML file will not be touched if nothing is printed, as such it's 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 @@ There are also these functions, for convenience. \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 @@ first call to |\pretty:n| to customize the behavior. 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 diff --git a/macros/latex/contrib/prettytok/prettytok_template.html b/macros/latex/contrib/prettytok/prettytok_template.html new file mode 100644 index 0000000000..8764d49809 --- /dev/null +++ b/macros/latex/contrib/prettytok/prettytok_template.html @@ -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- |