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.

Does anybody know how to use labels inside a code listing that it looks something similarly like this:

labels inside a code listening

I know that it's easier to use the line number but I prefer using some labels.

share|improve this question
    
add comment

migrated from stackoverflow.com Dec 4 '12 at 20:21

This question came from our site for professional and enthusiast programmers.

1 Answer

up vote 11 down vote accepted

The following example defines a new counter llabel for the listings' markings. Package pifont is used to get the symbols, therefore the markings are limited to the range of 1 upto 10. Otherwise, package tikz can be used to draw own symbols without this limitation.

Macro \llabel takes a symbolic name that can be used later for \ref. It needs to be executed right at the beginning of the line, because then its position is known. The label is put to the left with the distance \llabelsep from the listings line number. To get \llabel executed inside the listings the mathescape feature of package listings is used.

\documentclass{article}
\usepackage{listings}
\usepackage{xcolor}
\usepackage{pifont}

\makeatletter

\AtBeginDocument{%
  % Counter `lstlisting' is not defined before `\begin{document}'
  \newcounter{llabel}[lstlisting]%
  \renewcommand*{\thellabel}{%
    \ifnum\value{llabel}<0 %
      \@ctrerr
    \else
      \ifnum\value{llabel}>10 %
        \@ctrerr
      \else
        \protect\ding{\the\numexpr\value{llabel}+201\relax}%
      \fi
    \fi
  }%
}
\newlength{\llabelsep}
\setlength{\llabelsep}{5pt}

\newcommand*{\llabel}[1]{%
  \begingroup
    \refstepcounter{llabel}%
    \label{#1}%
    \llap{%
      \thellabel\kern\llabelsep
      \hphantom{\lst@numberstyle\the\lst@lineno}%
      \kern\lst@numbersep
    }%
  \endgroup
}
\makeatother

\begin{document}
\setcounter{section}{2}
\subsection{Hello, world!}  
\begin{lstlisting}[
  language=C,
  numbers=left,
  numberstyle=\small\itshape,
  stepnumber=1,
  frame=lines,
  backgroundcolor=\color{yellow!25},
  mathescape,
]   
$\llabel{header}$#include <stdio.h>

/* This is a comment */
$\llabel{main}$int main()
{
$\llabel{hello}$    printf("Hello, world!\n");
$\llabel{exit}$    return 0;
}

/* Another function */
$\llabel{foobar}$int foobar()
{
    return 0;
}
\end{lstlisting}
We first include the \verb|stdio.h| header file \ref{header}.
We then declare the \verb|main| function \ref{main}.
We then print ``Hello, world!'' \ref{hello}.
Finally, we return value 0 \ref{exit}.
Another function \verb|foobar| is defined in \ref{foobar}.
\end{document}

Result

It is also possible to have source files that keep working by using special markers and using option

escapeinside={/@}{@/}

instead of mathescape:

/*@\llabel{header}@*/#include <stdio.h>

/* This is a comment */
/*@\llabel{main}@*/int main()
{
/*@\llabel{hello}@*/    printf("Hello, world!\n");
/*@\llabel{exit}@*/    return 0;
}

/* Another function */
/*@\llabel{foobar}@*/int foobar()
{
    return 0;
}

Putting \llabel at end of line

The following variant allows to put \llabel anywhere on the source line, also the end of line, where it does not disrupt the formatting. For this purpose the line marker is also remembered by a label with the line number in its name. The marker is then put along the line number hooking into numberstyle:

\documentclass{article}
\usepackage{listings}
\usepackage{xcolor}
\usepackage{pifont}

\makeatletter
\AtBeginDocument{%
  % Counter `lstlisting' is not defined before `\begin{document}'
  \newcounter{llabel}[lstlisting]%
  \renewcommand*{\thellabel}{%
    \ifnum\value{llabel}<0 %  
      \@ctrerr
    \else
      \ifnum\value{llabel}>10 %
        \@ctrerr
      \else
        \protect\ding{\the\numexpr\value{llabel}+201\relax}%
      \fi
    \fi  
  }%   
}   
\newlength{\llabelsep}
\setlength{\llabelsep}{5pt}

\newcommand*{\llabel@name}{%
  llabel\the\value{lstlisting}.\the\lst@lineno
}
\newcommand*{\llabel}[1]{%
  \begingroup
    \refstepcounter{llabel}%
    \label{#1}%
    \label{\llabel@name}%
  \endgroup
}
\newcommand*{\llabelput}{%
  \@ifundefined{r@\llabel@name}{%
  }{%
    \ref{\llabel@name}%
    \kern\llabelsep
  }%
}   
\makeatother

\begin{document}
\setcounter{section}{2}
\subsection{Hello, world!}
\begin{lstlisting}[
  language=C,
  numbers=left,
  numberstyle=\small\itshape\llabelput,
  stepnumber=1,
  frame=lines,
  backgroundcolor=\color{yellow!25},
  columns=flexible,
  escapeinside={/*@}{@*/},
]
#include <stdio.h> /*@\llabel{header}@*/

/* This is a comment */
int main() /*@\llabel{main}@*/
{
    printf("Hello, world!\n"); /*@\llabel{hello}@*/
    return 0; /*@\llabel{exit}@*/
}

/* Another function */
int foobar() /*@\llabel{foobar}@*/
{
    return 0;
}   
\end{lstlisting}
We first include the \verb|stdio.h| header file \ref{header}.
We then declare the \verb|main| function \ref{main}.
We then print ``Hello, world!'' \ref{hello}.
Finally, we return value 0 \ref{exit}.
Another function \verb|foobar| is defined in \ref{foobar}.
\end{document}

This should also work with an external file instead of the embedded listings.

share|improve this answer
    
is it also possible to use label if the code is stored external in a *.cpp file? –  ei.schinken Dec 5 '12 at 10:24
    
Awesome. Referencing works fine but the llabel doesn't show up in the lstlisting. –  ei.schinken Dec 5 '12 at 14:37
    
@ei.schinken The markers in the listing of the latest variant is based on the output of the line number: no markers without line numbers. –  Heiko Oberdiek Dec 5 '12 at 14:53
    
Now it works properly except of the fact that it produces two reference labels if I'm using it on a line of code after an empty line of code. –  ei.schinken Dec 5 '12 at 15:24
    
@ei.schinken The latter variant that allows the comment with the \llabel in the middle or end of the line needs two \label, the second internal \label is used to get a relation between the marker and the line number. –  Heiko Oberdiek Dec 5 '12 at 15:40
add comment

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.