我想分享一下我遇到的一个问题的解决方案。(这是“回答你自己的问题”的事情之一,而且,这样,人们可以改进它——双重许可MirOS 许可证请。也欢迎对问题类的其他解决方案。
当您有一个列表(使用包lstlisting
中的列表listings
,这似乎是目前推荐的列表)时,有时无法从 PDF 中正确复制和粘贴它。有多种解决方案,但为什么不将列表作为纯文本文件发送呢?
如果您的列表是在单独的文件中,解决方案很简单 - \lstinputlisting
- 但这排除了替换,例如......
\newcommand{\myversion}{1.2}
\begin[escapeinside={〈}{〉}]{lstlisting}
tar -xzf myprogram-〈\myversion{}〉.tgz
\end{lstlisting}
...以及在与周围文本相同的文件中管理列表(以防止它们过时),并且有些人可能更喜欢将单个 PDF 中的所有列表包含在单个列表文件中。
答案1
解决方案(来源)
我深入研究了 Teχ SE 和listings
源代码,最终得出了以下 SSCCE:
% © 2015 mirabilos <[email protected]>, published also under The MirOS Licence
\documentclass{scrartcl}
% used packages
\RequirePackage[utf8]{inputenc}
\RequirePackage[LY1,TS1,T1]{fontenc}
% font for listings
\RequirePackage[varqu,varl]{inconsolata}
% the listings package
\RequirePackage[writefile]{listings}
% some useful basic definitions
\lstset{
basicstyle=\ttfamily,
upquote=true,
keepspaces,
literate=
{á}{{\'a}}1 {é}{{\'e}}1 {í}{{\'i}}1 {ó}{{\'o}}1 {ú}{{\'u}}1
{Á}{{\'A}}1 {É}{{\'E}}1 {Í}{{\'I}}1 {Ó}{{\'O}}1 {Ú}{{\'U}}1
{à}{{\`a}}1 {è}{{\`e}}1 {ì}{{\`i}}1 {ò}{{\`o}}1 {ù}{{\`u}}1
{À}{{\`A}}1 {È}{{\'E}}1 {Ì}{{\`I}}1 {Ò}{{\`O}}1 {Ù}{{\`U}}1
{ä}{{\"a}}1 {ë}{{\"e}}1 {ï}{{\"i}}1 {ö}{{\"o}}1 {ü}{{\"u}}1
{Ä}{{\"A}}1 {Ë}{{\"E}}1 {Ï}{{\"I}}1 {Ö}{{\"O}}1 {Ü}{{\"U}}1
{â}{{\^a}}1 {ê}{{\^e}}1 {î}{{\^i}}1 {ô}{{\^o}}1 {û}{{\^u}}1
{Â}{{\^A}}1 {Ê}{{\^E}}1 {Î}{{\^I}}1 {Ô}{{\^O}}1 {Û}{{\^U}}1
{æ}{{\ae}}1 {Æ}{{\AE}}1 {ß}{{\ss}}1 {œ}{{\oe}}1 {Œ}{{\OE}}1
{ő}{{\H{o}}}1 {Ő}{{\H{O}}}1 {ű}{{\H{u}}}1 {Ű}{{\H{U}}}1
{å}{{\r a}}1 {Å}{{\r A}}1 {ç}{{\c c}}1 {Ç}{{\c C}}1 {ø}{{\o}}1
{©}{{\textcopyright}}1 {™}{\texttrademark}1 {–}{-}1 {§}{\S}1
{£}{{\pounds}}1 {°}{\textdegree{}}1 {„}{{\quotedblbase}}1
{“}{{\textquotedblleft}}1 {”}{{\textquotedblright}}1
{‘}{{\textquoteleft}}1 {’}{{\textquoteright}}1
{«}{\guillemotleft}1 {»}{\guillemotright}1
{…}{{\fontencoding{LY1}\selectfont\symbol{'205}}}1,
columns=flexible,
showstringspaces=false,
extendedchars=true,
breaklines=true,
prebreak=\raisebox{0ex}[0ex][0ex]{\ensuremath{\hookleftarrow}},
frame=single,
showtabs=false,
showspaces=false,
showstringspaces=false,
escapeinside={〈}{〉},
}
% lst dumps definitions
\makeatletter
\newcounter{lstdumps}
\setcounter{lstdumps}{0}
\newcommand{\lstdumpname}{}
\lstnewenvironment{lstdump}[3][]
{\lst@TestEOLChar{#3}%
\lstset{#1}%
\csname\@lst @SetFirstNumber\endcsname%
\stepcounter{lstdumps}%
\renewcommand{\lstdumpname}{ (#2)}%
\lst@BeginAlsoWriteFile{\jobname.lst}%
\immediate\write\lst@WF{-----BEGIN LISTING \thelstdumps\lstdumpname-----}%
}
{
\immediate\write\lst@WF{-----END LISTING \thelstdumps\lstdumpname-----}%
\immediate\write\lst@WF{}%
\endgroup%
\csname\@lst @SaveFirstNumber\endcsname%
}
\lstnewenvironment{lstdumpx}[2][]
{\lst@TestEOLChar{#2}%
\lstset{#1}%
\csname\@lst @SetFirstNumber\endcsname%
\stepcounter{lstdumps}%
\renewcommand{\lstdumpname}{ [unnamed]}%
\lst@BeginAlsoWriteFile{\jobname.lst}%
\immediate\write\lst@WF{-----BEGIN LISTING \thelstdumps\lstdumpname-----}%
}
{
\immediate\write\lst@WF{-----END LISTING \thelstdumps\lstdumpname-----}%
\immediate\write\lst@WF{}%
\endgroup%
\csname\@lst @SaveFirstNumber\endcsname%
}
% usage: \lstdumpesc[file]{pdf} or \lstdumpesc{bothfileandpdf}
\def\lstdumpesc{\@ifnextchar[{\lstdumpesc@two}{\lstdumpesc@one}}
\def\lstdumpesc@one#1{\lst@WFAppend{#1}#1}
\def\lstdumpesc@two[#1]#2{\lst@WFAppend{#1}#2}
\makeatother
% document body
\newcommand{\myversion}{1.2}
\begin{document}
This is the MyProgram \myversion{} installation manual.
You need to have \texttt{myprogram-\myversion{}.tgz}
downloaded already. Start with:
\begin{lstdump}[language=sh]{extract}
tar -xzf myprogram-〈\lstdumpesc{\myversion}〉.tgz
cd 〈\lstdumpesc[myprogram-\myversion]{my*/«tab»}〉
\end{lstdump}
Oh, by the way, check this out:
\begin{lstdumpx}
zcat /usr/share/doc/mksh/examples/uhr.gz | mksh
\end{lstdumpx}
The second listing has no name in the \texttt{.lst} file.
\end{document}
解决方案(输出)
PDF 输出如下所示:
当保存为demo.tex
名为的文件时demo.lst
将生成以下内容:
-----BEGIN LISTING 1 (extract)-----
tar -xzf myprogram-1.2.tgz
cd myprogram-1.2
-----END LISTING 1 (extract)-----
-----BEGIN LISTING 2 [unnamed]-----
zcat /usr/share/doc/mksh/examples/uhr.gz | mksh
-----END LISTING 2 [unnamed]-----
基本上,所有lstdump
和lstdumpx
列表都已编号(我没有在 PDF 中显示这些编号,将它们以浅灰色打印在页边距上可能很有用——我们的页边距非常小,因为 PDF 主要用于在线使用,我们不使用列表编号,但它们很便宜,有些人可能喜欢它们),并且所有lstdump
列表都有名称,它们显示在纯文本文件中。此外,我们可以从列表中退出到 Teχ(用于替换),并且\lstdumpesc
命令可确保转义的文本还写入文件(如果给出了可选参数,则写入)。
额外的信息
这literate
部分允许使用一些列表中的 Unicode 字符,但它们只是从文件中省略.lst
- ASCII 之外的任何内容都不会显示,或者(例如在lstdump
环境的列表名称中)导致输出中出现随机的 8 位字符。
更多功能
列出数字
如果您希望列表编号另外显示在 PDF 中(这使交叉引用更容易),请添加marginnote
和可能的xcolor
包并插入行...
\marginnote{{\Huge\color{Gray}\thelstdumps}}%
…stepcounter
在每个定义的行后面。
列表文件中的文件和章节简介行
从这个答案我找到了一种方法,每次当前章节/节/小节编号不同时,都将其包含在输出文件中,但这需要hyperref
加载包。请注意,这可能需要第三次pdflatex
运行,以修复LaTeX Warning: Label(s) may have changed. Rerun to get cross-references right.
警告并在页面右侧获取边注。
包含这两个功能的第一个转储定义(再次完整)如下:
% lst dumps definitions
\makeatletter
\newcounter{lstdumps}
\setcounter{lstdumps}{0}
\newcommand{\lstdumpname}{}
\xdef\lstdumpsection{\@empty}%
\lstnewenvironment{lstdump}[3][]
{\lst@TestEOLChar{#3}%
\lstset{#1}%
\csname\@lst @SetFirstNumber\endcsname%
\stepcounter{lstdumps}%
\marginnote{{\huge\color{Gray}\thelstdumps}}%
\renewcommand{\lstdumpname}{ (#2)}%
\lst@BeginAlsoWriteFile{\jobname.lst}%
\ifx\lstdumpsection\@currentlabel\else%
\ifx\lstdumpsection\@empty%
\immediate\write\lst@WF{Listing dump for \jobname.tex}%
\immediate\write\lst@WF{}%
\fi%
\immediate\write\lst@WF{>>> (\@currentlabel) \@currentlabelname}%
\immediate\write\lst@WF{}%
\fi%
\immediate\write\lst@WF{-----BEGIN LISTING \thelstdumps\lstdumpname-----}%
}
{
\immediate\write\lst@WF{-----END LISTING \thelstdumps\lstdumpname-----}%
\immediate\write\lst@WF{}%
\endgroup%
\csname\@lst @SaveFirstNumber\endcsname%
\xdef\lstdumpsection{\@currentlabel}%
}
\lstnewenvironment{lstdumpx}[2][]
{\lst@TestEOLChar{#2}%
\lstset{#1}%
\csname\@lst @SetFirstNumber\endcsname%
\stepcounter{lstdumps}%
\marginnote{{\huge\color{Gray}\thelstdumps}}%
\renewcommand{\lstdumpname}{ [unnamed]}%
\lst@BeginAlsoWriteFile{\jobname.lst}%
\ifx\lstdumpsection\@currentlabel\else%
\ifx\lstdumpsection\@empty%
\immediate\write\lst@WF{Listing dump for \jobname.tex}%
\immediate\write\lst@WF{}%
\fi%
\immediate\write\lst@WF{>>> (\@currentlabel) \@currentlabelname}%
\immediate\write\lst@WF{}%
\fi%
\immediate\write\lst@WF{-----BEGIN LISTING \thelstdumps\lstdumpname-----}%
}
{
\immediate\write\lst@WF{-----END LISTING \thelstdumps\lstdumpname-----}%
\immediate\write\lst@WF{}%
\endgroup%
\csname\@lst @SaveFirstNumber\endcsname%
\xdef\lstdumpsection{\@currentlabel}%
}
% usage: \lstdumpesc[file]{pdf} or \lstdumpesc{bothfileandpdf}
\def\lstdumpesc{\@ifnextchar[{\lstdumpesc@two}{\lstdumpesc@one}}
\def\lstdumpesc@one#1{\lst@WFAppend{#1}#1}
\def\lstdumpesc@two[#1]#2{\lst@WFAppend{#1}#2}
\makeatother