5

I found this limitation in the current tikzmark solution for highlighting lines of listings code in beamer. When I put the whole lot in an onlyenv environment, it seems the marks are not set, or found. Example:

\documentclass{beamer}
\usepackage{tikz}
\usepackage{listings}
\usetikzlibrary{tikzmark,fit}
\usetikzmarklibrary{listings}
\newcommand{\showmark}[2]{%
  \tikz[remember picture,overlay]{\draw[red,thick] ({pic cs:line-#1-#2-first}) -- ({pic cs:line-#1-#2-end});}%
}
\begin{document}
\begin{frame}[fragile]
\begin{onlyenv}<1>
\showmark{first}{2}
\begin{lstlisting}[name=first]
Listing
In first slide
\end{lstlisting}
\end{onlyenv}
\begin{onlyenv}<2>
\showmark{second}{2}
\begin{lstlisting}[name=second]
Listing
In second slide
\end{lstlisting}
\end{onlyenv}
\end{frame}
\end{document}

I see a red line in the first slide, but not in the second. Is there any (simple) workaround for this problem? Or am I doing something wrong?

PS. The \showmark macro is just a quick way of showing the problem.

  • Did you run it twice? – Peter Grill Mar 10 '14 at 16:25
  • @PeterGrill Many more times than two, actually. Does it work for you? It could mean I need to update some packages in that case. – Jellby Mar 10 '14 at 16:29
5

Since you don't restart the value for the lines, the second line in the second listing is actually the fourth line; either restart the lines or use the proper value:

\documentclass{beamer}
\usepackage{tikz}
\usepackage{listings}
\usetikzlibrary{tikzmark,fit}
\usetikzmarklibrary{listings}
\newcommand{\showmark}[2]{%
  \tikz[remember picture,overlay]{\draw[red,thick] ({pic cs:line-#1-#2-first}) -- ({pic cs:line-#1-#2-end});}%
}
\begin{document}
\begin{frame}[fragile]
\begin{onlyenv}<1>
\showmark{aaa}{2}
\begin{lstlisting}[name=aaa]
Listing
In first slide
\end{lstlisting}
\end{onlyenv}
\begin{onlyenv}<2>
\showmark{second}{4}
\begin{lstlisting}[name=second]
Listing
In second slide
\end{lstlisting}

\end{onlyenv}
\end{frame}
\end{document}

enter image description here

Under normal conditions, using \resetcounteronoverlays (or \resetcountonoverlays for a TeX counter) would take care of preventing a counter from stepping on overlays; however, when the name=<name> option is used for a listing, the values for the line numbers are stored inside \lstno@<name> which is a macro and not a counter, so \resetbeameronoverlays will not work and there's no native way to prevent the undesired behaviour. One can manually set the counter to the appropriate value, or set explicitly the appropriate number for firstnumber, as shown below:

\documentclass{beamer}
\usepackage{tikz}
\usepackage{etoolbox}
\usepackage{listings}
\usetikzlibrary{tikzmark,fit}
\usetikzmarklibrary{listings}
\newcommand{\showmark}[2]{%
  \tikz[remember picture,overlay]{\draw[red,thick] ({pic cs:line-#1-#2-first}) -- ({pic cs:line-#1-#2-end});}%
}

\resetcounteronoverlays{lstnumber}

\begin{document}

\begin{frame}[fragile]
\begin{onlyenv}<1>
\showmark{first}{2}
\begin{lstlisting}[name=first]
Listing
In first slide
\end{lstlisting}
\end{onlyenv}
\begin{onlyenv}<2>
\showmark{second}{2}
\begin{lstlisting}[name=second,firstnumber=1]
Listing
In second slide
\end{lstlisting}
\end{onlyenv}
\end{frame}

\end{document}

or

\documentclass{beamer}
\usepackage{tikz}
\usepackage{etoolbox}
\usepackage{listings}
\usetikzlibrary{tikzmark,fit}
\usetikzmarklibrary{listings}
\newcommand{\showmark}[2]{%
  \tikz[remember picture,overlay]{\draw[red,thick] ({pic cs:line-#1-#2-first}) -- ({pic cs:line-#1-#2-end});}%
}

\resetcounteronoverlays{lstnumber}

\begin{document}

\begin{frame}[fragile]
\begin{onlyenv}<1>
\showmark{first}{2}
\begin{lstlisting}[name=first]
Listing
In first slide
\end{lstlisting}
\end{onlyenv}
\makeatletter
\def\lstno@second{1}
makeatother
\begin{onlyenv}<2>
\showmark{second}{2}
\begin{lstlisting}[name=second]
Listing
In second slide
\end{lstlisting}
\end{onlyenv}
\end{frame}

\end{document}

Related to this problem is Problem with listings when using line numbers, `name`, and `beamer` overlays. I initially though about manually resetting \lst@firstnumber, but as Andrew Swann explains in his answer, it's better to consider \lstno@<name>.

  • Thanks, that helps. I tried resetting the line numbers, because that would make each piece of code more self-contained. But when I add firstnumber=1 to both lstlisting options, I get the opposite behavior: red line in the second slide and not in the first. Besides, the manual seems to imply that by using the name option the lines start at 1... Could you provide an example resetting the line numbers? – Jellby Mar 11 '14 at 8:43
  • @Jellby unfortunately, the native beamer solution (\resetcounteronoverlays) won't work when name is used (the reason is included in my edited answer), so there's no "natural way to prevent the undesired behaviour". I provided a work-around in my edited answer. – Gonzalo Medina Mar 12 '14 at 12:33
  • Thanks, and do you know why adding firstnumber=1 to the first listing doesn't work? It works for all of them, even in other frames, except for the first (at least in my tests). – Jellby Mar 12 '14 at 13:22
  • @Jellby I also noticed that. I didn't dig enough into the code of listings, so I don't know the reason. – Gonzalo Medina Mar 12 '14 at 13:25
  • @Jellby I updated my answer with new information that might be of interest for you. – Gonzalo Medina Mar 12 '14 at 17:52

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.