4

I would like to enrich pgfkeys by the functionality of mandatory and recommended keys. If a mandatory key is not given, an error is shown. If a recommended key is not given, a warning is shown.

My idea is to have two handlers which can be used after the options have been processed:

\newcommand{\mycommand}[1][]{%
    \pgfqkeys{/path}{#1,
        key a/recommended,
        key b/mandatory,
    }%
    % ...
}

This is as far as I am:

\documentclass{article}
\usepackage{pgfkeys}
\newcommand{\PackageName}{pgfkeys extended}

\makeatletter
\pgfqkeys{/handlers}{%
    % ------- if given -------
    if given/.code 2 args={%
        \typeout{! path: \pgfkeyscurrentpath}%
        \pgfkeys{\pgfkeyscurrentpath/.get=\tmp@value}%
        \expandafter \ifx \expandafter \pgfkeysnovalue \tmp@value
            #2%
        \else
            #1%
        \fi
    },
    % ------- recommended -------
    recommended/.style={%
        if given=
            \relax
            \PackageWarning{\PackageName}{Recommended key `\pgfkeyscurrentkeyRAW' not given.}%
    },
}
\makeatother

\pgfqkeys{/test}{%
    hello/.initial,
    hello/.value required,
}


\begin{document}
content\ldots

%\pgfqkeys{/test}{hello=true}
%\pgfkeysvalueof{/test/hello}
\pgfkeys{/test/hello/if given=10}
\pgfkeys{/test/hello/recommended}

\end{document}

The if given handler works fine on it's own. But when it is called by the recommended handler \pgfkeyscurrentpath is empty.

I could change the recommended handler to a custom code instead of a style, save the \pgfkeyscurrentpath in a command before calling if given and then inside of if given check whether this command has been defined. If it is I use it, if it's not I use \pgfkeyscurrentpath. And in the end I mustn't forget to reset that command. But that seems overly complicated. Isn't there an easier solution?

And if I can't use my own handler here in a style, do I need to be careful that some of TikZ's keys can not be used in a style either?

3

First, it's a tikz standard to make all handler names start with a period. If you don't do this, you might get confused between normal keys and handlers, though of course you are free to do whatever you want.

If you call a handler like /path/to/key/.handler then the value stored in \pgfkeyscurrentpath is /path/to/key. If you just say .handler=something then the path you've given is empty and \pgfkeyscurrentpath will be set empty. One solution to this is to say \pgfkeyscurrentpath/.handler, so you can say:

\makeatletter
\pgfqkeys{/handlers}{%
    .if given/.code 2 args={%
        \typeout{! path: \pgfkeyscurrentpath}%
        \pgfkeys{\pgfkeyscurrentpath/.get=\tmp@value}%
        \expandafter \ifx \expandafter \pgfkeysnovalue \tmp@value
            #2%
        \else
            #1%
        \fi
    },
    .recommended/.style={%
        \pgfkeyscurrentpath/.if given= %%%% This is the only line that changed
            \relax
            \PackageWarning{\PackageName}{Recommended key `\pgfkeyscurrentkeyRAW' not given.}%
    },
}
\makeatother

If I were you though, I would probably define a command \ifkeyisgiven or something and then call that in .recommended. I think this is clearer:

\makeatletter
\def\ifkeyisgiven#1#2{
    \typeout{! path: \pgfkeyscurrentpath}%
    \pgfkeys{\pgfkeyscurrentpath/.get=\tmp@value}%
    \expandafter \ifx \expandafter \pgfkeysnovalue \tmp@value
        #2%
    \else
        #1%
    \fi
}

\pgfqkeys{/handlers}{%
    recommended/.code={%
       \ifkeyisgiven{}{
            \Packagewarning{\PackageName}{Recommended key `\pgfkeyscurrentkeyRAW' not given.}%
        }
    },
}
\makeatother
  • thanks a lot, also for pointing out the naming convention. Somehow I thought to remember the leading dot was reserved for the default handlers defined by pgfkeys, but I was wrong: "It is recommended (but not necessary) that the name of a handler starts with a dot (but not with .@), so that they are easy to detect for the reader." (pgf manual for version 3.0.0, section 82.3.5 Keys That Are Handled, page 890). – jakun Oct 20 '17 at 5:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.