如何保留环境中的所有空白?

如何保留环境中的所有空白?

我正在排版文学程序;它们看起来像这样:

\documentclass{article}

\usepackage{fontspec}
\newfontfamily{\Symbola}{Symbola}
\newfontfamily{\UbuntuMono}{Ubuntu Mono}
\DeclareTextFontCommand{\S}{\Symbola}

\usepackage{xcolor}

\newenvironment{code}{\setlength{\parindent}{0pt}\UbuntuMono}{}

\begin{document}
\begin{code}
  (fold\_left (\S{λ} x \textcolor{red}{y}.  x \S{⊕} \textcolor{red}{y})\\
             (a \S{∷} b \S{∷} c \S{∷} d \S{∷} nil))
\end{code}
\end{document}

我如何确保code环境保留所有空格?具体来说,空格也应存在于生成的 PDF 中:也就是说,从 PDF 复制粘贴也应复制空格。

以下是一些尝试:

  • 使用\hspace{}:查看源时不是很好,并且无法从生成的 PDF 中复制空格。
  • 将所有空格替换为~,并\-在行首添加空格。源代码变得丑陋(不是令人讨厌的),但空格仍然无法复制。
  • \catcode32=12在 的定义中使用code。从对齐角度来看,这可以很好地工作,看起来很完美……但空格仍然无法复制。
  • 使用listings包:会很棒,但它在 Unicode 上失效了,而且我厌倦了literate基于 - 的解决方法
  • 使用fancyvrb包:具有一个escapechar可能有前途的属性,并且源代码中重要的换行符并不是一个交易破坏者,但它似乎很重(?)。理想情况下,我也希望能够内联使用此环境。

我需要什么魔法才能让我的环境尊重所有空间,并使它们可以从 PDF 中复制粘贴?

答案1

重新审视答案

当有人向我指出,除了现代计算机之外,我最初的答案与 OP 能够实现的答案没有什么不同时 \catcode32=12,我又重新审视了一下。当使用 pdflatex 时,我得到了一个完全令人满意的答案,而对于 xelatex,我得到了一个不太令人满意的答案。在这两种情况下,他们首先将空格设为活动字符,然后重新定义为用白色打印特定字符。

已编辑以使空间具有适当的宽度。

-----pdflatex

这里我使用包palatino只是为了确保我不依赖现代计算机的某些特殊方面。这里,我用白色打印的空格“特定字符”是字体中可见的空格lmodern

\documentclass{article}
\usepackage{xcolor}
\usepackage{palatino}
\newsavebox\spacewd
\savebox\spacewd{\texttt{ }}
\newenvironment{code}{\par\catcode32=\active \setlength{\parindent}{0pt}\ttfamily}{\par}
{
\catcode32=\active %
\gdef {\makebox[\wd\spacewd][l]{%
\textcolor{white}{\fontfamily{lmtt}\selectfont\large\smash{\char32}}}}% 
}
\begin{document}
\noindent xyz
\begin{code}
  (fold\_left (\S{λ} x \textcolor{red}{y}.  x \S{⊕} \textcolor{red}{y})\\
             (a \S{∷} b \S{∷} c \S{∷} d \S{∷} nil))
\end{code}
\noindent this is
  a
    test to make    sure all 
      is back to normal
\end{document}

在此处输入图片描述

PDF 复制/粘贴操作如下:

在此处输入图片描述

这正是我们想要的。

-----赛莱特

这里我使用了libertine字体。这里唯一的怪癖是\textvisiblespace占用的水平宽度比\ttfamily空格少,因此为了避免 PDF 将间隔开的\textvisiblespaces 解释为双空格,我制作了\textvisiblespace插入的\large\smashed 以避免 PDF 将其解释为额外的间隙。此外,我使 左\makebox对齐,这样大白色\textvisiblespace就不会覆盖前一个字符。

\documentclass{article}
\usepackage{lmodern}
\usepackage{xcolor}
\usepackage{fontspec,libertine}
\newsavebox\spacewd
\savebox\spacewd{\texttt{ }}
\newenvironment{code}{\par\catcode32=\active \setlength{\parindent}{0pt}\ttfamily}{\par}
{
\catcode32=\active %
\gdef {\makebox[\wd\spacewd][l]{\textcolor{white}{\large\smash{\textvisiblespace}}}}% 
}

\begin{document}
\noindent xyz
\begin{code}
  (fold\_left (\S{λ} x \textcolor{red}{y}.  x \S{⊕} \textcolor{red}{y})\\
             (a \S{∷} b \S{∷} c \S{∷} d \S{∷} nil))
\end{code}
\noindent this is
  a
    test to make    sure all 
      is back to normal
\end{document}

在此处输入图片描述

从 PDF 复制/粘贴的结果为

在此处输入图片描述

其中另一个字符代替空格,在本例中我指定了\textvisiblespace。我验证了我的 TeXworks 编辑器可以全局用真实空格替换不可见的空格字符。

原始答案

这个答案是基于我一年前\obeyspacescode环境中使用以保留空格的建议。但是,正如评论中指出的那样,它不会检测行上的前导空格。

为了解决这个问题,我使用了 egreg 的答案在纯 Tex 宏中使用行尾分隔符。有了它,我能够在环境中截取行尾 (EOL) code。我利用这个事实在 中将 放在\mbox{}每个新行的开头code,以便\obeyspaces可以检测到每个后续行的前导空格。

对我来说,最难的部分是在退出时将 EOL 恢复到其正确位置code。我通过对标志宏进行测试来完成此操作,该标志宏在退出代码期间\endthis从 更改F为。Tcode

但是,从 PDF 复制/粘贴空白的根本问题仍然存在。

\documentclass{article}

%\usepackage{fontspec}
%\newfontfamily{\Symbola}{Symbola}
%\newfontfamily{\UbuntuMono}{Ubuntu Mono}
%\DeclareTextFontCommand{\S}{\Symbola}

\usepackage{xcolor}

\newenvironment{code}
{\par\setlength{\parindent}{0pt}\obeyspaces\ttfamily\gdef\endthis{F}\mymacro}
{\gdef\endthis{T}\par}

\def\mymacro{%
  \if\endthis T\def\next{}\else\def\next{\begingroup\catcode`\^^M=12 \xmymacro}\fi\next}
{\catcode`\^^M=12 %
 \gdef\xmymacro#1^^M{\mbox{}#1\endgroup\mymacro}%
}
\begin{document}
\noindent xyz
\begin{code}
  (fold\_left (\S{λ} x \textcolor{red}{y}.  x \S{⊕} \textcolor{red}{y})\\
             (a \S{∷} b \S{∷} c \S{∷} d \S{∷} nil))
\end{code}
\noindent this is
  a
    test to make    sure all 
      is back to normal
\end{document}

在此处输入图片描述

\catcode32=12OP 提到的 的定义中的 的使用code是类似的,但它产生了“视觉空间”

在此处输入图片描述

相关内容