pgf-tikz / pgf

A Portable Graphic Format for TeX
https://pgf-tikz.github.io/
1.15k stars 109 forks source link

PGFKeys' First Char Syntax with non-csname-able content raises error message in graphs library. #1355

Open Qrrbrbirlbel opened 2 months ago

Qrrbrbirlbel commented 2 months ago

As Q406795 shows non-csname-able content in a label with the quotes/" syntax will raise an error message (but produces correct output) because \tikz@lg@local@node@handle uses the node's options in \tikzgraphsset without the first char setup so that \pgfkeysifdefined tries the whole "…" … as a key name.

https://github.com/pgf-tikz/pgf/blob/d43fb104dadc1db7e2bcae6f02e0607078a98be1/tex/generic/pgf/frontendlayer/tikz/libraries/graphs/tikzlibrarygraphs.code.tex#L1207-L1214

Here, this can be easily solved by setting " to be gobbled:

\def\tikz@lg@local@node@handle#1{% 
   % 
   % Handle late options and operators 
   \pgfkeyssetvalue{/handlers/first char syntax/\expandafter\meaning\string"}{\pgfutil@gobble}% ← !
   \tikzgraphsset{source,target,.unknown/.code=,#1}% 
   \tikzgdlatenodeoptionacallback{\tikz@pp@name\tikz@lib@graph@name}% 
   \node also[graphs/redirect unknown to tikz,/tikz/graphs/.cd,#1](\tikz@lib@graph@name);% 
   \pgfkeysvalueof{/tikz/graphs/@operators}% 
}

The \tikz@lg@local@node@handle macro is only used once https://github.com/pgf-tikz/pgf/blob/d43fb104dadc1db7e2bcae6f02e0607078a98be1/tex/generic/pgf/frontendlayer/tikz/libraries/graphs/tikzlibrarygraphs.code.tex#L1056 where it is executed inside a group so setting the first char syntax should have no consequences.


Though, I wonder if we can just adjust \pgfkeysifdefined https://github.com/pgf-tikz/pgf/blob/d43fb104dadc1db7e2bcae6f02e0607078a98be1/tex/generic/pgf/utilities/pgfkeys.code.tex#L213-L219 so that it is safer without breaking everything else:

\long\def\pgfkeysifdefined#1{%
  \ifcsname pgfk@\detokenize\expandafter{\pgfkeys@expanded{#1}}\endcsname
    \expandafter\pgfkeys@firstoftwo
  \else
    \expandafter\pgfkeys@secondoftwo
  \fi
}

MWE

\documentclass[tikz]{standalone}
\usepackage{tikz}
\usetikzlibrary{graphs, graphs.standard, quotes}
\makeatletter
\def\tikz@lg@local@node@handle#1{% 
   % 
   % Handle late options and operators 
   \pgfkeyssetvalue{/handlers/first char syntax/\expandafter\meaning\string"}{\pgfutil@gobble}%
   \tikzgraphsset{source,target,.unknown/.code=,#1}% 
   \tikzgdlatenodeoptionacallback{\tikz@pp@name\tikz@lib@graph@name}% 
   \node also[graphs/redirect unknown to tikz,/tikz/graphs/.cd,#1](\tikz@lib@graph@name);% 
   \pgfkeysvalueof{/tikz/graphs/@operators}% 
}
%\long\def\pgfkeysifdefined#1{%
%  \ifcsname pgfk@\detokenize\expandafter{\pgfkeys@expanded{#1}}\endcsname
%    \expandafter\pgfkeys@firstoftwo
%  \else
%    \expandafter\pgfkeys@secondoftwo
%  \fi
%}
\makeatother
\begin{document}
\begin{tikzpicture}
\graph[grid placement, n = 4, chain shift = {(2,0)}, group shift = {(0,-2)}, 
  math nodes, nodes = {circle, draw, thick}, edges={very thick}] {
    subgraph I_n[V={s_1, s_2, s_3, s_4}],
    s_1["$P,Q$" left],
    s_2["$P, \neg Q$" right],
    s_3["$\neg P, Q$" left],
    s_4["$\neg P, \neg Q$" right],
    s_1 -> s_3,
    s_4 -> s_2,
    s_3 -> {s_3[>loop below], s_4},
    s_2 -> {s_2[>loop above], s_1}
  };
\end{tikzpicture}
\end{document}