我正在尝试创建一个允许并排显示两个环境的环境。这两个环境是\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
\compare
compare
接下来是第二个障碍:您想使用一个环境同时捕获两个这样的内容 — 但一个环境只有一个内容... 我提出的解决方案是使用两个环境,listingA
并且只在环境listingB
内部compare
有效。这两个环境将逐字文本(代码)存储在两个不同的文件中,然后环境compare
可以读取这些文件,以便并排显示代码,如您所愿。
笔记:
要使
equal height group
选项tcolorbox
发挥最大作用,通常需要进行两次编译。此选项可确保并排listingA
和listingB
(即来自同一compare
环境调用)具有相同的高度。如果您希望能够以字符开始您的列表
#
,显然您必须放弃参数listingA
和listingB
(列表标题)是可选的事实,请参见下文。
\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}