As all the solutions so far do not allow a highlight to span several lines, I'd like to present a version that will also work with listing
's breaklines
option.
The idea is based on the one I've used in this answer, which in turn is based on Ben's improvement of Ulrike's version that uses TikZ' remember picture
facilities. In short, the whole highlight is not rendered as a single unit but is broken into a lot of small pieces that are then able to get broken across lines with TeX's standard line breaking algorithm. What is a bit unfortunate about this approach is that it limits the number of highlight styles that can be used, because two adjacent highlight segments must fit together visually to produce another continuous segment. This is best demonstrated by modifying the \draw
command in the answer mentioned above to render framed nodes instead of line segments (note especially that, depending on the selected language, not even F1
is kept as a single unit):

To overcome this limitation we must eliminate the intermediate nodes such that each highlight on the same line only consists of a single segment. So the basic idea is to remember the position of the start node and check for each intermediate node if we can ignore it or if it is the end of this line's highlight. We use two hooks in \lst@discretionary
, one before and one after a potential break. If there's no break, both nodes stay on the same line and we can ignore them. Otherwise the first node will be the temporary end node and the second will start a new highlight on the following line. When the user-defined end node occurs, we know we are finished and must close the last opened highlight.
Implementing this approach is a bit more tricky, because the exact positions of all nodes are not known until the shipout for the current page occurs. That means we need a two-stage process. On the first compilation run all potential nodes are written to the .aux file (through \hl@mark
). I dropped the remember picture
approach here entirely and used the raw \pdfsavepos
because extra information about the node type and page number has to be stored along with the coordinates. This also seems to make the whole processing more performant when a lot of highlights are used in the document. Additionally, the coordinates of the origin are stored for each page and used later for correct positioning of the nodes.
The main logic is in the \hl@processmark
macro, which is called for every potential node. It decides which nodes are eventually used for output and which are discarded. If a complete highlight segment is found, the corresponding styling command call is (through \hl@draw
) added together with the page number to the \hl@shipout
token register. On the next shipout \hl@doshipout
then loops through all the saved segments' code and renders everything that should go on the current page.
To allow some type of customization of the output, the \hl@draw
command takes a parameter used for styling material. If the parameter is empty, the default styling command \hldefaultstyle
is used inside a \tikz
call. Otherwise the parameter is used as the command. In both cases four parameters are added to the call: the x- and y-coordinates of the first and last segment's node, respectively. Because the styling parameters have to be passed all the way down to the final shipout, they are stored in the .aux file, too.
For the user interface the following commands are defined:
\hlstyle
can be used for listings
delimiter styles. It takes one optional parameter in case a custom styling command should be used.
\hl
is similar to \hlstyle
but for uses in inline text. Note that this command doesn't work correctly with line breaks, so it should be used with care.
\hldefaultstyle
is the default styling command used if no custom styling commands are provided.
\hlunderlinestyle
, \hlmarkerstyle
, \hlboxstyle
are three example styling commands for underlined, marked and framed box output, respectively. Each command takes an optional parameter for the highlighting color.
Now here's the final example document:
\documentclass{article}
\usepackage{listings}
\usepackage{xcolor}
\usepackage{atbegshi}
\usepackage{ifthen}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{fit}
\makeatletter
\newcommand\if@empty[1]{%
\if\relax\detokenize{#1}\relax
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
}
\newcommand\ifthen[2]{\ifthenelse{#1}{#2}{}}
\newcommand\ifelse[2]{\ifthenelse{#1}{}{#2}}
% Is highlighting currently active in the listings environment?
\newif\ifhl@active
% Material executed at each page shipout
\newtoks\hl@shipout
% Extra styling parameters for the currently active highlight
\newtoks\hl@parameters
% Inline highlight style. This does not break across line ends
\newcommand\hl[2][]{\begingroup\hlstyle@start{#1}#2\endgroup}
% The highlight style for listings environments
\newcommand\hlstyle[1][]{\hlstyle@start{#1}}
\newcommand\hlstyle@start[1]{%
\global\hl@activetrue
\aftergroup\hlstyle@end
\write\@auxout{\noexpand\hl@setparameters{#1}}%
\hl@mark{S}%
}
\newcommand\hlstyle@end{%
\hl@mark{E}%
\global\hl@activefalse
}
% Sets the current highlight parameters
\newcommand\hl@setparameters[1]{%
\global\hl@parameters={#1}%
}
% Writes a new node marker with the current position and page number to the .aux file
\newcommand\hl@mark[1]{%
\ensuremath{\vcenter{\hbox{\pdfsavepos}}}%
\write\@auxout{\noexpand\hl@processmark{#1}{\the\pdflastxpos}{\the\pdflastypos}{\arabic{page}}}%
}
% Writes the current page origin to the .aux file, and issues the current \hl@shipout material
% to be processed
\AtBeginShipout{\AtBeginShipoutUpperLeft{%
\pdfsavepos
\write\@auxout{\noexpand\hl@processmark{Z}{\the\pdflastxpos}{\the\pdflastypos}{\arabic{page}}}%
\hl@doshipout
}}
% Maintains the current first and last node positions, checks whether a node marker should be used
% for the current highlighting segment, and issues a \hl@draw call if necessary.
% #1 is either 'S' (start node), 'M' (intermediate node), 'E' (end node), or 'Z' (page origin)
% #2/#3 are the x/y-coordinates, #4 is the page number
\newcommand\hl@processmark[4]{%
\if#1S%
\xdef\hl@firstx{#2}%
\xdef\hl@firsty{#3}%
\xdef\hl@firstp{#4}%
\else\if#1M%
\ifthenelse{\hl@firsty=#3}{%
% Still on same line
\xdef\hl@lastx{#2}%
\xdef\hl@lasty{#3}%
}{%
\ifelse{\hl@firstx=\hl@lastx \and \hl@firsty=\hl@lasty}{%
% Last highlight part is not empty
\expandafter\hl@draw\expandafter{\the\hl@parameters}%
}%
\xdef\hl@firstx{#2}%
\xdef\hl@firsty{#3}%
\xdef\hl@firstp{#4}%
}%
\else\if#1E%
\ifthen{\hl@firsty=#3}{%
% Still on same line
\xdef\hl@lastx{#2}%
\xdef\hl@lasty{#3}%
\ifelse{\hl@firstx=#2}{%
% Last highlight part is not empty
\expandafter\hl@draw\expandafter{\the\hl@parameters}%
}%
}%
\else\if#1Z%
\xdef\hl@zerox{#2}%
\xdef\hl@zeroy{#3}%
\fi\fi\fi\fi
}
% Add a new highlight segment to \hl@shipout to be processed on every shipout.
% #1 is the styling command used to draw the segment within a properly positioned \tikz call.
% If #1 is empty, \hldefaultstyle is used as a default. Every styling command can take
% arbitrary parameters, only the last four are mandatory (x_first, y_first, x_last, y_last)
\newcommand\hl@draw[1]{%
\edef\@temp{{\noexpand\tikz [ overlay, shift = {(-\hl@zerox sp, -\hl@zeroy sp)} ]
{\if@empty{#1}{\noexpand\hldefaultstyle}{\unexpanded{#1}}%
{\hl@firstx sp}{\hl@firsty sp}{\hl@lastx sp}{\hl@lasty sp}}}%
{\hl@firstp}%
}%
\expandafter\global\expandafter\addto@hook\expandafter\hl@shipout\expandafter{\@temp}%
}
% Processes the current \hl@shipout material. The material is a sequence of
% {TikZ commands}{page number} pairs
\def\hl@doshipout{%
\expandafter\hl@doshipout@\the\hl@shipout{}{}\@end
}
\def\hl@doshipout@#1#2#3\@end{%
\if@empty{#2}{}{%
\ifthen{\arabic{page}=#2}{#1}%
\hl@doshipout@#3\@end
}%
}
% Hook into listings' discretionary breaks
\let\orig@lst@discretionary=\lst@discretionary
\gdef\lst@discretionary{%
\ifhl@active
\hl@mark{M}%
\fi
\orig@lst@discretionary
\ifhl@active
\hl@mark{M}%
\fi
}
% Styling command for underlined text
\newcommand\hlunderlinestyle[5][black]{%
\draw [ yshift = -0.4\baselineskip, #1 ] (#2, #3) -- (#4, #5);
}
% Styling command for a simple marker highlights
\newcommand\hlmarkerstyle[5][yellow]{%
\draw [ line width = \baselineskip, #1 ] (#2, #3) -- (#4, #5);
}
% Styling command for a framed box
\newcommand\hlboxstyle[5][red]{%
\draw let \p1 = (#2, #3), \p2 = (#4, #5)
in node [ draw = #1,
fill = #1!10!white,
minimum height = \baselineskip,
fit = (\p1)(\p2),
anchor = west,
align = none, % prevent underfull node boxes
outer sep = 0pt, inner sep = 0pt ]
at (\p1) {};
}
% Default styling command
\let\hldefaultstyle=\hlmarkerstyle
\makeatother
\newcommand\delimstyleA{\hlstyle[{\hlboxstyle[green]}]}
\newcommand\delimstyleB{\hlstyle}
\newcommand\delimstyleC{\hlstyle[{\hlunderlinestyle[red, line width = 0.8pt]}]}
\lstset{
language=SQL,
columns=fullflexible,
basicstyle=\sffamily,
moredelim=**[is][\delimstyleA]{@}{@},
moredelim=**[is][\delimstyleB]{`}{`},
moredelim=**[is][\delimstyleC]{_}{_},
keepspaces,
breaklines
}
\begin{document}
\vspace*{15.5cm}
Example listing for \hl[{\hlboxstyle[blue]}]{SQL}'s \lstinline|_SELECT_| statement:
\begin{lstlisting}
SELECT name, `password`, _email_ FROM users
WHERE name=@'UNION SELECT "10", 1'@;
SELECT name, `password`, _email_ FROM users WHERE name=_'UNION SELECT "10", 1'_;
SELECT name, `password`, _email_ FROM users WHERE name=@'UNION SELECT x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31, x32, x33, x34, x35, x36, x37, x38, x39, x40'@;
\end{lstlisting}
\end{document}


listings
will help (on the long run I mean). Also check out thealltt
package which allows macro inside it. However it won't give you SQL syntax highlighting.