TransWikia.com

Forward list of key-value-pairs to other command in expl3

TeX - LaTeX Asked on October 1, 2021

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 Answers

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

expandaftercmdAexpandafter[l_options_clist]
% or
expandaftercmdAexpandafter{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:

deftemp{cmdB{arg1}}%
expandaftertempexpandafter[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
defexpandsecond@mo#1#2[#3]{%
  expandafterexpandafterexpandafter#1%
  expandafterexchangetwo@mm@to@omexpandafter{#3}{#2}%
}
defexchangetwo@mm@to@om#1#2{{#2}[#1]}

% store key-value pairs in macro
defoptions{key1,key2,key3}

% suppose cmdB has syntax cmdB{}[]
% this will expand to cmdB{arg1}[key1,key2,key3]
expandsecond@mocmdB{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:Notcbset{l_mybodule_tcb_clist}
    begin{mytcb}
}
{end{mytcb}}
ExplSyntaxOff

Correct answer by muzimuzhi Z on October 1, 2021

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}

Answered by Henri Menke on October 1, 2021

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

Answered by egreg on October 1, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP