How to keep indentations in Python code copied from LaTeX PDF?
The pdfTeX has command \pdffakespace
to insert a space into the document. This space is invisible, but it is taken into account during text copying.
So, my first idea was to insert \pdffakespace
after each space at the beginning of lines, but unfortunately, it results in spaces doubling in the copied text (one space comes from \pdffakespace
and another is generated by Acrobat Reader automatically from TeX's \hskip
).
Next idea was to count the number of leading spaces in the line and insert the necessary number of \pdffakespace
after those spaces. Unfortunately, Acrobat Reader trims that spaces to a single one (in spite of the fact that the sequence of space commands [( )]TJ
is actually presented in the generated PDF file).
But finally, I've found a tricky solution: group spaces into pairs and replace them with a sequence of \pdffakespace
and \hskip
of double space width. Starting with a standard preamble to make @
a letter
\makeatletter
we redefine the \@verbatim
command by adding \hook@par
at the end of \par
command definition (to process text after line break):
\def\@verbatim{\trivlist \item\relax
\if@minipage\else\vskip\parskip\fi
\leftskip\@totalleftmargin\rightskip\z@skip
\parindent\z@\parfillskip\@flushglue\parskip\z@skip
\@@par
\language\l@nohyphenation
\@tempswafalse
\def\par{%
\if@tempswa
\leavevmode \null \@@par\penalty\interlinepenalty
\else
\@tempswatrue
\ifhmode\@@par\penalty\interlinepenalty\fi
\fi\hook@par}% <=== HERE
\let\do\@makeother \dospecials
\obeylines \verbatim@font \@noligs
\everypar \expandafter{\the\everypar \unpenalty}%
}
Then we create a counter to count spaces at the beginning of lines
\newcount\nspaces
reset this counter at the beginning of lines, and count the sequence of spaces
\def\hook@par{\nspaces=0\relax\check@space}
\def\check@space{\futurelet\@let@token\do@check@space}
\def\do@check@space{%
\ifx\@let@token\@xobeysp%
\advance\nspaces 1%
\expandafter\skip@space%
\else%
\ifnum\nspaces>0%
\print@spaces%
\fi%
\fi}
\def\skip@space#1{\check@space}
And finally, we print paired spaces (with a special treat for the odd number of spaces, in this case, we finally out \pdffakespace
following a single-space \hskip
that will be merged with the previous \hskip
and results in a single space during text copying)
\def\print@spaces{%
\leavevmode\nobreak
\loop%
\pdffakespace%
\nobreak\hskip\dimexpr 2\fontdimen2\font\relax%
\advance\nspaces by -2\relax%
\unless\ifnum\nspaces<2\repeat%
\ifnum\nspaces>0%
\nobreak\hskip\fontdimen2\font\relax%
\pdffakespace%
\fi}
In the end, don't forget to restore @
back:
\makeatother
That's all. Voilà.