Referring with cleveref to a custom listing (\lstnewenvironment)

I use cleveref's \cref command for referencing, and \lstnewenvironment to create a new listing type. My document has multiple types of listings, each of them with their own counter.

However, cleveref insists on calling all types of listings listing, despite my definition of a \crefname for the custom listing types.

How can I refer with the correct label to a custom listing?

Minimal working example:

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

% Define listing type for queries
\newcounter{query}
\makeatletter
\lstnewenvironment{query}[1][]
{%
\lstset{#1}%
\renewcommand\lstlistingname{Query}%
\let\c@lstlisting=\c@query%
\let\thelstlisting=\thequery%
}
{}
\makeatother

% Set up reference label
\crefname{query}{query}{queries}

\begin{document}

\begin{lstlisting}[label=lst:MyListing,caption=My listing]
# Hello world
\end{lstlisting}

\begin{query}[label=qry:MyQuery,caption=My query]
SELECT * FROM MyTable;
\end{query}

Reference to \cref{lst:MyListing} and \cref{qry:MyQuery}.
\end{document}

• @ChristianHupfer So the key to making this work is changing that? How would we go about that? – Ruben Verborgh Apr 26 '15 at 11:59

You can coerce listings into using the right counter instead of the default lstlisting:

\documentclass{article}
\usepackage{etoolbox,listings,cleveref}

% Define listing type for queries
\newcounter{query}
\makeatletter
\lstnewenvironment{query}[1][]
{%
% make \lst@MakeCaption use query instead of lstlisting
\patchcmd{\lst@MakeCaption}{{lstlisting}}{{query}}{}{}%
\lstset{basicstyle=\ttfamily,columns=fullflexible,#1}%
\renewcommand\lstlistingname{Query}%
\let\thelstlisting=\thequery
}
{}
\makeatother

% Set up reference label
\crefname{query}{query}{queries}

\begin{document}

\begin{lstlisting}[label=lst:MyListing,caption=My listing]
# Hello world
\end{lstlisting}

\begin{query}[label=qry:MyQuery,caption=My query]
SELECT * FROM MyTable;
\end{query}

\begin{lstlisting}[label=lst:MyListing2,caption=My listing]
# Hello world
\end{lstlisting}

\begin{query}[label=qry:MyQuery2,caption=My query]
SELECT * FROM MyTable;
\end{query}

Reference to \cref{lst:MyListing} and \cref{qry:MyQuery}.

Reference to \cref{lst:MyListing2} and \cref{qry:MyQuery2}.
\end{document}


Fix for cooperation with hyperref

\documentclass{article}
\usepackage{etoolbox,listings,hyperref,bookmark,cleveref}

% Define listing type for queries
\newcounter{query}
\makeatletter
\patchcmd{\lst@MakeCaption}{{lstlisting}}{{\verborgh@counter}}{}{}%
\def\verborgh@counter{lstlisting}
\def\verborgh@prefix{L}
\AtBeginDocument{%
\patchcmd{\theHlstnumber}{\thelstnumber}{\verborgh@prefix\thelstnumber}{}{}%
}

\lstnewenvironment{query}[1][]
{%
% make \lst@MakeCaption use query instead of lstlisting
\def\verborgh@counter{query}%
\def\verborgh@prefix{Q}%
\lstset{basicstyle=\ttfamily,columns=fullflexible,#1}%
\renewcommand\lstlistingname{Query}%
}
{}
\makeatother

% Set up reference label
\crefname{query}{query}{queries}

\begin{document}

\begin{lstlisting}[label=lst:MyListing,caption=My listing]
# Hello world
\end{lstlisting}

\begin{query}[label=qry:MyQuery,caption=My query]
SELECT * FROM MyTable;
\end{query}

\begin{lstlisting}[label=lst:MyListing2,caption=My listing]
# Hello world
\end{lstlisting}

\begin{query}[label=qry:MyQuery2,caption=My query]
SELECT * FROM MyTable;
\end{query}

Reference to \cref{lst:MyListing} and \cref{qry:MyQuery}.

Reference to \cref{lst:MyListing2} and \cref{qry:MyQuery2}.
\end{document}

• Thanks @egreg, this works great for the MWE I had provided. Unfortunately, it fails in my actual document, because I also use the hyperref package (which I load before cleveref). Could you perhaps also indicate how it could work in this situation? – Ruben Verborgh Apr 26 '15 at 13:03
• @RubenVerborgh The fix for cooperation with hyperref is online. – egreg Apr 26 '15 at 13:57
• Fantastic, works like a charm! – Ruben Verborgh Apr 26 '15 at 14:21