倾向内含 lstlisting 的宏drenv
,我用内部构建我的环境lstlisting
。但它不起作用。如何改进我的代码使其工作?
代码:
\documentclass{article}
\usepackage{listings}
\ExplSyntaxOn
\NewDocumentEnvironment{drenv}{m +v O{}}
{
\begin{minipage}{#1}
\exp_args:Nx \scantokens%
{
\string\begin{lstlisting}[\unexpanded{#3}]
#2
\string\end{lstlisting}
}
\end{minipage}
}{}
\ExplSyntaxOff
\begin{document}
\begin{drenv}{6in}
some code\rule{1in}{5pt}\par
\fbox{frame box}
\end{drenv}[xleftmargin=2in]
\end{document}
编辑:
根据答案中的第三个解决方案(来自\lstnewenvironment
),我尝试了以下代码,但都失败了。哪里出了问题,如何让它正常工作?
\documentclass{article}
\usepackage{listings}
\usepackage{xparse}
%------------------------------
\newsavebox{\mybox}
\NewDocumentEnvironment{dr}{O{}m}
{
\begin{lrbox}{\mybox}
\begin{minipage}{#2}
}
{
\end{minipage}
\end{lrbox}
\colorbox{#1}{\usebox\mybox}
}
\lstnewenvironment{drenv}[3][]
{
\dr[#2]{#3}
\lstset{#1}
}
{
\enddr
}
%------------------------------
\begin{document}
\begin{drenv}{red}{5in}
\rule{2in}{5pt}
\end{drenv}
\end{document}
答案1
用来newverbs
收集环境体,将其写入文件,然后\input
它。
请注意,newverbs
不幸的是,文字 TAB 字符可能会发生一些意想不到的事情(转换为空格或删除)。然而,如果您写入文件而不是\scantokens
,XeTeX 无论如何都会遇到 TAB 字符问题:写入 - 如何将制表符输出到文件中 - TeX - LaTeX Stack Exchange。使用下面我的包的解决方案没有这个限制,或者如果您使用 newverbs 包,您可能可以手动修补它。
还提供了替代解决方案\scantokens
。但这样当出现问题时您可以更轻松地检查临时文件。
请注意,强制参数和可选参数已被去标记化(因此不要在那里放置有趣的 catcode 标记),并且我假设没有可选参数等同于空可选参数。
语法略有不同,这是为了使实现更容易,而且环境结束后的参数并不是一个好主意xparse - 在 \end{env} 后面带有强制或可选参数的环境 - TeX - LaTeX Stack Exchange。
(并不是说不可能实现其他的事情。只是我真的不明白这样做的意义何在)
省略最后一个可选参数可能会使新动词产生混淆,请参阅间距 - NewDocumentEnvironment 可选参数使用 \obeylines 改变行为 - TeX - LaTeX Stack Exchange,所以我把它放在强制参数之前。
这个答案中的代码不遵守 expl3 的命名约定(例如,其中__tempwrite
应该\g_lyl_tempwrite_file
是lyl
您自己的前缀。有关详细信息,请参阅 expl3.pdf)。使用时请自担风险。
顺便说一句,您最好不要将重要文档存储到名为的文件中,tempfile.tex
否则您将遇到问题。
\documentclass{article}
\usepackage{listings}
\usepackage{newverbs}
\ExplSyntaxOn
\iow_new:N \__tempwrite
\cs_new_protected:Npn \__processcontent:nnn #1 #2 #3 {
% #1 is the mandatory argument of the environment
% #2 is the verbatim content of the environment body
% #3 is the optional argument
\tl_set:Nn \__content {
\begin{minipage}{#1} ^^J
\begin{lstlisting}[#3] ^^J
#2 ^^J
}
\tl_put_right:Nx \__content { \string \end }
\tl_put_right:Nn \__content {
{lstlisting} ^^J
\end{minipage}
}
}
\cs_generate_variant:Nn \str_replace_all:Nnn {Nx}
\cs_generate_variant:Nn \__processcontent:nnn {VVV}
\cs_new_protected:Npn \__continue: {
\str_replace_all:Nxn \__saved_environment_body {\cs_to_str:N \^^M} {^^J}
\__processcontent:VVV \__saved_mandatory_arg \__saved_environment_body \__saved_optional_arg
\iow_open:Nn \__tempwrite {tempfile.tex}
\exp_args:NNV \iow_now:Nn \__tempwrite \__content
\iow_close:N \__tempwrite
\input {tempfile.tex}
% the 4 lines above can be replaced by::
%\exp_args:NV \scantokens \__content
%in that case the iow_new:N would be unnecessary
}
\NewDocumentEnvironment{drenv}{O{}m}
{
\collectverbenv{
\str_gset:Nn \__saved_optional_arg {#1}
\str_gset:Nn \__saved_mandatory_arg {#2}
\str_gset:Nn \__saved_environment_body
}
}{
\__continue:
}
\ExplSyntaxOff
\begin{document}
\begin{drenv}[xleftmargin=2in]{6in}
some code\rule{1in}{5pt}\par
\fbox{frame box}
\end{drenv}
\end{document}
输出正如您所期望的......
newverbs.pdf 中没有明确记录 endlinechar 是活动字符 13,但事实确实如此。
interface3.pdf 中也没有记录\iow_now:n
强制 newlinechar=10,但事实确实如此。(x 扩展令牌\iow_newline:
是唯一有记录的安全方法)
包装广告:
就我个人而言,我不喜欢使用精心设计的黑客技术将具有奇怪 catcode 的令牌放入令牌列表中,因此我为此编写了一个包 precattl。
另外,为了逐字收集环境主体,还有我的包 saveenv。
\documentclass{article}
\usepackage{listings}
\usepackage{saveenv}
\usepackage{precattl}
\ExplSyntaxOn
\iow_new:N \__tempwrite
\precattl_exec:n {
\cs_new_protected:Npn \__processcontent:nnn #1 #2 #3 {
% #1 is the mandatory argument of the environment
% #2 is the verbatim content of the environment body
% #3 is the optional argument
\tl_set:Nn \__content {
\begin{minipage}{#1} ^^J
\cO\\begin{lstlisting}[#3] ^^J
#2 ^^J
\cO\\end{lstlisting} ^^J
\end{minipage}
}
}
\cs_generate_variant:Nn \__processcontent:nnn {nV}
\NewDocumentEnvironment{drenv}{O{}m}
{
\saveenv \__saved_environment_body
}{
\endsaveenv
\str_replace_all:Nnn \__saved_environment_body {\cO\^^M} {^^J}
\__processcontent:nVn {#2} \__saved_environment_body {#1}
\iow_open:Nn \__tempwrite {tempfile.tex}
\exp_args:NNV \iow_now:Nn \__tempwrite \__content
\iow_close:N \__tempwrite
\input {tempfile.tex}
% the 4 lines above can be replaced by::
%\exp_args:NV \scantokens \__content
%in that case the iow_new:N would be unnecessary
}
}
\ExplSyntaxOff
\begin{document}
\begin{drenv}[xleftmargin=2in]{6in}
some code\rule{1in}{5pt}\par
\fbox{frame box}
\end{drenv}
\end{document}
对于这个特定的新环境来说,你实际上不需要重新扫描令牌,lstnewenvironment
而是可以使用:
\lstnewenvironment{drenv}[2][]
{
\minipage {#2}
\lstset{#1}
}
{
\endminipage
}
使用方法与上面相同。