\edef\x 技巧和 pgfmath

\edef\x 技巧和 pgfmath

使用下面的 MWE,我发现了以下问题:在 figure* 环境中,我有三个不同的 \lstset 指令。第一个和第三个(注释掉的)有效,第二个(原样)显示错误消息“语言 [ANSI]C 未定义”。错误消息中的语言名称似乎很完美。如果我使用 \edef 技巧,错误就会消失。我想知道为什么在行中

\begingroup\edef\x{\endgroup\noexpand\lstset{language={\ME@language}}}\x

我确实需要 \edef,为什么后面 3 行

> \ME@decorations % Decorating comments

如果我按照与此行中的 \ME@language 相同的方式处理它,则会失败

\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}}
      \lstset{language={\ME@language}}
 % \begingroup\edef\x{\endgroup\noexpand\lstset{language={\ME@language}}}\x
        \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}


#include <stdio.h>

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

答案1

当你说

\lstset{
   language=<whatever>,
}

TeX 不会扩展任何宏,<whatever>而是listings将其结果与已知语言列表进行比较。在<whatever>的情况下\ME@language,它是不是在列表中。

然而,如果你这样做

\begingroup\edef\x{\endgroup\noexpand\lstset{language={\ME@language}}}\x

TeX 最终会

\lstset{language=[ANSI]C}

并且listings会很高兴。

检测到未知语言的神秘错误信息具有欺骗性,因为它listings会传递\ME@language给错误显示命令,该命令会在发出消息时将其展开。

相关内容