How to know the status of a style? defined? empty?
It appears not -- .style
is a handler that sets .code
, which in turn is a handler that sets the internal .@cmd
attribute. Using Ryan Reich's incredibly cool trace-pgfkeys
package (from this question), the following code
\documentclass{article}
\usepackage{pgfkeys}
\usepackage[tracemacros]{trace-pgfkeys}
\pgfkeystracelevel{verbose}
\begin{document}
\makeatletter
\typeout{Setting /test1/.style}
\pgfkeys{/test1/.style={shape=rectangle}}
\typeout{Checking ifdefine /test1/.style}
\pgfkeysifdefined{/test1/.style}{True}{False}
\typeout{Checking ifdefine /test1/.code}
\pgfkeysifdefined{/test1/.code}{True}{False}
\typeout{Checking ifdefine /test1/.@cmd}
\pgfkeysifdefined{/test1/.@cmd}{True}{False}
\typeout{Checking ifdefine /test-missing/.style}
\pgfkeysifdefined{/test-missing/.style}{True}{False}
\typeout{Checking ifdefine /test-missing/.code}
\pgfkeysifdefined{/test-missing/.code}{True}{False}
\typeout{Checking ifdefine /test-missing/.@cmd}
\pgfkeysifdefined{/test-missing/.@cmd}{True}{False}
\typeout{Setting /test2/.style to nothing}
\pgfkeys{/test2/.style=}
\pgfkeysgetvalue{/test2/.@cmd}{\test}
\ifx\test\relax Empty \else Not empty \fi
\end{document}
produces the following document:
False False True
False False False
Not empty
and a lot of useful debugging output, the following trace for setting /test1/.style
:
Setting /test1/.style
[trace-pgfkeys]-: Tracing \pgfkeys call.
[trace-pgfkeys]-+ Key/value list: (/test1/.style={shape=rectangle})
[trace-pgfkeys]-+ Current key-value: (/test1/.style={shape=rectangle})
[trace-pgfkeys]-+ \pgfkeyscurrentkey (given): /test1/.style
[trace-pgfkeys]-: Full key; no path added.
[trace-pgfkeys]-> \pgfkeyscurrentkey : /test1/.style
[trace-pgfkeys]-+ \pgfkeyscurrentvalue : (shape=rectangle)
[trace-pgfkeys]-: Case one: key code?
[trace-pgfkeys]-: Case two: key value?
[trace-pgfkeys]-: Case three: key unknown. Splitting the path.
[trace-pgfkeys]-+ \pgfkeyscurrentpath (/test1)
[trace-pgfkeys]-+ \pgfkeyscurrentname (.style)
[trace-pgfkeys]-: Checking whether a handler is defined.
[trace-pgfkeys]-+ Executing all handlers.
[trace-pgfkeys]-: Tracing \pgfkeysgetvalue .
[trace-pgfkeys]-: Value: (\long macro:#1\pgfeov ->\pgfkeys {\pgfkeyscurrentpath /.code=\pgfkeysalso {#1}})
[trace-pgfkeys]--+ Storing key value in \pgfkeys@code
[trace-pgfkeys]--> Storing: /handlers/.style/.@cmd
[trace-pgfkeys]--+ Done storing.
[trace-pgfkeys]-: Handler code:
[trace-pgfkeys]-: \long macro:#1\pgfeov ->\pgfkeys {\pgfkeyscurrentpath /.code=\pgfkeysalso {#1}}
[trace-pgfkeys]--+ Executing handler.
[trace-pgfkeys]--> Handler: /handlers/.style
[trace-pgfkeys]---: Tracing \pgfkeys call.
[trace-pgfkeys]---+ Key/value list: (\pgfkeyscurrentpath /.code=\pgfkeysalso {shape=rectangle})
[trace-pgfkeys]---+ Current key-value: (\pgfkeyscurrentpath /.code=\pgfkeysalso {shape=rectangle})
[trace-pgfkeys]---+ \pgfkeyscurrentkey (given): /test1/.code
[trace-pgfkeys]---: Full key; no path added.
[trace-pgfkeys]---> \pgfkeyscurrentkey : /test1/.code
[trace-pgfkeys]---+ \pgfkeyscurrentvalue : (\pgfkeysalso {shape=rectangle})
[trace-pgfkeys]---: Case one: key code?
[trace-pgfkeys]---: Case two: key value?
[trace-pgfkeys]---: Case three: key unknown. Splitting the path.
[trace-pgfkeys]---+ \pgfkeyscurrentpath (/test1)
[trace-pgfkeys]---+ \pgfkeyscurrentname (.code)
[trace-pgfkeys]---: Checking whether a handler is defined.
[trace-pgfkeys]---+ Executing all handlers.
[trace-pgfkeys]---: Tracing \pgfkeysgetvalue .
[trace-pgfkeys]---: Value: (\long macro:#1\pgfeov ->\pgfkeysdef {\pgfkeyscurrentpath }{#1})
[trace-pgfkeys]----+ Storing key value in \pgfkeys@code
[trace-pgfkeys]----> Storing: /handlers/.code/.@cmd
[trace-pgfkeys]----+ Done storing.
[trace-pgfkeys]---: Handler code:
[trace-pgfkeys]---: \long macro:#1\pgfeov ->\pgfkeysdef {\pgfkeyscurrentpath }{#1}
[trace-pgfkeys]----+ Executing handler.
[trace-pgfkeys]----> Handler: /handlers/.code
[trace-pgfkeys]----: Tracing \pgfkeysdef .
[trace-pgfkeys]----: Code: (\pgfkeysalso {shape=rectangle})
[trace-pgfkeys]-----+ Defining key code.
[trace-pgfkeys]-----> New code: /test1
[trace-pgfkeys]-----: Tracing \pgfkeyslet .
[trace-pgfkeys]------+ Assigning key from \pgfkeys@temp
[trace-pgfkeys]------> Assigning: /test1/.@cmd
[trace-pgfkeys]------+ Done assigning.
[trace-pgfkeys]-----+ Done defining.
[trace-pgfkeys]----+ Done defining.
[trace-pgfkeys]---+ Execution finished.
[trace-pgfkeys]--+ Last key processed.
[trace-pgfkeys]-+ Execution finished.
[trace-pgfkeys]+ Last key processed.
Note that /.style
has a /.@cmd
that in turn sets /.code
, which itself has a /.@cmd
that finally sets the /test1/.@cmd
attribute directly. Hope that helps!
Here is my take on this answer. Basically, setting a .style
has the effect of setting .@cmd
to exactly the code \pgfkeysalso{<keys>}
. I take this to be the definition of "is a style", since there is no way to check that this kind of code wasn't produced by setting .code
directly, but then, if it quacks like a duck...
I provide three user commands:
\pgfkeysifstyle{<full key>}{<true>}{<false>}
, which acts based on whether the key is a style in the sense above.\lastpgfkeysstyle
, which stores the contents of the style if the key is a style. If it's not, don't use this.\pgfkeysifstyleempty
(same args), which acts based on whether that style is empty. If it's not a style, I go with "true" since otherwise you might want to use\lastpgfkeysstyle
.
The code:
\documentclass{article}
\usepackage{filecontents}
\begin{filecontents*}{pgfkeys-ifstyle.sty}
\RequirePackage{etoolbox}% for \ifstrequal, \ifdefempty
\def\lastpgfkeysstyle{}
% Checks if #1 = \pgfkeysalso{...} and, if so, puts the argument
% in \lastpgfkeysstyle
\def\@ifgetpgfkeysalso#1\pgfkeysalso#2#3\@nil{%
\ifstrequal{#1.#3}{.\pgfkeysalso{}}% \pgfkeysalso{#2} is the only thing there
{\def\lastpgfkeysstyle{#2}\@firstoftwo}
{\@secondoftwo}%
}
% So I don't need to write this again
\def\expandaftertwice{\expandafter\expandafter\expandafter}
\def\pgfkeysifstyle#1{%
% "Expand" the key's .@cmd until its code shows
% Even if there is no .@cmd, we get #1\pgfeov, which will not screw us up.
\toks0=\expandaftertwice{\csname pgfk@#1/.@cmd\endcsname##1\pgfeov}%
\expandafter\@ifgetpgfkeysalso\the\toks0 \pgfkeysalso{}\@nil% That space is very important!
}
\def\pgfkeysifstyleempty#1{%
\pgfkeysifstyle{#1}
{\ifdefempty{\lastpgfkeysstyle}}
{% We count a non-style as empty, since otherwise you might use \lastpgfkeysstyle
\PackageWarning{pgfkeys-ifstyle}
{In \noexpand\pgfkeysifstyleempty\MessageBreak
The key #1 is not defined as a style!\MessageBreak}
\@firstoftwo
}%
}
\end{filecontents*}
\usepackage{pgfkeys-ifstyle}
\usepackage{pgfkeys,pgffor}
\begin{document}
\pgfkeys{
/key 1/.style = {x, y, z},
/key 2/.code = {Not a style #1},
/key 3/.initial = {Not even a code},
/key 4/.style = {},% Empty style
/key 5/.code = {\pgfkeysalso{a, b, c} and other stuff},
/key 6/.code = {\pgfkeysalso{a, b, c}},
}
\newcommand*\teststyle[1]{%
\par\medskip\noindent
\pgfkeysifstyle{#1}{#1 has a style: \lastpgfkeysstyle}{#1 is not a style}\\
\pgfkeysifstyleempty{#1}{#1 has an empty style}{#1 does not have an empty style}
}
\foreach \n in {1,...,6} {\teststyle{/key \n}}
\end{document}
\documentclass{standalone}
\usepackage{tikz}
\makeatletter
\def\pgfkeysifstyledefined#1#2#3{%
\pgfkeys@ifcsname pgfk@#1/.@cmd\endcsname#2\else#3\fi}
\def\pgfkeysifstyleempty#1{%
\expandafter\expandafter\expandafter\pgfkeysifstyleempty@i
\csname pgfk@#1/.@cmd\endcsname\pgfeov}
\def\pgfkeysifstyleempty@i\pgfkeysalso#1#2#3{%
\if\relax\detokenize{#1}\relax
#2%
\else
#3%
\fi}
\makeatother
\begin{document}
\pgfkeysifstyledefined{/tikz/my style}{Defined}{Undefined}
\tikzset{my style/.style = {}}
\pgfkeysifstyledefined{/tikz/my style}{Defined}{Undefined}
\pgfkeysifstyleempty{/tikz/my style}{Empty}{Non empty}
\tikzset{my style/.style = {Test}}
\pgfkeysifstyleempty{/tikz/my style}{Empty}{Non empty}
\end{document}