texlive[50557] Master/texmf-dist: unravel (23mar19)

commits+karl at tug.org commits+karl at tug.org
Sat Mar 23 23:05:48 CET 2019


Revision: 50557
          http://tug.org/svn/texlive?view=revision&revision=50557
Author:   karl
Date:     2019-03-23 23:05:48 +0100 (Sat, 23 Mar 2019)
Log Message:
-----------
unravel (23mar19)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/latex/unravel/unravel.pdf
    trunk/Master/texmf-dist/source/latex/unravel/unravel.dtx
    trunk/Master/texmf-dist/tex/latex/unravel/unravel.sty

Modified: trunk/Master/texmf-dist/doc/latex/unravel/unravel.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/source/latex/unravel/unravel.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/unravel/unravel.dtx	2019-03-23 22:05:34 UTC (rev 50556)
+++ trunk/Master/texmf-dist/source/latex/unravel/unravel.dtx	2019-03-23 22:05:48 UTC (rev 50557)
@@ -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<num>":~do~<num>~steps~silently }
+    \@@_print:n { "|<num>":~silent~steps~until~<num>~fewer~"||" }
+    \@@_print:n { "u<text>":~silent~steps~until~the~input~starts~with~<text> }
     \@@_print:n
       { "o<num>":~1~=>~log~and~terminal,~0~=>~only~log,~-1~=>~neither.}
+    \@@_print:n { "q":~semi-quiet~(same~as~"o-1") }
     \@@_print:n { "C<code>":~run~some~expl3~code~immediately }
-    \@@_print:n { "|<num>":~silent~steps~until~<num>~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.

Modified: trunk/Master/texmf-dist/tex/latex/unravel/unravel.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/unravel/unravel.sty	2019-03-23 22:05:34 UTC (rev 50556)
+++ trunk/Master/texmf-dist/tex/latex/unravel/unravel.sty	2019-03-23 22:05:48 UTC (rev 50557)
@@ -11,7 +11,7 @@
 %% Communicate any suggestions for changing this package
 %% to Bruno Le Floch (blflatex+unravel at 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<num>":~do~<num>~steps~silently }
+    \__unravel_print:n { "|<num>":~silent~steps~until~<num>~fewer~"||" }
+    \__unravel_print:n { "u<text>":~silent~steps~until~the~input~starts~with~<text> }
     \__unravel_print:n
       { "o<num>":~1~=>~log~and~terminal,~0~=>~only~log,~-1~=>~neither.}
+    \__unravel_print:n { "q":~semi-quiet~(same~as~"o-1") }
     \__unravel_print:n { "C<code>":~run~some~expl3~code~immediately }
-    \__unravel_print:n { "|<num>":~silent~steps~until~<num>~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~



More information about the tex-live-commits mailing list