5

I have a prop list in which I save items using the \addtoprop command and then loop through the prop list and print it with the \foreachinprop command. The \foreachinprop command has several keys, but the wrapper key does not work as it should (does nothing).

\documentclass{article}
\ExplSyntaxOn
% Add to prop
\tl_new:N \l__prop_list_name_tl
\NewDocumentCommand \addtoprop { m +m }
  {
    \tl_set:Nn \l__prop_list_name_tl {#1}
    \prop_if_exist:cF { g_ \l__prop_list_name_tl _prop }
      { \prop_new:c { g_ \l__prop_list_name_tl _prop }  }
    \prop_gput_if_not_in:cen { g_ \l__prop_list_name_tl _prop }
      {
        \int_eval:n
          { \prop_count:c { g_ \l__prop_list_name_tl _prop } + 1 }
      }{ #2 }
  }
% foreach
\seq_new:N  \l__foreach_print_seq
\tl_new:N   \l__foreach_name_prop_tl
\tl_new:N   \g__foreach_temp_tl
\keys_define:nn { foreach }
  {
    before  .tl_set:N  = \l__foreach_before_tl,
    after   .tl_set:N  = \l__foreach_after_tl,
    start   .int_set:N = \l__foreach_start_int,
    start   .initial:n = 1,
    stop    .int_set:N = \l__foreach_stop_int,
    step    .int_set:N = \l__foreach_step_int,
    step    .initial:n = 1,
    wrapper .cs_set_protected:Np = \__foreach_wrapper:n #1,
    wrapper .initial:n = {#1},
    sep     .tl_set:N  = \l__foreach_sep_tl,
    sep     .initial:n = {},
  }
\NewDocumentCommand \foreachinprop { o m }
  {
    \__foreach_code:nn {#1} {#2}
  }
\cs_new_protected:Npn \__foreach_code:nn #1 #2
  {
    \group_begin:
      \tl_if_novalue:nF {#1}
        {
          \keys_set:nn { foreach } {#1}
        }
      \tl_set:Nn \l__foreach_name_prop_tl {#2}
      \seq_clear:N \l__foreach_print_seq
      \int_compare:nNnT { \l__foreach_stop_int } = { 0 }
        {
          \int_set:Nn \l__foreach_stop_int
            { \prop_count:c { g_ \l__foreach_name_prop_tl _prop } }
        }
      \int_step_function:nnnN
        { \l__foreach_start_int }
        { \l__foreach_step_int }
        { \l__foreach_stop_int }
        \__foreach_prop:n
      \tl_gset:Ne \g__foreach_temp_tl
        {
          \exp_args:NNV \seq_use:Nn
            \l__foreach_print_seq \l__foreach_sep_tl
        }
    \group_end:
    \exp_after:wN \tl_gclear:N
    \exp_after:wN \g__foreach_temp_tl \g__foreach_temp_tl
  }
\cs_new_protected:Npn \__foreach_prop:n #1
  {
    \seq_put_right:Ne \l__foreach_print_seq
      {
        \tl_if_empty:NF \l__foreach_before_tl
          { \exp_not:V \l__foreach_before_tl }
        % wrapper
        \__foreach_wrapper:n
          {
            \prop_item:cn { g_ \l__foreach_name_prop_tl _prop }{#1}
          }
        \tl_if_empty:NF \l__foreach_after_tl
          { \exp_not:V \l__foreach_after_tl }
      }
  }
\ExplSyntaxOff
\begin{document}
\addtoprop{test}{The first} \addtoprop{test}{The second}
\addtoprop{test}{The third} \addtoprop{test}{The fourth}
\foreachinprop[sep={\\}, before=FOO, after= BAZZ]{test} % OK
\foreachinprop[wrapper={\fbox{#1}}]{test} % NOT WORK
\end{document}

What should I modify so that the \__foreach_wrapper:n function works properly?

1
  • Is there any particular reason for using property lists instead of sequences? You're using indexed sets of data, hence sequences. By the way, naming a variable like \g_test_prop isn't a good idea.
    – egreg
    Commented Jun 22 at 21:09

2 Answers 2

5

You are defining the command inside a group and use it outside so it is always just #1 at the point of use (add \show as in

          \show\__foreach_wrapper:n
        \__foreach_wrapper:n

to see

You could move the group_end: or use a global definition, or not have a group, depending on your real use case.


Simplest (but perhaps not not best) is to use a global

    wrapper .cs_gset_protected:Np = \__foreach_wrapper:n #1,

produces

enter image description here

1
  • Thank you very much, moving group_end: is what suits me (and I take advantage of deleting a couple of unnecessary things). Commented Jun 22 at 20:54
4

You want to precompile the initial values, rather than using a group.

The code can be streamlined: for instance o in the argument list to \foreachinprop can be more simply +O{} and there's no need to check for emptiness, because \keys_set:nn is perfectly happy to set nothing.

Similarly, it's not needed to check for emptiness of \l__foreach_before_tl and \l__foreach_after_tl, because if they're empty nothing will be done.

At the end you can just use \seq_use:NV, no need to set a tl variable and to clear it, anyway.

However, you should fix the naming of variables. You're defining \g_test_prop which is really, really, really a bad name. And, please, avoid \exp_after:wN and \exp_args:... whenever possible: define the needed variants.

Also, I'm not sure why using property lists rather than sequences, because such are your property lists, as the keys are positive integer in sequence.

\documentclass{article}

\ExplSyntaxOn

% Add to prop
\tl_new:N \l__prop_list_name_tl
\NewDocumentCommand \addtoprop { m +m }
  {
    \tl_set:Nn \l__prop_list_name_tl {#1}
    \prop_if_exist:cF { g_ \l__prop_list_name_tl _prop }
      { \prop_new:c { g_ \l__prop_list_name_tl _prop }  }
    \prop_gput_if_not_in:cen { g_ \l__prop_list_name_tl _prop }
      {
        \int_eval:n
          { \prop_count:c { g_ \l__prop_list_name_tl _prop } + 1 }
      }{ #2 }
  }

% foreach
\seq_new:N  \l__foreach_print_seq
\tl_new:N   \l__foreach_name_prop_tl
\tl_new:N   \l__foreach_temp_tl
\cs_generate_variant:Nn \seq_use:Nn { NV }

\keys_define:nn { foreach }
  {
    before  .tl_set:N  = \l__foreach_before_tl,
    after   .tl_set:N  = \l__foreach_after_tl,
    start   .int_set:N = \l__foreach_start_int,
    stop    .int_set:N = \l__foreach_stop_int,
    step    .int_set:N = \l__foreach_step_int,
    wrapper .cs_set_protected:Np = \__foreach_wrapper:n #1,
    sep     .tl_set:N  = \l__foreach_sep_tl,
  }
\keys_precompile:nnN { foreach }
  {
    before={},after={},start=1,step=1,stop=0,wrapper=#1,sep=
  }
  \g_foreach_presets_tl

\NewDocumentCommand \foreachinprop { +O{} m }
  {
    \__foreach_code:nn {#1} {#2}
  }
\cs_new_protected:Npn \__foreach_code:nn #1 #2
  {
    \tl_use:N \g_foreach_presets_tl
    \keys_set:nn { foreach } {#1}
    \tl_set:Nn \l__foreach_name_prop_tl {#2}
    \seq_clear:N \l__foreach_print_seq
    \int_compare:nNnT { \l__foreach_stop_int } = { 0 }
      {
        \int_set:Nn \l__foreach_stop_int
          { \prop_count:c { g_ \l__foreach_name_prop_tl _prop } }
      }
    \int_step_function:nnnN
        { \l__foreach_start_int }
        { \l__foreach_step_int }
        { \l__foreach_stop_int }
        \__foreach_prop:n
    \seq_use:NV \l__foreach_print_seq \l__foreach_sep_tl
  }
\cs_new_protected:Npn \__foreach_prop:n #1
  {
    \seq_put_right:Ne \l__foreach_print_seq
      {
        \exp_not:V \l__foreach_before_tl
        % wrapper
        \__foreach_wrapper:n
          {
            \prop_item:cn { g_ \l__foreach_name_prop_tl _prop }{#1}
          }
        \exp_not:V \l__foreach_after_tl
      }
  }

\ExplSyntaxOff

\begin{document}

\addtoprop{test}{The first} \addtoprop{test}{The second}

\addtoprop{test}{The third} \addtoprop{test}{The fourth}

\foreachinprop[sep={\\}, before=FOO, after= BAZZ]{test} % OK

\foreachinprop[wrapper={\fbox{#1}}]{test} % OK

\foreachinprop[sep={\\}, before=FOO, after= BAZZ]{test} % OK

\foreachinprop[sep={\par}]{test} % OK

\foreachinprop[sep={\par},start=2,stop=3]{test} % OK

\foreachinprop[wrapper=\fbox{#1},start=2,stop=3]{test} % OK

\foreachinprop[sep={\par}]{test} % OK

\end{document}

enter image description here

Here's the implementation using sequences (and with some naming fixed).

\documentclass{article}

\ExplSyntaxOn

% Add to prop
\tl_new:N \l__prop_list_name_tl
\NewDocumentCommand \addtoprop { m +m }
  {
    \tl_set:Nn \l__prop_list_name_tl { pgl_list_#1}
    \seq_if_exist:cF { g_ \l__prop_list_name_tl _seq }
      { \seq_new:c { g_ \l__prop_list_name_tl _seq }  }
    \seq_if_in:cnF { g_ \l__prop_list_name_tl _seq } {#2}
      {
        \seq_gput_right:cn { g_ \l__prop_list_name_tl _seq } {#2}
      }
  }

% foreach
\seq_new:N  \l__foreach_print_seq
\tl_new:N   \l__foreach_name_prop_tl
\tl_new:N   \l__foreach_temp_tl
\cs_generate_variant:Nn \seq_use:Nn { NV }

\keys_define:nn { foreach }
  {
    before  .tl_set:N  = \l__foreach_before_tl,
    after   .tl_set:N  = \l__foreach_after_tl,
    start   .int_set:N = \l__foreach_start_int,
    stop    .int_set:N = \l__foreach_stop_int,
    step    .int_set:N = \l__foreach_step_int,
    wrapper .cs_set_protected:Np = \__foreach_wrapper:n #1,
    sep     .tl_set:N  = \l__foreach_sep_tl,
  }
\keys_precompile:nnN { foreach }
  {
    before={},after={},start=1,step=1,stop=0,wrapper=#1,sep=
  }
  \g_foreach_presets_tl

\NewDocumentCommand \foreachinprop { +O{} m }
  {
    \__foreach_code:nn {#1} {#2}
  }
\cs_new_protected:Npn \__foreach_code:nn #1 #2
  {
    \tl_use:N \g_foreach_presets_tl
    \keys_set:nn { foreach } {#1}
    \tl_set:Nn \l__foreach_name_prop_tl {pgl_list_#2}
    \seq_clear:N \l__foreach_print_seq
    \int_compare:nNnT { \l__foreach_stop_int } = { 0 }
      {
        \int_set:Nn \l__foreach_stop_int
          { \seq_count:c { g_ \l__foreach_name_prop_tl _seq } }
      }
    \int_step_function:nnnN
        { \l__foreach_start_int }
        { \l__foreach_step_int }
        { \l__foreach_stop_int }
        \__foreach_prop:n
    \seq_use:NV \l__foreach_print_seq \l__foreach_sep_tl
  }
\cs_new_protected:Npn \__foreach_prop:n #1
  {
    \seq_put_right:Ne \l__foreach_print_seq
      {
        \exp_not:V \l__foreach_before_tl
        % wrapper
        \__foreach_wrapper:n
          {
            \seq_item:cn { g_ \l__foreach_name_prop_tl _seq }{#1}
          }
        \exp_not:V \l__foreach_after_tl
      }
  }

\ExplSyntaxOff

\begin{document}

\addtoprop{test}{The first} \addtoprop{test}{The second}

\addtoprop{test}{The third} \addtoprop{test}{The fourth}

\foreachinprop[sep={\\}, before=FOO, after= BAZZ]{test} % OK

\foreachinprop[wrapper={\fbox{#1}}]{test} % OK

\foreachinprop[sep={\\}, before=FOO, after= BAZZ]{test} % OK

\foreachinprop[sep={\par}]{test} % OK

\foreachinprop[sep={\par},start=2,stop=3]{test} % OK

\foreachinprop[wrapper=\fbox{#1},start=2,stop=3]{test} % OK

\foreachinprop[sep={\par}]{test} % OK

\end{document}
1
  • It is always a pleasure to read your responses, modify the code with your proposal, thank you very much. Commented Jun 24 at 11:35

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .