我想创建一个命令来显示给定的LaTeX
代码及其格式化的输出。到目前为止,我注意到包做得很好,因为您可以使用包中showexpl
通过命令定义的样式以及一些其他原因。\lstdefinestyle{}
listings
问题
现在,借鉴以下问题的公认答案
我已经创建了以下命令
\usepackage{showexpl}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\LTXIO}{+v}{
\exp_args:Nx \scantokens
{
\string\LTXexample[\unexpanded{pos=b, numbers=none, basicstyle=\ttfamily}]
#1
\string\endLTXexample
}
}
\ExplSyntaxOff
用法如下
\LTXIO
{
\Huge{another}
\\\scriptsize{another}
}
但是,当要测试的命令写成一行时(例如\LTXIO{\Huge{another}}
),创建的命令会出现编译错误。显示的编译错误是
Package Listings Warning: Text dropped after begin of listing on input line 1.
所以问题是如何使LTXIO
命令处理单行和多行?
答案1
问题有三个方面:
第一点:
\scantokens
假装将未扩展的内容写入外部文本文件,然后输入该外部文本文件,从而该外部文本文件的内容在当前类别代码制度下被标记化。
+v
-arguments 将行尾编码为 -类别代码 12(其他)的字符 = 类别代码 12(其他)的回车符,而在执行整数参数的值^^M
时仍表示字符= 换行符。\scantokens
\newlinechar
^^J
您需要确保在将未扩展的内容伪造到外部文件时\newlinechar
,的值表示^^M
-character=回车符。\scantokens
方面2:
如果代码只有一行,则调用\begin{LTXexample}[...]
和第一行代码之间必须有换行符。
最后一行代码和 之间也必须有换行符\end{LTXexample}
。
因此,您需要一个例程来检测代码序列是否被换行符包围。
这可以以与检查前导和尾随空格相同的方式实现。关于空格标记,它与^^M
类别代码 12(其他)的字符标记 = 类别代码 12(其他)的回车字符标记有关,仅此而已。
检测前导空格和尾随空格的讨论见Michael Downes 的绕弯子答案 15。 (练习15是关于编写宏来修剪宏参数中的前导和尾随空格。
彼得·威尔逊 (Peter Wilson) 创建了一个格式良好的 pdf 文件,其中包含所有 Around-the-Bend 练习和答案。
方面三:
行缩进的处理。
的参数\LTXIO
可以包含多行代码。
这样的代码缩进该如何处理?
在下面的例子中,这种缩进保持原样。
\documentclass{article}
\usepackage{xparse}
\usepackage{showexpl}
\makeatletter
%%=============================================================================
%% Work around showexpl's weird overriding of xleftmargim/xrightmargin in case
%% of having no codeline-numbers -- that weirdness is in \SX@codeInput.
%%=============================================================================
\lst@Key{nocodelinenumbers}{false}[true]{%
\lstKV@SwitchCases{#1}{%
false:\\%
true:\long\def\lst@PlaceNumber{}%
}{\PackageError{Listings}{nocodelinenumbers #1 unknown}\@ehc}%
}%
%%=============================================================================
%% Check whether argument is empty:
%%=============================================================================
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is empty>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is not empty>}%
\newcommand\UD@CheckWhetherNull[1]{%
\romannumeral0\if\relax\detokenize{#1}\relax
\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{\@firstoftwo{\expandafter}{} \@firstoftwo}%
{\@firstoftwo{\expandafter}{} \@secondoftwo}%
}%
%%=============================================================================
%% Exchange arguments
%%=============================================================================
\newcommand\UD@Exchange[2]{#2#1}%
\begingroup
% Dummy-definition, will be overridden. Is used only to get ^^M of
% category code 12(other) as #1 and verbatimized calls as #2 and #3
% into subsequent definition-texts:
\NewDocumentCommand\UD@CheckWhetherLeadingEndl{+m+v+v}{%
\endgroup
%%===========================================================================
%% Check whether_verbatimized_ argument starts with a endline-character
%%===========================================================================
%% \UD@CheckWhetherLeadingEndl{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case <argument
%% which is to be checked>'s 1st token is a
%% endline-charactern>}%
%% {<Tokens to be delivered in case <argument
%% which is to be checked>'s 1st token is not
%% a endline-character>}%
\newcommand\UD@CheckWhetherLeadingEndl[1]{%
\UD@@CheckWhetherLeadingEndl\UD@SelDom##1\UD@SelDom#1\UD@@SelDom
}%
\@ifdefinable\UD@@CheckWhetherLeadingEndl{%
\long\def\UD@@CheckWhetherLeadingEndl##1\UD@SelDom#1##2\UD@@SelDom{%
\UD@CheckWhetherNull{##2}{\@secondoftwo}{\@firstoftwo}%
}%
}%
%%===========================================================================
%% Check whether _verbatimized_ argument ends with a endline-character
%%===========================================================================
%% \UD@CheckWhetherTrailingEndl{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case <argument
%% which is to be checked>'s last token is a
%% endline-charactern>}%
%% {<Tokens to be delivered in case <argument
%% which is to be checked>'s last token is not
%% a endline-character>}%
\newcommand\UD@CheckWhetherTrailingEndl[1]{%
\UD@@CheckWhetherTrailingEndl##1\UD@SelDom#1\UD@SelDom\UD@@SelDom
}%
\@ifdefinable\UD@@CheckWhetherTrailingEndl{%
\long\def\UD@@CheckWhetherTrailingEndl##1#1\UD@SelDom##2\UD@@SelDom{%
\UD@CheckWhetherNull{##2}{\@secondoftwo}{\@firstoftwo}%
}%
}%
%%===========================================================================
%% \LTXIO
%%===========================================================================
\newcommand*\LTXIO{%
\begingroup
% Make sure endline-chars yield linebreaks when \scantokens
% does its fake-writing-part:
\newlinechar=`\^^M %
% Make sure horizontal tabs won't cause problems when LTXIO reads its
% +v-argument:
\@makeother\^^I%
\InnerLTXIO
}%
\NewDocumentCommand{\InnerLTXIO}{+v}{%
\scantokens\expandafter{%
\romannumeral0%
\UD@CheckWhetherLeadingEndl{##1}{%
\UD@CheckWhetherTrailingEndl{##1}{%
\UD@Exchange{##1}%
}{%
\UD@Exchange{##1#1}%
}%
}{%
\UD@CheckWhetherTrailingEndl{##1}{%
\UD@Exchange{#1##1}%
}{%
\UD@Exchange{#1##1#1}%
}%
}%
{ \endgroup#2}%
#3%
}%
}%
}%
%%-----------------------------------------------------------------------------
%% Now let's change the catcode of ^^M and then call the dummy-definition
%% of \UD@CheckWhetherLeadingEndl so that it can fetch the catcode-12-^^M
%% and the verbatim-phrases for closing the group and overriding itself
%% and defining all those macros where that catcode-12-^^M and those
%% verbatimized phrases are needed:
\catcode`\^^M=12 %
\UD@CheckWhetherLeadingEndl%
{^^M}%
{\begin{LTXexample}[pos=b, frame=single, linewidth=\textwidth, xleftmargin=3.4pt,
xrightmargin=3.4pt, basicstyle=\ttfamily, nocodelinenumbers, showspaces=true,
showtabs=true]}%
{\end{LTXexample}}%
\makeatother
\begin{document}
\noindent\textbf{The input}
\begin{verbatim*}
\LTXIO
{
{%
\Huge
another
piece
of
text%
}\\
{\scriptsize another piece of text}
}
\end{verbatim*}
\noindent\textbf{yields:}\vspace*{\partopsep}\vspace*{\topsep}
\LTXIO
{
{%
\Huge
another
piece
of
text%
}\\
{\scriptsize another piece of text}
}
\bigskip
\noindent\null\hrule height 2pt\hfill\null
\bigskip
\noindent\textbf{The input}
\begin{verbatim*}
\LTXIO{{\Huge another piece of text}}
\end{verbatim*}
\noindent\textbf{yields:}\vspace*{\partopsep}\vspace*{\topsep}
\LTXIO{{\Huge another piece of text}}
\end{document}