% File: prettytok.sty % Copyright 2022-2023 user202729 % % This work may be distributed and/or modified under the conditions of the % LaTeX Project Public License (LPPL), either version 1.3c of this license or % (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. \ProvidesExplPackage{prettytok}{2023-04-18}{0.2.0}{Pretty-print token list} \RequirePackage{precattl} \RequirePackage{l3keys2e} \keys_define:nn{prettytok}{ mode.choices:nn={ term-8bit, term-shell, html }{ \str_set:Nx \_prettytok_mode {\l_keys_choice_tl} }, mode.initial:n = { term-8bit }, ignore-tlanalysis-bug.bool_set:N=\_prettytok_ignore_tlanalysis_bug, term-shell-decode-cmd.tl_set:N=\_prettytok_term_shell_decode_cmd, term-shell-decode-cmd.initial:n={}, term-shell-decode-cmd-print.bool_set:N=\_prettytok_term_shell_decode_cmd_print, html-file-name.tl_set:N=\_prettytok_html_file_name, html-file-name.initial:x={pretty-\jobname.html}, html-refresh-strategy.tl_set:N=\_prettytok_html_refresh_strategy, html-refresh-strategy.initial:n=4, html-refresh-duration.tl_set:N=\_prettytok_html_refresh_duration, html-refresh-duration.initial:n=1000, term-prefix.tl_set:N=\prettytermprefix, term-prefix.initial:n={>~}, term-prefix-more.tl_set:N=\prettytermprefixmore, term-prefix-more.initial:n={>~ ..~}, term-wrap-limit.tl_set:N=\prettytermwraplimit, term-wrap-limit.initial:n=70, } \ProcessKeysOptions{prettytok} % ======== check tl_analysis bug. \bool_if:NF \_prettytok_ignore_tlanalysis_bug { \tl_set:Nn \_prettytok_test {} \tl_analysis_map_inline:nn {ab} { \tl_analysis_map_inline:nn {cd} { \tl_put_right:Nx \_prettytok_test {#1 ##1 .} } } \tl_if_eq:NnF \_prettytok_test {ac.ad.bc.bd.} { \msg_new:nnn {prettytok} {tl-analysis-bug} { Because~of~an~tl-analysis~bug~(see~https://github.com/latex3/latex3/issues/1073),~ functions~will~not~be~usable~inside~tl-analysis~functions!~ Upgrade~your~LaTeX~version,~or~ pass-option~"ignore-tlanalysis-bug"~to~ignore~this~error. } \msg_error:nn {prettytok} {tl-analysis-bug} } } % ======== load Lua module. \sys_if_engine_luatex:T{ \directlua{require("prettytok")} \precattl_exec:n { \directlua{prettyprint_frozenrelaxtok=token.get_next().tok}\cFrozenRelax } } % ======== 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 \tl_build_put_right:Nn {NV} \cs_generate_variant:Nn \iow_now:Nn {NV} \str_if_eq:VnTF \_prettytok_mode {html} { \iow_new:N \_prettytok_file \ior_new:N \_prettytok_input_template_file \iow_open:NV \_prettytok_file \_prettytok_html_file_name \precattl_exec:n{ % write the template \ior_open:Nn \_prettytok_input_template_file {prettytok_template.html} \ior_str_map_variable:NNn \_prettytok_input_template_file \_prettytok_line { \str_replace_all:Nnn \_prettytok_line {\cO\^^I} {~} % workaround: XeTeX prints literal tab character as ^^I which obviously breaks JavaScript \iow_now:NV \_prettytok_file \_prettytok_line } \ior_close:N \_prettytok_input_template_file % refresh strategy \iow_now:Nx \_prettytok_file {set_refresh_strategy(\_prettytok_html_refresh_strategy,\_prettytok_html_refresh_duration)} \cs_new_protected:Npn \pretty:n #1 { % ======== 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 {)//