Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

In my document I want several different custom listing environments. The solution from fraktalek works like a charm, except for one thing: \autoref doesn't work for me. I have tried the following:

\newcounter{algorithm}
\lstnewenvironment{algorithm}[1][]{
        \renewcommand\lstlistingname{Algorithm}
        \setcounter{lstlisting}{\value{algorithm}}
        \lstset{#1}
} {\addtocounter{algorithm}{1}}

\newcounter{program}
\lstnewenvironment{program}[1][]{
        \renewcommand\lstlistingname{Program}
        \setcounter{lstlisting}{\value{program}}
        \lstset{#1}
} {\addtocounter{program}{1}}

\def\algorithmautorefname{Algorithm}
\def\programautorefname{Program}

But, in my document,

\autoref{alg:firstalgorithm}, \autoref{prg:firstprogram}, \autoref{alg:secondalgorithm}

returns

Listing 1.1, Listing 1.1, Listing 1.2.

The separate numbering is correct, but autoref does not recognize the separate counters. However, if I use

\def\lstlistingautorefname{Code fragment}

instead, the result changes to

Code fragment 1.1, Code fragment 1.1, Code fragment 1.2.

I have tried putting this command inside the \lstnewenvirontment commands, but this again gave

Listing 1.1, Listing 1.1, Listing 1.2

as a result. Obviously, I would like to result to be

Algorithm 1.1, Program 1.1, Algorithm 1.2.

Any thoughts on how to achieve this?

share|improve this question

2 Answers 2

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}

Alternative lstlisting environments (algorithm+program) with correct caption, counter and hyperlinks

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=....

share|improve this answer
    
This works, and I now understand the problem a bit better. The lack of support for lists of algorithms is not a problem indeed, although I'm working on a rather large document (a currently ca. 160 page algorithms & programming exercise book). –  MartinKS Aug 6 '11 at 10:21
    
With this solution, two new questions arise: 1) is there a difference between \renewcommand{\theprogram}{\thesection.\arabic{program}}% and \numberwithin{program}{section} (both seem to give the desired result) and 2) is it possible to use the formatting defined by the caption package (in this case \usepackage[font=small,format=plain,labelsep=period, labelfont=bf, justification=centerlast]{caption}? –  MartinKS Aug 6 '11 at 10:28
1  
@MartinKS: 1) Yes. \renewcommand{\theprogram}{\thesection.\arabic{program}} only redefines the way the counter program is typeset, while \numberwithin{program}{section} also executes \@addtoreset{program}{section}, meaning program will be reset (effectively \setcounter{program}{0}) whenever you use \section[..]{...}. 2) I've updated my answer to reflect the settings you requested from the caption package. This was done by adding a macro \listingcaption{<caption label>}{<caption>} that now contains the relevant formatting. –  Werner Aug 6 '11 at 15:39
    
I have discovered a major flow in your solution. I have also found a way to avoid this problem and solve the problem in a different way. I will post that solution separately. The problem is that when you drop the listings caption option, the caption becomes separated from the code if the float option from the listings package is used for the environment. It seems that the caption is no longer connected to the floating algorithm/program environment. –  MartinKS Aug 6 '11 at 16:43
    
This is true, since the caption is inherently separate (it is inserted manually) from the newly defined listings environment. You never suggested that your listing should be able to float using listings' float option. That's why I suggested using the float package. This should allow the two to float together. –  Werner Aug 6 '11 at 16:49
up vote 2 down vote accepted

After Werner's solution, I arrived at the problem that I could no longer let the new environments float.

After some further research, I now can present a new way to tackle the original problem. Instead of creating a new float using \lstnewenvironment{algorithm}, you can also create a floating container and put a non-floating lstlisting-environment in it. Werner suggested to use the float package. Since I have adopted floatrow for other floats in my documents, I have use that package here too. The floatrow package extends the layout possibilities for floats and works well together with caption.

We begin with loading the necessary packages

\usepackage[font=small,format=plain,labelsep=period,
    labelfont=bf, justification=centerlast]{caption}    
\usepackage{floatrow}
\usepackage{listings}

Next, we create the desired floating containers with floatrow

\DeclareNewFloatType{algorithm}{name=Algorithm, placement=htbp, within=section}
\DeclareNewFloatType{codefragment}{name=Code fragment, placement=htbp,within=section}

The name will be used for captions and references, within specifies that the new floats will be numbered within sections.

We want captions to be placed above our newly created floats. Since floatrow handles the caption position and puts them below floats by default (whatever the place of \caption inside the float), we have to specify this by

\floatsetup[algorithm]{style=plaintop}
\floatsetup[codefragment]{style=plaintop}

and probably also

\floatsetup[table]{style=plaintop}

Now, in our document, we can create an algoritm or code fragment with

\begin{algorithm}
\caption{Hello world!}
\label{alg:myfirstalgorithm}
\begin{lstlisting}
Hello world!
How are you today?
\end{lstlisting}
\end{algorithm}

\begin{codefragment}
\caption{Hello world!}
\label{alg:myfirstalgorithm}
\begin{lstlisting}
Hello world!
How are you today?
\end{lstlisting}
\end{codefragment}

This solutions allows the listings to float with the desired caption. It is also easy to create a list the new float types:

\listof{algorithm}{List of Algorithms}
\listof{codefragment}{List of Code fragments}

By creating an appropriate floatbox with the floatrow package, it would also be possible to compare code fragments side by side easily. Here follows a more elaborate example, with separate formatting for pseudo code and C++/matlab code.

\documentclass{article}

% math  
\usepackage{amsmath}                    % ams math
\usepackage{amssymb}                    % ams symbols

% fonts & typesetting
\usepackage{mathpazo}               % Palatino & Pazo math
\usepackage[scaled=0.85]{berasans}  % bera sans and mono scaled to fit with Palatino
\usepackage[scaled=0.85]{beramono}
\usepackage{microtype}                  % better typesetting
\usepackage[T1]{fontenc}                % font encoding
\usepackage[utf8x]{inputenc}            % input encoding
\usepackage{textcomp}                   % required for the upquote option of the listings package

\usepackage[colorlinks=true]{hyperref}
\usepackage[font=small,format=plain,labelsep=period,
    labelfont=bf, justification=centerlast]{caption}    % nice captions
\usepackage{floatrow}
\usepackage{listings}

% create new numbered floats for different types of listings
\DeclareNewFloatType{algorithm}{name=Algorithm, placement=htbp, within=section}
\DeclareNewFloatType{codefragment}{name=Code fragment, placement=htbp,within=section}

% captions above code floats
\floatsetup[algorithm]{style=plaintop}
\floatsetup[codefragment]{style=plaintop}


% pseudo language definition
\lstdefinelanguage{pseudo}{
morekeywords={for, for all, while, do, end, if, then, else, return, divides, min, max, require, ensure, print},
sensitive=false,
mathescape=true,
escapechar=`}

% pseudo style definition
\lstdefinestyle{pseudo}{
language=pseudo,
basicstyle=\rmfamily,
keywordstyle=\bfseries,
columns=[l]fullflexible,    
showstringspaces=false,
numbers=left,       
numberstyle=\footnotesize,
tabsize=2,
aboveskip={0pt},
belowskip={0pt},
frame=lines}

% normal code style definition
\lstdefinestyle{realcode}{
    basicstyle=\ttfamily,
    keywordstyle=\bfseries,
    commentstyle=\textit,
    numberstyle=\footnotesize,
    showstringspaces=false,
    numbers=left,
    tabsize=2,
    breaklines=true,
    breakatwhitespace=false,
    aboveskip={0pt},
    belowskip={0pt},
    upquote=true,
    extendedchars=true,
    frame=lines,
    columns=[c]fixed}

% Matlab and C++style definition
\lstdefinestyle{matlab}{language=matlab,style=realcode}     
\lstdefinestyle{C++}{language=C++,style=realcode}       


\begin{document}
\pagestyle{empty}

\listof{algorithm}{List of Algorithms}
\listof{codefragment}{List of Code fragments}

\section{Computing $N!$}

Check out the pseudo code in \autoref{alg:myfirstalgorithm}, and then the Matlab and C++ equivalents in  \autoref{alg:myfirstprogram} and \autoref{alg:mysecondprogram}.

\begin{algorithm}
\caption{Compute $N!$.}
\label{alg:myfirstalgorithm}
\begin{lstlisting}[style=pseudo]
$z \gets 1$ 
for $k\in[1,\dotsc,N]$ do
    $z \gets z\cdot k$
return $z$
\end{lstlisting}
\end{algorithm}

\begin{codefragment}
\caption{Compute $N!$, Matlab implementation.}
\label{alg:myfirstprogram}
\begin{lstlisting}[style=matlab]
function z = computefactorial(N)
    z = 1;
    for k = 1 : N
        z = z * k;
    end
end
\end{lstlisting}
\end{codefragment}

\begin{codefragment}
\caption{Compute $N!$, C++ implementation.}
\label{alg:mysecondprogram}
\begin{lstlisting}[style=C++]
int z = computefactorial(int N)  { 
    z = 1;
    for (int k = 1; k <= N; k++) { 
        z = z * k;
    }
    return z;
}
\end{lstlisting}
\end{codefragment}



\end{document}

The output of this is

output of code

A weakness of this method is that in the document, you have to nest two environments. This gives more clutter than Werner's solution.

Ideally, the \lstnewenvironment action should be modified to create a seperate counter for newly generated environments.

Suggestions and remarks are still very welcome! This is the first time I'm diving this deep in the details, but I'm enjoying it!

share|improve this answer
    
This looks great. It is not uncommon (=common?) to have nested environments. For example, using the tabular environment inside the (floating) table environment is the de facto way of presenting standard tables in LaTeX. –  Werner Aug 6 '11 at 18:15
1  
In my opinion, line numbers are not so useful. Their existence makes the code look stuffy. –  xport Aug 7 '11 at 12:37

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.