How to make listings code indentation remain unchanged when copied from PDF?

So I am using listings package for code examples. But there is a problem. When I copy the code examples from the final PDF document, they are usually not the same - the indentation is gone, there are random spaces after parenthesis, etc. Does anyone know how to make sure that the code that I copy from the final document is the same as I wrote it in the LaTeX document?

Here is what I mean. Compile this document:

\documentclass[12pt,oneside]{memoir}

\usepackage{listings}
\usepackage[T1]{fontenc}
\usepackage{xcolor}
\usepackage{textcomp}

\definecolor{codebg}{HTML}{EEEEEE}
\definecolor{codeframe}{HTML}{CCCCCC}

\lstset{language=Awk}
\lstset{backgroundcolor=\color{codebg}}
\lstset{frame=single}
\lstset{framesep=10pt}
\lstset{rulecolor=\color{codeframe}}
\lstset{upquote=true}
\lstset{basicstyle=\ttfamily}
\lstset{showstringspaces=false}

\begin{document}

This code example prints out all users on your system:

\begin{lstlisting}[language=c]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_LINE_LEN 1024

int main() {
char line[MAX_LINE_LEN];
FILE *in = fopen("/etc/passwd", "r");
if (!in) exit(EXIT_FAILURE);

while (fgets(line, MAX_LINE_LEN, in) != NULL) {
char *sep = strchr(line, ':');
if (!sep) exit(EXIT_FAILURE);
*sep = '\0';
printf("%s\n", line);
}
fclose(in);
return EXIT_SUCCESS;
}
\end{lstlisting}

\end{document}


Now compile it, open it, select and copy the code example and paste it in a text editor. Here is the result I get:

# include <stdio .h>
# include <stdlib .h>
# include <string .h>
# define MAX_LINE_LEN 1024
int main () {
char line [ MAX_LINE_LEN ];
FILE *in = fopen ("/ etc / passwd ", "r");
if (! in) exit ( EXIT_FAILURE );
while ( fgets (line , MAX_LINE_LEN , in) != NULL ) {
char * sep = strchr (line , ':');
if (! sep ) exit ( EXIT_FAILURE );
* sep = '\0 ';
printf ("%s\n", line );
}
fclose (in );
return EXIT_SUCCESS ;
}


Jeez! What's this... The indentation is gone. There are spaces in included headers <stdio .h>, there are spaces after parenthesis [ MAX_LINE_LEN ].

Anyone knows how to fix this? I'd like the code examples in my book to be copy/paste-able into a text editor so people can try them out easily.

-
Rather than copying the code from the pdf output, you can make a hyperlink to open the underlying code snippet file. Please wait, I will show you how to do this. :-) – xport Jun 5 '11 at 13:48

To prevent random spaces when copying the text from a listing, you need to use

\lstset{columns=flexible}


But you will now note that the text is not neatly aligned anymore; to solve this, you need to also use

\lstset{keepspaces=true}


This will not solve your problem with spaces disappearing at the beginning of lines when copying. The following hack will produce visible spaces and then make them invisible by coloring them in the background color:

\makeatletter
\def\lst@outputspace{{\ifx\lst@bkgcolor\empty\color{white}\else\lst@bkgcolor\fi\lst@visiblespace}}
\makeatother


This hack is not perfect, however, as the typesetted character is really a visible space, not a space (so searching the pdf for char line will not work) and some PDF readers (like Mac's preview) will copy a visible space. It works under Acrobat Reader and it's extremely pleasant to be able to quickly copy/paste code without problem (perhaps the problem can be circumvented by writing direct PDF code to tell that it's a space, I've never had the time to try). It might also not work with all typewriter fonts.

Here's the full code of your example:

\documentclass[12pt,oneside]{memoir}

\usepackage{listings}
\usepackage[T1]{fontenc}
\usepackage{xcolor}
\usepackage{textcomp}

\definecolor{codebg}{HTML}{EEEEEE}
\definecolor{codeframe}{HTML}{CCCCCC}

\lstset{language=Awk}
\lstset{backgroundcolor=\color{codebg}}
\lstset{frame=single}
\lstset{framesep=10pt}
\lstset{rulecolor=\color{codeframe}}
\lstset{upquote=true}
\lstset{basicstyle=\ttfamily}
\lstset{showstringspaces=false}

\lstset{columns=flexible}
\lstset{keepspaces=true}
\makeatletter
\def\lst@outputspace{{\ifx\lst@bkgcolor\empty\color{white}\else\lst@bkgcolor\fi\lst@visiblespace}}
\makeatother

\begin{document}

This code example prints out all users on your system:

\begin{lstlisting}[language=c]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_LINE_LEN 1024

int main() {
char line[MAX_LINE_LEN];
FILE *in = fopen("/etc/passwd", "r");
if (!in) exit(EXIT_FAILURE);

while (fgets(line, MAX_LINE_LEN, in) != NULL) {
char *sep = strchr(line, ':');
if (!sep) exit(EXIT_FAILURE);
*sep = '\0';
printf("%s\n", line);
}
fclose(in);
return EXIT_SUCCESS;
}
\end{lstlisting}

\end{document}

-
Thanks for the answer Philippe, now I certainly see space characters being copied, but when I paste, I get weird question marks where spaces should be! Look at this paste: pastebin.com/E2bAXzwW . I tried vim and notepad, and both got these question marks. (I use MikTex, btw.) – Peteris Krumins Jun 5 '11 at 21:51
@Peteris: probably that's how the visible space is copied. Which PDF viewer are you using? It works without problem for me when copying from acrobat reader to notepad. – Philippe Goutet Jun 5 '11 at 22:42
I use Foxit reader. I also tried SumatraPDF reader and Google Chrome's built-in reader and I get the same result. I also just tried generating the pdf with TexLive on Linux, and I get the same results again with those question marks all over the place. Not sure what's going on! – Peteris Krumins Jun 6 '11 at 9:36
@Peteris: I can reproduce the problem with Foxit Reader and it disappears if you load the lmodern package. But it's not guaranteed that it will also work with all other viewers. – Philippe Goutet Jun 6 '11 at 18:47

My answer will not answer your question. :-) But I have a good way to manage code snippet inclusion to be easily accessible for the readers. Rather than copying the code from the pdf, it will be better if you allow the readers to open the underlying code file by clicking hyperlinks.

Try compile the following code. I use latex-dvips-ps2pdf compilation steps. You can use pdflatex of course, but don't forget to remove dvips option in \documentclass.

For the sake of easy maintainability, create your own package as follows:

\NeedsTeXFormat{LaTeX2e}[1994/06/01]
\ProvidesPackage{xport}[2011/06/05 v0.01 LaTeX package for my own purpose]
\RequirePackage[utf8x]{inputenc}
\RequirePackage{xcolor}

\RequirePackage{caption}
\captionsetup
{%
font={small,rm},
labelfont={color=Maroon,bf},
justification=justified%
}

\RequirePackage{listings}
\AtBeginDocument
{%
\renewcommand*{\lstlistlistingname}{Code List}%
\renewcommand*{\lstlistingname}{Code}%
}

\lstset
{%
%linewidth=\linewidth,
breaklines=true,
tabsize=3,
showstringspaces=false%
}

\lstdefinestyle{Common}
{%
extendedchars=\true,
language={[Sharp]C},
%alsolanguage={PSTricks},
frame=single,
%===========================================================
framesep=3pt,%expand outward.
framerule=0.4pt,%expand outward.
xleftmargin=3.4pt,%make the frame fits in the text area.
xrightmargin=3.4pt,%make the frame fits in the text area.
%===========================================================
rulecolor=\color{Red}%
}

\lstdefinestyle{A}%
{%
style=Common,
backgroundcolor=\color{Yellow!10},
basicstyle=\scriptsize\color{Black}\ttfamily,
keywordstyle=\color{Orange},
identifierstyle=\color{Cyan},
stringstyle=\color{Red},
}

\newcommand{\IncludeCSharp}[2][style=A]%
{%
\lstinputlisting[#1,caption={\href{#2}{#2}}]{#2}%
}

%to make hyperlinks point to the top of figure or table.
%it must be loaded after hyperref.
\RequirePackage[all]{hypcap}% cannot be used in beamer.

\endinput


In the main input file, you can call \IncludeCSharp as follows:

\documentclass[dvips,dvipsnames,cmyk,12pt]{article}
\usepackage[a4paper,margin=2cm]{geometry}
\usepackage{xport}
\begin{document}

\IncludeCSharp[style=A]{Codes/Program.cs}

\end{document}


The imported C# file is named Program.cs in Codes/ sub directory.

using System;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");//This is a comment.
/*This is a comment too.*/
}
}
}

-
It is my settings for my real books. – xport Jun 5 '11 at 14:08
Thanks! Gonna try it! – Peteris Krumins Jun 5 '11 at 15:01
This is good, but yeah, it doesn't exactly answer the question. Ideally I'd love both - have users be able to copy code correctly from the pdf, and click hyperlinks to open files. Now I know how to do the 2nd but the 1st is still an open question. I'll leave the question open for more answers, maybe someone knows how to achieve correct copy/pasting. (I have seen a lot of PDFs with correct copy/pasting in them!) – Peteris Krumins Jun 5 '11 at 15:33

you can use the following modifcation

\newlength{\lstcolumnwidth}
\settowidth{\lstcolumnwidth}{\ttfamily M}


The indention at the beginning of line isn't a problem by LaTeX. This is a problem of the reader. There are no settings for such case. You can get an odd solution with the following code:

\lstset{showspaces=true}
\makeatletter
\def\lst@visiblespace{\textcolor{codebg}{-}}
\makeatother


With packages like attachefile2 you can attach the original c-file.

-
 Can you improve your answer? I don't really understand what you mean by "the indention isn't able to influence." – Peteris Krumins Jun 5 '11 at 15:03 Thanks for improving your answer! – Peteris Krumins Jun 5 '11 at 15:36 @Macro: where can I find attachefile2? – xport Jun 5 '11 at 15:47 It is part of the oberdieck bundle. I edited my post. – Marco Daniel Jun 5 '11 at 15:51 Thanks. – xport Jun 5 '11 at 15:56