How can I highlight some lines from source code?
You can use any (All)TeX macro you wish within listings by enclosing it within escape brackets,
(*@ \textcolor{blue}{code} @*)
The funny eyes are the escapes you define them as follows:
\lstset{escapeinside={(*@}{@*)}}
For highlighting the soul
package provides a nice highlight macro \hl
, try it in the following minimal
\documentclass{article}
\usepackage{soul,listings,xcolor}
\lstnewenvironment{teX}[1][]
{\lstset{language=[LaTeX]TeX}\lstset{escapeinside={(*@}{@*)},
numbers=left,numberstyle=\normalsize,stepnumber=1,numbersep=5pt,
breaklines=true,
%firstnumber=last,
%frame=tblr,
framesep=5pt,
basicstyle=\normalsize\ttfamily,
showstringspaces=false,
keywordstyle=\itshape\color{blue},
%identifierstyle=\ttfamily,
stringstyle=\color{maroon},
commentstyle=\color{black},
rulecolor=\color{black},
xleftmargin=0pt,
xrightmargin=0pt,
aboveskip=\medskipamount,
belowskip=\medskipamount,
backgroundcolor=\color{white}, #1
}}
{}
\begin{document}
\begin{teX}
\test{this is some code}
(*@ \textcolor{blue}{code} @*)
(*@ \hl{yellow code} @*)
\end{teX}
\end{document}
I normally use an environment for "listings" settings, but you can use any other code style as well.
Another useful trick is to use the "listings" setting for emphasis in macros, like this:
\gdef\emphasis#1{\lstset{emph={begin,end,#1},
emphstyle={\itshape\ttfamily\textcolor{blue}}}}
\gdef\hlemphasis#1{\lstset{emph={begin,end,#1},
emphstyle={\hl{blue}}}}
This way you can emphasize keywords.
The following is my approach to highlight complete lines or ranges/sets of lines in a listing in combination with beamer overlay specification.
The highlighting itself is done with Martin Scharrer's lstlinebgrd
package, which adds a linebackgroundcolor
key to the listings
interface. In the following, I use this key together with a \btLstHL<overlay spec>{line range list}
command, so that we set the color only on certain lines and only if the given <overlay spec>
does match:
\begin{lstlisting}[
linebackgroundcolor={%
\btLstHL<1>{1-3}% on slide 1, highlight lines 1-3
\btLstHL<2>{6,9}% on slide 2, highlight lines 6 and 9
\btLstHL<3>{7}%
\btLstHL<4>{8}%
}]
/**
* Prints Hello World.
**/
#include <stdio.h>
int main(void) {
printf("Hello World!");
return 0;
}
\end{lstlisting}
We get the following result:
The complete code:
\documentclass[dvipsnames,cmyk]{beamer}
\usepackage{pgf, pgffor}
\usepackage{listings}
\usepackage{lstlinebgrd} % see http://www.ctan.org/pkg/lstaddons
\makeatletter
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% \btIfInRange{number}{range list}{TRUE}{FALSE}
%
% Test in int number <number> is element of a (comma separated) list of ranges
% (such as: {1,3-5,7,10-12,14}) and processes <TRUE> or <FALSE> respectively
\newcount\bt@rangea
\newcount\bt@rangeb
\newcommand\btIfInRange[2]{%
\global\let\bt@inrange\@secondoftwo%
\edef\bt@rangelist{#2}%
\foreach \range in \bt@rangelist {%
\afterassignment\bt@getrangeb%
\bt@rangea=0\range\relax%
\pgfmathtruncatemacro\result{ ( #1 >= \bt@rangea) && (#1 <= \bt@rangeb) }%
\ifnum\result=1\relax%
\breakforeach%
\global\let\bt@inrange\@firstoftwo%
\fi%
}%
\bt@inrange%
}
\newcommand\bt@getrangeb{%
\@ifnextchar\relax%
{\bt@rangeb=\bt@rangea}%
{\@getrangeb}%
}
\def\@getrangeb-#1\relax{%
\ifx\relax#1\relax%
\bt@rangeb=100000% \maxdimen is too large for pgfmath
\else%
\bt@rangeb=#1\relax%
\fi%
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% \btLstHL<overlay spec>{range list}
%
% TODO BUG: \btLstHL commands can not yet be accumulated if more than one overlay spec match.
%
\newcommand<>{\btLstHL}[1]{%
\only#2{\btIfInRange{\value{lstnumber}}{#1}{\color{orange!30}\def\lst@linebgrdcmd{\color@block}}{\def\lst@linebgrdcmd####1####2####3{}}}%
}%
\makeatother
\begin{document}
\begin{frame}[fragile]{MyListing}
\lstset{language=C, numbers=left}
\begin{lstlisting}[
gobble=4,
linebackgroundcolor={%
\btLstHL<1>{1-3}%
\btLstHL<2>{6,9}%
\btLstHL<3>{7}%
\btLstHL<4>{8}%
}]
/**
* Prints Hello World.
**/
#include <stdio.h>
int main(void) {
printf("Hello World!");
return 0;
}
\end{lstlisting}
\end{frame}
\end{document}
The following is a solution for the highlighting of parts of a line. It is a combination of the approches I have suggested in:
- How to make overlay still work inside lstlisting environment?
- Highlight text in code listing while also keeping syntax highlighting
Basically, I use the listings moredelim=**
option to define delimiters, which styles then apply on top of all other formattings, so that the syntax formatting is kept.
To be not limited to a standard font command for the delimiter style, I use an lrbox to grab the content of the current group. The resulting box holds the (syntax-formatted) output of listings, which can be used to implement more fancy highlighting styles.
In the example code, the implementation of the \btHL
command employs TikZ to typeset the lrbox into a TikZ node. Additional, beamer overlay specifications and TikZ/PGF options to both, the tikzpicture and the node can be given in the optional argument (such as \btHL<1->[fill=red!20,draw=red]
), which provides for pretty flexible highlighters.
(Note: when the optional argument is used inside some listings argument, the whole \btHL[<key>=<value>,...]
command has to be put into curly braces in order to not confuse the listings key=value parser.)
The \btHL
command can as well be used inside normal text. It does, however, not work across line breaks.
\documentclass{beamer}
\usepackage[T1]{fontenc}
\usepackage{beramono}
\usepackage{listings}
\lstset{
basicstyle=\scriptsize\ttfamily,language=[LaTeX]Tex,breaklines=true,
breakautoindent=true,breakindent=2ex,
}
\lstMakeShortInline{!}
\usepackage{tikz}
\usetikzlibrary{positioning,calc}
\tikzset{onslide/.code args={<#1>#2}{%
\only<#1>{\pgfkeysalso{#2}} % \pgfkeysalso doesn't change the path
}}
\makeatletter
\newenvironment<>{btHighlight}[1][]
{\begin{onlyenv}#2\begingroup\tikzset{bt@Highlight@par/.style={#1}}\begin{lrbox}{\@tempboxa}}
{\end{lrbox}\bt@HL@box[bt@Highlight@par]{\@tempboxa}\endgroup\end{onlyenv}}
\newcommand<>\btHL[1][]{%
\only#2{\begin{btHighlight}[#1]\bgroup\aftergroup\bt@HL@endenv}%
}
\def\bt@HL@endenv{%
\end{btHighlight}%
\egroup
}
\newcommand{\bt@HL@box}[2][]{%
\tikz[#1]{%
\pgfpathrectangle{\pgfpoint{1pt}{0pt}}{\pgfpoint{\wd #2}{\ht #2}}%
\pgfusepath{use as bounding box}%
\node[anchor=base west, fill=orange!30,outer sep=0pt,inner xsep=1pt, inner ysep=0pt, rounded corners=3pt, minimum height=\ht\strutbox+1pt,#1]{\raisebox{1pt}{\strut}\strut\usebox{#2}};
}%
}
\makeatother
\begin{document}
\begin{frame}[fragile]{Highlighting single elements in listings}
\scriptsize !\btHL<overlay spec>[tikz key=val list]! highlights till the end of a group (no line breaks, though). Hence, it can be used as a ordinary font command with listings:
\par
\bigskip
\lstset{language=C, gobble=4}
\begin{lstlisting}[
moredelim={**[is][\btHL<1>]{@1}{@}},
moredelim={**[is][{\btHL<2>}]{@2}{@}}
]
#include @2<stdio.h>@
int @1main@(void) {
@2printf("Hello World!")@;
return 0;
}
\end{lstlisting}
\end{frame}
\begin{frame}[fragile]{Highlighting single elements in listings}
\scriptsize !\btHL<overlay spec>[tikz key=val list]! actually draws the content inside a TikZ node, so you can play with named nodes and other options:
\par
\bigskip
\begin{lstlisting}[language=C, gobble=4, numbers=left,
moredelim={**[is][{%
\btHL[name=X, remember picture, onslide=<2->{fill=red!50}]%
}]{@}{@}},
]
@int main (void)@ {
printf("Hello World!");
return 0;
}
\end{lstlisting}
% main() is typset into the node (X):
\tikz[remember picture, overlay]{
\path<2> node[red, above right=3mm of X](L){This is the entry point};
\draw<2>[->, red, shorten >=5pt] (L.west)--(X);
}
\end{frame}
\end{document}