3

I'm trying to write a lstlisting-environment which sets the filename as line 0. I tryed

\documentclass{article}
\usepackage[utf8]{inputenc}

\usepackage{listings}

\lstset{numbers=left}

% @param 1 : filename
\lstnewenvironment{code}[1]{\setcounter{lstlisting}{0}, #1}{}


\begin{document}

\begin{code}[main.cpp]
#include <iostream>
using namespace std::cout

int main(void){
    cout << "Hello World";
}
\end{code}

\end{document}

but it didn't work. Any ideas?

4
  • 2
    Should it look like \begin{lstlisting}[firstnumber=0] main.cpp? Wouldn't that be easier? – LaRiFaRi Aug 17 '15 at 13:17
  • 1
    [...] sets the filename as line 0. What do you mean by that? – jub0bs Aug 18 '15 at 8:51
  • @Jubobs, I believe what OP means is that in their example, the result would be like "0. main.cpp <newline> 1. #include <iostream> etc". – Pouya Aug 20 '15 at 9:51
  • @Pouya You may be right :) but I don't think that's such a good idea. – jub0bs Aug 20 '15 at 9:58
5

Think twice

Are you suggesting inserting the filename at the top of your listing, on a line numbered by 0, as if it were a line of code? I think that's a bad idea: you run the risk of confusing your readers.

Typeset the filename as the listing's title

A better alternative, in my opinion, is to typeset the filename as the listing's title, by passing the parameter to the title key; see below.

enter image description here

Besides, in your example, you define your code environment so that it accept a mandatory parameter, but you use it as if it accepted an optional one; that's not right. Anyway, a better approach is to allow for an optional argument alongside the mandatory one, so you can still pass options to the underlying listings environment:

\lstnewenvironment{code}[2][]{%
  \lstset{%
    numbers = left,
    title   = #2,
    #1,
  }%
}{}

Code

\documentclass{article}

\usepackage{listings}

\lstnewenvironment{code}[2][]{%
  \lstset{%
    numbers = left,
    title   = #2,
    #1,
  }%
}{}

\begin{document}

\begin{code}{main.cpp}
#include <iostream>
using namespace std::cout

int main(void){
    cout << "Hello World";
}
\end{code}

\end{document}

External listings: how to programmatically use the filename as title

(See daleif's comment)

If you're inserting an external file with \lstinputlisting and want to programmatically typeset the relative path to that file, or just its filename, as title of that listing, you can do as in the following example.

enter image description here

Code

\documentclass{article}

\usepackage[T1]{fontenc} % <-- to correctly print underscores
\usepackage{listings}
\usepackage{filecontents}

% assuming folder "./foo" exists...
\begin{filecontents*}{foo/my_main_program.cpp}
#include <iostream>
using namespace std::cout

int main(void){
    cout << "Hello World";
}
\end{filecontents*}

\makeatletter
\newcommand\inputcode[2][]{%
  \filename@parse{\detokenize{#2}}
  \lstinputlisting[%
    numbers = left,
    % title   = \lstname,                    % <-- relative path
    title   = \filename@base.\filename@ext,  % <-- only the filename
    #1,
  ]{#2}%
}
\makeatother

\begin{document}

\inputcode{foo/my_main_program.cpp}

\end{document}
9
  • What if main.cpp is an external file. Can \lstinputlisting be hacked such that it automatically adds the filename as the title? Then one does not have to type this twice, and thus reduces human error – daleif Aug 20 '15 at 11:24
  • 1
    @daleif Sure; see my edit. – jub0bs Aug 20 '15 at 11:59
  • Where does \filename@parse and friends come from? The kernel? – daleif Aug 20 '15 at 12:07
  • 1
    @daleif Yes; see this answer by David. I'm not sure whether \filename@parse is very portable. – jub0bs Aug 20 '15 at 12:10
  • 1
    @daleif See my last edit. Using detokenize was enough to fix the underscore problem. – jub0bs Aug 23 '15 at 11:00

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.