From f5771bdcad46793d095405812d90b49792c91248 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Sat, 16 Nov 2019 22:15:42 +0000 Subject: unravel (16nov19) git-svn-id: svn://tug.org/texlive/trunk@52822 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/doc/latex/unravel/unravel.pdf | Bin 689310 -> 692007 bytes Master/texmf-dist/source/latex/unravel/unravel.dtx | 270 ++++++++++++++------- Master/texmf-dist/tex/latex/unravel/unravel.sty | 175 ++++++++----- 3 files changed, 293 insertions(+), 152 deletions(-) diff --git a/Master/texmf-dist/doc/latex/unravel/unravel.pdf b/Master/texmf-dist/doc/latex/unravel/unravel.pdf index df3f7437be8..b8f069b2bb1 100644 Binary files a/Master/texmf-dist/doc/latex/unravel/unravel.pdf and b/Master/texmf-dist/doc/latex/unravel/unravel.pdf differ diff --git a/Master/texmf-dist/source/latex/unravel/unravel.dtx b/Master/texmf-dist/source/latex/unravel/unravel.dtx index cd7e87a4bf9..1b205fb31b2 100644 --- a/Master/texmf-dist/source/latex/unravel/unravel.dtx +++ b/Master/texmf-dist/source/latex/unravel/unravel.dtx @@ -23,9 +23,9 @@ % % \title{The \textsf{unravel} package: \\ % watching TeX digest tokens\thanks{This -% file has version number 0.2g, last revised 2019/03/23.}} +% file has version number 0.2h, last revised 2019/11/15.}} % \author{Bruno Le Floch} -% \date{2019/03/23} +% \date{2019/11/15} % % \maketitle % \tableofcontents @@ -213,6 +213,24 @@ % neither if the option is negative. % \end{function} % +% \begin{function}{prompt-input} +% Comma-delimited list option (empty by default) whose items are used +% one by one as if the user typed them at the prompt. Since the +% key-value list is itself comma-delimited, the value here must be +% wrapped in braces. For instance, |prompt-input = {s10, m, u\def}| +% skips $10$ steps, shows the first token's meaning, then continues +% silently until the first token is~|\def|, and any subsequent prompt +% is treated normally with user interaction. This can be useful when +% repeatedly debugging complicated code when the issue is known to lie +% quite late in the code. +% +% As for any |clist|, spaces are discarded around each comma and empty +% entries are removed, then for each item one pair of braces is +% removed (if any is present); to get an empty item use an empty brace +% group, such as in |prompt-input = {s10, {}, x}|. Category codes are +% those in effect when the |prompt-input| option is read. +% \end{function} +% % \begin{function}{trace-assigns, trace-expansion, trace-other} % Boolean options (default \texttt{true}) controlling what steps % produce any output at all. The keys |trace-assigns|, @@ -246,17 +264,14 @@ % \tn{lastpenalty}, \tn{lastskip}, \tn{currentiflevel} and % \tn{currentiftype} may have wrong values. Perhaps % \tn{currentgrouplevel} and \tn{currentgrouptype} too. -% \item Tokens passed to \tn{afterassignment} are not yet kept after -% \pkg{unravel} is done even if there has been no assignment. +% \item Setting \tn{globaldefs} to a non-zero value may cause problems. % \item Tokens passed to \tn{aftergroup} are lost when \pkg{unravel} is % done. -% \item In \XeTeX{}, characters beyond the basic multilingual plane may -% break \pkg{unravel} (not tested). % \item For \pkg{unravel}, category codes are fixed when a file is read % using \tn{input}, % while \TeX{} only fixes category codes when the corresponding % characters are converted to tokens. Similarly, the argument of -% \tn{scantokens} is converted to the new category code r\'egime in +% \tn{scantokens} is converted to the new category code regime in % one go, and the result must be balanced. % \item Explicit begin-group and end-group characters other than the % usual left and right braces may make \pkg{unravel} choke, or may be @@ -273,10 +288,7 @@ % \subsection{Future perhaps} % % \begin{itemize} -% \item Allow users to change some settings globally/for one |\unravel|. % \item Allow to replay steps that have already been run. -% \item Fix the display for \tn{if} and \tn{ifcat} (remove extraneous -% \cs{exp_not:N}). % \item Use the |file-error| fatal error message: first implement % \cs{@@_file_if_exist:nTF} and use it to determine whether % \tn{input} will throw a fatal error in \tn{batchmode} and @@ -545,7 +557,7 @@ {% \csname @@_setup_restore:\endcsname \ProvidesExplPackage - {unravel} {2019/03/23} {0.2g} {Watching TeX digest tokens}% + {unravel} {2019/11/15} {0.2h} {Watching TeX digest tokens}% \csname @@_setup_unravel:\endcsname }% % \end{macrocode} @@ -870,16 +882,11 @@ % % \subsubsection{Helpers for control flow} % -% \begin{macro}[EXP]{\@@_exit:w, \@@_exit_error:w, \@@_exit_hard:w, \@@_exit_point:} +% \begin{macro}[EXP]{\@@_exit:w, \@@_exit_hard:w, \@@_exit_point:} % Jump to the very end of this instance of \cs{unravel}. % \begin{macrocode} \cs_new_eq:NN \@@_exit_point: \prg_do_nothing: \cs_new:Npn \@@_exit:w #1 \@@_exit_point: { } -\cs_new:Npn \@@_exit_error:w #1 \@@_exit_point: #2 \@@_final_bad: - { - \@@_error:nnnnn { runaway-unravel } { } { } { } { } - #2 - } \cs_new:Npn \@@_exit_hard:w #1 \@@_exit_point: #2 \@@_exit_point: { } % \end{macrocode} % \end{macro} @@ -1151,31 +1158,31 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}{\@@_prev_input_join_get:nN} -% \begin{macro}{\@@_join_get_aux:NNN} +% \begin{macro}{\@@_prev_input_join_get:nnN} +% \begin{macro}{\@@_join_get_aux:NNnN} % Pops the previous-input sequence twice to get some value in % \cs{l_@@_head_tl} and some sign or decimal number in % \cs{l_@@_tmpa_tl}. Combines them into a value, using % the appropriate evaluation function, determined based % on~|#1|. % \begin{macrocode} -\cs_new_protected:Npn \@@_prev_input_join_get:nN #1 +\cs_new_protected:Npn \@@_prev_input_join_get:nnN #1 { \int_case:nnF {#1} { - { 2 } { \@@_join_get_aux:NNN \skip_eval:n \tex_glueexpr:D } - { 3 } { \@@_join_get_aux:NNN \muskip_eval:n \tex_muexpr:D } + { 2 } { \@@_join_get_aux:NNnN \skip_eval:n \tex_glueexpr:D } + { 3 } { \@@_join_get_aux:NNnN \muskip_eval:n \tex_muexpr:D } } { \@@_error:nnnnn { internal } { join-factor } { } { } { } - \@@_join_get_aux:NNN \use:n \prg_do_nothing: + \@@_join_get_aux:NNnN \use:n \prg_do_nothing: } } -\cs_new_protected:Npn \@@_join_get_aux:NNN #1#2#3 +\cs_new_protected:Npn \@@_join_get_aux:NNnN #1#2#3#4 { \@@_prev_input_gpop:N \l_@@_head_tl \@@_prev_input_gpop:N \l_@@_tmpa_tl - \tl_set:Nx #3 { #1 { \l_@@_tmpa_tl #2 \l_@@_head_tl } } + \tl_set:Nx #4 { #1 { \l_@@_tmpa_tl #2 \l_@@_head_tl #3 } } } % \end{macrocode} % \end{macro} @@ -1212,6 +1219,7 @@ % \g_@@_default_internal_debug_bool , \g_@@_internal_debug_bool , % \g_@@_default_number_steps_bool , \g_@@_number_steps_bool , % \g_@@_default_online_int , \g_@@_online_int , +% \g_@@_default_prompt_input_clist , \g_@@_prompt_input_clist , % \g_@@_default_trace_assigns_bool , \g_@@_trace_assigns_bool , % \g_@@_default_trace_expansion_bool , \g_@@_trace_expansion_bool , % \g_@@_default_trace_other_bool , \g_@@_trace_other_bool , @@ -1227,6 +1235,7 @@ \bool_new:N \g_@@_default_internal_debug_bool \bool_new:N \g_@@_default_number_steps_bool \int_new:N \g_@@_default_online_int +\clist_new:N \g_@@_default_prompt_input_clist \bool_new:N \g_@@_default_trace_assigns_bool \bool_new:N \g_@@_default_trace_expansion_bool \bool_new:N \g_@@_default_trace_other_bool @@ -1241,6 +1250,7 @@ \bool_new:N \g_@@_internal_debug_bool \bool_new:N \g_@@_number_steps_bool \int_new:N \g_@@_online_int +\clist_new:N \g_@@_prompt_input_clist \bool_new:N \g_@@_trace_assigns_bool \bool_new:N \g_@@_trace_expansion_bool \bool_new:N \g_@@_trace_other_bool @@ -2289,11 +2299,10 @@ \@@_tex_primitive:nnn { pdfximagebbox } { convert } { 31 } \@@_tex_primitive:nnn { jobname } { convert } { 32 } \sys_if_engine_luatex:T - { - \@@_tex_primitive:nnn { directlua } { convert } { 33 } - \@@_tex_primitive:nnn { expanded } { convert } { 34 } - \@@_tex_primitive:nnn { luaescapestring } { convert } { 35 } - } + { \@@_tex_primitive:nnn { directlua } { convert } { 33 } } +\@@_tex_primitive:nnn { expanded } { convert } { 34 } +\sys_if_engine_luatex:T + { \@@_tex_primitive:nnn { luaescapestring } { convert } { 35 } } \sys_if_engine_xetex:T { \@@_tex_primitive:nnn { Ucharcat } { convert } { 40 } @@ -2329,8 +2338,11 @@ % % \begin{macro}{\@@_get_next:} % \begin{macro}{\@@_get_next_aux:w} -% If the input is empty, forcefully exit. Otherwise, -% remove the first token in the input, and store it in +% If the input is empty, insert a frozen \tn{relax} (the alternative +% would be either to grab a token in the input stream after +% \cs{unravel}, which is tough, or simply produce an error and exit; +% perhaps this should be configurable). +% Then remove the first token in the input, and store it in % \cs{l_@@_head_gtl}. Set \cs{l_@@_head_token} equal in meaning to % that first token. Then set \cs{l_@@_head_tl} to contain the token, % unless it is a begin-group or end-group character, in which case @@ -2339,20 +2351,22 @@ \cs_new_protected:Npn \@@_get_next: { \@@_input_if_empty:TF - { \@@_exit_error:w } { - \@@_input_gpop:N \l_@@_head_gtl - \gtl_head_do:NN \l_@@_head_gtl \@@_get_next_aux:w - \gtl_if_tl:NTF \l_@@_head_gtl - { - \tl_set:Nx \l_@@_head_tl - { \gtl_head:N \l_@@_head_gtl } - \token_if_eq_meaning:NNT - \l_@@_head_token \@@_special_relax: - \@@_get_next_notexpanded: - } - { \tl_clear:N \l_@@_head_tl } + \@@_error:nnnnn { runaway-unravel } { } { } { } { } + \@@_back_input_gtl:N \c_@@_frozen_relax_gtl } + { } + \@@_input_gpop:N \l_@@_head_gtl + \gtl_head_do:NN \l_@@_head_gtl \@@_get_next_aux:w + \gtl_if_tl:NTF \l_@@_head_gtl + { + \tl_set:Nx \l_@@_head_tl + { \gtl_head:N \l_@@_head_gtl } + \token_if_eq_meaning:NNT + \l_@@_head_token \@@_special_relax: + \@@_get_next_notexpanded: + } + { \tl_clear:N \l_@@_head_tl } } \cs_new_protected:Npn \@@_get_next_aux:w { \cs_set_eq:NN \l_@@_head_token } @@ -2582,7 +2596,7 @@ % sequence is \tn{nullfont} or similar (note that we do not search for % \verb*|select font|, as the code to trim the escape character from % the meaning may have removed the leading~|s|). Otherwise, we expect -% the \tn{meaning} to be \tn{char} or \tn{mathchar} followed by +% the \tn{meaning} to be \tn{char} or \tn{mathchar} or similar followed by % |"|~and an uppercase hexadecimal number, or one of \tn{count}, % \tn{dimen}, \tn{skip}, \tn{muskip} or \tn{toks} followed by a % decimal number. @@ -2610,7 +2624,7 @@ % Insert \cs{q_mark} before the first non-letter (in fact, anything % less than~|A|) in the \tn{meaning} by looping one character at a % time (skipping spaces, but there should be none). We expect the -% first part to be |char| or~|mathchar| (or |kchar| in up\TeX{}), +% first part to be |char| or~|mathchar| (or |kchar| or |omathchar| in (u)p\TeX{}), % or one of |count|, |dimen|, % |skip|, |muskip|, or |toks|. In the first two (three) cases, the command is % |char_given| or |math_given|. It is otherwise identical to the @@ -2646,6 +2660,7 @@ { char } { \@@_set_cmd_aux_given:n { char_given } } { kchar } { \@@_set_cmd_aux_given:n { char_given } } { mathchar } { \@@_set_cmd_aux_given:n { math_given } } + { omathchar } { \@@_set_cmd_aux_given:n { math_given } } } { \@@_set_cmd_aux_primitive:nTF {#1} @@ -3784,7 +3799,6 @@ % \end{macrocode} % \end{macro} % -% ^^A todo: comment % \begin{macro}{\@@_scan_expr:N} % \begin{macro}{\@@_scan_expr_aux:NN, \@@_scan_factor:N} % \begin{macrocode} @@ -3974,6 +3988,10 @@ % and |inf| is |#2|. The third argument of this procedure is omitted % here, as the corresponding shortcut is provided as a separate % function, \cs{@@_scan_dim_unit:nN}. +% +% Ideally, \cs{@@_scan_inf_unit_loop:} would produce an \pkg{unravel} +% error when reaching the third ``L'', rather than letting TeX produce +% the error later on. % \begin{macrocode} \cs_new_protected:Npn \@@_scan_dimen:nN #1#2 { @@ -4038,11 +4056,14 @@ { \@@_prev_input_gpush: \@@_scan_something_internal:n {#1} - \@@_prev_input_join_get:nN {#1} \l_@@_tmpa_tl + \int_compare:nNnTF \g_@@_val_level_int = { 0 } + { \@@_prev_input_join_get:nnN {#1} { sp } \l_@@_tmpa_tl } + { \@@_prev_input_join_get:nnN {#1} { } \l_@@_tmpa_tl } \@@_prev_input_gpush:N \l_@@_tmpa_tl - \@@_break:w + \exp_after:wN \use_none:n \@@_break:w } - { \@@_back_input: } + { } + \@@_back_input: \int_compare:nNnT {#1} = { 3 } { \@@_scan_keyword:nT { mMuU } { \@@_break:w } @@ -4069,6 +4090,7 @@ \@@_tex_error:nV { missing-pt } \l_@@_head_tl \@@_prev_input:n { pt } \@@_break_point: + \@@_skip_optional_space: } \cs_new_protected:Npn \@@_scan_inf_unit_loop: { \@@_scan_keyword:nT { lL } { \@@_scan_inf_unit_loop: } } @@ -4119,7 +4141,7 @@ { \@@_break:w } } { \@@_back_input: \@@_scan_dimen:nN {#1} \c_false_bool } - \@@_prev_input_join_get:nN {#1} \l_@@_tmpa_tl + \@@_prev_input_join_get:nnN {#1} { } \l_@@_tmpa_tl \@@_prev_input_gpush: \@@_prev_input_gpush:N \l_@@_tmpa_tl \@@_scan_keyword:nT { pPlLuUsS } @@ -4127,7 +4149,7 @@ \@@_scan_keyword:nT { mMiInNuUsS } { \@@_scan_dimen:nN {#1} \c_true_bool } \@@_break_point: - \@@_prev_input_join_get:nN {#1} \l_@@_tmpa_tl + \@@_prev_input_join_get:nnN {#1} { } \l_@@_tmpa_tl \@@_prev_input_silent:V \l_@@_tmpa_tl } % \end{macrocode} @@ -4185,7 +4207,6 @@ % \end{macrocode} % \end{macro} % -% ^^A todo: hash doubling is wrong % \begin{macro}{\@@_scan_toks_to_str:} % \begin{macrocode} \cs_new_protected:Npn \@@_scan_toks_to_str: @@ -4359,8 +4380,6 @@ % \end{macrocode} % \end{macro} % -% ^^A todo: catch runaway expand/get_x_next. (get_next too, probably) -% % \begin{macro}{\@@_scan_alt_rule:} % \begin{macrocode} \cs_new_protected:Npn \@@_scan_alt_rule: @@ -4686,6 +4705,7 @@ % \end{macro} % % \begin{macro}{\@@_mathchar:n, \@@_mathchar:x} +% ^^A todo: \omathchar support % \begin{macrocode} \cs_new_protected:Npn \@@_mathchar:n #1 { @@ -4970,29 +4990,18 @@ % \end{macrocode} % \end{macro} % -% \subsection{One step} -% -% \begin{macro}{\@@_do_step:} -% Perform the action if the corresponding command exists. If that -% command does not exist, complain, and leave the token in the output. -% \begin{macrocode} -\cs_new_protected:Npn \@@_do_step: - { - \@@_set_action_text: - \bool_if:NT \g_@@_internal_debug_bool - { \@@_exp_args:Nx \iow_term:n { Cmd:~\int_to_arabic:n { \l_@@_head_cmd_int } } } - \cs_if_exist_use:cF - { @@_cmd_ \int_use:N \l_@@_head_cmd_int : } - { \@@_error:nxxxx { internal } { unknown-command } { } { } { } } - } -% \end{macrocode} -% \end{macro} -% % \subsection{Commands} % % We will implement commands in order of their command codes (some of % the more elaborate commands call auxiliaries defined in other -% sections). +% sections). Some cases are forbidden. +% +% \begin{macro}{\@@_forbidden_case:} +% \begin{macrocode} +\cs_new_protected:Npn \@@_forbidden_case: + { \@@_tex_error:nV { forbidden-case } \l_@@_head_tl } +% \end{macrocode} +% \end{macro} % % \subsubsection{Characters: from 0 to 15} % @@ -5395,8 +5404,6 @@ } % \end{macrocode} % -% ^^A todo: implement \@@_forbidden_case: -% % \begin{macro}{\@@_do_move:} % Scan a dimension and a box, and perform the shift, printing the % appropriate action. @@ -7023,8 +7030,8 @@ % \tn{pdffilemoddate}, \tn{pdffilesize}, \tn{pdfmdfivesum}, % \tn{pdffiledump}, \tn{pdfmatch}, \tn{pdflastmatch}, % \tn{pdfuniformdeviate}, \tn{pdfnormaldeviate}, \tn{pdfinsertht}, -% \tn{pdfximagebbox}, \tn{jobname}, and in -% \LuaTeX{} \tn{directlua}, \tn{expanded}, \tn{luaescapestring}. +% \tn{pdfximagebbox}, \tn{jobname}, \tn{expanded}, and in +% \LuaTeX{} \tn{directlua}, \tn{luaescapestring}, and in \XeTeX{} \tn{Ucharcat}. % \item |the=111| for \tn{the}, \tn{unexpanded}, and \tn{detokenize}. % \item |top_bot_mark=112| \tn{topmark}, \tn{firstmark}, \tn{botmark}, % \tn{splitfirstmark}, \tn{splitbotmark}, \tn{topmarks}, @@ -7378,7 +7385,8 @@ \cs_if_eq:NNTF #1 \@@_get_token_xdef: { \tl_put_right:NV \l_@@_defining_tl \l_@@_head_tl - \@@_prev_input:V \l_@@_head_tl + \@@_prev_input_silent:x { \l_@@_head_tl } + \@@_print_action: } { \cs_if_eq:NNTF #1 \@@_get_token_x: @@ -7624,7 +7632,7 @@ \@@_print_expansion:x { \g_@@_action_text_str = false ~ - => ~ skipped ~ to ~ \iow_char:N\\fi + => ~ skip ~ to ~ \tl_to_str:N \l_@@_head_tl } } \cs_new_protected:Npn \@@_cond_false_loop:n #1 @@ -7671,7 +7679,6 @@ % \end{macrocode} % \end{macro} % -% ^^A todo: fix interaction with noexpand and active chars (what interaction?) % \begin{macro}{\@@_test_two_chars:nn, \@@_test_two_chars_get:n, \@@_test_two_chars_gtl:N} % \begin{macrocode} \cs_new_protected:Npn \@@_test_two_chars:nn #1 @@ -7710,7 +7717,10 @@ \gtl_if_head_is_group_begin:NTF #1 { \c_group_begin_token } { \gtl_if_head_is_group_end:NTF #1 { \c_group_end_token } - { \exp_not:N \exp_not:N \gtl_head_do:NN #1 \exp_not:N } + { + \exp_not:N \exp_not:N + \exp_not:f { \gtl_head_do:NN #1 \exp_stop_f: } + } } } } @@ -7872,10 +7882,9 @@ \@@_set_action_text:x { \g_@@_action_text_str \c_space_tl - => ~ skipped ~ to ~ \tl_to_str:N \l_@@_head_tl + => ~ skip ~ to ~ \tl_to_str:N \l_@@_head_tl } } - % ^^A todo: in the terminal output the token itself is missing. \@@_print_expansion: \@@_cond_pop: } @@ -8222,13 +8231,28 @@ } \cs_new_protected:Npn \@@_prompt_aux: { - \int_compare:nNnT { \tex_interactionmode:D } = { 3 } + \clist_if_empty:NTF \g_@@_prompt_input_clist { - \bool_if:NTF \g_@@_explicit_prompt_bool - { \@@_ior_str_get:Nc \c_@@_prompt_ior } - { \@@_ior_str_get:Nc \c_@@_noprompt_ior } - { Your~input } - \exp_args:Nv \@@_prompt_treat:n { Your~input } + \int_compare:nNnT { \tex_interactionmode:D } = { 3 } + { + \bool_if:NTF \g_@@_explicit_prompt_bool + { \@@_ior_str_get:Nc \c_@@_prompt_ior } + { \@@_ior_str_get:Nc \c_@@_noprompt_ior } + { Your~input } + \exp_args:Nv \@@_prompt_treat:n { Your~input } + } + } + { + \clist_gpop:NN \g_@@_prompt_input_clist \l_@@_tmpa_tl + \group_begin: + \@@_set_escapechar:n { 92 } + \@@_print:x + { + \bool_if:NT \g_@@_explicit_prompt_bool { Your~input= } + \tl_to_str:N \l_@@_tmpa_tl + } + \group_end: + \exp_args:NV \@@_prompt_treat:n \l_@@_tmpa_tl } } \cs_new_protected:Npn \@@_prompt_treat:n #1 @@ -8248,7 +8272,11 @@ \group_end: \@@_exit_hard:w } - { X } { \tex_batchmode:D \tex_end:D } + { X } + { + \tex_batchmode:D + \tex_read:D -1 to \l_@@_tmpa_tl + } { s } { \@@_prompt_scan_int:nn {#1} \@@_prompt_silent_steps:n } { o } { \@@_prompt_scan_int:nn {#1} @@ -8379,6 +8407,7 @@ { \exp_not:N \@@:nn \tl_to_str:N \g_@@_until_tl } } { + \int_gzero:N \g_@@_nonstop_int \int_gset:Nn \g_@@_online_int { 1 } \tl_gclear:N \g_@@_before_print_state_tl } @@ -8483,6 +8512,7 @@ max-input .int_gset:N = \g_@@_default_max_input_int , number-steps .bool_gset:N = \g_@@_default_number_steps_bool , online .int_gset:N = \g_@@_default_online_int , + prompt-input .clist_gset:N = \g_@@_default_prompt_input_clist , trace-assigns .bool_gset:N = \g_@@_default_trace_assign_bool , trace-expansion .bool_gset:N = \g_@@_default_trace_expansion_bool , trace-other .bool_gset:N = \g_@@_default_trace_other_bool , @@ -8497,6 +8527,7 @@ max-input .int_gset:N = \g_@@_max_input_int , number-steps .bool_gset:N = \g_@@_number_steps_bool , online .int_gset:N = \g_@@_online_int , + prompt-input .clist_gset:N = \g_@@_prompt_input_clist , trace-assigns .bool_gset:N = \g_@@_trace_assigns_bool , trace-expansion .bool_gset:N = \g_@@_trace_expansion_bool , trace-other .bool_gset:N = \g_@@_trace_other_bool , @@ -8589,6 +8620,7 @@ \@@_exit_point: \@@_print_outcome: \@@_final_test: + \@@_final_after_assignment: \@@_exit_point: } \cs_new_protected:Npn \unravel_get:nnN #1#2#3 @@ -8609,6 +8641,7 @@ \bool_gset_eq:NN \g_@@_internal_debug_bool \g_@@_default_internal_debug_bool \bool_gset_eq:NN \g_@@_number_steps_bool \g_@@_default_number_steps_bool \int_gset_eq:NN \g_@@_online_int \g_@@_default_online_int + \clist_gset_eq:NN \g_@@_prompt_input_clist \g_@@_default_prompt_input_clist \bool_gset_eq:NN \g_@@_trace_assigns_bool \g_@@_default_trace_assigns_bool \bool_gset_eq:NN \g_@@_trace_expansion_bool \g_@@_default_trace_expansion_bool \bool_gset_eq:NN \g_@@_trace_other_bool \g_@@_default_trace_other_bool @@ -8669,6 +8702,22 @@ % \end{macrocode} % \end{macro} % +% \begin{macro}{\@@_do_step:} +% Perform the action if the corresponding command exists. If that +% command does not exist, complain, and leave the token in the output. +% \begin{macrocode} +\cs_new_protected:Npn \@@_do_step: + { + \@@_set_action_text: + \bool_if:NT \g_@@_internal_debug_bool + { \@@_exp_args:Nx \iow_term:n { Cmd:~\int_to_arabic:n { \l_@@_head_cmd_int } } } + \cs_if_exist_use:cF + { @@_cmd_ \int_use:N \l_@@_head_cmd_int : } + { \@@_error:nxxxx { internal } { unknown-command } { } { } { } } + } +% \end{macrocode} +% \end{macro} +% % ^^A todo: improve error message % \begin{macro}{\@@_final_test:, \@@_final_bad:} % Make sure that the \cs{unravel} finished correctly. The error @@ -8694,6 +8743,17 @@ % \end{macrocode} % \end{macro} % +% \begin{macro}{\@@_final_after_assignment:} +% Salvage any remaining \tn{afterassignment} token. +% \begin{macrocode} +\cs_new_protected:Npn \@@_final_after_assignment: + { + \gtl_if_empty:NF \g_@@_after_assignment_gtl + { \gtl_head_do:NN \g_@@_after_assignment_gtl \tex_afterassignment:D } + } +% \end{macrocode} +% \end{macro} +% % \subsection{Messages} % % \begin{macrocode} @@ -8745,12 +8805,14 @@ \msg_new:nnn { unravel } { bad-unless } { \iow_char:N\\unless~not~followed~by~conditional. } \msg_new:nnn { unravel } { runaway-if } - { Runaway~\iow_char:N\\if... } + { Runaway~\iow_char:N\\if...~Exiting~\iow_char:N\\unravel } \msg_new:nnn { unravel } { runaway-macro-parameter } { Runaway~macro~parameter~\# #2~after \\\\ \iow_indent:n {#1} } +\msg_new:nnn { unravel } { runaway-text } + { Runaway~braced~argument~for~TeX~primitive.~Exiting~\iow_char:N\\unravel } \msg_new:nnn { unravel } { extra-or } { Extra~\iow_char:N\\or. } \msg_new:nnn { unravel } { missing-equals } @@ -8779,12 +8841,32 @@ { TeX~provides~no~further~help~for~this~error. } { TeX's~advice~is:\\\\ \iow_indent:n {#3} } } -\msg_new:nnn { unravel } { runaway-unravel } - { Runaway~\iow_char:N\\unravel } +\msg_new:nnnn { unravel } { runaway-unravel } + { Runaway~\iow_char:N\\unravel,~so~\iow_char:N\\relax~inserted. } + { + Some~TeX~command~expects~input~beyond~the~end~of~ + the~argument~of~\iow_char:N\\unravel. + } % \end{macrocode} % % Some error messages from \TeX{} itself. % \begin{macrocode} +\@@_tex_msg_new:nnn { forbidden-case } + { + You~can't~use~`\exp_after:wN \token_to_str:N \l_@@_head_tl'~in~ + \mode_if_vertical:TF { vertical } + { + \mode_if_horizontal:TF { horizontal } + { \mode_if_math:TF { math } { no } } + } ~ mode. + } + { + Sorry,~but~I'm~not~programmed~to~handle~this~case;~ + I'll~just~pretend~that~you~didn't~ask~for~it.~ + If~you're~in~the~wrong~mode,~you~might~be~able~to~ + return~to~the~right~one~by~typing~`I\iow_char:N\}'~or~ + `I\iow_char:N\$'~or~`I\iow_char:N\\par'. + } \@@_tex_msg_new:nnn { incompatible-mag } { Incompatible~magnification~ diff --git a/Master/texmf-dist/tex/latex/unravel/unravel.sty b/Master/texmf-dist/tex/latex/unravel/unravel.sty index b09b7fa0de5..ec8a48459e8 100644 --- a/Master/texmf-dist/tex/latex/unravel/unravel.sty +++ b/Master/texmf-dist/tex/latex/unravel/unravel.sty @@ -153,7 +153,7 @@ {% \csname __unravel_setup_restore:\endcsname \ProvidesExplPackage - {unravel} {2019/03/23} {0.2g} {Watching TeX digest tokens}% + {unravel} {2019/11/15} {0.2h} {Watching TeX digest tokens}% \csname __unravel_setup_unravel:\endcsname }% \cs_new_eq:NN \__unravel_currentgrouptype: \tex_currentgrouptype:D @@ -324,11 +324,6 @@ } \cs_new_eq:NN \__unravel_exit_point: \prg_do_nothing: \cs_new:Npn \__unravel_exit:w #1 \__unravel_exit_point: { } -\cs_new:Npn \__unravel_exit_error:w #1 \__unravel_exit_point: #2 \__unravel_final_bad: - { - \__unravel_error:nnnnn { runaway-unravel } { } { } { } { } - #2 - } \cs_new:Npn \__unravel_exit_hard:w #1 \__unravel_exit_point: #2 \__unravel_exit_point: { } \cs_new_eq:NN \__unravel_break_point: \prg_do_nothing: \cs_new:Npn \__unravel_break:w #1 \__unravel_break_point: { } @@ -473,23 +468,23 @@ \gtl_concat:NNN \l__unravel_prev_input_gtl \l__unravel_prev_input_gtl #1 \__unravel_prev_input_gpush_gtl:N \l__unravel_prev_input_gtl } -\cs_new_protected:Npn \__unravel_prev_input_join_get:nN #1 +\cs_new_protected:Npn \__unravel_prev_input_join_get:nnN #1 { \int_case:nnF {#1} { - { 2 } { \__unravel_join_get_aux:NNN \skip_eval:n \tex_glueexpr:D } - { 3 } { \__unravel_join_get_aux:NNN \muskip_eval:n \tex_muexpr:D } + { 2 } { \__unravel_join_get_aux:NNnN \skip_eval:n \tex_glueexpr:D } + { 3 } { \__unravel_join_get_aux:NNnN \muskip_eval:n \tex_muexpr:D } } { \__unravel_error:nnnnn { internal } { join-factor } { } { } { } - \__unravel_join_get_aux:NNN \use:n \prg_do_nothing: + \__unravel_join_get_aux:NNnN \use:n \prg_do_nothing: } } -\cs_new_protected:Npn \__unravel_join_get_aux:NNN #1#2#3 +\cs_new_protected:Npn \__unravel_join_get_aux:NNnN #1#2#3#4 { \__unravel_prev_input_gpop:N \l__unravel_head_tl \__unravel_prev_input_gpop:N \l__unravel_tmpa_tl - \tl_set:Nx #3 { #1 { \l__unravel_tmpa_tl #2 \l__unravel_head_tl } } + \tl_set:Nx #4 { #1 { \l__unravel_tmpa_tl #2 \l__unravel_head_tl #3 } } } \tl_new:N \g__unravel_before_print_state_tl \tl_new:N \g__unravel_before_prompt_tl @@ -499,6 +494,7 @@ \bool_new:N \g__unravel_default_internal_debug_bool \bool_new:N \g__unravel_default_number_steps_bool \int_new:N \g__unravel_default_online_int +\clist_new:N \g__unravel_default_prompt_input_clist \bool_new:N \g__unravel_default_trace_assigns_bool \bool_new:N \g__unravel_default_trace_expansion_bool \bool_new:N \g__unravel_default_trace_other_bool @@ -513,6 +509,7 @@ \bool_new:N \g__unravel_internal_debug_bool \bool_new:N \g__unravel_number_steps_bool \int_new:N \g__unravel_online_int +\clist_new:N \g__unravel_prompt_input_clist \bool_new:N \g__unravel_trace_assigns_bool \bool_new:N \g__unravel_trace_expansion_bool \bool_new:N \g__unravel_trace_other_bool @@ -1263,11 +1260,10 @@ \__unravel_tex_primitive:nnn { pdfximagebbox } { convert } { 31 } \__unravel_tex_primitive:nnn { jobname } { convert } { 32 } \sys_if_engine_luatex:T - { - \__unravel_tex_primitive:nnn { directlua } { convert } { 33 } - \__unravel_tex_primitive:nnn { expanded } { convert } { 34 } - \__unravel_tex_primitive:nnn { luaescapestring } { convert } { 35 } - } + { \__unravel_tex_primitive:nnn { directlua } { convert } { 33 } } +\__unravel_tex_primitive:nnn { expanded } { convert } { 34 } +\sys_if_engine_luatex:T + { \__unravel_tex_primitive:nnn { luaescapestring } { convert } { 35 } } \sys_if_engine_xetex:T { \__unravel_tex_primitive:nnn { Ucharcat } { convert } { 40 } @@ -1288,20 +1284,22 @@ \cs_new_protected:Npn \__unravel_get_next: { \__unravel_input_if_empty:TF - { \__unravel_exit_error:w } { - \__unravel_input_gpop:N \l__unravel_head_gtl - \gtl_head_do:NN \l__unravel_head_gtl \__unravel_get_next_aux:w - \gtl_if_tl:NTF \l__unravel_head_gtl - { - \tl_set:Nx \l__unravel_head_tl - { \gtl_head:N \l__unravel_head_gtl } - \token_if_eq_meaning:NNT - \l__unravel_head_token \__unravel_special_relax: - \__unravel_get_next_notexpanded: - } - { \tl_clear:N \l__unravel_head_tl } + \__unravel_error:nnnnn { runaway-unravel } { } { } { } { } + \__unravel_back_input_gtl:N \c__unravel_frozen_relax_gtl } + { } + \__unravel_input_gpop:N \l__unravel_head_gtl + \gtl_head_do:NN \l__unravel_head_gtl \__unravel_get_next_aux:w + \gtl_if_tl:NTF \l__unravel_head_gtl + { + \tl_set:Nx \l__unravel_head_tl + { \gtl_head:N \l__unravel_head_gtl } + \token_if_eq_meaning:NNT + \l__unravel_head_token \__unravel_special_relax: + \__unravel_get_next_notexpanded: + } + { \tl_clear:N \l__unravel_head_tl } } \cs_new_protected:Npn \__unravel_get_next_aux:w { \cs_set_eq:NN \l__unravel_head_token } @@ -1470,6 +1468,7 @@ { char } { \__unravel_set_cmd_aux_given:n { char_given } } { kchar } { \__unravel_set_cmd_aux_given:n { char_given } } { mathchar } { \__unravel_set_cmd_aux_given:n { math_given } } + { omathchar } { \__unravel_set_cmd_aux_given:n { math_given } } } { \__unravel_set_cmd_aux_primitive:nTF {#1} @@ -2386,11 +2385,14 @@ { \__unravel_prev_input_gpush: \__unravel_scan_something_internal:n {#1} - \__unravel_prev_input_join_get:nN {#1} \l__unravel_tmpa_tl + \int_compare:nNnTF \g__unravel_val_level_int = { 0 } + { \__unravel_prev_input_join_get:nnN {#1} { sp } \l__unravel_tmpa_tl } + { \__unravel_prev_input_join_get:nnN {#1} { } \l__unravel_tmpa_tl } \__unravel_prev_input_gpush:N \l__unravel_tmpa_tl - \__unravel_break:w + \exp_after:wN \use_none:n \__unravel_break:w } - { \__unravel_back_input: } + { } + \__unravel_back_input: \int_compare:nNnT {#1} = { 3 } { \__unravel_scan_keyword:nT { mMuU } { \__unravel_break:w } @@ -2417,6 +2419,7 @@ \__unravel_tex_error:nV { missing-pt } \l__unravel_head_tl \__unravel_prev_input:n { pt } \__unravel_break_point: + \__unravel_skip_optional_space: } \cs_new_protected:Npn \__unravel_scan_inf_unit_loop: { \__unravel_scan_keyword:nT { lL } { \__unravel_scan_inf_unit_loop: } } @@ -2457,7 +2460,7 @@ { \__unravel_break:w } } { \__unravel_back_input: \__unravel_scan_dimen:nN {#1} \c_false_bool } - \__unravel_prev_input_join_get:nN {#1} \l__unravel_tmpa_tl + \__unravel_prev_input_join_get:nnN {#1} { } \l__unravel_tmpa_tl \__unravel_prev_input_gpush: \__unravel_prev_input_gpush:N \l__unravel_tmpa_tl \__unravel_scan_keyword:nT { pPlLuUsS } @@ -2465,7 +2468,7 @@ \__unravel_scan_keyword:nT { mMiInNuUsS } { \__unravel_scan_dimen:nN {#1} \c_true_bool } \__unravel_break_point: - \__unravel_prev_input_join_get:nN {#1} \l__unravel_tmpa_tl + \__unravel_prev_input_join_get:nnN {#1} { } \l__unravel_tmpa_tl \__unravel_prev_input_silent:V \l__unravel_tmpa_tl } \cs_new_protected:Npn \__unravel_scan_file_name: @@ -3002,15 +3005,8 @@ } \__unravel_print_action: } -\cs_new_protected:Npn \__unravel_do_step: - { - \__unravel_set_action_text: - \bool_if:NT \g__unravel_internal_debug_bool - { \__unravel_exp_args:Nx \iow_term:n { Cmd:~\int_to_arabic:n { \l__unravel_head_cmd_int } } } - \cs_if_exist_use:cF - { __unravel_cmd_ \int_use:N \l__unravel_head_cmd_int : } - { \__unravel_error:nxxxx { internal } { unknown-command } { } { } { } } - } +\cs_new_protected:Npn \__unravel_forbidden_case: + { \__unravel_tex_error:nV { forbidden-case } \l__unravel_head_tl } \__unravel_new_tex_cmd:nn { relax } % 0 { \token_if_eq_meaning:NNT \l__unravel_head_token \__unravel_special_relax: @@ -4730,7 +4726,8 @@ \cs_if_eq:NNTF #1 \__unravel_get_token_xdef: { \tl_put_right:NV \l__unravel_defining_tl \l__unravel_head_tl - \__unravel_prev_input:V \l__unravel_head_tl + \__unravel_prev_input_silent:x { \l__unravel_head_tl } + \__unravel_print_action: } { \cs_if_eq:NNTF #1 \__unravel_get_token_x: @@ -4905,7 +4902,7 @@ \__unravel_print_expansion:x { \g__unravel_action_text_str = false ~ - => ~ skipped ~ to ~ \iow_char:N\\fi + => ~ skip ~ to ~ \tl_to_str:N \l__unravel_head_tl } } \cs_new_protected:Npn \__unravel_cond_false_loop:n #1 @@ -4980,7 +4977,10 @@ \gtl_if_head_is_group_begin:NTF #1 { \c_group_begin_token } { \gtl_if_head_is_group_end:NTF #1 { \c_group_end_token } - { \exp_not:N \exp_not:N \gtl_head_do:NN #1 \exp_not:N } + { + \exp_not:N \exp_not:N + \exp_not:f { \gtl_head_do:NN #1 \exp_stop_f: } + } } } } @@ -5106,10 +5106,9 @@ \__unravel_set_action_text:x { \g__unravel_action_text_str \c_space_tl - => ~ skipped ~ to ~ \tl_to_str:N \l__unravel_head_tl + => ~ skip ~ to ~ \tl_to_str:N \l__unravel_head_tl } } - % ^^A todo: in the terminal output the token itself is missing. \__unravel_print_expansion: \__unravel_cond_pop: } @@ -5347,13 +5346,28 @@ } \cs_new_protected:Npn \__unravel_prompt_aux: { - \int_compare:nNnT { \tex_interactionmode:D } = { 3 } + \clist_if_empty:NTF \g__unravel_prompt_input_clist { - \bool_if:NTF \g__unravel_explicit_prompt_bool - { \__unravel_ior_str_get:Nc \c__unravel_prompt_ior } - { \__unravel_ior_str_get:Nc \c__unravel_noprompt_ior } - { Your~input } - \exp_args:Nv \__unravel_prompt_treat:n { Your~input } + \int_compare:nNnT { \tex_interactionmode:D } = { 3 } + { + \bool_if:NTF \g__unravel_explicit_prompt_bool + { \__unravel_ior_str_get:Nc \c__unravel_prompt_ior } + { \__unravel_ior_str_get:Nc \c__unravel_noprompt_ior } + { Your~input } + \exp_args:Nv \__unravel_prompt_treat:n { Your~input } + } + } + { + \clist_gpop:NN \g__unravel_prompt_input_clist \l__unravel_tmpa_tl + \group_begin: + \__unravel_set_escapechar:n { 92 } + \__unravel_print:x + { + \bool_if:NT \g__unravel_explicit_prompt_bool { Your~input= } + \tl_to_str:N \l__unravel_tmpa_tl + } + \group_end: + \exp_args:NV \__unravel_prompt_treat:n \l__unravel_tmpa_tl } } \cs_new_protected:Npn \__unravel_prompt_treat:n #1 @@ -5373,7 +5387,11 @@ \group_end: \__unravel_exit_hard:w } - { X } { \tex_batchmode:D \tex_end:D } + { X } + { + \tex_batchmode:D + \tex_read:D -1 to \l__unravel_tmpa_tl + } { s } { \__unravel_prompt_scan_int:nn {#1} \__unravel_prompt_silent_steps:n } { o } { \__unravel_prompt_scan_int:nn {#1} @@ -5496,6 +5514,7 @@ { \exp_not:N \__unravel:nn \tl_to_str:N \g__unravel_until_tl } } { + \int_gzero:N \g__unravel_nonstop_int \int_gset:Nn \g__unravel_online_int { 1 } \tl_gclear:N \g__unravel_before_print_state_tl } @@ -5552,6 +5571,7 @@ max-input .int_gset:N = \g__unravel_default_max_input_int , number-steps .bool_gset:N = \g__unravel_default_number_steps_bool , online .int_gset:N = \g__unravel_default_online_int , + prompt-input .clist_gset:N = \g__unravel_default_prompt_input_clist , trace-assigns .bool_gset:N = \g__unravel_default_trace_assign_bool , trace-expansion .bool_gset:N = \g__unravel_default_trace_expansion_bool , trace-other .bool_gset:N = \g__unravel_default_trace_other_bool , @@ -5566,6 +5586,7 @@ max-input .int_gset:N = \g__unravel_max_input_int , number-steps .bool_gset:N = \g__unravel_number_steps_bool , online .int_gset:N = \g__unravel_online_int , + prompt-input .clist_gset:N = \g__unravel_prompt_input_clist , trace-assigns .bool_gset:N = \g__unravel_trace_assigns_bool , trace-expansion .bool_gset:N = \g__unravel_trace_expansion_bool , trace-other .bool_gset:N = \g__unravel_trace_other_bool , @@ -5617,6 +5638,7 @@ \__unravel_exit_point: \__unravel_print_outcome: \__unravel_final_test: + \__unravel_final_after_assignment: \__unravel_exit_point: } \cs_new_protected:Npn \unravel_get:nnN #1#2#3 @@ -5630,6 +5652,7 @@ \bool_gset_eq:NN \g__unravel_internal_debug_bool \g__unravel_default_internal_debug_bool \bool_gset_eq:NN \g__unravel_number_steps_bool \g__unravel_default_number_steps_bool \int_gset_eq:NN \g__unravel_online_int \g__unravel_default_online_int + \clist_gset_eq:NN \g__unravel_prompt_input_clist \g__unravel_default_prompt_input_clist \bool_gset_eq:NN \g__unravel_trace_assigns_bool \g__unravel_default_trace_assigns_bool \bool_gset_eq:NN \g__unravel_trace_expansion_bool \g__unravel_default_trace_expansion_bool \bool_gset_eq:NN \g__unravel_trace_other_bool \g__unravel_default_trace_other_bool @@ -5666,6 +5689,15 @@ \__unravel_do_step: \__unravel_main_loop: } +\cs_new_protected:Npn \__unravel_do_step: + { + \__unravel_set_action_text: + \bool_if:NT \g__unravel_internal_debug_bool + { \__unravel_exp_args:Nx \iow_term:n { Cmd:~\int_to_arabic:n { \l__unravel_head_cmd_int } } } + \cs_if_exist_use:cF + { __unravel_cmd_ \int_use:N \l__unravel_head_cmd_int : } + { \__unravel_error:nxxxx { internal } { unknown-command } { } { } { } } + } \cs_new_protected:Npn \__unravel_final_test: { \bool_if:nTF @@ -5683,6 +5715,11 @@ \__unravel_error:nnnnn { internal } { the-last-unravel-finished-badly } { } { } { } } +\cs_new_protected:Npn \__unravel_final_after_assignment: + { + \gtl_if_empty:NF \g__unravel_after_assignment_gtl + { \gtl_head_do:NN \g__unravel_after_assignment_gtl \tex_afterassignment:D } + } \msg_new:nnn { unravel } { unknown-primitive } { Internal~error:~the~primitive~'#1'~is~not~known. } \msg_new:nnn { unravel } { extra-fi-or-else } @@ -5731,12 +5768,14 @@ \msg_new:nnn { unravel } { bad-unless } { \iow_char:N\\unless~not~followed~by~conditional. } \msg_new:nnn { unravel } { runaway-if } - { Runaway~\iow_char:N\\if... } + { Runaway~\iow_char:N\\if...~Exiting~\iow_char:N\\unravel } \msg_new:nnn { unravel } { runaway-macro-parameter } { Runaway~macro~parameter~\# #2~after \\\\ \iow_indent:n {#1} } +\msg_new:nnn { unravel } { runaway-text } + { Runaway~braced~argument~for~TeX~primitive.~Exiting~\iow_char:N\\unravel } \msg_new:nnn { unravel } { extra-or } { Extra~\iow_char:N\\or. } \msg_new:nnn { unravel } { missing-equals } @@ -5765,8 +5804,28 @@ { TeX~provides~no~further~help~for~this~error. } { TeX's~advice~is:\\\\ \iow_indent:n {#3} } } -\msg_new:nnn { unravel } { runaway-unravel } - { Runaway~\iow_char:N\\unravel } +\msg_new:nnnn { unravel } { runaway-unravel } + { Runaway~\iow_char:N\\unravel,~so~\iow_char:N\\relax~inserted. } + { + Some~TeX~command~expects~input~beyond~the~end~of~ + the~argument~of~\iow_char:N\\unravel. + } +\__unravel_tex_msg_new:nnn { forbidden-case } + { + You~can't~use~`\exp_after:wN \token_to_str:N \l__unravel_head_tl'~in~ + \mode_if_vertical:TF { vertical } + { + \mode_if_horizontal:TF { horizontal } + { \mode_if_math:TF { math } { no } } + } ~ mode. + } + { + Sorry,~but~I'm~not~programmed~to~handle~this~case;~ + I'll~just~pretend~that~you~didn't~ask~for~it.~ + If~you're~in~the~wrong~mode,~you~might~be~able~to~ + return~to~the~right~one~by~typing~`I\iow_char:N\}'~or~ + `I\iow_char:N\$'~or~`I\iow_char:N\\par'. + } \__unravel_tex_msg_new:nnn { incompatible-mag } { Incompatible~magnification~ -- cgit v1.2.3