1

I find that the value of a key defined by \pgfkeys inside an environment can not be invoked outside this environment.

In the following example, I want to typeset the value of the key aaa outside the environment minipage and fail.

How to make this kind of keys be "seen" outside environment?

Example:

\documentclass{article}
\usepackage{tikz}
\begin{document}

\begin{minipage}{1.0\linewidth}
  \pgfkeys{aaa/.initial=aaa,bbb/.initial=bbb}
  Inside minipage, the value of the key "aaa" is \pgfkeysvalueof{/aaa}
\end{minipage}
Outside minipage, the value of the key "aaa" is |\pgfkeysvalueof{/aaa}|

\end{document}
6
  • 2
    This is due to scoping. You will get the same effect with using \def inside the minipage. Aug 12, 2022 at 8:28
  • Is this correct for all environment? I mean scoping.
    – lyl
    Aug 12, 2022 at 8:31
  • In general, yes, since virually all environments use scoping. But scoping is a very basic thing: You will aready get an error if you try {\def\hello{hello}} \hello. In your case, you would need to assign the key gloablly (or outside of the scope). See: tex.stackexchange.com/q/15204/47927 Aug 12, 2022 at 8:37
  • 2
    @lyl Yes, all() LaTeX environments form a group. ( document avoids a group for technical reasons, but as the LaTeX run ends with \end{document} is this not really an issue.)
    – Joseph Wright
    Aug 12, 2022 at 8:53
  • Currently pgfkeys has no provisions to set keys globally. It is recommended to instead move the keys definition to the global scope (usually the document preamble). Aug 12, 2022 at 10:12

2 Answers 2

3

Since the other answer and comments explain why your code behaves the way it does, here's a .ginitial handler that is global.

That means that both the initialization aaa/.ginitial = aaa as well as just assigning a new value via aaa = AAA will be global.

However, the handlers .add, .prefix, .append, .get and .link will not change the value globally.
(We'll need .gadd, .gprefix, … for that.)

In the code below, the key /bbb remains local.

Code

\documentclass{article}
\usepackage{tikz}

\makeatletter
\long\def\pgfkeysgdef#1#2{%
  \long\def\pgfkeys@temp##1\pgfeov{#2}%
  \pgfkeysglet{#1/.@cmd}{\pgfkeys@temp}%
  \pgfkeyssetgvalue{#1/.@body}{#2}%
}
\long\def\pgfkeysglet#1#2{%
  \expandafter\global\expandafter\let\csname pgfk@#1\endcsname#2%
}
\long\def\pgfkeyssetgvalue#1#2{%
  \pgfkeys@temptoks{#2}\expandafter\xdef\csname pgfk@#1\endcsname{\the\pgfkeys@temptoks}%
}
\pgfkeys{
  /handlers/.ginitial/.code=%
    \edef\pgfkeys@temp{% \pgfkeysgdef is basically /.gcode
      \noexpand\pgfkeysgdef{\pgfkeyscurrentpath}%
        {\noexpand\pgfkeyssetgvalue{\pgfkeyscurrentpath}{####1}}}%
    \pgfkeys@temp
    \pgfkeyssetgvalue{\pgfkeyscurrentpath}{#1}%
}
\makeatother
\begin{document}

\noindent
\begin{minipage}{1.0\linewidth}
\pgfkeys{aaa/.ginitial = aaa, bbb/.initial = bbb, aaa = AAA}
Inside minipage, the values of the keys --/aaa--/bbb-- are --\pgfkeysvalueof{/aaa}--\pgfkeysvalueof{/bbb}--
\end{minipage}
Outside minipage, the values of the key --/aaa--/bbb-- are --\pgfkeysvalueof{/aaa}--\pgfkeysvalueof{/bbb}--
\end{document}

Output

enter image description here

1
  • That said, the point and power of PGFkeys is to only have keys/styles be local. Maybe there's a better solution if we'd know the real world application. Aug 12, 2022 at 15:37
1

Due to scoping, the keys you set inside the minipage are only defined inside this environment. Therefore, you would need to define the key outside of the environment or define it gobally somehow.

You could apply the approach in this answer and create a global version of the \pgfkeys macro. However, this approach is probably risky because everything \pgfkeys does internally will be global. This may lead to unintended results in certain cases and break other code (thanks to Skillmon and David Carlisle for pointing to this).

For very simple assignments, you could maybe also use \global\pgfkeyslet, but using this approach, things like .initial would not be applicable. Also, the same warning as above applies here. So, do not use this if you plan to have others use your code!

I'd recommend, therefore, to restructure the logic of your document and define the keys outside of the environment.

\documentclass{article}
\usepackage{tikz}

%%% not recoomended!
\newcommand\gpgfkeys[1]{%
\begingroup%
 \globaldefs=1\relax%
 \pgfkeys{#1}%
\endgroup%
}
%%%

\begin{document}

\pgfkeys{aaa/.initial=aaa}

\noindent
\begin{minipage}{1.0\linewidth}
  
  \def\mybbbkey{bbb}                   %%%
  \global\pgfkeyslet{/bbb}{\mybbbkey}  %%% 
                                       %%%
  \gpgfkeys{ccc/.initial=ccc}          %%% not recommended!
  
  Inside minipage, the value of the key "aaa" is \pgfkeysvalueof{/aaa} \\
  Inside minipage, the value of the key "aaa" is \pgfkeysvalueof{/bbb} \\
  Inside minipage, the value of the key "ccc" is \pgfkeysvalueof{/ccc}
\end{minipage}

\bigskip

\noindent
Outside minipage, the value of the key "aaa" is ---\pgfkeysvalueof{/aaa}--- \\
Outside minipage, the value of the key "bbb" is ---\pgfkeysvalueof{/bbb}--- \\
Outside minipage, the value of the key "ccc" is ---\pgfkeysvalueof{/ccc}---

\end{document}

enter image description here

8
  • 2
    I'd not recommend switching on \globaldefs on code you haven't completely written yourself and have not absolute control over!
    – Skillmon
    Aug 12, 2022 at 9:02
  • @Skillmon Wouldn't your concerns then also apply to the linked answer? Aug 12, 2022 at 9:16
  • 2
    pgfkeys makes hundreds of internal definitions parsing the structure and this makes all of them global, it might work in some cases but only accidentally, and it may break arbitrary other code with global settings to interal registers. Aug 12, 2022 at 9:23
  • 1
    Yes comments apply to that answer too Aug 12, 2022 at 9:25
  • 1
    I'd have made the warning stronger, "do not use this in production" for example. \global\pgfkeyslet is like \global\newcommand if it ever does what you expect either your are very lucky or you know every line of code executed and your expectations are acurate Aug 12, 2022 at 10:06

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .