samcarter
Background: I'm trying to make the `piece` pic from the `jigsaw` package compatible with the `pic text` and `pic text options`.
Adding the text itself works fine, I'm just running into a problem when trying to pass options to the text.
Below is the approach I tried. It works fine for options like `draw`, but for other options, like `text=blue`, I get the following error about the option being
```
! Package pgfkeys Error: I do not know the key '/tikz/text=blue' and I am going
to ignore it. Perhaps you misspelled it.
```
I assume the `=` is causing the problem? Is there a workaround?
```
\documentclass{article}
\usepackage{tikz}
\tikzset{
pics/test/.style n args={4}{
code = {
\path[pic actions] (0,0) rectangle (1,1);
\node[
% /tikz/text=blue % works
\tikzpictextoptions
] at (0.5,0.5) {\tikzpictext};
}
}
}
\begin{document}
\begin{tikzpicture}
\path pic[
pic text = {text},
%pic text options={draw}, % works
pic text options={text=blue}
]{test={1}{-1}{0}{0}};
\end{tikzpicture}
\end{document}
```
Top Answer
Skillmon
Your problem is the way Ti*k*Z parses the options and builds the error messages afterwards, which can lead to quite confusing results.
In your example `pgfkeys` will see the following key list: `\tikzpictextoptions`. It'll split that on the comma (none there), so the first and only element will be `\tikzpictextoptions`. Then it'll try to split at the equals sign (none there), so the key name/path will be `\tikzpictextoptions`. It'll check whether such a key is defined using `\ifcsname` in which the `\tikzpictextoptions` will get expanded, now `pgfkeys` will check whether a key with the name `text=blue` in the current default path exists (it doesn't). Next it'll throw an error, and inside that error the parsed key name will again be fully expanded, leading to the message about an undefined key named `text=blue` in the current default path `/tikz/`.
**I therefore postulate the following rule of thumb:**
If a message of `pgfkeys` about an unknown key contains an equals sign, the problem is expansion, and you should've expanded your key-list earlier.
The following works:
```
\documentclass{article}
\usepackage{tikz}
\tikzset{
pics/test/.style n args={4}{
code = {
\path[pic actions] (0,0) rectangle (1,1);
\expandafter\node\expandafter[\expandafter{\tikzpictextoptions}]
at (0.5,0.5) {\tikzpictext};
}
}
}
\begin{document}
\begin{tikzpicture}
\path pic[
pic text = {text},
%pic text options={draw}, % works
pic text options={text=blue}
]{test={1}{-1}{0}{0}};
\end{tikzpicture}
\end{document}
```
Answer #2
Qrr
The other answers already tell you why it doesn't work (the whole content of `\tikzpictextoptions` will be tested to be the key name because the parser is dumb), they all fallback to low-level expansion control (which isn't wrong but can be annoying in more complex cases).
However, PGFKeys and TikZ already come with tools to handle this.
They are
* the `.expand once` handler and
* the `style` style.
The latter is very simple, it's defined as
```
\tikzset{style/.style={#1}}
```
meaning it just applies the styles that are given to it, which is pretty pointless *unless* you have to do something with `#1`.
In this case you want to expand `#1`, i.e. `\pictextoptions`, before the actual PGFKeys parser sees it.
## Code
```
\documentclass{article}
\usepackage{tikz}
\tikzset{
pics/test/.style n args={4}{
code = {
\path[pic actions] (0,0) rectangle (1,1);
\node[style/.expand once=\tikzpictextoptions] at (0.5,0.5) {\tikzpictext};
}
}
}
\begin{document}
\begin{tikzpicture}
\path pic[
pic text = {text},
pic text options={text=blue}
]{test={1}{-1}{0}{0}};
\end{tikzpicture}
\end{document}
```
Answer #3
frougon
I haven't investigated what precisely happens, but it works if you manually expand `\tikzpictextoptions` so that `\node` sees `text=blue` as opposed to `\tikzpictextoptions` inside its optional argument:
```
\documentclass{article}
\usepackage{tikz}
\tikzset{
pics/test/.style n args={4}{
code = {
\path[pic actions] (0,0) rectangle (1,1);
\expanded{%
\noexpand\node[{%
\unexpanded\expandafter{\tikzpictextoptions}}]}
at (0.5,0.5) {\tikzpictext};
}
}
}
\begin{document}
\begin{tikzpicture}
\path pic[
pic text={text},
pic text options={text=blue},
]{test={1}{-1}{0}{0}};
\end{tikzpicture}
\end{document}
```
![image.png](/image?hash=9a83f01801d16a87658493856f0ba24b1eda8ca6e4082d2e53cea38d564f3b5b)
This is an improved version of my original answer thanks to [Skillmon's comment](https://topanswers.xyz/transcript?room=3386&id=153281#c153281) and more careful reading of his code:
- because current engines have the `\expanded` primitive, the revised code can use
```
\expanded{%
\noexpand\node[{%
\unexpanded\expandafter{\tikzpictextoptions}}]}
at (0.5,0.5) {\tikzpictext};
```
instead of this older technique:
```
\begingroup
\edef\tmp{\endgroup
\noexpand\node[{%
\unexpanded\expandafter{\tikzpictextoptions}}]}%
\tmp
```
- the outer curly braces in the resulting `\node[{...}]` make the construct safe in case `\tikzpictextoptions` contains square brackets (they will be automatically stripped by TeX when it grabs the optional argument of `\node`).
Note: this is essentially the same as what Skillmon [did](https://topanswers.xyz/tex?q=3340#a3413). I had initially not seen his answer because my network connection was down for a few hours and the page didn't automatically refresh when the connection went back up.