Summary
I have a caller macro that should pass options to other nested macros within it. However, the key is not found when I pass it from the caller macro, yet it is correctly defined (I think) since it is found when I call the inner macros with it.
Setup
In my following simplification of the original setup, I have a \caller
macro that receives the options, stores them into a \nodeopts
macro using .store in
key handler within its set of keys /caller
.
\pgfkeys{
/caller/.cd,
opts/.store in=\nodeopts,
opts/.default=,
}
\newcommand{\caller}[1][]{\pgfkeys{/caller/.cd, opts, #1}\node[\nodeopts]}
Then, I process these parameters in the \node
macro that uses its own /node
directory for its own keys.
\pgfkeys{
/node/.cd,
background color/.store in={\bgcolor},
background color/.default=none,
}
\newcommand{\node}[1][]{\pgfkeys{/node/.cd, background color=yellow, #1}\nodeh{red}}
And once the keys are set, it calls the final macro that does the actual job:
\newcommand{\nodeh}[1]{\tikz\draw[fill=\bgcolor, draw=#1] (0,0) circle (10pt);}
Problem
If I call \caller[opts={background color=blue}]
, I get
Package pgfkeys Error: I do not know the key '/node/background color=blue' and I am going to ignore it. Perhaps you misspelled it.
Which is strange since calling \node[background color=blue]
works as expected. And even if I print the content of the options inside \nodeopts
(for example, \newcommand{\caller}[1][]{\pgfkeys{/caller/.cd, opts, #1}\nodeopts\node[\nodeopts]}
) I can see that the options are being passed.
My limited knowledge of pgfkeys
is telling me that there is an expansion shenanigan happening in the middle. I tried to find a way to debug the keys and how they are expanded but I couldn't find information about that as well.
Question
How should I declared the parameters or used them to achieve my goal of passing parameters down the macros?
Could explain the expansion mechanism and why the macro calling from the outside doesn't work?
MWE
\documentclass{article}
\usepackage{tikz}
\pgfkeys{
/node/.cd,
background color/.store in={\bgcolor},
background color/.default=none,
exec/.expand after=#1,
}
\newcommand{\node}[1][]{\pgfkeys{/node/.cd, background color=yellow, #1}\nodeh{red}}
\newcommand{\nodeh}[1]{\tikz\draw[fill=\bgcolor, draw=#1] (0,0) circle (10pt);}
\pgfkeys{
/caller/.cd,
opts/.store in=\nodeopts,
opts/.default=,
}
\newcommand{\caller}[1][]{\pgfkeys{/caller/.cd, opts, #1}%
%\nodeopts% uncomment to see the parameters
\node[\nodeopts]% error with macro expansion
%\node[exec=\nodeopts]% attempt to expand also results in '/node/exec' key not found
}
\begin{document}
\node
\node[background color=blue]
\caller
% this call gives an error:
% Package pgfkeys Error: I do not know the key '/node/background color=blue' and I am going to ignore it. Perhaps you misspelled it.
\caller[opts={background color=blue}]
\end{document}
\nodeopts
needs to be expanded once to be properly parsed by PGFKeys. Either do\expandafter\node\expandafter[\nodeopts]
or/tikz/style/.expand once={#1}
(or make your own key that expands#1
once or use any other tool for expansion)..default
doesn't set the initial value for\bgcolor
but the default parameter to the key if the key is used without a parameter (i.e. without the=
)./node/exec/.expand once=#1
but I got the same error that the key didn't exist. But in that case, I wanted to expand it inside of\node
(like\newcommand{\caller}[1][]{\pgfkeys{/caller/.cd, opts, #1}\node[exec=\nodeopts]}
). I want to avoid the\expandafter
dance since my final setup is more involved and it broke my head to get the proper expansion. How would you go with the.expand once
with my own key? Or should I have another layer to just expand it?\node[exec=\nodeopts]
exec
isn't in the search path once you do\node
. in general, I'd avoid naming paths with standardtikz
/pgf
names as it will make things horrible to debug. everything pgf/tikz does is contained, local. it goes to enormous trouble not to contaminate the global environment.\pgfkeys{...}
may change directory, but after that closing}
you are back to normal. so you can say, eg.exec/.expand once=\nodeopts
or whatever, but you have to think about the grouping and search paths, too.