From e5620bf8a25cab7f8e9f19da6c93e3bb051a3732 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Sat, 23 Mar 2019 22:05:48 +0000 Subject: unravel (23mar19) git-svn-id: svn://tug.org/texlive/trunk@50557 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/doc/latex/unravel/unravel.pdf | Bin 704507 -> 689310 bytes Master/texmf-dist/source/latex/unravel/unravel.dtx | 182 +++++++++++++++++---- Master/texmf-dist/tex/latex/unravel/unravel.sty | 140 +++++++++++++--- 3 files changed, 259 insertions(+), 63 deletions(-) (limited to 'Master/texmf-dist') diff --git a/Master/texmf-dist/doc/latex/unravel/unravel.pdf b/Master/texmf-dist/doc/latex/unravel/unravel.pdf index a60dc093b62..df3f7437be8 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 8c3b8c23a9f..cd7e87a4bf9 100644 --- a/Master/texmf-dist/source/latex/unravel/unravel.dtx +++ b/Master/texmf-dist/source/latex/unravel/unravel.dtx @@ -1,5 +1,5 @@ % \iffalse -%% File: unravel.dtx Copyright (C) 2013, 2015, 2018 Bruno Le Floch +%% File: unravel.dtx Copyright (C) 2013, 2015, 2018-2019 Bruno Le Floch %% %% It may be distributed and/or modified under the conditions of the %% LaTeX Project Public License (LPPL), either version 1.3c of this @@ -23,9 +23,9 @@ % % \title{The \textsf{unravel} package: \\ % watching TeX digest tokens\thanks{This -% file has version number 0.2f, last revised 2018/12/28.}} +% file has version number 0.2g, last revised 2019/03/23.}} % \author{Bruno Le Floch} -% \date{2018/12/28} +% \date{2019/03/23} % % \maketitle % \tableofcontents @@ -545,7 +545,7 @@ {% \csname @@_setup_restore:\endcsname \ProvidesExplPackage - {unravel} {2018/12/28} {0.2f} {Watching TeX digest tokens}% + {unravel} {2019/03/23} {0.2g} {Watching TeX digest tokens}% \csname @@_setup_unravel:\endcsname }% % \end{macrocode} @@ -611,8 +611,8 @@ \cs_generate_variant:Nn \tl_if_head_eq_meaning:nNT { V } \cs_generate_variant:Nn \tl_if_single_token:nT { V } \cs_generate_variant:Nn \gtl_gput_right:Nn { NV } -\cs_generate_variant:Nn \ior_str_get:NN { Nc } \cs_generate_variant:Nn \gtl_if_empty:NTF { c } +\cs_generate_variant:Nn \gtl_if_tl:NT { c } \cs_generate_variant:Nn \gtl_to_str:N { c } \cs_generate_variant:Nn \gtl_gpop_left:NN { c } \cs_generate_variant:Nn \gtl_get_left:NN { c } @@ -620,6 +620,7 @@ \cs_generate_variant:Nn \gtl_gconcat:NNN { ccc , cNc } \cs_generate_variant:Nn \gtl_gclear:N { c } \cs_generate_variant:Nn \gtl_gclear_new:N { c } +\cs_generate_variant:Nn \gtl_left_tl:N { c } % \end{macrocode} % % \begin{macro}{\@@_tl_if_in:ooTF} @@ -869,11 +870,17 @@ % % \subsubsection{Helpers for control flow} % -% \begin{macro}[EXP]{\@@_exit:w, \@@_exit_point:} +% \begin{macro}[EXP]{\@@_exit:w, \@@_exit_error: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} % @@ -2332,7 +2339,7 @@ \cs_new_protected:Npn \@@_get_next: { \@@_input_if_empty:TF - { \@@_exit:w } + { \@@_exit_error:w } { \@@_input_gpop:N \l_@@_head_gtl \gtl_head_do:NN \l_@@_head_gtl \@@_get_next_aux:w @@ -2812,6 +2819,33 @@ % \end{macrocode} % \end{macro} % +% \begin{macro}{\@@_input_get_left:N, \@@_input_get_left_aux:nN} +% \begin{variable}{\l_@@_input_get_left_tl} +% \begin{macrocode} +\tl_new:N \l_@@_input_get_left_tl +\cs_new_protected:Npn \@@_input_get_left:N #1 + { + \tl_clear:N #1 + \exp_args:NV \@@_input_get_left_aux:nN \g_@@_input_int #1 + } +\cs_new_protected:Npn \@@_input_get_left_aux:nN #1#2 + { + \int_compare:nNnF {#1} = 0 + { + \tl_set:Nx \l_@@_input_get_left_tl + { \gtl_left_tl:c { g_@@_input_#1_gtl } } + \tl_concat:NNN #2 #2 \l_@@_input_get_left_tl + \gtl_if_tl:cT { g_@@_input_#1_gtl } + { + \exp_args:Nf \@@_input_get_left_aux:nN + { \int_eval:n { #1 - 1 } } #2 + } + } + } +% \end{macrocode} +% \end{variable} +% \end{macro} +% % \begin{macro}{\@@_input_gpop:N} % Call \cs{@@_input_if_empty:TF} to remove empty levels from the input % stack, then extract the first token from the left-most non-empty @@ -4235,7 +4269,7 @@ \@@_input_gpop_item:NF \l_@@_head_tl { \@@_error:nnnnn { runaway-text } { } { } { } { } - \@@_exit:w + \@@_exit_hard:w } \tl_set:Nx \l_@@_head_tl { { \exp_not:V \l_@@_head_tl } } \bool_if:NT #1 @@ -7460,7 +7494,7 @@ \cs_new_protected:Npn \@@_pass_text_empty: { \@@_error:nnnnn { runaway-if } { } { } { } { } - \@@_exit:w + \@@_exit_hard:w } % \end{macrocode} % \end{macro} @@ -7521,6 +7555,8 @@ { \int_case:nnF \l_@@_head_char_int { + { 0 } { \@@_test_two_chars:nn { 0 } {#1} } % if + { 1 } { \@@_test_two_chars:nn { 1 } {#1} } % ifcat { 12 } { \@@_test_ifx:n {#1} } { 16 } { \@@_test_case:n {#1} } { 21 } { \@@_test_pdfprimitive:n {#1} } % ^^A todo and \unless @@ -7530,8 +7566,6 @@ \@@_print_expansion: \int_case:nn \l_@@_head_char_int { - { 0 } { \@@_test_two_chars: } % if - { 1 } { \@@_test_two_chars: } % ifcat { 2 } % ifnum { \@@_test_two_vals:N \@@_scan_int: } { 3 } % ifdim @@ -7637,29 +7671,48 @@ % \end{macrocode} % \end{macro} % -% ^^A todo: fix interaction with noexpand and active chars -% ^^A todo: fix non-brace begin-group and end-group tokens -% \begin{macro}{\@@_test_two_chars:, \@@_test_two_chars_aux:} +% ^^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: +\cs_new_protected:Npn \@@_test_two_chars:nn #1 { - \@@_test_two_chars_aux: - \@@_prev_input:V \l_@@_head_tl - \@@_test_two_chars_aux: - \@@_prev_input:V \l_@@_head_tl + \@@_prev_input_gpush_gtl:N \l_@@_head_gtl + \@@_print_expansion: + \@@_test_two_chars_get:n {#1} + \@@_test_two_chars_get:n {#1} + \@@_prev_input_gpop_gtl:N \l_@@_head_gtl + \@@_set_action_text:x { \gtl_to_str:N \l_@@_head_gtl } + \gtl_pop_left_item:NNTF \l_@@_head_gtl \l_@@_head_tl { } { } + \gtl_pop_left:NN \l_@@_head_gtl \l_@@_tmpb_gtl + \@@_test_two_chars_gtl:N \l_@@_tmpb_gtl + \@@_test_two_chars_gtl:N \l_@@_head_gtl + \l_@@_head_tl \scan_stop: + \exp_after:wN \@@_cond_true:n + \else: + \exp_after:wN \@@_cond_false:n + \fi: } -\cs_new_protected:Npn \@@_test_two_chars_aux: +\cs_new_protected:Npn \@@_test_two_chars_get:n #1 { \@@_get_x_next: - \gtl_if_tl:NF \l_@@_head_gtl + \int_compare:nNnT {#1} = 0 { - \tl_set:Nx \l_@@_head_tl + \gtl_if_head_is_N_type:NF \l_@@_head_gtl + { \gtl_set:Nx \l_@@_head_gtl { \gtl_to_str:N \l_@@_head_gtl } } + } + \@@_prev_input_gtl:N \l_@@_head_gtl + \@@_print_action:x { \gtl_to_str:N \l_@@_head_gtl } + } +\cs_new_protected:Npn \@@_test_two_chars_gtl:N #1 + { + \tl_put_right:Nx \l_@@_head_tl + { + \gtl_if_head_is_group_begin:NTF #1 { \c_group_begin_token } { - \gtl_if_head_is_group_begin:NTF \l_@@_head_gtl - { \c_group_begin_token } { \c_group_end_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 } } } - \tl_put_left:Nn \l_@@_head_tl { \exp_not:N } % ^^A todo: prettify. } % \end{macrocode} % \end{macro} @@ -8145,6 +8198,14 @@ % % \subsubsection{Prompt} % +% \begin{macro}{\@@_ior_str_get:NN, \@@_ior_str_get:Nc} +% \begin{macrocode} +\cs_new_protected:Npn \@@_ior_str_get:NN #1#2 + { \tex_readline:D #1 to #2 } +\cs_generate_variant:Nn \@@_ior_str_get:NN { Nc } +% \end{macrocode} +% \end{macro} +% % \begin{macro}{\@@_prompt:} % \begin{macrocode} \cs_new_protected:Npn \@@_prompt: @@ -8164,8 +8225,8 @@ \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 } + { \@@_ior_str_get:Nc \c_@@_prompt_ior } + { \@@_ior_str_get:Nc \c_@@_noprompt_ior } { Your~input } \exp_args:Nv \@@_prompt_treat:n { Your~input } } @@ -8185,7 +8246,7 @@ { x } { \group_end: - \exp_after:wN \@@_exit:w \@@_exit:w + \@@_exit_hard:w } { X } { \tex_batchmode:D \tex_end:D } { s } { \@@_prompt_scan_int:nn {#1} @@ -8202,9 +8263,11 @@ \tl_gput_left:Nn \g_@@_tmpc_tl { \tl_gclear:N \g_@@_tmpc_tl } \group_insert_after:N \g_@@_tmpc_tl + \group_insert_after:N \@@_prompt: } { | } { \@@_prompt_scan_int:nn {#1} \@@_prompt_vert:n } + { u } { \@@_prompt_until:n {#1} } { a } { \@@_prompt_all: } } { \@@_prompt_help: } @@ -8225,14 +8288,15 @@ \cs_new_protected:Npn \@@_prompt_help: { \@@_print:n { "m":~meaning~of~first~token } - \@@_print:n { "q":~semi-quiet~(same~as~"o-1") } - \@@_print:n { "x"/"X":~exit~this~instance~of~unravel/TeX } + \@@_print:n { "a":~print~state~again,~without~truncating } \@@_print:n { "s":~do~~steps~silently } + \@@_print:n { "|":~silent~steps~until~~fewer~"||" } + \@@_print:n { "u":~silent~steps~until~the~input~starts~with~ } \@@_print:n { "o":~1~=>~log~and~terminal,~0~=>~only~log,~-1~=>~neither.} + \@@_print:n { "q":~semi-quiet~(same~as~"o-1") } \@@_print:n { "C":~run~some~expl3~code~immediately } - \@@_print:n { "|":~silent~steps~until~~fewer~"||" } - \@@_print:n { "a":~print~state~again,~without~truncating } + \@@_print:n { "x"/"X":~exit~this~instance~of~unravel/TeX } \@@_prompt_aux: } \cs_new_protected:Npn \@@_prompt_silent_steps:n #1 @@ -8297,6 +8361,37 @@ % % ^^A todo: I suspect a bug if given 'a' twice in a row % +% \begin{macro}{\@@_prompt_until:n} +% \begin{variable}{\g_@@_until_tl} +% \begin{macrocode} +\tl_new:N \g_@@_until_tl +\cs_new_protected:Npn \@@_prompt_until:n #1 + { + \tl_gset:Nx \g_@@_until_tl { \tl_tail:n {#1} } + \int_gset:Nn \g_@@_online_int { -1 } + \tl_gset:Nn \g_@@_before_print_state_tl + { + \@@_input_get_left:N \l_@@_tmpa_tl + \@@_exp_args:Nx \use:n + { + \exp_not:N \tl_if_in:nnTF + { \exp_not:N \@@:nn \tl_to_str:N \l_@@_tmpa_tl } + { \exp_not:N \@@:nn \tl_to_str:N \g_@@_until_tl } + } + { + \int_gset:Nn \g_@@_online_int { 1 } + \tl_gclear:N \g_@@_before_print_state_tl + } + { + \int_gset:Nn \g_@@_nonstop_int + { \int_max:nn { \g_@@_nonstop_int } { 2 } } + } + } + } +% \end{macrocode} +% \end{variable} +% \end{macro} +% % \subsubsection{Errors} % % \begin{macro}{\@@_not_implemented:n} @@ -8547,13 +8642,26 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}{\@@_main_loop:} -% Loop forever, getting the next token (with expansion) and -% performing the corresponding command. +% \begin{macro}{\@@_main_loop:, \@@_get_x_next_or_done:} +% Loop forever, getting the next token (with expansion) and performing +% the corresponding command. We use \cs{@@_get_x_next_or_done:}, +% which is basically \cs{@@_get_x_next:} but with a different +% behaviour when there are no more tokens: running out of tokens here +% is a successful exit of \cs{unravel}. Note that we cannot put the +% logic into \cs{@@_main_loop:} because \cs{@@_expand_do:N} suppresses +% the loop when a token is marked with \cs{notexpanded:}, and we don't +% want that to suppress the main loop, only the expansion loop. % \begin{macrocode} +\cs_new_protected:Npn \@@_get_x_next_or_done: + { + \@@_input_if_empty:TF { \@@_exit:w } { } + \@@_get_next: + \@@_token_if_expandable:NT \l_@@_head_token + { \@@_expand_do:N \@@_get_x_next_or_done: } + } \cs_new_protected:Npn \@@_main_loop: { - \@@_get_x_next: + \@@_get_x_next_or_done: \@@_set_cmd: \@@_do_step: \@@_main_loop: @@ -8671,6 +8779,8 @@ { 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 } % \end{macrocode} % % Some error messages from \TeX{} itself. diff --git a/Master/texmf-dist/tex/latex/unravel/unravel.sty b/Master/texmf-dist/tex/latex/unravel/unravel.sty index 7051a79b324..b09b7fa0de5 100644 --- a/Master/texmf-dist/tex/latex/unravel/unravel.sty +++ b/Master/texmf-dist/tex/latex/unravel/unravel.sty @@ -11,7 +11,7 @@ %% Communicate any suggestions for changing this package %% to Bruno Le Floch (blflatex+unravel@gmail.com). %% -%% File: unravel.dtx Copyright (C) 2013, 2015, 2018 Bruno Le Floch +%% File: unravel.dtx Copyright (C) 2013, 2015, 2018-2019 Bruno Le Floch %% %% It may be distributed and/or modified under the conditions of the %% LaTeX Project Public License (LPPL), either version 1.3c of this @@ -153,7 +153,7 @@ {% \csname __unravel_setup_restore:\endcsname \ProvidesExplPackage - {unravel} {2018/12/28} {0.2f} {Watching TeX digest tokens}% + {unravel} {2019/03/23} {0.2g} {Watching TeX digest tokens}% \csname __unravel_setup_unravel:\endcsname }% \cs_new_eq:NN \__unravel_currentgrouptype: \tex_currentgrouptype:D @@ -178,8 +178,8 @@ \cs_generate_variant:Nn \tl_if_head_eq_meaning:nNT { V } \cs_generate_variant:Nn \tl_if_single_token:nT { V } \cs_generate_variant:Nn \gtl_gput_right:Nn { NV } -\cs_generate_variant:Nn \ior_str_get:NN { Nc } \cs_generate_variant:Nn \gtl_if_empty:NTF { c } +\cs_generate_variant:Nn \gtl_if_tl:NT { c } \cs_generate_variant:Nn \gtl_to_str:N { c } \cs_generate_variant:Nn \gtl_gpop_left:NN { c } \cs_generate_variant:Nn \gtl_get_left:NN { c } @@ -187,6 +187,7 @@ \cs_generate_variant:Nn \gtl_gconcat:NNN { ccc , cNc } \cs_generate_variant:Nn \gtl_gclear:N { c } \cs_generate_variant:Nn \gtl_gclear_new:N { c } +\cs_generate_variant:Nn \gtl_left_tl:N { c } \cs_new_protected:Npn \__unravel_tl_if_in:ooTF #1#2#3#4 { \group_begin: @@ -323,6 +324,12 @@ } \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: { } \prg_new_conditional:Npnn \__unravel_cmd_if_internal: { TF } @@ -1281,7 +1288,7 @@ \cs_new_protected:Npn \__unravel_get_next: { \__unravel_input_if_empty:TF - { \__unravel_exit:w } + { \__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 @@ -1578,6 +1585,26 @@ { g__unravel_input_ \int_use:N \g__unravel_input_int _gtl } #1 } } +\tl_new:N \l__unravel_input_get_left_tl +\cs_new_protected:Npn \__unravel_input_get_left:N #1 + { + \tl_clear:N #1 + \exp_args:NV \__unravel_input_get_left_aux:nN \g__unravel_input_int #1 + } +\cs_new_protected:Npn \__unravel_input_get_left_aux:nN #1#2 + { + \int_compare:nNnF {#1} = 0 + { + \tl_set:Nx \l__unravel_input_get_left_tl + { \gtl_left_tl:c { g__unravel_input_#1_gtl } } + \tl_concat:NNN #2 #2 \l__unravel_input_get_left_tl + \gtl_if_tl:cT { g__unravel_input_#1_gtl } + { + \exp_args:Nf \__unravel_input_get_left_aux:nN + { \int_eval:n { #1 - 1 } } #2 + } + } + } \cs_new_protected:Npn \__unravel_input_gpop:N #1 { \__unravel_input_if_empty:TF @@ -2524,7 +2551,7 @@ \__unravel_input_gpop_item:NF \l__unravel_head_tl { \__unravel_error:nnnnn { runaway-text } { } { } { } { } - \__unravel_exit:w + \__unravel_exit_hard:w } \tl_set:Nx \l__unravel_head_tl { { \exp_not:V \l__unravel_head_tl } } \bool_if:NT #1 @@ -4777,7 +4804,7 @@ \cs_new_protected:Npn \__unravel_pass_text_empty: { \__unravel_error:nnnnn { runaway-if } { } { } { } { } - \__unravel_exit:w + \__unravel_exit_hard:w } \cs_new_protected:Npn \__unravel_cond_push: { @@ -4820,6 +4847,8 @@ { \int_case:nnF \l__unravel_head_char_int { + { 0 } { \__unravel_test_two_chars:nn { 0 } {#1} } % if + { 1 } { \__unravel_test_two_chars:nn { 1 } {#1} } % ifcat { 12 } { \__unravel_test_ifx:n {#1} } { 16 } { \__unravel_test_case:n {#1} } { 21 } { \__unravel_test_pdfprimitive:n {#1} } % ^^A todo and \unless @@ -4829,8 +4858,6 @@ \__unravel_print_expansion: \int_case:nn \l__unravel_head_char_int { - { 0 } { \__unravel_test_two_chars: } % if - { 1 } { \__unravel_test_two_chars: } % ifcat { 2 } % ifnum { \__unravel_test_two_vals:N \__unravel_scan_int: } { 3 } % ifdim @@ -4917,25 +4944,45 @@ \__unravel_prev_input:V \l__unravel_head_tl #1 } -\cs_new_protected:Npn \__unravel_test_two_chars: +\cs_new_protected:Npn \__unravel_test_two_chars:nn #1 { - \__unravel_test_two_chars_aux: - \__unravel_prev_input:V \l__unravel_head_tl - \__unravel_test_two_chars_aux: - \__unravel_prev_input:V \l__unravel_head_tl + \__unravel_prev_input_gpush_gtl:N \l__unravel_head_gtl + \__unravel_print_expansion: + \__unravel_test_two_chars_get:n {#1} + \__unravel_test_two_chars_get:n {#1} + \__unravel_prev_input_gpop_gtl:N \l__unravel_head_gtl + \__unravel_set_action_text:x { \gtl_to_str:N \l__unravel_head_gtl } + \gtl_pop_left_item:NNTF \l__unravel_head_gtl \l__unravel_head_tl { } { } + \gtl_pop_left:NN \l__unravel_head_gtl \l__unravel_tmpb_gtl + \__unravel_test_two_chars_gtl:N \l__unravel_tmpb_gtl + \__unravel_test_two_chars_gtl:N \l__unravel_head_gtl + \l__unravel_head_tl \scan_stop: + \exp_after:wN \__unravel_cond_true:n + \else: + \exp_after:wN \__unravel_cond_false:n + \fi: } -\cs_new_protected:Npn \__unravel_test_two_chars_aux: +\cs_new_protected:Npn \__unravel_test_two_chars_get:n #1 { \__unravel_get_x_next: - \gtl_if_tl:NF \l__unravel_head_gtl + \int_compare:nNnT {#1} = 0 { - \tl_set:Nx \l__unravel_head_tl + \gtl_if_head_is_N_type:NF \l__unravel_head_gtl + { \gtl_set:Nx \l__unravel_head_gtl { \gtl_to_str:N \l__unravel_head_gtl } } + } + \__unravel_prev_input_gtl:N \l__unravel_head_gtl + \__unravel_print_action:x { \gtl_to_str:N \l__unravel_head_gtl } + } +\cs_new_protected:Npn \__unravel_test_two_chars_gtl:N #1 + { + \tl_put_right:Nx \l__unravel_head_tl + { + \gtl_if_head_is_group_begin:NTF #1 { \c_group_begin_token } { - \gtl_if_head_is_group_begin:NTF \l__unravel_head_gtl - { \c_group_begin_token } { \c_group_end_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 } } } - \tl_put_left:Nn \l__unravel_head_tl { \exp_not:N } % ^^A todo: prettify. } \cs_new_protected:Npn \__unravel_test_ifx:n #1 { @@ -5283,6 +5330,9 @@ } \cs_new_protected:Npn \__unravel_print_outcome: { \__unravel_print_message:nn { } { [=====~End~=====] } } +\cs_new_protected:Npn \__unravel_ior_str_get:NN #1#2 + { \tex_readline:D #1 to #2 } +\cs_generate_variant:Nn \__unravel_ior_str_get:NN { Nc } \cs_new_protected:Npn \__unravel_prompt: { \int_compare:nNnF \g__unravel_nonstop_int > 0 @@ -5300,8 +5350,8 @@ \int_compare:nNnT { \tex_interactionmode:D } = { 3 } { \bool_if:NTF \g__unravel_explicit_prompt_bool - { \ior_str_get:Nc \c__unravel_prompt_ior } - { \ior_str_get:Nc \c__unravel_noprompt_ior } + { \__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 } } @@ -5321,7 +5371,7 @@ { x } { \group_end: - \exp_after:wN \__unravel_exit:w \__unravel_exit:w + \__unravel_exit_hard:w } { X } { \tex_batchmode:D \tex_end:D } { s } { \__unravel_prompt_scan_int:nn {#1} @@ -5338,9 +5388,11 @@ \tl_gput_left:Nn \g__unravel_tmpc_tl { \tl_gclear:N \g__unravel_tmpc_tl } \group_insert_after:N \g__unravel_tmpc_tl + \group_insert_after:N \__unravel_prompt: } { | } { \__unravel_prompt_scan_int:nn {#1} \__unravel_prompt_vert:n } + { u } { \__unravel_prompt_until:n {#1} } { a } { \__unravel_prompt_all: } } { \__unravel_prompt_help: } @@ -5361,14 +5413,15 @@ \cs_new_protected:Npn \__unravel_prompt_help: { \__unravel_print:n { "m":~meaning~of~first~token } - \__unravel_print:n { "q":~semi-quiet~(same~as~"o-1") } - \__unravel_print:n { "x"/"X":~exit~this~instance~of~unravel/TeX } + \__unravel_print:n { "a":~print~state~again,~without~truncating } \__unravel_print:n { "s":~do~~steps~silently } + \__unravel_print:n { "|":~silent~steps~until~~fewer~"||" } + \__unravel_print:n { "u":~silent~steps~until~the~input~starts~with~ } \__unravel_print:n { "o":~1~=>~log~and~terminal,~0~=>~only~log,~-1~=>~neither.} + \__unravel_print:n { "q":~semi-quiet~(same~as~"o-1") } \__unravel_print:n { "C":~run~some~expl3~code~immediately } - \__unravel_print:n { "|":~silent~steps~until~~fewer~"||" } - \__unravel_print:n { "a":~print~state~again,~without~truncating } + \__unravel_print:n { "x"/"X":~exit~this~instance~of~unravel/TeX } \__unravel_prompt_aux: } \cs_new_protected:Npn \__unravel_prompt_silent_steps:n #1 @@ -5428,6 +5481,30 @@ } \cs_new:Npn \__unravel_prompt_all_aux:N #1 { \exp_not:n { \int_gset:Nn #1 } { \int_use:N #1 } } +\tl_new:N \g__unravel_until_tl +\cs_new_protected:Npn \__unravel_prompt_until:n #1 + { + \tl_gset:Nx \g__unravel_until_tl { \tl_tail:n {#1} } + \int_gset:Nn \g__unravel_online_int { -1 } + \tl_gset:Nn \g__unravel_before_print_state_tl + { + \__unravel_input_get_left:N \l__unravel_tmpa_tl + \__unravel_exp_args:Nx \use:n + { + \exp_not:N \tl_if_in:nnTF + { \exp_not:N \__unravel:nn \tl_to_str:N \l__unravel_tmpa_tl } + { \exp_not:N \__unravel:nn \tl_to_str:N \g__unravel_until_tl } + } + { + \int_gset:Nn \g__unravel_online_int { 1 } + \tl_gclear:N \g__unravel_before_print_state_tl + } + { + \int_gset:Nn \g__unravel_nonstop_int + { \int_max:nn { \g__unravel_nonstop_int } { 2 } } + } + } + } \cs_new_protected:Npn \__unravel_not_implemented:n #1 { \__unravel_error:nnnnn { not-implemented } {#1} { } { } { } } \cs_new_protected:Npn \__unravel_error:nnnnn #1#2#3#4#5 @@ -5575,9 +5652,16 @@ \bool_gset_false:N \g__unravel_name_in_progress_bool \gtl_clear:N \l__unravel_after_group_gtl } +\cs_new_protected:Npn \__unravel_get_x_next_or_done: + { + \__unravel_input_if_empty:TF { \__unravel_exit:w } { } + \__unravel_get_next: + \__unravel_token_if_expandable:NT \l__unravel_head_token + { \__unravel_expand_do:N \__unravel_get_x_next_or_done: } + } \cs_new_protected:Npn \__unravel_main_loop: { - \__unravel_get_x_next: + \__unravel_get_x_next_or_done: \__unravel_set_cmd: \__unravel_do_step: \__unravel_main_loop: @@ -5681,6 +5765,8 @@ { 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 } \__unravel_tex_msg_new:nnn { incompatible-mag } { Incompatible~magnification~ -- cgit v1.2.3