Skip to content

Handler config 'full or existing' can set non-existent keys when '.search also' is in effect. #1143

@fritzw

Description

@fritzw

Brief outline of the bug

With /handler config=full or existing, an assignment like key/.style={stuff} should only set the style if key exists in the current path or somewhere in the search paths set with .search also. However, when one or more paths are passed to .search also, and key does not exist in the current path, key/.style={stuff} will always be executed it in the first search path, regardless of whether it exists there or not. It will never fail, like it should when the key on which the handler is called does not exist.

In the example below, the first case (with color=green) appears to work. The style every foo is set in /main path, because the style did not exist in /second path. However, in the second example you can see it fail: every foo is set in /third path although it did not exist there before, despite the handler config.

Cause of the bug

If you look at the log file, you can see the cause of the issue (thanks to the patched commands):

  1. .search also executes \pgfqkeys{/third path}{every foo/.style/.try/.expand once=value} (defined in \pgfkeys@searchalso@appendentry).
  2. \pgfkeys@add@path@as@needed prepends /third path and sets \ifpgfkeysaddeddefaultpath=\iftrue (in \pgfkeys@addpath).
  3. \pgfkeys@ifexecutehandler@handlefullorexisting executes .expand once because it exempt from /handler config.
  4. .expand once executes \pgfkeysalso{/third path/every foo/.style/.try=value}.
  5. \pgfkeysalso calls \pgfkeys@add@path@as@needed, which sees an absolute path and sets \ifpgfkeysaddeddefaultpath=\iffalse (in \pgfkeys@nevermind).
  6. .try calls \pgfkeys@ifexecutehandler@handlefullorexisting with \pgfkeyscurrentpath=/third path/every foo/.style, which succeeds because \ifpgfkeysaddeddefaultpath is false.

Log file excerpt:

[...]
pgfkeys@addpath: every foo/.style
pgfkeys@addpath: every foo/.style/.try/.expand once
pgfkeysalso: /third path/every foo/.style/.try={color=blue}
pgfkeys@nevermind: /third path/every foo/.style/.try
/third path/every foo/.style={color=blue}
pgfkeys@nevermind: /third path/every foo/.code
[...]

Minimal working example (MWE)

\documentclass{article}
\usepackage{pgfkeys}

\pgfkeys{
    /main path/foo/.code={\{\pgfkeysalso{/main path/every foo} foo\}},
    /main path/every foo/.style={color=red}, % It even works if this is commented out
    /main path/color/.code=color\{#1\},
    /handler config=full or existing,
}

\usepackage{etoolbox}
\makeatletter
\pretocmd\pgfkeys@nevermind{
    \immediate\write16{pgfkeys@nevermind: \detokenize{#1}}
}{}{}
\pretocmd\pgfkeys@addpath{
    \immediate\write16{pgfkeys@addpath: \detokenize{#1}}
}{}{}
\pretocmd\pgfkeysalso{
    \immediate\write16{pgfkeysalso: \expandafter\expandafter\expandafter\detokenize\expandafter\expandafter\expandafter{#1}}
}{}{}
\pgfkeys{/handlers/.style/.code=\immediate\write16{\pgfkeyscurrentpath/.style={#1}}\pgfkeys{\pgfkeyscurrentpath/.code=\pgfkeysalso{#1}}}
\makeatother

\begin{document}
\pgfkeys{
    /second path/.cd,
    /second path/.search also={/main path},
    every foo/.style={color=green}, % no 'every foo' in /second path
    foo
}
This worked, foo is green, not red

\pgfkeys{
    /second path/.cd,
    /second path/.search also={/third path, /main path},
    every foo/.style={color=blue},
    foo
}
This failed, foo is still green, not blue
\end{document}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions