30

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.

1
  • 4
    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. :-) Jun 5, 2011 at 13:48

4 Answers 4

17

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}
5
  • @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. Jun 5, 2011 at 22:42
  • 2
    @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. Jun 6, 2011 at 18:47
  • It doesn't work with evince; nor with qpdfview; nor with zathura.
    – Clément
    Aug 7, 2016 at 21:15
  • 1
    I found out that removing the column=flexible or fullflexible solves some problems if I add basicstyle=\fontfamily{pcr}\selectfont... this font family does not create extra spaces... Also I tested your code on my linux pdfviewers (evince and ocular) and did not work... But may be a combination of your answer and the fontfamily I found without flexible columns may solves the problem of copy-pasting from pdf
    – koleygr
    Jul 1, 2017 at 19:42
  • @koleygr I have posted a question here and you solved it partially! (Although the identation does not work). Do you want to answer partially there? And do you know how to fix this? Thank you!
    – manooooh
    Jul 22, 2018 at 4:24
5

you can use the following modifcation

\newlength{\lstcolumnwidth}
\settowidth{\lstcolumnwidth}{\ttfamily M}
\lstset{basicstyle=\ttfamily,basewidth=\lstcolumnwidth,columns=fixed, fontadjust=true} 

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.

2
  • @Macro: where can I find attachefile2? Jun 5, 2011 at 15:47
  • It is part of the oberdieck bundle. I edited my post. Jun 5, 2011 at 15:51
4

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}, 
        commentstyle=\color{Green}% 
}

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

%for beamer, use \hypersetup instead.
\RequirePackage[colorlinks=true,bookmarksnumbered=true,bookmarksopen=true]{hyperref}

%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.*/
        }
    }
}
1
  • It is my settings for my real books. Jun 5, 2011 at 14:08
0

(Please refer to this thread: How make a LaTeX document that generates a PDF from which copy-paste works correctly for empty lines and leading space indentation? , trying to compile all the wisdom from these various partial discussions of this question, in one place.)

You must log in to answer this question.