l3keys y comandos recursivos

l3keys y comandos recursivos

Estoy intentando crear una l3keyslista llamada mykeysque se utiliza para controlar el comportamiento del comando mycommand:n. Inicialmente, es sólo la identidad. La configuración command=\textitdebería cambiarlo a \textit(compuesto con identidad). En general, la configuración command=\foodebería redefinirse mycommand:npara convertirse en #1\foo{mycommand:n{#1}}. Sin embargo, tal como está ahora, fracasa estrepitosamente.¿Es posible hacer que esto funcione?

\documentclass{article}

\usepackage{expl3}

\ExplSyntaxOn

\cs_new:Npn \identity:n #1 { #1 }


\keys_define:nn { mykeys }
{
    command .multichoice:,
    command / none .code:n = {
        \cs_set_eq:NN \mycommand:n \identity:n %this resets \mycommand:n
                                               %to become the identity
    },
    command / unknown .code:n = {
        \cs_set:Npx \mycommand:n ##1
        {
            #1 { \mycommand:n { ##1 } }
        }
    }
}

\keys_set:nn { mykeys } { command=none }

\ExplSyntaxOff

\begin{document}

\ExplSyntaxOn

\mycommand:n{test1} % should produce test1

\keys_set:nn { mykeys } { command=\textit }

\mycommand:n{test2} % should produce \textit{test2}

\keys_set:nn { mykeys } { command=\textbf }

\mycommand:n{test3} % should produce \textbf{\textit{test3}}

\ExplSyntaxOff

\end{document}

Respuesta1

No estoy particularmente interesado en la interfaz, pero aquí almacenaría los comandos para la aplicación en secuencia.

\documentclass{article}
\usepackage{expl3,xparse}
\ExplSyntaxOn

\seq_new:N \l__mycommand_cmds_seq
\tl_new:N \l__mycommand_tmp_tl

\keys_define:nn { mykeys }
  {
    command .code:n = 
      {
        \str_if_eq:nnTF {#1} { none }
          { \seq_clear:N \l__mycommand_cmds_seq }
          { \seq_put_right:Nn \l__mycommand_cmds_seq {#1} }
      }
  }
\keys_set:nn { mykeys } { command = none }

\cs_new_protected:Npn \mycommand_main:n #1
  {
    \group_begin:
      \tl_set:Nn \l__mycommand_tmp_tl {#1}
      \seq_map_inline:Nn \l__mycommand_cmds_seq
        {
          \tl_set:Nx \l__mycommand_tmp_tl
            { \exp_not:n {##1} { \exp_not:V \l__mycommand_tmp_tl } }
        }
    \exp_args:NV \group_end:
    \l__mycommand_tmp_tl
  }

\NewDocumentCommand \mysetup { +m } { \keys_set:nn { mykeys } {#1} }
\NewDocumentCommand \mycommand { m }
  { \mycommand_main:n {#1} }
\ExplSyntaxOff

\begin{document}

\mycommand{test1} % should produce test1

\mysetup{command = \textit}

\mycommand{test2} % should produce \textit{test2}

\mysetup{command = \textbf}

\mycommand{test3} % should produce \textbf{\textit{test3}}

\end{document}

Se podría hacer una prueba de token único/macro como parte de la configuración de keyval, pero probablemente sea excesivo.

Se podría crear la lista de tokens "funcionales" durante la configuración de keyval, pero sospecho que tener la secuencia disponible para inspección podría ser útil en la depuración.

Respuesta2

ingrese la descripción de la imagen aquí

Siempre que los comandos involucrados expongan su implementación después de una sola expansión, puede hacer algo como lo siguiente

\documentclass{article}

\usepackage{expl3}

\ExplSyntaxOn

\cs_new:Npn \identity:n #1 { #1 }

\cs_new:Npn\wrap_def:NN#1#2{
  \exp_after:wN\cs_set:Npn
   \exp_after:wN#2\exp_after:wN##\exp_after:wN1\exp_after:wN{
   \exp_after:wN#1\exp_after:wN{#2{##1}}}
  }





\keys_define:nn { mykeys }
{
    command .multichoice:,
    command / none .code:n = {
        \cs_set_eq:NN \mycommand:n \identity:n %this resets \mycommand:n
                                               %to become the identity
    },
    command / unknown .code:n = {
        \wrap_def:NN #1 \mycommand:n
    }
}

\keys_set:nn { mykeys } { command=none }

\ExplSyntaxOff

\begin{document}

\ExplSyntaxOn

\mycommand:n{test1} % should produce test1

\keys_set:nn { mykeys } { command=\textit }


\mycommand:n{test2} % should produce \textit{test2}

\keys_set:nn { mykeys } { command=\textbf }

\mycommand:n{test3} % should produce \textbf{\textit{test3}}

\ExplSyntaxOff

\end{document}

Respuesta3

Implementando la sugerencia de David:

\documentclass{article}

\usepackage{expl3}

\ExplSyntaxOn

\tl_new:N \l_gaussler_command_start_tl
\tl_new:N \l_gaussler_command_end_tl

\keys_define:nn { mykeys }
 {
  command .multichoice:,
  command / none .code:n =
   {
    \tl_clear:N \l_gaussler_command_start_tl
    \tl_clear:N \l_gaussler_command_end_tl
    \cs_set_protected:Nn \gaussler_thecommand:n { ##1 }
   },
  command / unknown .code:n =
   {
    \tl_put_left:Nn \l_gaussler_command_start_tl { \exp_not:N #1 \gaussler_command_open: }
    \tl_put_right:Nn \l_gaussler_command_end_tl { \gaussler_command_close: }
    \cs_set_protected:Nx \gaussler_thecommand:n
     {
      \tl_use:N \l_gaussler_command_start_tl
      ##1 
      \tl_use:N \l_gaussler_command_end_tl
     }
   }
 }
\cs_new:Nn \gaussler_command_open: { \if_true: { \else: } \fi: }
\cs_new:Nn \gaussler_command_close: { \if_false: { \else: } \fi: }

\keys_set:nn { mykeys } { command=none }

\ExplSyntaxOff

\begin{document}

\ExplSyntaxOn

\gaussler_thecommand:n{test1} % should produce test1

\keys_set:nn { mykeys } { command=\textit }

\gaussler_thecommand:n{test2} % should produce \textit{test2}

\keys_set:nn { mykeys } { command=\textbf }

\gaussler_thecommand:n{test3} % should produce \textbf{\textit{test3}}

\keys_set:nn { mykeys } { command=none }

\gaussler_thecommand:n{test4}

\ExplSyntaxOff

\end{document}

ingrese la descripción de la imagen aquí

información relacionada