1

I have a parser for the environment keys and command of a package and it works very well. For MWE purposes I have two environments myenv and myenv*, both represent list environments, but only the first can be nested up to 4 levels, I have the command \setmymodule with which I can configure the keys in the style of package enumitem.

That is, I can use \setmymodule[level,1]{keys}, \setmymodule[level,2]{keys}, \setmymodule[myenv*]{keys} and I've added a \printhis command that encapsulates both environments, \printhis* to myenv* and \printhis to myenv, so I've extended the \setmymodule command to accept: \setmymodule[print,1]{keys}, \setmymodule[print,2]{keys} ... \setmymodule[print*]{keys}.

But I have a problem and I can't adapt it to accept \setmymodule[print,*]{keys}. The MWE I have is the following:

\documentclass{article}
\ExplSyntaxOn
% Some vars
\int_new:N \l_mymodule_int
\int_new:N \l_mymodule_s_int
% set level
\cs_new:Nn \__mymodule_level: { \int_to_roman:n { \l_mymodule_int } }
% keys for environments
\cs_set_protected:Npn \mymodule_tmp:nn #1 #2
  {
    \keys_define:nn { mymodule / #1 }
      {
        keya .tl_set:c = { l_mymodule_keya_#2_tl },
        keyb .tl_set:c = { l_mymodule_keyb_#2_tl },
      }
  }
\clist_map_inline:nn { {level-1}{i}, {level-2}{ii}, {level-3}{iii}, {level-4}{iv}, {myenv*}{v} } { \mymodule_tmp:nn #1 }

% envs
\NewDocumentEnvironment{myenv}{ O{} }
  {
    \int_incr:N \l_mymodule_int
    \tl_if_novalue:nF {#1}
      {
        \exp_args:Ne \keys_set:nn
          { mymodule / level-\int_use:N \l_mymodule_int } {#1}
      }
    \texttt{myenv ~ level: \int_use:N \l_mymodule_int}; ~
    \texttt{keya ~ = ~ \tl_use:c { l_mymodule_keya_ \__mymodule_level: _tl } } ; ~
    \texttt{keyb ~ = ~ \tl_use:c { l_mymodule_keyb_ \__mymodule_level: _tl } } \par
  }{}
\NewDocumentEnvironment{myenv*}{ O{} }
  {
    \int_incr:N \l_mymodule_s_int
    \tl_if_novalue:nF {#1}
      { \keys_set:nn { mymodule / myenv* } {#1} }
    \texttt{myenv* ~ level: \int_use:N \l_mymodule_s_int }; ~
    \texttt{keya ~ = ~ \tl_use:N \l_mymodule_keya_v_tl }; ~
    \texttt{keyb ~ = ~ \tl_use:N \l_mymodule_keyb_v_tl} ; \par
  }{}

% keys for \printhis
\tl_new:N \l_mymodule_print_v_tl
\tl_new:N \l_mymodule_print_starred_tl
\cs_set_protected:Npn \mymodule_tmp:nnn #1 #2 #3
  {
    \keys_define:nn { mymodule / #1 }
      {
        print*  .code:n = \tl_put_right:Nn \l_mymodule_print_starred_tl
                             { \setmymodule[myenv*] {##1} },
        print-* .code:n = \tl_put_right:Nn \l_mymodule_print_v_tl
                             { \setmymodule[myenv*] {##1} },
      }
    \tl_new:c { l_mymodule_print_#3_tl }
    \keys_define:nn { mymodule / #1 }
      {
        print-#2 .code:n = \tl_put_right:cn { l_mymodule_print_#3_tl }
                              { \setmymodule[level,#2] {##1} },
      }
  }
\clist_map_inline:nn { {print}{1}{i}, {print}{2}{ii}, {print}{3}{iii}, {print}{4}{iv}, } { \mymodule_tmp:nnn #1 }
%% cmd
\NewDocumentCommand \printhis { s O{} m }
  {
    \group_begin:
      \tl_use:N \l_mymodule_print_i_tl
      \tl_use:N \l_mymodule_print_ii_tl
      \tl_use:N \l_mymodule_print_iii_tl
      \tl_use:N \l_mymodule_print_iv_tl
      \tl_use:N \l_mymodule_print_v_tl
      \__mymodule_print_this:nnn { #1 } { #2 } { #3 }
    \group_end:
  }
\cs_new_protected:Npn \__mymodule_print_this:nnn #1 #2 #3
  {
    \bool_if:nTF {#1}
      {
        \tl_use:N \l_mymodule_print_starred_tl
        \begin{myenv*}[#2]
          % use \seq_map_inline:cn here #3
         \end{myenv*}
      }
      {
        \begin{myenv}[#2]
          % use \seq_map_inline:cn here #3
        \end{myenv}
      }
  }

%% Add keys
\keys_define:nn { mymodule / meta-families }
  {
    level-1 .code:n = { \keys_set:nn { mymodule / level-1 } {#1} } ,
    level-2 .code:n = { \keys_set:nn { mymodule / level-2 } {#1} } ,
    level-3 .code:n = { \keys_set:nn { mymodule / level-3 } {#1} } ,
    level-4 .code:n = { \keys_set:nn { mymodule / level-4 } {#1} } ,
    myenv*  .code:n = { \keys_set:nn { mymodule / myenv*  } {#1} } ,
    print-1 .code:n = { \keys_set:nn { mymodule / print } { print-1 = {#1} } } ,
    print-2 .code:n = { \keys_set:nn { mymodule / print } { print-2 = {#1} } } ,
    print-3 .code:n = { \keys_set:nn { mymodule / print } { print-3 = {#1} } } ,
    print-4 .code:n = { \keys_set:nn { mymodule / print } { print-4 = {#1} } } ,
    print-* .code:n = { \keys_set:nn { mymodule / print } { print-* = {#1} } } ,
    print*  .code:n = { \keys_set:nn { mymodule / print } { print*  = {#1} } } ,
    unknown .code:n = { \msg_error:nn { mymodule } { unknown-key-family } } ,
  }
\seq_const_from_clist:Nn \c_mymodule_all_families_seq
  {
    level-1 , level-2 , level-3 , level-4 , myenv*,
    print-1 , print-2 , print-3 , print-4 , print-*, print*,
  }
% Define |\setmymodule|
\tl_new:N \l_mymodule_setkey_tmpa_tl
\tl_new:N \l_mymodule_setkey_tmpb_tl
\int_new:N \l_mymodule_setkey_tmpa_int
\seq_new:N \l_mymodule_setkey_tmpa_seq
\seq_new:N \l_mymodule_setkey_tmpb_seq
\NewDocumentCommand \setmymodule { o +m }
  {
    \tl_if_novalue:nTF {#1}
      {
        \seq_map_inline:Nn \c_mymodule_all_families_seq
      }
      {
        \seq_clear:N \l_mymodule_setkey_tmpa_seq
        \seq_set_from_clist:Nn \l_mymodule_setkey_tmpb_seq {#1}
        \int_set:Nn \l_mymodule_setkey_tmpa_int
          {
            \seq_count:N \l_mymodule_setkey_tmpb_seq
          }
        \int_compare:nNnTF { \l_mymodule_setkey_tmpa_int } > { 1 }
          {
            \seq_pop_left:NN \l_mymodule_setkey_tmpb_seq \l_mymodule_setkey_tmpa_tl
            \seq_map_function:NN \l_mymodule_setkey_tmpb_seq \__mymodule_set_parse:n
            \seq_set_map_e:NNn \l_mymodule_setkey_tmpa_seq \l_mymodule_setkey_tmpa_seq
              {
                \tl_use:N \l_mymodule_setkey_tmpa_tl - ##1
              }
          }
          {
            \seq_put_right:Ne \l_mymodule_setkey_tmpa_seq { \tl_trim_spaces:n {#1} }
          }
        \seq_if_empty:NTF \l_mymodule_setkey_tmpa_seq
          { \seq_map_inline:Nn \c_mymodule_all_families_seq }
          { \seq_map_inline:Nn \l_mymodule_setkey_tmpa_seq }
      }
      {
        \keys_set:nn { mymodule / meta-families } { ##1 = {#2} }
      }
  }
\cs_new_protected:Npn \__mymodule_set_parse:n #1
  {
    \tl_set:Ne \l_mymodule_setkey_tmpb_tl { \tl_trim_spaces:n {#1} }
    \int_step_inline:nnn { 0 } { 4 } % <- max level
      { \tl_remove_all:Nn \l_mymodule_setkey_tmpb_tl {##1} }
    \tl_if_empty:NTF \l_mymodule_setkey_tmpb_tl
      {
        \seq_put_right:Ne \l_mymodule_setkey_tmpa_seq
          { \tl_trim_spaces:n {#1} }
      }
      { \__mymodule_set_error:nn {#1} { } }
  }

\cs_new_protected:Npn \__mymodule_set_error:nn #1 #2
  { \msg_error:nnn { mymodule } { invalid-key } {#1} {#2} }

\msg_new:nnn { mymodule } { unknown-key-family }
  {
    Unknown ~ key ~ family ~ `\l_keys_key_str' ~ for ~ mymodule.
  }
\msg_new:nnn { mymodule } { invalid-key }
  {
    The ~ key ~ '#1' ~ is ~ not ~ know ~ the ~ level ~ #2.
  }
\ExplSyntaxOff
\begin{document}
\begin{myenv}[keya=Foo,keyb=Baz]
  \begin{myenv}[keya=BAZ]
  \end{myenv}
\end{myenv}
% myenv*
  \begin{myenv*}[keya=STAR]
  \end{myenv*}
\setmymodule[print*]{keyb=WWWWW }
  \begin{myenv}
  \end{myenv}
Befor
\setmymodule[print,1]{ keyb=HHH }
\printhis{KK}
Now
\setmymodule[print*]{ keya=HHH }
\printhis*{ZZZ}
\setmymodule[print,*]{ keya=HHH }
\end{document}

How can I add an exception to the \setmymodule code so that it accepts \setmymodule[print,*]{keys}?

Clarification

If it's a bit complicated...I'll try to explain, the issue goes through the following:

In the real implementation, when you execute

\begin{myenv}[save=foo]
  ...
   \begin{myenv}
  ...
     \begin{myenv*}
     ...
     \end{myenv*}
  ...
    \end{myenv}
  ...
\end{myenv}

it stores in a \seq_var = foo the entire structure except the first level, including myenv* (which can be nested in it),

When you execute \begin{myenv*}[save=foo] it also saves the entire structure which can contain myenv in a \seq_var = foo (without myenv* nested).

When running \printhis (without *) it opens with:

\begin{myenv}[opt first level]
  \seq_map_inline:cn \seq_var = foo
\end{myenv}

So if there is myenv* in \seq_var = foo and I can't configure it with \setmymodule[myenv*]{keys} because it modifies all myenv* environments outside of \printhis, so I need to be able to access these keys somehow and in this case it would be \setmymodule[print,*]{keys} which is different from \setmymodule[print*]{keys} which sets the default keys (in \l_mymodule_print_starred_tl) for \printhis* which executes:

\tl_use:N \l_mymodule_print_starred_tl
\begin{myenv*}[opt first level]
  \seq_map_inline:cn \seq_var = foo
\end{myenv*}

and will not necessarily have the same default settings as myenv* in the document.

Of course the MWE is a bit ugly but I couldn't find another way to put some code where the use of \setmymodule could be checked :(

6
  • I'm a bit confused. IIRC in enumitem you don't use \setlist[level,1]{...} but just \setlist[1]{...} or is your list called level?
    – Skillmon
    Commented May 27 at 21:17
  • @Skillmon I had to leave it in levels :( ...because I couldn't find a way to fit the rest of the environment names so that it would work Commented May 27 at 21:19
  • 1
    What is print,* supposed to do?
    – cfr
    Commented May 28 at 1:17
  • 3
    The code here is far from minimal and there is almost no description of what it does or what changes you want to make, I think you need to edit the question to make it understandable. Commented May 28 at 7:39
  • 1
    I'm afraid the "Clarification" doesn't explain anything, the pseudo-code you posted in it works more towards further confusion.
    – Skillmon
    Commented May 28 at 18:09

1 Answer 1

1

I really have no idea what your code is supposed to be doing, but I think that replacing \int_step_inline:nnn { 0 } { 4 } with \clist_map_inline:nn { 0, 1, 2, 3, 4, * } does what you want:

\documentclass{article}
\ExplSyntaxOn
% Some vars
\int_new:N \l_mymodule_int
\int_new:N \l_mymodule_s_int
% set level
\cs_new:Nn \__mymodule_level: { \int_to_roman:n { \l_mymodule_int } }
% keys for environments
\cs_set_protected:Npn \mymodule_tmp:nn #1 #2
  {
    \keys_define:nn { mymodule / #1 }
      {
        keya .tl_set:c = { l_mymodule_keya_#2_tl },
        keyb .tl_set:c = { l_mymodule_keyb_#2_tl },
      }
  }
\clist_map_inline:nn { {level-1}{i}, {level-2}{ii}, {level-3}{iii}, {level-4}{iv}, {myenv*}{v} } { \mymodule_tmp:nn #1 }

% envs
\NewDocumentEnvironment{myenv}{ O{} }
  {
    \int_incr:N \l_mymodule_int
    \tl_if_novalue:nF {#1}
      {
        \exp_args:Ne \keys_set:nn
          { mymodule / level-\int_use:N \l_mymodule_int } {#1}
      }
    \texttt{myenv ~ level: \int_use:N \l_mymodule_int}; ~
    \texttt{keya ~ = ~ \tl_use:c { l_mymodule_keya_ \__mymodule_level: _tl } } ; ~
    \texttt{keyb ~ = ~ \tl_use:c { l_mymodule_keyb_ \__mymodule_level: _tl } } \par
  }{}
\NewDocumentEnvironment{myenv*}{ O{} }
  {
    \int_incr:N \l_mymodule_s_int
    \tl_if_novalue:nF {#1}
      { \keys_set:nn { mymodule / myenv* } {#1} }
    \texttt{myenv* ~ level: \int_use:N \l_mymodule_s_int }; ~
    \texttt{keya ~ = ~ \tl_use:N \l_mymodule_keya_v_tl }; ~
    \texttt{keyb ~ = ~ \tl_use:N \l_mymodule_keyb_v_tl} ; \par
  }{}

% keys for \printhis
\tl_new:N \l_mymodule_print_v_tl
\tl_new:N \l_mymodule_print_starred_tl
\cs_set_protected:Npn \mymodule_tmp:nnn #1 #2 #3
  {
    \keys_define:nn { mymodule / #1 }
      {
        print*  .code:n = \tl_put_right:Nn \l_mymodule_print_starred_tl
                             { \setmymodule[myenv*] {##1} },
        print-* .code:n = \tl_put_right:Nn \l_mymodule_print_v_tl
                             { \setmymodule[myenv*] {##1} },
      }
    \tl_new:c { l_mymodule_print_#3_tl }
    \keys_define:nn { mymodule / #1 }
      {
        print-#2 .code:n = \tl_put_right:cn { l_mymodule_print_#3_tl }
                              { \setmymodule[level,#2] {##1} },
      }
  }
\clist_map_inline:nn { {print}{1}{i}, {print}{2}{ii}, {print}{3}{iii}, {print}{4}{iv}, } { \mymodule_tmp:nnn #1 }
%% cmd
\NewDocumentCommand \printhis { s O{} m }
  {
    \group_begin:
      \tl_use:N \l_mymodule_print_i_tl
      \tl_use:N \l_mymodule_print_ii_tl
      \tl_use:N \l_mymodule_print_iii_tl
      \tl_use:N \l_mymodule_print_iv_tl
      \tl_use:N \l_mymodule_print_v_tl
      \__mymodule_print_this:nnn { #1 } { #2 } { #3 }
    \group_end:
  }
\cs_new_protected:Npn \__mymodule_print_this:nnn #1 #2 #3
  {
    \bool_if:nTF {#1}
      {
        \tl_use:N \l_mymodule_print_starred_tl
        \begin{myenv*}[#2]
          % use \seq_map_inline:cn here #3
         \end{myenv*}
      }
      {
        \begin{myenv}[#2]
          % use \seq_map_inline:cn here #3
        \end{myenv}
      }
  }

%% Add keys
\keys_define:nn { mymodule / meta-families }
  {
    level-1 .code:n = { \keys_set:nn { mymodule / level-1 } {#1} } ,
    level-2 .code:n = { \keys_set:nn { mymodule / level-2 } {#1} } ,
    level-3 .code:n = { \keys_set:nn { mymodule / level-3 } {#1} } ,
    level-4 .code:n = { \keys_set:nn { mymodule / level-4 } {#1} } ,
    myenv*  .code:n = { \keys_set:nn { mymodule / myenv*  } {#1} } ,
    print-1 .code:n = { \keys_set:nn { mymodule / print } { print-1 = {#1} } } ,
    print-2 .code:n = { \keys_set:nn { mymodule / print } { print-2 = {#1} } } ,
    print-3 .code:n = { \keys_set:nn { mymodule / print } { print-3 = {#1} } } ,
    print-4 .code:n = { \keys_set:nn { mymodule / print } { print-4 = {#1} } } ,
    print-* .code:n = { \keys_set:nn { mymodule / print } { print-* = {#1} } } ,
    print*  .code:n = { \keys_set:nn { mymodule / print } { print*  = {#1} } } ,
    unknown .code:n = { \msg_error:nn { mymodule } { unknown-key-family } } ,
  }
\seq_const_from_clist:Nn \c_mymodule_all_families_seq
  {
    level-1 , level-2 , level-3 , level-4 , myenv*,
    print-1 , print-2 , print-3 , print-4 , print-*, print*,
  }
% Define |\setmymodule|
\tl_new:N \l_mymodule_setkey_tmpa_tl
\tl_new:N \l_mymodule_setkey_tmpb_tl
\int_new:N \l_mymodule_setkey_tmpa_int
\seq_new:N \l_mymodule_setkey_tmpa_seq
\seq_new:N \l_mymodule_setkey_tmpb_seq
\NewDocumentCommand \setmymodule { o +m }
  {
    \tl_if_novalue:nTF {#1}
      {
        \seq_map_inline:Nn \c_mymodule_all_families_seq
      }
      {
        \seq_clear:N \l_mymodule_setkey_tmpa_seq
        \seq_set_from_clist:Nn \l_mymodule_setkey_tmpb_seq {#1}
        \int_set:Nn \l_mymodule_setkey_tmpa_int
          {
            \seq_count:N \l_mymodule_setkey_tmpb_seq
          }
        \int_compare:nNnTF { \l_mymodule_setkey_tmpa_int } > { 1 }
          {
            \seq_pop_left:NN \l_mymodule_setkey_tmpb_seq \l_mymodule_setkey_tmpa_tl
            \seq_map_function:NN \l_mymodule_setkey_tmpb_seq \__mymodule_set_parse:n
            \seq_set_map_e:NNn \l_mymodule_setkey_tmpa_seq \l_mymodule_setkey_tmpa_seq
              {
                \tl_use:N \l_mymodule_setkey_tmpa_tl - ##1
              }
          }
          {
            \seq_put_right:Ne \l_mymodule_setkey_tmpa_seq { \tl_trim_spaces:n {#1} }
          }
        \seq_if_empty:NTF \l_mymodule_setkey_tmpa_seq
          { \seq_map_inline:Nn \c_mymodule_all_families_seq }
          { \seq_map_inline:Nn \l_mymodule_setkey_tmpa_seq }
      }
      {
        \keys_set:nn { mymodule / meta-families } { ##1 = {#2} }
      }
  }
\cs_new_protected:Npn \__mymodule_set_parse:n #1
  {
    \tl_set:Ne \l_mymodule_setkey_tmpb_tl { \tl_trim_spaces:n {#1} }
    \clist_map_inline:nn { 0, 1, 2, 3, 4, * } %%% CHANGED %%%
      { \tl_remove_all:Nn \l_mymodule_setkey_tmpb_tl {##1} }
    \tl_if_empty:NTF \l_mymodule_setkey_tmpb_tl
      {
        \seq_put_right:Ne \l_mymodule_setkey_tmpa_seq
          { \tl_trim_spaces:n {#1} }
      }
      { \__mymodule_set_error:nn {#1} { } }
  }

\cs_new_protected:Npn \__mymodule_set_error:nn #1 #2
  { \msg_error:nnn { mymodule } { invalid-key } {#1} {#2} }

\msg_new:nnn { mymodule } { unknown-key-family }
  {
    Unknown ~ key ~ family ~ `\l_keys_key_str' ~ for ~ mymodule.
  }
\msg_new:nnn { mymodule } { invalid-key }
  {
    The ~ key ~ '#1' ~ is ~ not ~ know ~ the ~ level ~ #2.
  }
\ExplSyntaxOff
\begin{document}
\begin{myenv}[keya=Foo,keyb=Baz]
  \begin{myenv}[keya=BAZ]
  \end{myenv}
\end{myenv}
% myenv*
  \begin{myenv*}[keya=STAR]
  \end{myenv*}
\setmymodule[print*]{keyb=WWWWW }
  \begin{myenv}
  \end{myenv}
Befor
\setmymodule[print,1]{ keyb=HHH }
\printhis{KK}
Now
\setmymodule[print*]{ keya=HHH }
\printhis*{ZZZ}
\setmymodule[print,*]{ keya=HHH }
\end{document}

output

This makes the code compile without any errors, but I'm not sure if it does what you wanted it to do.

1
  • 1
    That's exactly the change I need, thank you millions :D Commented May 28 at 12:53

You must log in to answer this question.

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