环境协调两个内部环境

环境协调两个内部环境

我正在尝试创建一个允许并排显示两个环境的环境。这两个环境是\code环境。\code环境允许传递代码的标题以及代码本身。

我想到的解决方案是在第一个环境中使用一个 minipage,在第二个环境中使用另一个 minipage。现在,我不想一遍又一遍地做所有这些工作,而是想定义一个新环境,允许传递两个标题以及代码。也许是这样的:\compare{title 1}{title 2}{code 1}{code 2}

如何实现?提前谢谢您。

输出

\documentclass{article}
\usepackage{enumitem}
\usepackage{listings}
\usepackage[most]{tcolorbox}

\makeatletter
\newenvironment{code}[1][]{%
    \@totalleftmargin=0pt%
    \def\foot{#1} 
    \tcbwritetemp}%
    {\endtcbwritetemp%
    \ifx\foot\@empty
    \tcbox[before = \begin{center}, after = \end{center},
    fonttitle = \color{white}\itshape\ttfamily, colframe = blue, 
    listing only, listing options = {language = c++}
    ]%
    {\tcbusetemplisting}%
    \else
    \tcbox[title = {\foot}, % The title option is present here
    before = \begin{center}, after = \end{center},
    fonttitle = \color{white}\itshape\ttfamily, colframe = blue, 
    listing only, listing options = {language = c++}
    ]%
    {\tcbusetemplisting}%
    \fi
}%
\makeatother

\lstset{
    frameround=fttt,
    language=c++,
    breaklines=true,
    keywordstyle=\color{blue}\bfseries, 
    basicstyle=\ttfamily\color{red},
    numberstyle=\color{black},
    keepspaces=true
    }

% DOESN'T WORK
\newenvironment{compare}[4]{
\begin{minipage}{0.4\textwidth}
\begin{code}[#1]
#3
\begin{code}
\end{minipage}
\begin{minipage}{0.4\textwidth}
    \begin{code}[#2]
#4
    \begin{code}
\end{minipage}
}

\begin{document}    
    Start a list:
    \begin{enumerate}[label = \textbf{--}]
        \item The first item:\\
        \begin{minipage}[t]{0.4\textwidth}
            \begin{code}[title1]
xx
            \end{code}
        \end{minipage}
        \begin{minipage}[t]{0.4\textwidth}
            \begin{code}[title2]
yy
            \end{code}
        \end{minipage}
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % Instead of doing all the above, I want to have something like the following:
    %\compare[title 1][title 2]{int x = 0;}{int y = 1;}
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    \end{enumerate}
\end{document}

答案1

在您的“不起作用”环境中,存在不匹配\begin{code}和,并且缺少参数(如果您想使用,则应该使用而不是)。但据我所知,最大的问题是逐字材料无法方便地在参数中捕获;环境更适合这种情况。\end{code}compare\newenvironment\newcommand\comparecompare

接下来是第二个障碍:您想使用一个环境同时捕获两个这样的内容 — 但一个环境只有一个内容... 我提出的解决方案是使用两个环境,listingA并且只在环境listingB内部compare有效。这两个环境将逐字文本(代码)存储在两个不同的文件中,然后环境compare可以读取这些文件,以便并排显示代码,如您所愿。

笔记:

  • 要使equal height group选项tcolorbox发挥最大作用,通常需要进行两次编译。此选项可确保并排listingAlistingB(即来自同一compare环境调用)具有相同的高度。

  • 如果您希望能够以字符开始您的列表#,显然您必须放弃参数listingAlistingB(列表标题)是可选的事实,请参见下文。

\documentclass{article}
\usepackage{enumitem}
\usepackage[most]{tcolorbox}

\makeatletter

\lstset{
    frameround=fttt,
    language=c++,
    breaklines=true,
    keywordstyle=\color{blue}\bfseries,
    basicstyle=\ttfamily\color{red},
    numberstyle=\color{black},
    keepspaces=true
    }

\newtoks\titleListingA
\newtoks\titleListingB
% We need to define a new 'equal height group' every time the 'compare'
% environment is used, so that listings A and B in a given call of the
% 'compare' environment have the same height; but this height is not
% necessarily the same across several calls to the 'compare' environment. So,
% we'll use a name based on the number of times the 'compare' environment has
% been called in the document.
\newcounter{myCompareEnvCounter}

\newenvironment{listingA}[1][]{%
  \errmessage{Use of environment 'listingA' is invalid outside 'compare'}}{}

\newenvironment{listingB}[1][]{%
  \errmessage{Use of environment 'listingB' is invalid outside 'compare'}}{}

\newenvironment{compare}{%
  \renewenvironment{listingA}[1][]{%
    \global\titleListingA={##1}%
    \tcbverbatimwrite{\jobname_listingA.cxx}%
  }{\endtcbverbatimwrite\ignorespacesafterend}%
  %
  \renewenvironment{listingB}[1][]{%
    \global\titleListingB={##1}%
    \tcbverbatimwrite{\jobname_listingB.cxx}%
  }{\endtcbverbatimwrite\ignorespacesafterend}%
  \stepcounter{myCompareEnvCounter}%
  \ignorespaces
}{%
  \unskip
  % Common options for the two boxes: expand the counter representation
  \edef\mytcbOptions{%
    \unexpanded{width=(\linewidth-4pt)/2,
      before=, after=\hfill,
      fonttitle = \color{white}\itshape\ttfamily, colframe = blue,
      listing only, listing options = {language = c++},
      equal height group=myCompareGroup-}\themyCompareEnvCounter}%
  \expandafter\tcbset\expandafter{\mytcbOptions}%
  \par\noindent
  %
  \expandafter\ifx\expandafter\@nil\the\titleListingA\@nil
    \tcbset{notitle}%
  \else
    \tcbset{adjusted title={\the\titleListingA}}%
  \fi
  \tcbinputlisting{listing file={\jobname_listingA.cxx}}%
  %
  \expandafter\ifx\expandafter\@nil\the\titleListingB\@nil
    \tcbset{notitle}%
  \else
    \tcbset{adjusted title={\the\titleListingB}}%
  \fi
  \tcbinputlisting{listing file={\jobname_listingB.cxx}}%
  %
  \renewenvironment{listingA}[1][]{%
    \errmessage{Use of environment 'listingA' is invalid outside 'compare'}}{}%
  %
  \renewenvironment{listingB}[1][]{%
    \errmessage{Use of environment 'listingB' is invalid outside 'compare'}}{}%
  \ignorespacesafterend
}

\makeatother

\begin{document}
Start a list:
\begin{enumerate}[label = \textbf{--}]
\item The first item:
  \begin{compare}
    \begin{listingA}[\#verycool]
int a = 0;
    \end{listingA}
%
    \begin{listingB}[Second listing]
int b = 0;
    \end{listingB}
  \end{compare}

\item Other item:
  \begin{compare}
    \begin{listingA}            % no title here
// Comment here
#include <cstdlib>

int main(int argc, char **argv)
{
  return EXIT_SUCCESS;
}
    \end{listingA}
%
    \begin{listingB}[Some title]
int zzz = 12;
    \end{listingB}
  \end{compare}
\end{enumerate}
\end{document}

截屏

listingA这是相同的代码,但将和 的参数listingB(即列表标题)设为必需(如果您不想要标题,只需使用空值或空白值)。这允许代码列表以字符开头#,因此可能是可取的。此版本使用etoolbox\ifblank命令来测试相关参数是否为空(即为空或仅包含空格标记)。

\documentclass{article}
\usepackage{enumitem}
\usepackage{etoolbox}
\usepackage[most]{tcolorbox}

\makeatletter

\lstset{
    frameround=fttt,
    language=c++,
    breaklines=true,
    keywordstyle=\color{blue}\bfseries,
    basicstyle=\ttfamily\color{red},
    numberstyle=\color{black},
    keepspaces=true
    }

\newtoks\titleListingA
\newtoks\titleListingB
% We need to define a new 'equal height group' every time the 'compare'
% environment is used, so that listings A and B in a given call of the
% 'compare' environment have the same height; but this height is not
% necessarily the same across several calls to the 'compare' environment. So,
% we'll use a name based on the number of times the 'compare' environment has
% been called in the document.
\newcounter{myCompareEnvCounter}

\newenvironment{listingA}[1][]{%
  \errmessage{Use of environment 'listingA' is invalid outside 'compare'}}{}

\newenvironment{listingB}[1][]{%
  \errmessage{Use of environment 'listingB' is invalid outside 'compare'}}{}

\newenvironment{compare}{%
  \renewenvironment{listingA}[1]{%
    \global\titleListingA={##1}%
    \tcbverbatimwrite{\jobname_listingA.cxx}%
  }{\endtcbverbatimwrite\ignorespacesafterend}%
  %
  \renewenvironment{listingB}[1]{%
    \global\titleListingB={##1}%
    \tcbverbatimwrite{\jobname_listingB.cxx}%
  }{\endtcbverbatimwrite\ignorespacesafterend}%
  \stepcounter{myCompareEnvCounter}%
  \ignorespaces
}{%
  \unskip
  % Common options for the two boxes: expand the counter representation
  \edef\mytcbOptions{%
    \unexpanded{width=(\linewidth-4pt)/2,
      before=, after=\hfill,
      fonttitle = \color{white}\itshape\ttfamily, colframe = blue,
      listing only, listing options = {language = c++},
      equal height group=myCompareGroup-}\themyCompareEnvCounter}%
  \expandafter\tcbset\expandafter{\mytcbOptions}%
  \par\noindent
  %
  \expandafter\ifblank\expandafter{\the\titleListingA}{%
    \tcbset{notitle}%
  }{%
    \tcbset{adjusted title={\the\titleListingA}}%
  }%
  \tcbinputlisting{listing file={\jobname_listingA.cxx}}%
  %
  \expandafter\ifblank\expandafter{\the\titleListingB}{%
    \tcbset{notitle}%
  }{%
    \tcbset{adjusted title={\the\titleListingB}}%
  }%
  \tcbinputlisting{listing file={\jobname_listingB.cxx}}%
  %
  \renewenvironment{listingA}[1][]{%
    \errmessage{Use of environment 'listingA' is invalid outside 'compare'}}{}%
  %
  \renewenvironment{listingB}[1][]{%
    \errmessage{Use of environment 'listingB' is invalid outside 'compare'}}{}%
  \ignorespacesafterend
}

\makeatother

\begin{document}
Start a list:
\begin{enumerate}[label = \textbf{--}]
\item The first item:
  \begin{compare}
    \begin{listingA}{\#verycool}
int a = 0;
    \end{listingA}
%
    \begin{listingB}{Second listing}
int b = 0;
    \end{listingB}
  \end{compare}

\item Other item:
  \begin{compare}
    \begin{listingA}{}          % no title here
#include <cstdlib>

int main(int argc, char **argv)
{
  return EXIT_SUCCESS;
}
    \end{listingA}
%
    \begin{listingB}{Some title}
int zzz = 12;
    \end{listingB}
  \end{compare}
\end{enumerate}
\end{document}

第二版截图

相关内容