7

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?

3 Answers 3

5

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

6
  • 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
    Commented Aug 6, 2011 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
    Commented Aug 6, 2011 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
    Commented Aug 6, 2011 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
    Commented Aug 6, 2011 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
    Commented Aug 6, 2011 at 16:49
3

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!

2
  • 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
    Commented Aug 6, 2011 at 18:15
  • 1
    In my opinion, line numbers are not so useful. Their existence makes the code look stuffy. Commented Aug 7, 2011 at 12:37
3

I have been struggling with the same problem for a couple of days. In my case, I couldn't wrap the listings in floats, since I wanted them to be able to break across multiple pages. And it isn't really desirable for me to break up the caption and label in separate arguments, as in Werner's solution, since I want to be able to use the listing environment's built-in caption support to make it easy to re-style each listing environment using \captionsetup.

I'm no TeXpert, but I've managed to hack together the following solution that seems to work. It's based on similar ideas as discussed elsewhere here on TeX.SX. The implementation is quite rough in the edges, but it's based on the idea of patching \lst@MakeCaption to replace all hard-coded references to the \c@lstlisting counter with per-environment counters. Also, it integrates the fix already presented here to give each listing environment a separate "List of ...".

What I ended up with is a macro \newcustomlstenvironment that wraps \lstnewenvironment, but takes as additional arguments the caption/autoref name to be associated with the new listing environment, and the auxiliary file extension to be used for producing the list of listings.

One problem that I've tried to accommodate (although not very elegantly), is that both the hyperref package and the caption package will wrap the \lst@MakeCaption macro. And depending on the order these two packages have been loaded, one might wrap the macro before the other. Hence, it's a bit of work to identify the actual renamed macro that should be patched in place of \lst@MakeCaption.

Finally, since the listings package provides no means for using \lstinputlisting with different listing environments, I've also wrapped this macro in a \lstinput<name of environment> macro that is environment-specific.

So here is an MWE (although it's not that "minimal"):

\documentclass{book}

% Packages needed by our "hack"
\usepackage{xpatch}
\usepackage[hang,bf,small,hypcap]{caption}
\usepackage{listings}
\usepackage{hyperref}

%%%%%%%%%%%%%%%%%%%%%%%% THE HACK %%%%%%%%%%%%%%%%%%%%%%%%
\makeatletter

\AtBeginDocument{
  \global\@namedef{cmdname@lst@MakeCaption}{lst@MakeCaption}

  \@ifpackageloaded{caption}{
    % If hyperref is loaded before caption, then hyperref will have wrapped \lst@MakeCaption first in \NROrg@lst@MakeCaption
    \xpatchcmd\caption@ORI@lst@MakeCaption{\NROrg@lst@MakeCaption}{\NROrg@lst@MakeCaption}
      {%
        \global\@namedef{cmdname@lst@MakeCaption}{NROrg@lst@MakeCaption}
        \global\@namedef{cmdname@caption@lst@MakeCaption}{lst@MakeCaption}% caption package's override of \lst@MakeCaption
      }{%
        \global\@namedef{cmdname@lst@MakeCaption}{caption@ORI@lst@MakeCaption}
        \global\@namedef{cmdname@caption@lst@MakeCaption}{NROrg@lst@MakeCaption}% caption package's override of \lst@MakeCaption
      }
  }{}
  \@ifpackageloaded{hyperref}{
    % If caption is loaded before hyperref, then caption will have wrapped \lst@MakeCaption first in \caption@ORI@lst@MakeCaption
    \xpatchcmd\NROrg@lst@MakeCaption{\caption@ORI@lst@MakeCaption}{\caption@ORI@lst@MakeCaption}
      {\global\@namedef{cmdname@lst@MakeCaption}{caption@ORI@lst@MakeCaption}}{\global\@namedef{cmdname@lst@MakeCaption}{NROrg@lst@MakeCaption}}
  }{}

  % Define convenient macro for patching the actual (potentially wrapped) \lst@MakeCaption
  \gdef\@patch@lst@MakeCaption#1#2{
    \expandafter\xpatchcmd\csname\cmdname@lst@MakeCaption\endcsname{#1}{#2}{}{\@latex@error{Failed to patch \@backslashchar lst@MakeCaption}\@ehd}
  }

  % Define convenient macro for patching the caption package's re-implementation of \lst@MakeCaption
  \gdef\@patch@caption@lst@MakeCaption#1#2{
    \@ifundefined{cmdname@caption@lst@MakeCaption}{}{
      \expandafter\xpatchcmd\csname\cmdname@caption@lst@MakeCaption\endcsname{#1}{#2}{}{\@latex@error{Failed to patch caption's \@backslashchar lst@MakeCaption}\@ehd}
    }
  }

  % Patch ToC-stuff in \lst@MakeCaption
  \global\@namedef{ext@lstlisting}{lol}
  \global\@patch@lst@MakeCaption
    {\addcontentsline{lol}{lstlisting}}
    {\addcontentsline{\@nameuse{ext@lstlisting}}{lstlisting}}
  \global\@patch@lst@MakeCaption
    {\addcontentsline{lol}{lstlisting}}
    {\addcontentsline{\@nameuse{ext@lstlisting}}{lstlisting}}
}

\gdef\@customlstenvironmenthook#1{
  % Override listing name as shown in caption
  \def\lstlistingname{\@nameuse{#1name}}
  % Override counter as shown in caption
  \expandafter\let\csname c@lstlisting\expandafter\endcsname\csname c@#1\endcsname
  \expandafter\let\csname thelstlisting\expandafter\endcsname\csname the#1\endcsname
  \expandafter\let\csname theHlstlisting\expandafter\endcsname\csname theH#1\endcsname
  %
  % Prepend #1- to \theHlstnumber to make this hyperref counter unique too
  % (otherwise, hyperref will complain with "destination with the same identifier
  % (name{lstnumber.X.Y.Z}) has been already used, duplicate ignored").
  % Thanks to Heiko "the man" Oberdiek!!
  % (see https://groups.google.com/forum/#!msg/comp.text.tex/vO5PaIkhfkE/ouW-6192yd4J)
  \begingroup
    \global\let\gtmp@theHlstnumber\theHlstnumber
    \toks@\expandafter{\theHlstnumber}%
    \xdef\gtmp@theHlstnumber{#1-\the\toks@}%
  \endgroup
  \let\theHlstnumber\gtmp@theHlstnumber
  %
  % Patch \lst@MakeCaption to use the counter of our customized lstlisting environment.
  \@patch@lst@MakeCaption
    {\ifx\lst@@caption\@empty\expandafter\lst@HRefStepCounter\else
      \expandafter\refstepcounter\fi {lstlisting}}
    {\ifx\lst@@caption\@empty\expandafter\lst@HRefStepCounter\else
      \expandafter\refstepcounter\fi {#1}}
  %
  % Patch ToC output from \lst@MakeCaption so we get a separate "List of ..." for each environment.
  \@patch@lst@MakeCaption
    {\addcontentsline{\@nameuse{ext@lstlisting}}{lstlisting}\lst@name}
    {\addcontentsline{\@nameuse{ext@#1}}{#1}\lst@name}
  \@patch@lst@MakeCaption
    {\addcontentsline{\@nameuse{ext@lstlisting}}{lstlisting}{\protect\numberline{\thelstlisting}\lst@@caption}}
    {\addcontentsline{\@nameuse{ext@#1}}{#1}{\protect\numberline\expandafter{\csname the#1\endcsname}\lst@@caption}}
  %
  % Now, patch caption's implementation of \lst@MakeCaption, so we may style each environment differently using \captionsetup
  \@patch@caption@lst@MakeCaption
    {\caption@setoptions{lstlisting}}
    {\caption@setoptions{#1}}
  \@patch@caption@lst@MakeCaption
    {\caption@begin{lstlisting}}
    {\caption@begin{#1}}
}

% Usage: \newcustomlstenvironment
%          {<Environment name>}{<Aux extension>}{<Caption/autref name>}
%          [<number>][<opt. default arg.>]{<starting code>}{ending code>} <-- These are passed directly to \lstnewenvironment
\lst@UserCommand\newcustomlstenvironment#1#2#3#4#{%
  \newcustomlstenvironment@{#1}{#2}{#3}{#4}
}
\gdef\newcustomlstenvironment@#1#2#3#4#5#6{
  % Define separate counter for our customized lstlisting environment.
  % Note: only supports numbering with or without chapter number first (same as lstlisting).
  \lst@ifnumberbychapter
    \newcounter{#1}[chapter]
    \global\@namedef{the#1}%
      {\ifnum \c@chapter>\z@ \thechapter.\fi \arabic{#1}}
  \else
    \newcounter{#1}
    \global\@namedef{the#1}{\arabic{#1}}
  \fi
  %
  % Hyperref has separate counter that needs a unique name.
  % Again, thanks to Mr. Oberdiek!
  \global\@namedef{theH#1}%
    {lst.#1-\csname the\@ifundefined{theHchapter}{}{H}chapter\endcsname .\arabic{#1}}
  %
  % Override autoref names for our environment.
  \global\@namedef{#1name}{#3}
  \global\@namedef{#1autorefname}{#3}
  %
  % Define aux extension
  \global\@namedef{ext@#1}{#2}
  %
  % Create new listing environment as usual, by calling \lstnewenvironment
  % Note: #4 contains something like "[N][]", corresponding to [<number>][<opt. default arg.>]
  %       arguments of \lstnewenvironment (see listings doc, §4.16).
  \lstnewenvironment{#1}#4{
    \@customlstenvironmenthook{#1}
    %
    % Contents passed to {<starting code} of \lstnewenvrionment (e.g. \lstset{#1,..})
    #5%
  }{%
    % Contents passed to {<ending code>} of \lstnewenvrionment
    #6%
  }
  \expandafter\newcommand\csname lstinput#1\endcsname[2][]{
    \begingroup
      \@customlstenvironmenthook{#1}
      #5%
      \lstinputlisting[##1]{##2}
      #6%
    \endgroup
  }
}

\makeatother

%%%%%%%%%%%%%%%%%%%%%%%% EXAMPLE %%%%%%%%%%%%%%%%%%%%%%%%

% Packages used by our example
\usepackage{xcolor}
\usepackage{float}
\usepackage{filecontents}

\begin{filecontents*}{samplecode.c}
#include <stdio.h>

int main(void)
{
  printf("Hello world!\n");
  return 0;
}
\end{filecontents*}

\lstset{captionpos=b,numbers=left,backgroundcolor=\color[rgb]{0.9,0.9,1}}

\makeatletter
\newcustomlstenvironment{codesnippet}{locodesnippet}{Code Snippet}[1][]
  {\lstset{#1,language=C,frame=tb,captionpos=t,backgroundcolor=\color[rgb]{1,1,0.9}}%
   \csname lst@SetFirstNumber\endcsname}
  {\csname lst@SaveFirstNumber\endcsname}

\newcustomlstenvironment{algorithm}{loalgorithm}{Algorithm}[1][]
  {\lstset{#1,language=C,frame=tblr,captionpos=t,backgroundcolor=\color[rgb]{0.9,1,0.9}}%
   \csname lst@SetFirstNumber\endcsname}
  {\csname lst@SaveFirstNumber\endcsname}
\makeatother

\begin{document}
\listof{lstlisting}{List of Listings}
\listof{codesnippet}{List of Code Snippets}
\listof{algorithm}{List of Algorithms}

\chapter{Chapter}

\begin{lstlisting}[caption={Test 1},label={listing:test1},name={test}]
Line 1
Line 2
\end{lstlisting}

\begin{lstlisting}[caption={Test 2},label={listing:test2},name={test}]
Line 3
Line 4
\end{lstlisting}

Referencing normal listings: \autoref{listing:test1}, \autoref{listing:test2}.

\begin{codesnippet}[caption={First snippet},label={snippet:first},name={hello}]
#include <stdio.h>
\end{codesnippet}

\begin{algorithm}[caption={First algorithm},label={alg:first},name={myalg}]
A
B
\end{algorithm}

\begin{codesnippet}[caption={Second snippet},label={snippet:second},name={hello}]
int main(void)
{
  printf("Hello world!\n");
  return 0;
}
\end{codesnippet}

Referencing snippets: \autoref{snippet:first}, \autoref{snippet:second}.

\begin{algorithm}[caption={Second algorithm},label={alg:second},name={myalg}]
C
\end{algorithm}

Referencing algorithms: \autoref{alg:first}, \autoref{alg:second}.

\chapter{Input}

\lstinputcodesnippet[caption={this is my caption},label={snippet:input}]{samplecode.c}

Referencing snippet: \autoref{snippet:input}.

\end{document}

I've used the book class to demonstrate that chapter numbers are properly added as prefix to the reference numbers. The result will look something like this:

List of Listings List of Code Snippets List of Algorithms Chapter Input

As this is my first time posting here, I would be very happy to get some feedback or suggestions! Also, I'm sorry to re-open a several-year-old post, but I thought this might be helpful.

Edit

It turned out that to be able to style the caption of each listing environment differently using \captionsetup, it was also necessary to patch the changes that have been made to \lst@MakeCaption by the caption package. And depending on whether hyperref was loaded before caption or not, the command that needs to be patched in this case could either be the \lst@MakeCaption or the \NROrg@lst@MakeCaption command.

I have updated the code above with the changes needed to get \captionsetup to work. As an example, the following can be added to the end of the preamble

\captionsetup[codesnippet]{box=colorbox,boxcolor={yellow}}
\captionsetup[lstlisting]{box=colorbox,boxcolor={cyan},skip=-1pt}

to make the listing captions look like this: Styled captions

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .