4

I would like to pass a list of key-value pairs to another command/environment. In this MWE to tcolorbox, but it should work in general (e.g. pass parameters to \LoadClass[params]{article}).

\documentclass{article}
\usepackage{xparse,graphicx}

\RequirePackage{tcolorbox}
\tcbuselibrary{xparse}
\DeclareTColorBox{mytcb}{O{}}{#1}

\ExplSyntaxOn
\keys_define:nn { mybodule/bfigure }
{
    caption .tl_set:N = \l_mybodule_caption_tl,
    tcb     .clist_set:N = \l_mybodule_tcb_clist,
}

\NewDocumentEnvironment{bfigure}{O{}}
{
    \keys_set:nn { mybodule/bfigure } { #1 }  
    \begin{mytcb}[\l_mybodule_tcb_clist]
}
{\end{mytcb}}
\ExplSyntaxOff

\begin{document}
    \begin{bfigure}[tcb={left=-3pt}]
        \includegraphics[width=1cm]{example-grid-100x100pt}
    \end{bfigure}
\end{document}

I am not quite sure how I can achieve this. Can anyone help?

3
  • 1
    \exp_args:No\tcbset{\l_mybodule_tcb_clist} before the tcolorbox is probably the easiest. Jul 21, 2020 at 7:49
  • Why are you even doing this? It's not like PGF already has a powerful key-value system. Jul 29, 2020 at 7:32
  • @HenriMenke I am in already existing environment which utilizes expl3 and I am not allowed to change this. Jul 29, 2020 at 9:30

3 Answers 3

1
+50

The general idea is that you need to expand \l_mybodule_tcb_clist before passing it to some command/environment as comma-separated key-value list.

Firstly, it only takes one step of expansion to get the contents of a l3clist variable.

Then, in a simple case, if we have \cmdA[options] or \cmdA{options}, then

\expandafter\cmdA\expandafter[\l_options_clist]
% or
\expandafter\cmdA\expandafter{\l_options_clist}

does the job. \LoadClass[params]{article} falls into this type.

In a more complex situation, if there are other arguments before options, for example \cmdB{arg1}[options], then you can treat it as first argument by providing a new macro:

\def\temp{\cmdB{arg1}}%
\expandafter\temp\expandafter[\l_options_clist]

For an expandable solution, you can use macro expansion to exchange the order of arguments, expand the first argument, and then restore the order. The mechanism used by latex3 functions in l3expan (sub)package is similar to this.

% follow xparse' arg-spec names, 
% m stands for mandatory, o stands for optional
\def\expandsecond@mo#1#2[#3]{%
  \expandafter\expandafter\expandafter#1%
  \expandafter\exchangetwo@mm@to@om\expandafter{#3}{#2}%
}
\def\exchangetwo@mm@to@om#1#2{{#2}[#1]}

% store key-value pairs in macro
\def\options{key1,key2,key3}

% suppose \cmdB has syntax \cmdB{}[]
% this will expand to \cmdB{arg1}[key1,key2,key3]
\expandsecond@mo\cmdB{arg1}[\options]

\begin{envname}[options] falls into this type.

Specially, in your example, since environment mytcb is used inside a group created by environment bfigure, \tcbset{options}\begin{mytcb} is equivalent to \begin{mytcb}[options], hence there is @UlrikeFischer's suggestion in comment:

\ExplSyntaxOn
\NewDocumentEnvironment{bfigure}{O{}}
{
    \keys_set:nn { mybodule/bfigure } { #1 }
    \exp_args:No\tcbset{\l_mybodule_tcb_clist}
    \begin{mytcb}
}
{\end{mytcb}}
\ExplSyntaxOff
2
  • 1
    Why don't you just use \exp_args:N... directly. For example \exp_args:NnV \use:n { \begin { mytcb } [ } \l_mymodule_tcb_clist ] does exactly what you want to achieve and is more robust than your \expandsecond@mo since it'll reliably work even if \l_mymodule_tcb_clist contains ].
    – Skillmon
    Sep 10, 2021 at 7:59
  • @Skillmon Ah yes, yours is more robust. Sep 10, 2021 at 8:51
1

It is very unfortunate that all the different key-value systems for LaTeX are mutually incompatible which requires serializing key-value trees as comma-separated lists and passing them around. As of yet, there also seems to be no predominant key-value system which everyone else should adhere to.

Since you are interacting with tcolorbox, I can only recommend using pgfkeys. In contrast to l3keys this integrates naturally with the rest of the package and you can easily access the /tcb subtree and just pass on your options.

\documentclass{article}
\usepackage{xparse,graphicx}

\RequirePackage{tcolorbox}
\tcbuselibrary{xparse}
\DeclareTColorBox{mytcb}{O{}}{#1}

\pgfqkeys{/mybodule/bfigure}{%
    caption/.initial={},
    tcb/.style={/tcb/.cd,#1},
}

\NewDocumentEnvironment{bfigure}{O{}}{%
    \pgfqkeys{/mybodule/bfigure}{#1}%
    \begin{mytcb}%
}{%
    Caption: \pgfkeysvalueof{/mybodule/bfigure/caption}%
    \end{mytcb}%
}

\begin{document}
    \begin{bfigure}[caption={foobar},tcb={left=-3pt}]
        \includegraphics[width=1cm]{example-grid-100x100pt}
    \end{bfigure}
\end{document}
1

You're apparently using mytcb as an auxiliary environment, so there should be no problem into making it accept a mandatory argument rather than an optional one.

\documentclass{article}
\usepackage{xparse,graphicx}

\usepackage{tcolorbox}
\tcbuselibrary{xparse}
\DeclareTColorBox{mytcb}{m}{#1}

\ExplSyntaxOn
\keys_define:nn { mybodule/bfigure }
{
    caption .tl_set:N = \l_mybodule_caption_tl,
    tcb     .clist_set:N = \l_mybodule_tcb_clist,
}

\NewDocumentEnvironment{bfigure}{O{}}
{
    \keys_set:nn { mybodule/bfigure } { #1 }  
    \exp_args:NnV \begin{mytcb} \l_mybodule_tcb_clist
}
{\end{mytcb}}
\ExplSyntaxOff

\begin{document}

\begin{bfigure}[tcb={left=-3pt}]
\includegraphics[width=1cm]{example-grid-100x100pt}
\end{bfigure}

\begin{bfigure}[tcb={left=20pt,right=4cm}]
\includegraphics[width=1cm]{example-grid-100x100pt}
something that will show the effect of the \texttt{right}
option, for lack of knowledge what other keys you plan to use 
\end{bfigure}

\end{document}

enter image description here

1
  • Thx, but the tcb is just an MWE. I have the use case of passing a list of optional key-value-pairs to functions/envs which I do not have control over. Jul 29, 2020 at 10:50

You must log in to answer this question.

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