带有 lstlisting 的环境

带有 lstlisting 的环境

倾向内含 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_filelyl您自己的前缀。有关详细信息,请参阅 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
 }

使用方法与上面相同。

相关内容