tikz/pgf Upgrade und Dekorationen

tikz/pgf Upgrade und Dekorationen

Seit einem größeren Upgrade in pgf lässt sich mein Code nicht mehr kompilieren. Ich versuche, eine „dekorierte“ Quellcodeliste zu erstellen, bei der die Dekorationen beispielsweise das Hervorheben einiger Zeilen (siehe MWE), Bälle auf einigen Zeilen, Bilder usw. sein können. Die Dekorationen sind optional und ich übergebe sie als Makroargumente. Hier ist mein MWE

    \documentclass{book}
    \usepackage{xcolor}
    \usepackage{xkeyval}
    \usepackage{listings}
    \usepackage{tikz}   
\usetikzlibrary{shapes,positioning,arrows,fit,backgrounds,calc,tikzmark,shadows}%

    \definecolor{ForestGreen}{rgb}{0.0, 0.4, 0.0}
    \definecolor{burntorange}{rgb}{0.8, 0.33, 0.0}
    \newlength{\mywidth} % Used in defining listing width
    \definecolor{ivory}{rgb}{1.0, 1.0, 0.94}
        \colorlet{SeparatorColor}{burntorange}

        \makeatletter
        \define@key{MEMacros}{decorations}{\def\ME@decorations{#1}}
        \define@key{MEMacros}{language}{\def\ME@language{#1}}
        \define@key{MEMacros}{number}{\def\ME@number{#1}}
        \presetkeys{MEMacros}{number=1}{}%
    \makeatother


    %%Usage \MESourceFile[keys]{source file}{caption}{label}
    \makeatletter
    \newcommand\MESourceFile[4][]{
    \setkeys{MEMacros}{ %language={[ANSI]C},
     decorations={},#1}% 
          \begingroup%
            \lstset{    language={[ANSI]C}      }   

             {\begin{figure*}[h!btp] }
             \caption{#3}
            \begingroup\edef\x{\endgroup\noexpand\lstinputlisting[label=#4, name=#4] {#2}
                {\ME@decorations} % Decorating comments
                }\x
            {\end{figure*}}
      \endgroup%
    }
    \makeatother
    % % Prepare for some decorations on the listing files
        \makeatletter
        \newif\iflst@linemark

        \lst@AddToHook{EveryLine}{%
     \begingroup
     \advance\c@lstnumber by 1\relax
     \pgfmark{line-\lst@name-\the\c@lstnumber-start}%
     \endgroup
        }

        \lst@AddToHook{EOL}{\pgfmark{line-\lst@name-\the\c@lstnumber-end}%
        \global\lst@linemarktrue
        }

        \lst@AddToHook{OutputBox}{%
     \iflst@linemark
     \pgfmark{line-\lst@name-\the\c@lstnumber-first}%
     \global\lst@linemarkfalse
     \fi
        }

        \def\tkzlst@fnum#1\relax#2\@STOP{%
     \def\@test{#2}%
     \ifx\@test\@empty
     \def\tkzlst@start{0}%
     \else
     \@tempcnta=#1\relax
     \advance\@tempcnta by -1\relax
     \def\tkzlst@start{\the\@tempcnta}%
     \fi
        }

        \lst@AddToHook{Init}{%
     \expandafter\tkzlst@fnum\lst@firstnumber\relax\@STOP
     \pgfmark{line-\lst@name-\tkzlst@start-start}%
        }

    % % Put a balloon around some lines in a source
    % Usage: \MEHighlightLines{BallonName}{SourceName}{FirstLine}{LastLine}
    \newcommand\MEHighlightLines[4]{%
      \pgfmathtruncatemacro\pgf@temp{%
       #3-1
      }%
      \iftikzmark{line-#2-\pgf@temp-start}{%
       \iftikzmark{line-#2-#3-first}{%
         \xdef\b@lines{({pic cs:line-#2-\pgf@temp-start} -| {pic           cs:line-#2-#3-first})}%
       }{%
         \iftikzmark{line-#2-#3-start}{%
           \xdef\b@lines{({pic cs:line-#2-\pgf@temp-start} -| {pic             cs:line-#2-#3-start})}%
         }{%
           \xdef\b@lines{(pic cs:line-#2-\pgf@temp-start)}%
         }%
       }%
      }{%
       \xdef\b@lines{}%
      }%
      \foreach \k in {#3,...,#4} {%
       \iftikzmark{line-#2-\k-first}{%
         \xdef\b@lines{\b@lines (pic cs:line-#2-\k-first) }
       }{}
       \iftikzmark{line-#2-\k-end}{%
         \xdef\b@lines{\b@lines (pic cs:line-#2-\k-end) }
       }{}
      }%
      \ifx\b@lines\pgfutil@empty
      \else
      \edef\pgf@temp{\noexpand\tikz[remember picture,overlay]\noexpand\node[fit={\b@lines}, color=ForestGreen,yshift=-2pt,
         draw, fill=green!30, opacity=0.4,  inner sep=1pt, rounded corners=5pt] (#1) {};
      }%
            \pgf@temp
      \fi
            }
    \makeatother

    \begin{document}
    \MESourceFile[decorations={
    %\MEHighlightLines{HelloWorldsystem}{lst:HelloWorld.c}{1}{3}
    }
    ]{HelloWorld.c}{Hello world}{lst:HelloWorld.c}
    \MEHighlightLines{HelloWorldsystem}{lst:HelloWorld.c}{1}{3}
    \end{document}

und den tollen Code möchte ich schmücken

#include <stdio.h>

int main()
{
     printf("hello, world\n");
}

Der Code soll ein hervorgehobenes Kästchen um die Zeilen 1 bis 3 setzen. Der Code funktioniert so, wie er ist. Er soll nur demonstrieren, dass das Makro \MEHighlightLines einwandfrei funktioniert. Jetzt können Sie die vorletzte Zeile mit diesem Makro auskommentieren und die Zeile mit demselben Makro drei Zeilen darüber auskommentieren.

Nun erhalten Sie die Fehlermeldung

! Undefined control sequence.
\pgfmathsetcount ... \pgfmath@onquick #2\pgfmath@ 
                                                  {\afterassignment \pgfmath...

Da der einzige Unterschied darin besteht, dass das Makro jetzt als Argument übergeben und nicht direkt aufgerufen wird, vermute ich, dass die Ursache in der Erweiterung des Makros in der neuen PGF-Datei liegt. Die Methode zur Argumentübergabe ist

\begingroup\edef\x{\endgroup\noexpand\lstinputlisting[label=#4, name=#4] {#2}
    {\ME@decorations} % Decorating comments
    }\x

Der Fehler liegt irgendwo beim Erweitern meiner übergebenen Makros in der aktualisierten PGF-Datei. (Die Verzierungen müssen zusammen mit der Auflistung beibehalten werden, daher erzwinge ich sie in einer \figure. Alternative Implementierungsideen sind ebenfalls willkommen (als Workaround), aber der beste Weg wäre, den Makroerweiterungsfehler zu beheben.)

Antwort1

Der Fehler ist ganz klar: Der Code

\begingroup\edef\x{\endgroup\noexpand\lstinputlisting[label=#4, name=#4] {#2}
{\ME@decorations} % Decorating comments
}\x

sollte sein

\lstinputlisting[label=#4, name=#4] {#2}
\ME@decorations % Decorating comments

Es gibt absolut keinen Grund, den Trick hier anzuwenden, \edef\xund das Problem besteht genau darin, dass \ME@decorationses nicht überlebt, \edefweil es Zuweisungen enthält (z. B. \pgfmathtruncatemacro).

Übrigens, auch {\begin{figure*}[htbp]}mit {\end{figure*}}ist falsch und \lstsetkann durchaus nach hinten losgehen \begin{figure*}, sodass das Umliegende überflüssig \begingroupwird \endgroup.

Hier ist eine korrigierte (und neu formatierte) Version.

\documentclass{book}
\usepackage{xcolor}
\usepackage{xkeyval}
\usepackage{listings}
\usepackage{tikz}   
\usetikzlibrary{
  shapes,
  positioning,
  arrows,
  fit,
  backgrounds,
  calc,
  tikzmark,
  shadows,
}

\definecolor{ForestGreen}{rgb}{0.0, 0.4, 0.0}
\definecolor{burntorange}{rgb}{0.8, 0.33, 0.0}
\newlength{\mywidth} % Used in defining listing width
\definecolor{ivory}{rgb}{1.0, 1.0, 0.94}
\colorlet{SeparatorColor}{burntorange}

\makeatletter
\define@key{MEMacros}{decorations}{\def\ME@decorations{#1}}
\define@key{MEMacros}{language}{\def\ME@language{#1}}
\define@key{MEMacros}{number}{\def\ME@number{#1}}
\presetkeys{MEMacros}{number=1}{}%
\makeatother

%%Usage \MESourceFile[keys]{source file}{caption}{label}
\makeatletter
\newcommand\MESourceFile[4][]{%
  \setkeys{MEMacros}{%
    %language={[ANSI]C},%
    decorations={},%
    #1%
  }%
  \begin{figure*}[h!btp]
  \lstset{language={[ANSI]C}}
  \caption{#3}
  \lstinputlisting[label=#4, name=#4]{#2}%
  \ME@decorations % Decorating comments
  \end{figure*}
}
%% Prepare for some decorations on the listing files
\newif\iflst@linemark

\lst@AddToHook{EveryLine}{%
  \begingroup
  \advance\c@lstnumber by \@ne
  \pgfmark{line-\lst@name-\the\c@lstnumber-start}%
  \endgroup
}

\lst@AddToHook{EOL}{%
  \pgfmark{line-\lst@name-\the\c@lstnumber-end}%
  \global\lst@linemarktrue
}

\lst@AddToHook{OutputBox}{%
  \iflst@linemark
    \pgfmark{line-\lst@name-\the\c@lstnumber-first}%
    \global\lst@linemarkfalse
  \fi
}

\def\tkzlst@fnum#1\relax#2\@STOP{%
  \def\@test{#2}%
  \ifx\@test\@empty
    \def\tkzlst@start{0}%
  \else
    \@tempcnta=#1\relax
    \advance\@tempcnta by \m@ne
    \def\tkzlst@start{\the\@tempcnta}%
  \fi
}

\lst@AddToHook{Init}{%
  \expandafter\tkzlst@fnum\lst@firstnumber\relax\@STOP
  \pgfmark{line-\lst@name-\tkzlst@start-start}%
}

%% Put a balloon around some lines in a source
% Usage: \MEHighlightLines{BallonName}{SourceName}{FirstLine}{LastLine}
\newcommand\MEHighlightLines[4]{%
  \pgfmathtruncatemacro\pgf@temp{#3-1}%
  \iftikzmark{line-#2-\pgf@temp-start}
    {%
     \iftikzmark{line-#2-#3-first}
       {%
        \xdef\b@lines{({pic cs:line-#2-\pgf@temp-start} -| {pic cs:line-#2-#3-first})}%
       }
       {%
        \iftikzmark{line-#2-#3-start}
          {%
           \xdef\b@lines{({pic cs:line-#2-\pgf@temp-start} -| {pic cs:line-#2-#3-start})}%
          }
          {%
           \xdef\b@lines{(pic cs:line-#2-\pgf@temp-start)}
          }%
       }%
    }
    {%
     \xdef\b@lines{}%
    }%
  \foreach \k in {#3,...,#4} {%
     \iftikzmark{line-#2-\k-first}
       {%
         \xdef\b@lines{\b@lines (pic cs:line-#2-\k-first) }
       }
       {}%
       \iftikzmark{line-#2-\k-end}
         {%
          \xdef\b@lines{\b@lines (pic cs:line-#2-\k-end) }
         }
         {}%
  }%
  \ifx\b@lines\pgfutil@empty
  \else
    \edef\pgf@temp{%
      \noexpand\tikz[remember picture,overlay]
      \noexpand\node[
        fit={\b@lines}, color=ForestGreen,yshift=-2pt,
        draw, fill=green!30, opacity=0.4,  inner sep=1pt, rounded corners=5pt
      ] (#1) {};
    }%
    \pgf@temp
  \fi
}
\makeatother

\begin{document}

\MESourceFile[%
  decorations={
    \MEHighlightLines{HelloWorldsystem}{lst:HelloWorld.c}{1}{3}
  }%
]{HelloWorld.c}{Hello world}{lst:HelloWorld.c}

\end{document}

Bildbeschreibung hier eingeben

verwandte Informationen