由於 pgf 進行了重大升級,我的程式碼不再編譯。我正在嘗試製作“裝飾”源列表,其中裝飾可以像突出顯示某些行(參見 MWE)、某些行上的球、圖像等。這是我的 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}
和我想要裝飾的偉大代碼
#include <stdio.h>
int main()
{
printf("hello, world\n");
}
該程式碼的目的是在第 1-3 行周圍放置一個突出顯示的方塊。該代碼按原樣有效。這只是為了證明 \MEHighlightLines 巨集工作正常。現在,您可以使用該巨集註解掉最後一行,並取消註解上面 3 行包含相同巨集的行。
現在您收到錯誤訊息
! Undefined control sequence.
\pgfmathsetcount ... \pgfmath@onquick #2\pgfmath@
{\afterassignment \pgfmath...
由於唯一的區別是現在巨集作為參數傳遞,而不是直接調用,我猜原因隱藏在新 pgf 中擴展巨集中。參數傳遞方法是
\begingroup\edef\x{\endgroup\noexpand\lstinputlisting[label=#4, name=#4] {#2}
{\ME@decorations} % Decorating comments
}\x
錯誤出在升級後的 pgf 中擴展我傳遞的巨集的某個地方。 (裝飾必須與清單保持在一起,因此我將它們強制放在圖中。也歡迎替代實作想法(作為解決方法),但最好的方法是修復巨集擴展錯誤。)
答案1
嗯,錯誤很明顯:程式碼
\begingroup\edef\x{\endgroup\noexpand\lstinputlisting[label=#4, name=#4] {#2}
{\ME@decorations} % Decorating comments
}\x
應該
\lstinputlisting[label=#4, name=#4] {#2}
\ME@decorations % Decorating comments
這裡絕對沒有理由使用這個\edef\x
技巧,問題正是它\ME@decorations
不存在,\edef
因為它包含賦值(例如\pgfmathtruncatemacro
)。
順便說一下,也{\begin{figure*}[htbp]}
用{\end{figure*}}
錯了,\lstset
可以好好追一下\begin{figure*}
,這樣週邊\begingroup
就\endgroup
變得多餘了。
這是一個固定(和重新格式化)的版本。
\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}