8

I would like to add listings source as attachment to a PDF (created by pdflatex). For \lstinputlisting this is pretty easy:

\RequirePackage{listings}
\RequirePackage{embedfile}

\let\lstinputlistingO=\lstinputlisting
\renewcommand{\lstinputlisting}[2][]{\embedfile{\detokenize{#2}}\lstinputlistingO[#1]{#2}}

but how can I do the same with \begin{listing} ... \end{listing}? (referenced filename should be the something like listing 12)

diabonas
  • 25,784
someonr
  • 8,531

2 Answers2

9

As embedfile can only embed external files, you have to write the content of the environment to a file first. To do this, the capabilities of the listings package, namely the \lst@BeginAlsoWriteFile macro, can be used:

\usepackage{listings}
\usepackage{embedfile}

\makeatletter
\lst@RequireAspects{writefile}

\lstnewenvironment{lstembedlisting}[2][]{%
\bgroup%
\lstset{#1}%
\lst@BeginAlsoWriteFile{#2}%
}
{%
\lst@EndWriteFile%
\embedfile{#2}%
\egroup%
}
\makeatother

This code snippet creates a new environment called lstembedlisting, which can be used like the normal lstlisting, except that it expects an additional filename as a mandatory argument. The code inside the environment is typeset and written to that file at the same time. Afterwards, \embedfile is called to attach it to the PDF.

Full MWE:

\documentclass{article}

\usepackage{listings}
\usepackage{embedfile}

\makeatletter
\lst@RequireAspects{writefile}

\lstnewenvironment{lstembedlisting}[2][]{%
\bgroup%
\lstset{#1}%
\lst@BeginAlsoWriteFile{#2}%
}
{%
\lst@EndWriteFile%
\embedfile{#2}%
\egroup%
}
\makeatother

\begin{document}
\begin{lstembedlisting}[language=TeX]{listing_12.tex}
Hello world!
\bye
\end{lstembedlisting}
\end{document}
diabonas
  • 25,784
5

Since it is tricky working with verbatim content, which is the case when dealing with listings, there is no easy single-command way out in my opinion. A two-step process using the filecontents package, however, is easy. Not as clean as diabonas' answer though...

enter image description here

\documentclass{article}
\usepackage{listings}% http://ctan.org/pkg/listings
\usepackage{embedfile}% http://ctan.org/pkg/embedfile
\usepackage{filecontents}% http://ctan.org/pkg/filecontents

% Automatically embed listings file as attachment with \lstinputlisting
\let\lstinputlistingO=\lstinputlisting
\renewcommand{\lstinputlisting}[2][]{\embedfile{\detokenize{#2}}\lstinputlistingO[#1]{#2}}

\begin{document}

\lstinputlisting{A.tex} % Insert listing and embed in PDF

% Write listing to file
\begin{filecontents*}{B.tex}
Here is some more code
\end{filecontents*}
\lstinputlisting{B.tex} % Insert listing and embed in PDF
\end{document}

filecontents allows for using the filecontents (and filecontents*) environment outside the preamble of your document. If you don't like using filecontents* and would rather use something like \begin{listing}...\end{listing}, you could add the following to your document preamble:

\expandafter\let\expandafter\listing\csname filecontents*\endcsname
\expandafter\let\expandafter\endlisting\csname endfilecontents*\endcsname

However, adapting filecontents in general to accept an optional argument (which would include your listing formatting) is rather difficult, apart from rewriting the package (as far as I know).

This option saves the file first and then inputs it. The opposite approach of setting it first and then embedding it would be more difficult.

Werner
  • 603,163