TransWikia.com

Using passed value as the name of a control sequence with pgfkeys

TeX - LaTeX Asked on July 15, 2021

I have the following family of options

pgfkeys{
    /opts/.is family,
    /opts,
    name/.store in = @@Style@Name,
    property/.code = {
        expandaftergdefexpandaftercsname @@Style@ @@StyleName @Poperty endcsname#1},
}

I want to create a global command @@Style@<value of the "name">@Property and assign it the value of "property" if it is passed.

For example, the code pgfkeys{/opts, name = A, property = B} should create a command @@Style@A@Propety with the value B. How can I do that.

Minimal non-working example:

documentclass{article}

usepackage{pgfkeys}

makeatletter

pgfkeys{
    /opts/.is family,
    /opts,
    name/.store in = @@Style@Name,
    property/.code = {
        expandaftergdefexpandaftercsname @@Style@ @@StyleName @Poperty endcsname#1},
}

begin{document}

    pgfkeys{/opts, name = A, property = B}
    
    @@Style@A@Propety

end{document}

One Answer

The exact syntax from the question is implemented below (see With the syntax from the question), but my suggestion would be to use a slightly different one, namely:

pgfkeys{/myopts={A=foo, B={bar bazquux}}}

in order to set @@Style@A@Property to foo and @@Style@B@Property to bar bazquux (thus two assignments in this example, but you can perform as many as you want with my code). Indeed, the syntax you asked for requires stateful code:

  • one needs to remember that the property name has been set until we see the value, or that the value has been set until we see the name;

  • one needs to specify what happens with dubious input like pgfkeys{/opts, name=foo, name=bar, property=whatever} or pgfkeys{/opts, property=whatever}, etc.

The syntax I propose can be implemented by defining the /some dir/.unknown handler, which is invoked by pgfkeys whenever an unknown key in /some dir is used.

documentclass{article}
usepackage{pgfkeys}
usepackage{etoolbox}  % for csgdef (syntactic sugar)

makeatletter
pgfkeys{
  /myopts/dir/.unknown/.code={%
    csgdef{@@Style@pgfkeyscurrentname @Property}{#1}%
  },
  /myopts/.code={pgfkeys{/myopts/dir/.cd, #1}},
}
makeatother

begin{document}

pgfkeys{/myopts={A=foo, B={bar bazquux}}}

makeatletter
show@@Style@A@Property % @@Style@A@Property=macro:->foo.
show@@Style@B@Property % @@Style@B@Property=macro:->bar bazquux.
makeatother

end{document}

Regarding the code you posted, please note that

expandaftergdefexpandaftercsname @@Style@ @@StyleName @Property endcsname#1}

should rather be something like this:

expandaftergdefcsname @@Style@@@StyleName @Propertyendcsname{#1}

(no need for the second expandafter because it is csname that needs to be expanded early here; beware of unwanted spaces; wrap the macro replacement text within curly braces).

With the syntax from the question

Since the OP insists on having exactly the syntax from the question, namely pgfkeys{/opts, name = A, property = B}, here it is. I don't recommend it, though (there might be good reasons but they haven't been revealed so far, AFAICT). The name must be given before the property (as in the question).

documentclass{article}
usepackage{pgfkeys}
usepackage{etoolbox}  % for csgdef (syntactic sugar)

makeatletter
pgfkeys{
  /opts/.is family,
  /opts/name/.store in=@@My@PropName,
  /opts/property/.code={%
    csgdef{@@Style@@@My@PropName @Property}{#1}%
  },
}
makeatother

begin{document}

pgfkeys{/opts, name = A, property = B}

makeatletter
show@@Style@A@Property % @@Style@A@Property=macro:->B.
makeatother

end{document}

Answered by frougon on July 15, 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