4

I have a number of code examples annotated with a number set by a counter, lstNoteCounter and referred to in the text below the code: My markup works, but it isn't convenient for a large document:

\documentclass{article}
\usepackage{listings}
\lstset{
   basicstyle=\footnotesize\ttfamily, % Standardschrift
   escapechar=¢,
   language=python,
 }
\usepackage{pifont}     % dings for margin numbers
\usepackage{ifthen}
\newcounter{lstNoteCounter}
\newcommand{\lnnum}[1]{% Print pifont circled number for line label
\noindent
\ifcase#1%
% nothing for 0
\or\normalsize\ding{202}%
\or\normalsize\ding{203}%
\or\normalsize\ding{204}%
\or\normalsize\ding{205}%       % in practice, we continue to 9
\else{NUM TOO HIGH}%
\fi%
}

\newcommand*{\lnote}{%
\stepcounter{lstNoteCounter}\vbox{\llap{{\lnnum{\thelstNoteCounter}}\hskip 1em}}%
}

\newcommand*{\lnoteref} {%
\stepcounter{lstNoteCounter}{\lnnum{\thelstNoteCounter}\hskip 0.5em}%
}


\begin{document}

\begin{lstlisting}[frame=lines]
¢\lnote¢def cosec(x):
    return 1/math.sin(x)

¢\lnote¢csc = cosec
print(csc(math.pi/3))
\end{lstlisting}
% I have to reset manually HERE:
\setcounter{lstNoteCounter}{0}

\lnoteref There is no \texttt{cosec} function in Python's \texttt{math} module, so we define one.

\lnoteref Python functions are objects so we can assign them to identifiers.

% I have to reset manually HERE:
\setcounter{lstNoteCounter}{0}

\begin{lstlisting}[frame=lines]
¢\lnote¢def sec(x):
    return 1/math.cos(x)

¢\lnote¢print(sec(math.pi/3))
\end{lstlisting}

% I have to reset manually HERE:
\setcounter{lstNoteCounter}{0}

\lnoteref There is no \texttt{sec} function either, so define one.

\lnoteref Will print \texttt{2}.

\end{document}

How can I automatically reset lstNoteCounter before and after either the lstlisting or lstinputlisting environments so I don't have to issue the commands \setcounter{lstNoteCounter}{0} manually each time?

4

I believe it's better to use the \label-\ref mechanism. If you change your mind about the numbering, you just need to change the definition of \lnnumding. Linking the counter to mocklisting that's stepped at each call of python resets it to zero.

By setting labels you gain more flexibility (at the expense of having to provide a label).

\documentclass{article}
\usepackage{listings}
\usepackage{pifont}     % dings for margin numbers

\lstset{
   basicstyle=\footnotesize\ttfamily, % Standardschrift
   escapechar=¢,
   language=python,
 }

\lstnewenvironment{python}[1][]
 {\stepcounter{mocklisting}\lstset{#1}}
 {}

\newcounter{mocklisting}
\newcounter{lstNoteCounter}[mocklisting]
\renewcommand{\thelstNoteCounter}{\lnnumding{\arabic{lstNoteCounter}}}

\DeclareRobustCommand{\lnnumding}[1]{\mbox{\normalsize\ding{\number\numexpr201+#1}}}

\newcommand*{\lnote}[1]{%
  \refstepcounter{lstNoteCounter}\label{#1}%
  \makebox[0pt][r]{\thelstNoteCounter\hspace{1em}}%
}

\newcommand*{\lnoteref}[1]{\ref{#1}\hspace{.5em}\ignorespaces}


\begin{document}

\begin{python}[frame=lines]
¢\lnote{A}¢def cosec(x):
    return 1/math.sin(x)

¢\lnote{B}¢csc = cosec
print(csc(math.pi/3))
\end{python}

\lnoteref{A} There is no \texttt{cosec} function in Python's \texttt{math} module,
so we define one.

\lnoteref{B} Python functions are objects so we can assign them to identifiers.

\begin{python}[frame=lines]
¢\lnote{C}¢def sec(x):
    return 1/math.cos(x)

¢\lnote{D}¢print(sec(math.pi/3))
\end{python}

\lnoteref{C} There is no \texttt{sec} function either, so define one.

\lnoteref{D} Will print \texttt{2}.

\end{document}

enter image description here

  • Thanks for your help: I'd like to go with your suggestion, but I'm getting stuck applying to to \lstinputlisting as well. How should I define a custom environment for this to work in the same way as lstlisting? – xnx Jan 6 '15 at 20:12
  • @xnx \newcommand{\inputpython}[2][]{\stepcounter{mocklisting}\lstinputlisting[#1]{#2}} – egreg Jan 6 '15 at 22:23
4

The best way I think it is to define a new listing environment that does that at its beginning and at its end.

For example, let's call it mylisting:

\lstnewenvironment{mylisting}[1][]
{\lstset{%
   basicstyle=\footnotesize\ttfamily, % Standardschrift
   escapechar=¢,
   language=python,
   #1
 }%
\setcounter{lstNoteCounter}{0}}
{\setcounter{lstNoteCounter}{0}}

and in your document use mylisting instead of lstlisting.

MWE:

\documentclass{article}
\usepackage{listings}

\lstnewenvironment{mylisting}[1][]
{\lstset{%
   basicstyle=\footnotesize\ttfamily, % Standardschrift
   escapechar=¢,
   language=python,
   #1
 }%
\setcounter{lstNoteCounter}{0}}
{\setcounter{lstNoteCounter}{0}}

\usepackage{pifont}     % dings for margin numbers
\usepackage{ifthen}
\newcounter{lstNoteCounter}
\newcommand{\lnnum}[1]{% Print pifont circled number for line label
\noindent
\ifcase#1%
% nothing for 0
\or\normalsize\ding{202}%
\or\normalsize\ding{203}%
\or\normalsize\ding{204}%
\or\normalsize\ding{205}%       % in practice, we continue to 9
\else{NUM TOO HIGH}%
\fi%
}

\newcommand*{\lnote}{%
\stepcounter{lstNoteCounter}\vbox{\llap{{\lnnum{\thelstNoteCounter}}\hskip 1em}}%
}

\newcommand*{\lnoteref} {%
\stepcounter{lstNoteCounter}{\lnnum{\thelstNoteCounter}\hskip 0.5em}%
}

\begin{document}

\begin{mylisting}[frame=lines]
¢\lnote¢def cosec(x):
    return 1/math.sin(x)

¢\lnote¢csc = cosec
print(csc(math.pi/3))
\end{mylisting}

\lnoteref There is no \texttt{cosec} function in Python's \texttt{math} module, so we define one.

\lnoteref Python functions are objects so we can assign them to identifiers.

\begin{mylisting}[frame=lines]
¢\lnote¢def sec(x):
    return 1/math.cos(x)

¢\lnote¢print(sec(math.pi/3))
\end{mylisting}

\lnoteref There is no \texttt{sec} function either, so define one.

\lnoteref Will print \texttt{2}.

\end{document} 

Output:

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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