4

With the MWE below, I find the following trouble: within the figure* environment, I have three different \lstset instructions. The first and 3rd (commented out) work, the 2nd (as is) presents with error message " language [ANSI]C undefined". It looks like in the error message the language name is perfect. If I uses the \edef trick, the error goes away. I wonder why in line

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

I do need \edef, and why 3 lines later

> \ME@decorations % Decorating comments

fails if I handle it in the same way as \ME@language in this line

\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");
}
2
  • I think you truncated your question
    – percusse
    May 11, 2015 at 20:37
  • The output seems good, but that's because output to the .log may necessarily be expanded. The \edef\x-trick expands it so that it works as expected.
    – Werner
    May 11, 2015 at 20:44

1 Answer 1

2

When you say

\lstset{
   language=<whatever>,
}

TeX doesn't expand any macro in <whatever> and listings compares what it got with the known list of languages. In the case <whatever> is \ME@language, it is not in the list.

However, if you do

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

TeX will eventually do

\lstset{language=[ANSI]C}

and listings will be happy.

The mysterious error message saying that an unknown language was detected is deceiving, because listings passes \ME@language to the error showing command, which will expand it when the message is issued.

1
  • Hmm. I used to design my systems in a way that the error cause and the message informing about that is the same. It is pretty misleading. Thanks for the explanation.
    – katang
    May 12, 2015 at 18:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.