TeX - LaTeX Asked by T. Pluess on May 4, 2021
Consider the following MWE:
documentclass[a4paper]{article}
usepackage{keyval}
makeatletter
define@key{my}{foo}[]{foo is enabledpar}
define@key{my}{bar}[0]{bar is set to #1par}
makeatother
newcommand{somecommand}[2][none]{arg 1: #1, arg 2: #2}
newcommand{othercommand}[2][]{setkeys{my}{#1} somecommand{#2}}
begin{document}
othercommand[foo,bar=9]{baz}
end{document}
This works fine as long as the only optional arguments passed to othercommand
are either foo
or bar
. Since these are optional arguments, they may be omitted as well. But what I would like to do now is the following: if there is another optional argument given, not known to the othercommand
, it shall be passed to the somecommand
. Example: if I write
othercommand[foo, bar=29, zap=12]{baz}
I want the options foo
and bar
still be processed by the othercommand
. But the zap=12
option is not known, so it shall be passed to somecommand
without modification, such that I can write
newcommand{othercommand}[2][]{setkeys{my}{#1} somecommand[pass unknown options here]{#2}}
For documentclasses, there is a command like “pass options to class” which passes unknown documentclass options to the underlying document class. I wonder whether such a mechanism can be used here as well.
The following is an example how this could be done with expkv
. Note that the unknown key isn't forwarded exactly like it was passed in (that information is lost when expkv
has parsed the current key=val pair), but in a way in which most key=value packages would parse an equivalent value of pair (I say most because some of the wide spread packages have some issues regarding brace stripping, most notably it is possible that pgfkeys
doesn't parse correctly something which is passed in as key= {value}
).
documentclass[]{article}
usepackage{expkv}
makeatletter
ekvdefNoVal{my}{foo}{foo is enabledpar}
ekvdef{my}{bar}{bar is set to #1par}
ekvdefNoVal{my}{bar}{bar is set to 0par}
newcommandpluess@add@to@list[2]
{%
ifx@empty#1%
def#1{#2}%
else
edef#1{unexpandedexpandafter{#1,#2}}%
fi
}
ekvdefunknownNoVal{my}{pluess@add@to@listpluess@my@unknown@list{#1}}
ekvdefunknown{my}{pluess@add@to@listpluess@my@unknown@list{#2= {#1}}}
newcommand*pluess@my@unknown@list{}
ekvsetdefmy@set{my}
newcommandothercommand[2][]
{%
begingroup
letpluess@my@unknown@list@empty
my@set{#1}%
expandaftersomecommandexpandafter
[expandafter{pluess@my@unknown@list}]%
{#2}%
endgroup
}
newcommandsomecommand[2][none]{arg 1: #1, arg 2: #2par}
makeatother
begin{document}
othercommand{baz}
othercommand[foo, bar=9]{baz}
othercommand[foo, bar=9, zip=12]{baz}
end{document}
If you want to only use the optional argument of somecommand
if there were any unknown keys and else stick to its default, you could use:
documentclass[]{article}
usepackage{expkv}
makeatletter
ekvdefNoVal{my}{foo}{foo is enabledpar}
ekvdef{my}{bar}{bar is set to #1par}
ekvdefNoVal{my}{bar}{bar is set to 0par}
newcommandpluess@add@to@list[2]
{%
ifx@empty#1%
def#1{#2}%
else
edef#1{unexpandedexpandafter{#1,#2}}%
fi
}
ekvdefunknownNoVal{my}{pluess@add@to@listpluess@my@unknown@list{#1}}
ekvdefunknown{my}{pluess@add@to@listpluess@my@unknown@list{#2= {#1}}}
newcommand*pluess@my@unknown@list{}
ekvsetdefmy@set{my}
newcommandothercommand[2][]
{%
begingroup
letpluess@my@unknown@list@empty
my@set{#1}%
ifxpluess@my@unknown@list@empty
expandafter@firstoftwo
else
expandafter@secondoftwo
fi
{somecommand}%
{%
expandaftersomecommandexpandafter
[expandafter{pluess@my@unknown@list}]%
}%
{#2}%
endgroup
}
newcommandsomecommand[2][none]{arg 1: #1, arg 2: #2par}
makeatother
begin{document}
othercommand{baz}
othercommand[foo, bar=9]{baz}
othercommand[foo, bar=9, zip=12]{baz}
end{document}
Answered by Skillmon on May 4, 2021
The l3keys
module of LaTeX3 has the function keys_set_known:nnN
which stores every unknown key in a token list.
You could use it in the following way:
documentclass[]{article}
% Inside of ExplSyntaxOn ... ExplSyntaxOff spaces are ignored and you have to
% use ~ to insert a space instead. Also _ and : can be part of macro names which
% is used to add some structure.
ExplSyntaxOn
keys_define:nn { my }
{
foo .code:n = { foo ~ is ~ enabled par }
,foo .value_forbidden:n = { true }
,bar .code:n = { bar ~ is ~ set ~ to ~ #1par }
,bar .default:n = { 0 }
}
tl_new:N l__my_unknown_keys_tl
NewDocumentCommand othercommand { O{} m }
{
group_begin:
keys_set_known:nnN { my } {#1} l__my_unknown_keys_tl
exp_args:NNo somecommand [ l__my_unknown_keys_tl ] {#2}
group_end:
}
NewDocumentCommand somecommand { O{none} m }
{
arg ~ 1: ~ #1, ~ arg ~ 2: ~ #2par
}
ExplSyntaxOff
begin{document}
othercommand{baz}
othercommand[foo, bar=9]{baz}
othercommand[foo, bar=9, zip=12]{baz}
end{document}
If you want to only use the optional argument of somecommand
if there were any unknown keys and else stick to its default, you could use:
documentclass[]{article}
% Inside of ExplSyntaxOn ... ExplSyntaxOff spaces are ignored and you have to
% use ~ to insert a space instead. Also _ and : can be part of macro names which
% is used to add some structure.
ExplSyntaxOn
keys_define:nn { my }
{
foo .code:n = { foo ~ is ~ enabled par }
,foo .value_forbidden:n = { true }
,bar .code:n = { bar ~ is ~ set ~ to ~ #1par }
,bar .default:n = { 0 }
}
tl_new:N l__my_unknown_keys_tl
NewDocumentCommand othercommand { O{} m }
{
group_begin:
keys_set_known:nnN { my } {#1} l__my_unknown_keys_tl
tl_if_empty:NTF l__my_unknown_keys_tl
{ somecommand {#2} }
{ exp_args:NNo somecommand [ l__my_unknown_keys_tl ] {#2} }
group_end:
}
NewDocumentCommand somecommand { O{none} m }
{
arg ~ 1: ~ #1, ~ arg ~ 2: ~ #2par
}
ExplSyntaxOff
begin{document}
othercommand{baz}
othercommand[foo, bar=9]{baz}
othercommand[foo, bar=9, zip=12]{baz}
end{document}
Answered by Skillmon on May 4, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP