2

I just learn \pgfkeys, but don't quite understand how to use it for making a macro with key=value options.

I'd like to give the following simple example as a practice to show my idea.

\documentclass{article}
\usepackage{tikz}

\newcommand{\mycolorbox}[1][]{ \pgfkeys{ color/.initial=red, text/.initial=some text, #1, exe/.code=\colorbox{color}{text} } } \begin{document} \mycolorbox[color=blue, text=This is a practice.] \end{document}

This does not work. Anyone can help me with this?

lyl
  • 2,727

3 Answers3

4

You want to define your own namespace for keys and separate key definition from usage.

\documentclass{article}
\usepackage{tikz}

\pgfkeys{/lyl/mycolorbox/.cd, % define your own space color/.store in=\mycolorboxcolor, text/.store in=\mycolorboxtext, color=red!40, text=some text, }

\newcommand{\mycolorbox}[1][]{% \begingroup \pgfkeys{/lyl/mycolorbox/.cd,#1}% \colorbox{\mycolorboxcolor}{\mycolorboxtext}% \endgroup }

\begin{document}

\mycolorbox[color=blue!20]

\mycolorbox[text=This is a practice.]

\mycolorbox[color=blue!20, text=This is a practice.]

\end{document}

The expl3 version:

\documentclass{article}
\usepackage{xcolor}

\ExplSyntaxOn

\keys_define:nn { lyl/mycolorbox } { color .tl_set:N = \l__lyl_mycolorbox_color_tl, text .tl_set:N = \l__lyl_mycolorbox_text_tl, color .initial:n = red!40, text .initial:n = some~text, }

\NewDocumentCommand{\mycolorbox}{O{}} { \group_begin: \keys_set:nn { lyl/mycolorbox } { #1 } \colorbox{\l__lyl_mycolorbox_color_tl}{\l__lyl_mycolorbox_text_tl} \group_end: }

\ExplSyntaxOff

\begin{document}

\mycolorbox[color=blue!20]

\mycolorbox[text=This is a practice.]

\mycolorbox[color=blue!20, text=This is a practice.]

\end{document}

enter image description here

egreg
  • 1,121,712
  • Does that mean if I have 20 keys, then I have to use 20 macros to store them? in an article, maybe many commands needs key=value. So many marco names are too heavy to namespace? Do I understand it right? – lyl Jun 08 '21 at 12:57
  • @lyl There is plenty of memory space for macros, don't worry. – egreg Jun 08 '21 at 13:07
  • I tried this: \def\mycolorboxtext{aaa}\mycolorbox[color=blue!20], and aaa was typeset. Does that mean the namespace is polluted? It seems that \begingroup...\endgroup does not work? – lyl Jun 08 '21 at 13:07
  • @lyl I added an expl3 version that I'd prefer. Anyway, don't do \def\mycolorboxtext. – egreg Jun 08 '21 at 13:12
  • If you have lots of keys, I'd go for a programmatic set up of all of them – Joseph Wright Jun 08 '21 at 13:12
  • @ Joseph Wright Would you provide more details about your idea? – lyl Jun 08 '21 at 13:19
  • @egrg Many thanks for your solutions and suggestion!! And are there better ways to prevent those key macros from polluting namespace? – lyl Jun 08 '21 at 13:21
3

Another way to store values is inside the key paths themselves (that doesn't mean you don't use as many commands, so this doesn't ease the namespace-heaviness).

\documentclass[]{article}

\usepackage{xcolor} \usepackage{pgfkeys}

\pgfkeys {% /mycolorbox/.is family ,/mycolorbox ,color/.initial=blue ,text/.initial=some text } \newcommand\mycolorbox[1][] {% \begingroup \pgfqkeys{/mycolorbox}{#1}% \colorbox {\pgfkeysvalueof{/mycolorbox/color}} {\pgfkeysvalueof{/mycolorbox/text}}% \endgroup }

\begin{document} \mycolorbox

\mycolorbox[color=red]

\mycolorbox[text=foobar] \end{document}

(note: \pgfqkeys{/<path>}{<keys>} is the same as \pgfkeys{/<path>/.cd,<keys>} but faster)

enter image description here

Skillmon
  • 60,462
  • Thank you for this solution. And how does \begingroup...\endgroup here work? – lyl Jun 08 '21 at 13:17
  • \begingroup...\endgroup just keeps the changes to the options local to this one command, so that the next invocation isn't dependent on the previous one. The two commands (\begingroup and \endgroup) are TeX primitives. – Skillmon Jun 08 '21 at 13:23
  • Oh,I see. It's the cost of non-macro to store value of keys. Many thanks! – lyl Jun 08 '21 at 13:44
  • @lyl no, you'd do the same if you used macros to store the values. All that \pgfkeys{/foo/bar/.initial={<value>}} does is store the value inside a macro with a long name that is \pgfk@/foo/bar (slashes are part of the macro name). – Skillmon Jun 08 '21 at 17:09
2

If you're just setting up a simple macro with a few keys (and that's the only interface accessing and using those keys), you could as well build your macro with expkv-cs:

\documentclass[]{article}

\usepackage{xcolor} \usepackage{expkv-cs}

\ekvcSplit\mycolorbox { color=blue ,text=some text } {\colorbox{#1}{#2}}%

\begin{document} \mycolorbox{}

\mycolorbox{color=red}

\mycolorbox{text=foobar} \end{document}

(expkv-cs defines the macro \mycolorbox with a mandatory argument, if you want to use an optional one, just add a wrapper like: \newcommand\mycolorbox[1][]{\mycolorboxSplit{#1}} and changing the name of the macro after \ekvcSplit to \mycolorboxSplit).

enter image description here

Skillmon
  • 60,462