The trick is to define a macro called \listingname
or \listingautorefname
which stores the name hyperref
should use for the reference. In your case, adding the line
\providecommand*{\listingautorefname}{Listing}
produces correct references.
The solution I'm proposing here is adequate for relatively small documents, but will not work for more complex documents where the user wants to produce something like a \listofalgorithms
or \listofprograms
. Since this was not specified in the original question, it is not included here. However, I'm sure it is easy to extend it to include such requirements using the float
package, for example.
Some background to the solution...
One problem is that the lstlisting
environment provided by the
listings
package is special. It's
contents has to be parsed in a way such that nothing is expanded,
except for \end{lstlisting}
. That's why it cannot be broken up
using:
\newenvironment{myenvironment}[1][]{%
\begin{lstlisting}[#1]% Begin listing
}{\end{lstlisting}}% End listing
giving you a error during compilation. As a consolation, the
listings
package provides an alternative in the form of
\lstnewenvironment{<name>}[<number>][<opt. default arg.>]{<start code>}{<end code>}
analogous to LaTeX's
\newenvironment{nam}[args][opt]{begdef}{enddef}
definition. However, merely using this definition as-is in the
solution to different counters for different listing
environments
causes hyperref
to complain in the following
way
! pdfTeX warning (ext4): destination with the same identifier
(name{page.1}) has been already used, duplicate ignored
This is because the same counter is used - namely lstlisting
-
across the newly defined listing environments. In fact, they are the
same environments, just with different names (due to the command
\renewcommand\lstlistingname{<name>}
). This warning motives why
using
\def\algorithmautorefname{Algorithm}
\def\programautorefname{Program}
does not sway \autoref{...}
from using the correct reference title,
since \autoref{...}
still sees each newly defined environment
(algorithm
and program
) as lstlisting
.
One proposed solution would be to add some macros that both prints a correct caption (albeit manually) and correctly hyperlinks to the respective lstlisting
. This is done by introducing a "pre-hook" to each new \lstnewenvironment
and modifying the way in which parameters are passed to it. Caption and label support via listings
' caption={...}
and label=...
is dropped in lieu of a manual alternative. This way lstlisting
environments are always using a incrementally different counter in the background, thereby avoiding the hyperref
duplicate destination warning.
\documentclass{article}
\usepackage{listings}
\usepackage{hyperref}
\newcommand{\listingcaption}[2]{%
\parbox{0.95\textwidth}{% Width of caption is 95% of \textwidth
\leftskip=0pt plus.5fil% These 3 lines allow for a
\rightskip=0pt plus-.5fil% justification=centerlast option similar
\parfillskip=0pt plus1fil% to that offered by the `caption` package
\small \textbf{#1~\thealgorithm}.\ #2% Caption formatting
}%
}
% ================== ALGORITHM ==================
\newcounter{algorithm}
%\renewcommand{\thealgorithm}{\thesection.\arabic{algorithm}}% Algorithm counter definition
\newcommand{\algorithmprehook}[2]{%
\refstepcounter{algorithm}% Increment counter for correct reference
\listingcaption{Algorithm}{#1}% Algorithm caption
\label{#2}% Label algorithm
}
\lstnewenvironment{algorithm}[3][]{% \begin{algorithm}[<listings options>]{<caption>}{<label>}...
\algorithmprehook{#2}{#3}% Algorithm pre-hook
\lstset{#1}% Set listings options
} {}% ...\end{algorithm}
\def\algorithmautorefname{Algorithm}% Autoref caption
% ================== PROGRAM ==================
\newcounter{program}
%\renewcommand{\theprogram}{\thesection.\arabic{program}}% Program counter definition
\newcommand{\programprehook}[2]{%
\refstepcounter{program}% Increment counter for correct reference
\listingcaption{Program}{#1}% Program caption
\label{#2}% Label program
}
\lstnewenvironment{program}[3][]{% \begin{program}[<listings options>]{<caption>}{<label>}...
\programprehook{#2}{#3}% Program pre-hook
\lstset{#1}% Set listings options
} {}% ...\end{program}
\def\programautorefname{Program}% Autoref caption
\begin{document}
\pagestyle{empty}
\begin{algorithm}[]{My first algorithm. This is an extremely long caption, giving a detailed %
description of the context and code. Justification is ``centerlast''}{alg:firstalgorithm}
Here is some algorithm code;
Then some more code;
And it ends here.
\end{algorithm}
\begin{program}[]{My first program}{prg:firstprogram}
Here is some program code;
Which is a little shorter.
\end{program}
\begin{algorithm}[]{My second algorithm}{alg:secondalgorithm}
The final algorithm code is very short.
\end{algorithm}
\autoref{alg:firstalgorithm}, \autoref{prg:firstprogram}, \autoref{alg:secondalgorithm}
\end{document}
The macro \listingcaption{<caption label>}{<caption>}
, which provides the manual caption support, takes 2 mandatory arguments. <caption label>
is the type of label (Algorithm or Program in this case) and <caption>
is the actual caption. The formatting of the caption is similar to the specification
\captionsetup[<float type>]{%
font=small,%
format=plain,%
labelsep=period,%
labelfont=bf,%
justification=centerlast%
}
supported by the caption
package. The option justification=centerlast
was obtained from this recent blog entry, originally suggested by Victor Eijkhout's TeX by Topic.
When using the float
package for managing captions, counters and \listof...
entries, it is advisable to also forego using the listings
options for caption={...}
and label=...
.
Best Answer
The
\autoref
command tries to detect the underlying counter for the reference, this islstlisting
in this case and looks for a corresponding\lstlistingautorefname
, which is not defined so far. This has to be provided then.The unfortunate feature for this that each
lstlisting
environment still has the same counter. And othernon-algorithm
environments fromlistings
will now provide the wrongautoref
- name.