7

I would like to have the actual line numbers next to my code listings but if I use firstnumber=\inputlineno, this gets evaluated one line too early:

\documentclass{article}
\usepackage{listings}
\lstset{numbers=left, firstnumber=\inputlineno, frame = single}
\begin{document}
\begin{lstlisting}
... here is some great code on line 6 in our file ...
\end{lstlisting}
This is line $\the\inputlineno$ in our file.
\end{document}

line number 5 shown, should be 6

Naively, I want to do firstnumber=\inputlineno+1. How?

Something I already tried was firstnumber=\value{mycounter} and set this counter to the right value at the beginning of the code listing via \AtBeginEnvironment or \lstnewenvironment. Both gave me the error "You can't use `\inputlineno' in horizontal mode.".

  • 1
    Welcome to TeX.SX! Try firstnumber=\numexpr\inputlineno+1\relax. Just out of curiosity: why do you want to use the actual input line number? Could you perhaps expand on your example? – jub0bs May 11 '14 at 21:34
  • Thank you @Jubobs, this works beautifully! Could you post it as an answer so I can properly thank you for it? I kept the example as minimal as possible - my real .lhs file contains a lot of haskell code in literate programming style. So especially for errors coming from the Haskell compiler it is nice to have the actual input line numbers also in the PDF. – m4lvin May 11 '14 at 21:50
  • 1
    The value of \inputlineno corresponds to the line where \begin{lstlisting} is scanned. – egreg May 11 '14 at 21:54
  • @m4lvin No problem. Thanks for satisfying my curiosity. – jub0bs May 11 '14 at 22:04
  • 1
    @Jubobs No, because listings evaluates the initial number before starting to typeset the code. – egreg May 12 '14 at 11:49
5

In listings.sty we find

\def\lst@InitLstNumber{%
     \global\c@lstnumber\lst@firstnumber
     \global\advance\c@lstnumber\lst@advancenumber
     \global\advance\c@lstnumber-\lst@advancelstnum
     \ifx \lst@firstnumber\c@lstnumber
         \global\advance\c@lstnumber-\lst@advancelstnum
     \fi%
     \lst@ifincluderangemarker\else%
         \global\advance\c@lstnumber by 1%
     \fi%
     }

and in lstmisc.sty there's other related code:

\lst@Key{firstnumber}{auto}{%
    \lstKV@SwitchCases{#1}%
    {auto&\let\lst@firstnumber\@undefined\\%
     last&\let\lst@firstnumber\c@lstnumber
    }{\def\lst@firstnumber{#1\relax}}}
\lst@AddToHook{PreSet}{\let\lst@advancenumber\z@}
\lst@AddToHook{PreInit}
    {\ifx\lst@firstnumber\@undefined
         \def\lst@firstnumber{\lst@lineno}%
     \fi}
\gdef\lst@SetFirstNumber{%
    \ifx\lst@firstnumber\@undefined
        \@tempcnta 0\csname\@lst no@\lst@intname\endcsname\relax
        \ifnum\@tempcnta=\z@ \@tempcnta\lst@firstline
                       \else \lst@nololtrue \fi
        \advance\@tempcnta\lst@advancenumber
        \edef\lst@firstnumber{\the\@tempcnta\relax}%
    \fi}
\gdef\lst@SaveFirstNumber{%
    \expandafter\xdef
        \csname\@lst no\ifx\lst@intname\@empty @ \else @\lst@intname\fi
        \endcsname{\the\c@lstnumber}}
\newcounter{lstnumber}% \global
\global\c@lstnumber\@ne % init
\renewcommand*\thelstnumber{\@arabic\c@lstnumber}

So, when firstnumber=\inputlineno is found when processing the options, the internal counter lstnumber is given the current value of \inputlineno, which always is the line number in the file being currently read by TeX, at the point of reading.

Thus the value of \inputlineno is asked for when

\begin{lstlisting}[firstnumber=\inputlineno]

is being processed; for the actual typesetting of line numbers, listings uses the current value of lstnumber.

The workaround is, obviously,

firstnumber=\numexpr\inputlineno+1\relax

making sure the option is on the last line of the options, in case it is not used in a \lstset. So, for instance,

\documentclass{article}
\usepackage{listings}

\begin{document}
\begin{lstlisting}[
  numbers=left,
  frame = single,
  firstnumber=\numexpr\inputlineno+1\relax]
... here is some great code on line 6 in our file ...
\end{lstlisting}
This is line $\the\inputlineno$ in our file.
\end{document}

But the \lstset method is of course better.

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.