Skip to content

Comma required at the end of \pgfkeys #1417

@ilyaza

Description

@ilyaza

Brief outline of the bug

Without comma at the end of \pgfkeys, the MWE produces:

  ! Extra }, or forgotten \endgroup.

(probably due to \unskip being redefined to become closing-brace). Checked with tl2022 (in unknown state) and tl2023 (in pristine state).

Background: I have a large (a few K-LoC) system of macros based on PGF/TiKZ in use for about a decade, and a few aspects of its operation are quite flaky. (In total, it is probably several man-days lost on trying to debug this.)

This bug seems to be the root cause of ALL the flakiness I observe.

Example of a similar trace

In this shortened form, the traces of the runs with/without the comma are very different. However, in the process of isolation there was one version where the diffs contained a small standalone fragment (paraphrased below by removing irrelevant part). Essentially, at end of the argument-to-\pgfkeys, \unskip is redefined to become close-brace:

@@ -500161,753 +500240,55 @@ edef \pgfkeyscurrentkey {\pgfkeyscurrent
 mpty \else \pgfkeys@add@path@as@needed \pgfkeys@spdef \pgfkeyscurrentvalue {#2}
 \ifx \pgfkeyscurrentvalue \pgfkeysnovalue@text \pgfkeysifdefined {\pgfkeyscurre
 ntkey /.@def}{\pgfkeysgetvalue {\pgfkeyscurrentkey /.@def}{\pgfkeyscurrentvalue
  }} {}\fi \ifx \pgfkeyscurrentvalue \pgfkeysvaluerequired \def \pgf@marshal {\p
 gfkeysvalueof {/errors/value required/.@cmd}}\expandafter \pgf@marshal \expanda
 fter {\pgfkeyscurrentkey }{}\pgfeov \else \pgfkeys@case@one \fi \fi 
 #1<-every scope/.try
 #2<-\pgfkeysnovalue 
 #3<-
 
 \pgfkeys@spdef #1#2->\futurelet \pgfkeys@possiblespace \pgfkeys@sp@a #2\pgfkeys
 @stop \pgfkeys@stop  \pgfkeys@stop \relax #1
 #1<-\pgfkeyscurrentkey 
 #2<-every scope/.try
 {\futurelet}
-{changing \unskip=\unskip}
-{into \unskip=end-group character }}
-{\hfil}
-{end-group character }}
-! Extra }, or forgotten \endgroup.
-<recently read> }
-                 
-<template> \unskip \hfil }
-                          \hskip \tabcolsep \endtemplate 
-\pgfkeys@spdef ...uturelet \pgfkeys@possiblespace 
-                                                  \pgfkeys@sp@a #2\pgfkeys@s...
-
-\pgfkeys@unpack ...s@spdef \pgfkeyscurrentkey {#1}
-                                                  \edef \pgfkeyscurrentkey {...
-
-\pgfkeys@@normal ...pgfkeysnovalue =\pgfkeys@stop 
-                                                  \pgfkeys@parse 
-\pgfkeys@@qset ...aultpath {#2/}\pgfkeys@parse #3,
-                                                  \pgfkeys@mainstop \def \pg...
-
-\scope ...y@groupfalse \tikzset {every scope/.try}
-                                                  \tikz@collect@scope@anims ...
-
-\tikz@picture ...{.5}\tikz@installcommands \scope 
-                                                  [every picture,#1]\iftikz@...
-
-\tikz@opt [#1]->\tikzpicture [#1]
-                                 \pgfutil@ifnextchar \bgroup {\tikz@ }{\tikz...
-
-\\Tcircled ...vevmode \tikz [baseline=(char.base)]
-                                                  {\node [circle,#1,inner se...
-
-\NUMcc ... #1>0 \circledAsDivisor {\NUMc {#2}{#3}}
-                                                  \else \NUMc {#2}{#3}\fi 
-\joinedRowsInTable ...}\NUMcc 00{14}&\NUMcc 11{13}
-                                                  &\NUMcc 00{12}&\NUMcc 01{1...
-l.145      \joinedRowsInTable
-                             
-? s
+{changing \pgfkeys@possiblespace=undefined}
+{into \pgfkeys@possiblespace=the letter e}
 
 \pgfkeys@sp@a ->\ifx \pgfkeys@possiblespace \pgfkeys@sptoken \expandafter \pgfk
 eys@sp@b \else \expandafter \pgfkeys@sp@b \expandafter  \fi 
 {\ifx: (level 2) entered on line 145}
 {false}
 {\else: \ifx (level 2) entered on line 145}
 {\expandafter}
 {\expandafter}
 {\fi: \ifx (level 2) entered on line 145}
 
 \pgfkeys@sp@b  #1 \pgfkeys@stop ->\pgfkeys@sp@c #1
 #1<-every scope/.try\pgfkeys@stop \pgfkeys@stop 
 
 \pgfkeys@sp@c #1\pgfkeys@stop #2\relax #3->\pgfkeys@temptoks {#1}\edef #3{\the 
 \pgfkeys@temptoks }

Minimal working example (MWE)

\documentclass{article}
\usepackage{tikz}

\begin{document}
{%    \tracingall  \tracingstacklevels=0
     \pgfkeys{/joinerDefault/.initial=&}%   With comma at end, works.  Otherwise \unskip is redefined to close-brace, breaking:
     \begin{tabular}{c}
         \leavevmode\tikz \node {12};
     \end{tabular}
}
\end{document}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions