# Highlight text in code listing while also keeping syntax highlighting

I’m using the listings package for code listings. Now I try to highlight some part of the code using \hl from the soul package.

Here’s an example of a resulting query where the injected part of a SQL injection should be highlighted:

\begin{lstlisting}[escapechar=@,language=SQL]
SELECT name, password FROM users WHERE name='@\hl{' UNION SELECT "10", 1 \#}@';
\end{lstlisting}


But inside the highlighted part the SQL syntax highlighting is not applied.

So I tried to use \lstlinline for the code part inside \hl as well but it didn’t work:

\begin{lstlisting}[escapechar=@,language=SQL]
SELECT name, password FROM users WHERE name='@\hl{\lstinline[language=SQL]$' UNION SELECT "10", 1 #$}@';
\end{lstlisting}


Although this \lstinline part works outside the lstlisting block, it doesn’t work inside it. The error I get for that particular line is:

Extra }, or forgotten \endgroup.

Maybe I’m just missing just some special syntax to get this working. Or is it not possible at all to get proper syntax highlighting for the \hl-highlighted part as well?

-
Very related question: \fbox inside listings. –  Martin Scharrer Apr 7 '11 at 14:43
@Martin Scharrer: That seems to be a little bit complicated. I hope there is an inline solution for this. –  Gumbo Apr 7 '11 at 15:09
I know, especially if you have many of such blocks. Maybe opening a bug report for listings will help (on the long run I mean). Also check out the alltt package which allows macro inside it. However it won't give you SQL syntax highlighting. –  Martin Scharrer Apr 7 '11 at 15:20
Since you have some responses below that seem to answer your question, please consider marking one of them as ‘Accepted’ by clicking on the tickmark below their vote count (see How do you accept an answer?). This shows which answer helped you most, and it assigns reputation points to the author of the answer (and to you!). It's part of this site's idea to identify good questions and answers through upvotes and acceptance of answers. –  Jubobs Jan 14 at 18:42
@Jubobs Unfortunately, I don’t remember which one of these suggestions I’ve used, if had used one of these at all. I think I’ve actually scrapped the language and used it without. That worked pretty well. –  Gumbo Jan 14 at 19:39

It's almost a year later, but as the OP has not yet accepted an answer, I still see my chance :-)

In the following, I use the same basic principle as in my other answer, that is, employ listings moredelim=** option to define delimiters, which styles then apply on top of all other formattings, so that the syntax formatting is kept.

However, instead of being limited to a standard font command for the delimiter style, I now 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 TikZ/PGF options to both, the tikzpicture and the node can be given in the optional argument (such as \btHL[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, which is a possible disadvantage compared to the approach that culminated from Bens answer. Insides of listings, however, this usually is not an issue.

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{listings,xcolor,beramono}
\usepackage{tikz}

\makeatletter
\newenvironment{btHighlight}[1][]
{\begingroup\tikzset{bt@Highlight@par/.style={#1}}\begin{lrbox}{\@tempboxa}}
{\end{lrbox}\bt@HL@box[bt@Highlight@par]{\@tempboxa}\endgroup}

\newcommand\btHL[1][]{%
\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

\lstdefinestyle{SQL}{
language={SQL},basicstyle=\ttfamily,
moredelim=**[is][\btHL]{}{},
moredelim=**[is][{\btHL[fill=green!30,draw=red,dashed,thin]}]{@}{@},
}

\begin{document}

A listing with {\btHL highlighting of all \textbf{important} elements} looks as follows:

\begin{lstlisting}[style=SQL]
SELECT name, password FROM users @WHERE@ name=@UNION SELECT@
\end{lstlisting}


-
This works really well for me, thanks! There is only one small glitch: if a line starts with spaces, those spaces are highlighted, too. –  Axel Rauschmayer Oct 23 '13 at 21:02

try it with an explit \textbf:

\documentclass [a4paper]{article}
\usepackage[T1]{fontenc}
\usepackage[scaled=0.83]{beramono}
\usepackage {listings,soul}
\begin{document}

\begin{lstlisting}[language=SQL,escapechar=@,language=SQL,basicstyle=\ttfamily]
SELECT name, password FROM users WHERE name='@\hl{' \textbf{UNION SELECT} "10", 1 \#}@';
\end{lstlisting}

\end{document}


-
Thank’s for your reply. Unfortunately, that is rather the manual workaround, which I wanted to avoid. –  Gumbo Apr 7 '11 at 15:33

I don't think that the combination of \hl + \lstinline can work. Both soul and listings analyze and handle the input one token after the other and do a lot of \catcode magic. They will tread on another toes. But you could try something like this:

 \documentclass{article}
\usepackage{listings,xcolor,tikz}
\newcommand\bh{\tikz[remember picture]
\node (begin highlight) {};
}
\newcommand\eh{\tikz[remember picture]
\node (end highlight) {};
\tikz[remember picture, overlay]
\draw[yellow,line width=10pt,opacity=0.3] (begin highlight) -- (end
highlight);
}

\begin{document}

\bh abc bce bde bde \eh

\begin{lstlisting}[escapechar=@,language=SQL]
WHERE name=@\bh@UNION SELECT@\eh@
\end{lstlisting}

\end{document}

-

Ulrike's suggestion is extremely clever. My version is inspired by what @Ulrike did, but has some improvements:

• The style of the highlight shading is explicitly factored out into \tikzstyle{highlighter} = [...] to clearly show how the visual appearance can be customized. For example, two commented-out lines in my solution show how to make the highlight swipe a bit wavy for a more human-looking result.

• No extra whitespace is added at the start or end of the highlighted region. This required avoiding line breaks in macro definitions, creating the tikz anchor points using \coordinate instead of \node, and creating all tikz diagrams as overlay diagrams.

• The highlighting stroke is added below the text rather than above it. This keeps highlights from affecting the text ink color. Black text with a yellow highlight remains purely black instead of becoming dark yellow.

• Some common code shared by the \bh and \eh macros is factored out into a new \tikzhighlight macro. No visual effect from this, but the vertical centering code is subtle enough that I felt it warranted being factored out.

With those enticements in mind, here's my take on Ulrike's solution:

\documentclass{article}

% required packages
\usepackage{atbegshi,ifthen,listings,tikz}

% change this to customize the appearance of the highlight
\tikzstyle{highlighter} = [
yellow,
line width = \baselineskip,
]

% enable these two lines for a more human-looking highlight
%\usetikzlibrary{decorations.pathmorphing}
%\tikzstyle{highlighter} += [decorate, decoration = random steps]

% implementation of the core highlighting logic; do not change!
\newcounter{highlight}[page]
\newcommand{\tikzhighlightanchor}[1]{\ensuremath{\vcenter{\hbox{\tikz[remember picture, overlay]{\coordinate (#1 highlight \arabic{highlight});}}}}}
\newcommand{\bh}[0]{\stepcounter{highlight}\tikzhighlightanchor{begin}}
\newcommand{\eh}[0]{\tikzhighlightanchor{end}}
\AtBeginShipout{\AtBeginShipoutUpperLeft{\ifthenelse{\value{highlight} > 0}{\tikz[remember picture, overlay]{\foreach \stroke in {1,...,\arabic{highlight}} \draw[highlighter] (begin highlight \stroke) -- (end highlight \stroke);}}{}}}

\begin{document}

Works in \bh{}plain text too\eh{} (but not across line breaks).

\begin{lstlisting}[escapechar=@, language=SQL, basicstyle=\sffamily, columns=fullflexible]
SELECT name, password FROM users WHERE name='@\bh@' UNION SELECT "10", 1 #@\eh@';
\end{lstlisting}

\end{document}


The only limitation I am aware of, which also applies to Ulrike's version, is that highlighting does not span line breaks correctly.

-
This whole tikz-based approach took on a life of its own, eventually leading to a good, robust solution. That is currently the best known (to me) approach to highlighting selected listings lines while keeping automatic syntax highlighting. It will actually work just as well for stroking highlights between any pair of locations on a given page. –  Ben Liblit Jun 4 '11 at 23:51

If you are not determined to use \hl (or some simulation of it) and could live with some font-based formatting instead, listings moredelim option would be the most elegant solution. With the moredelim=** syntax you can define delimiters which styles apply on top of all other formattings:

\documentclass{article}
\usepackage{listings,xcolor}

\lstdefinestyle{SQL}{
language={SQL},
moredelim=**[is][\slshape]{}{},
moredelim=**[is][\color{orange}]{@}{@},
}

\begin{document}

\begin{lstlisting}[style=SQL]
SELECT name, password FROM users @WHERE@ name=@UNION SELECT@
\end{lstlisting}

\end{document}


Unfortunately, as with all formattings in listings, you can only use macros that affect the text inside the current group. Hence \color and font commands work, but \hl cannot be applied in this way.

-

If PDF annotations are okay, you can give the pdfcomment package a try. Then you can also add a comment.

\documentclass[a4paper]{article}
\usepackage[T1]{fontenc}
\usepackage[scaled=0.83]{beramono}
\usepackage{listings,xcolor,pdfcomment}
\begin{document}
\begin{lstlisting}[language=SQL,escapechar=@,language=SQL,basicstyle=\ttfamily]
SELECT name, password FROM users WHERE name='@\pdfmarkupcomment[markup=Underline,color=black,author=Gumbo]{' \textbf{UNION SELECT} "10", 1 \#}{This is the injected part of a SQL injection}@';
\end{lstlisting}
\end{document}


-