TeX - LaTeX Asked on February 5, 2021
I’m trying to generate a set of keys using a foreach
loop, but they don’t appear to be created properly.
I’ve tried debugging with a handler that shows the keys, but they look correct to me in the log. There must be something that I’m missing, but I can’t figure out what.
See the comments in the MWE below for where the error shows up.
MWE:
documentclass{article}
RequirePackage{pgfkeys}
RequirePackage{pgffor}
RequirePackage{etoolbox}
pgfkeys{/handlers/.store in cs/.code=pgfkeysalso{%
pgfkeyscurrentpath/.code=expandafterdefcsname#1endcsname{##1}}%
}
pgfkeysdef{/handlers/.show path}
{%
edefpath{pgfkeyscurrentpath}%
pgfkeysgetvalue{pgfkeyscurrentpath}{val}%
showpath%
}
makeatletter
defmeide@keys{pgfqkeys{/meide}}
newcommandmeide@setup[3]{%
% #1 = name
% #2 = number of levels
% #3 = further key/value pairs
meide@keys{
#1/.cd,
levels/.store in cs=meide@#1@levels,
levels=#2,
}%
foreach level in {0,...,csuse{meide@#1@levels}}%
{%
meide@setup@level{#1}{level}%
}%
meide@keys{#1/.cd,#3}%
}
newcommandmeide@setup@level[2]{
% #1 = name
% #2 = level to create
begingroupedefx{endgroupnoexpand%
meide@keys{
#1/level #2/.cd,
% uncomment the '.show path' handler to see the current keypaths. I see them as expected:
% /meide/name/level 0/myvals
% /meide/name/level 1/myvals
%myvals/.show path,
myvals/.code 2 args={%
% #1 = first
% #2 = second
csxdef{meide@#1@myvals@level #2@first}{unexpanded{##1}}%
csxdef{meide@#1@myvals@level #2@second}{unexpanded{##2}}%
}
}%
}x%
}
% setting up one of the levels manually to show how it should work
meide@keys{
name/level 0/myvals/.code 2 args={%
% #1 = first
% #2 = second
csxdef{meide@name@myvals@level 0@first}{#1}%
csxdef{meide@name@myvals@level 0@second}{#2}%
},
}
meide@setup{name}{1}{
level 0/myvals={a}{b}, % works because it was created manually
level 1/myvals={c}{d}, % Package pgfkeys Error: I do not know the key '/meide/name/level 1/myvals', to which you passed '{c}{d}'
}
makeatother
begin{document}
csuse{meide@name@myvals@level 0@first} % displays 'a'
csuse{meide@name@myvals@level 1@first} % displays nothing
end{document}
This doesn't work because your myvals/.code 2 args={...}
is a local assignment, but it is executed inside a TeX group. Indeed, the foreach
loop in meide@setup
executes the loop code inside a TeX group. Once this group is finished, all local definitions performed therein automatically vanish. In order to solve this problem, I simply replaced the foreach
loop with expl3
's int_step_inline:nnn
macro, which doesn't create a group around the loop code.
I also removed the edef
and the associated tricks, because I don't see why they are needed here. With these two changes, everything appears to work as expected.
documentclass{article}
usepackage{pgfkeys}
usepackage{expl3}
usepackage{etoolbox}
ExplSyntaxOn
% Borrow int_step_inline:nnn from expl3
cs_new_eq:NN intstepinline int_step_inline:nnn
ExplSyntaxOff
pgfkeys{/handlers/.store in cs/.code=pgfkeysalso{%
pgfkeyscurrentpath/.code=expandafterdefcsname#1endcsname{##1}}%
}
pgfkeysdef{/handlers/.show path}
{%
edefpath{pgfkeyscurrentpath}%
pgfkeysgetvalue{pgfkeyscurrentpath}{val}%
showpath
}
makeatletter
newcommandmeide@keys{pgfqkeys{/meide}}
newcommandmeide@setup[3]{%
% #1 = name
% #2 = number of levels
% #3 = further key/value pairs
meide@keys{
#1/.cd,
levels/.store in cs=meide@#1@levels,
levels=#2,
}%
intstepinline{0}{csuse{meide@#1@levels}}
{%
meide@setup@level{#1}{##1}%
}%
meide@keys{#1/.cd,#3}%
}
newcommandmeide@setup@level[2]{%
meide@keys{
#1/level #2/.cd,
% uncomment the '.show path' handler to see the current keypaths. I see them as expected:
% /meide/name/level 0/myvals
% /meide/name/level 1/myvals
%myvals/.show path,
myvals/.code 2 args={%
% #1 = first
% #2 = second
csxdef{meide@#1@myvals@level #2@first}{##1}%
csxdef{meide@#1@myvals@level #2@second}{##2}%
},
}%
}
meide@setup{name}{1}{
level 0/myvals={a}{b}, % works
level 1/myvals={c}{d}, % now also works
}
makeatother
begin{document}
csuse{meide@name@myvals@level 0@first} % displays 'a'
csuse{meide@name@myvals@level 0@second} % displays 'b'
csuse{meide@name@myvals@level 1@first} % displays 'c'
csuse{meide@name@myvals@level 1@second} % displays 'd'
end{document}
Please try to provide a minimal example next time: this takes too much time to read and analyze. You could probably reduce the code, although I understand that maybe you didn't manage to locate the problem very precisely.
Answered by frougon on February 5, 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