前言
在《用 minted 宏包制作 example 环境》中,我们知道一种最基本的 example 环境的制作方法,即:
\documentclass{article} \usepackage{verbatim,xcolor}
\makeatletter \newwrite\example@out \newlength\savefboxrule \newlength\savefboxsep \edef\example@name{\jobname-example.aux} \newenvironment{example} {\begingroup\@bsphack \immediate\openout\example@out=\example@name \let\do\@makeother\dospecials\catcode`\^^M\active \def\verbatim@processline{\immediate\write\example@out{\the\verbatim@line}} \verbatim@start} {\immediate\closeout\example@out\@esphack\endgroup \trivlist\item\relax \setlength{\savefboxrule}{\fboxrule} \setlength{\savefboxsep}{\fboxsep} \setlength{\fboxsep}{0.015\textwidth} \setlength{\fboxrule}{0.4pt} \fcolorbox[gray]{0}{0.95}{% \begin{minipage}[c]{0.45\textwidth} \setlength{\fboxrule}{\savefboxrule} \setlength{\fboxsep}{\savefboxsep} \small\verbatiminput{\example@name} \end{minipage} } \hfill \fbox{% \begin{minipage}[c]{0.45\textwidth} \setlength{\fboxrule}{\savefboxrule} \setlength{\fboxsep}{\savefboxsep} \setlength{\parskip}{1ex plus 0.4ex minus 0.2ex} \normalsize\input{\example@name} \end{minipage} } \endtrivlist } \makeatother \begin{document} \begin{example} \begin{equation}\label{eq:1} E = mc^2 \end{equation} The equation~(\ref{eq:1}) is a famous mass energy equation. \end{example} \end{document}
|
然而这种方法无法添加导言区(可以用 %
去注释文档类及宏包,但这并不开箱即用),因此我给出一种全局设置导言区的方法。
正文
注意:前两种方法不再推荐。
低级方法
基本思路:在输出代码之前输出固定的导言区。
由于在盒子中使用 \verb
会报错,因此使用
来输出 \
、{
和 }
,用法为
\char`\\ \char`\{ \char`\}
|
输出 \ { }
定义一个导言区命令
\def\mypreamble{% \char`\\documentclass\char`\{article\char`\}\\ \char`\\begin\char`\{document\char`\} }
|
然后输出代码部分为
\texttt{\mypreamble} \verbatiminput{\example@name} \texttt{\char`\\end\char`\{document\char`\}}
|
这时候会注意到,导言区与正文之间存在纵向间距,这是由于 verbatim
环境内部使用了 trivlist
环境,所以在前后有 \topsep + \parskip (+ \partopsep)
的纵向间距(参考《怎么把MATLAB的程序插入latex而不改变段前段后的行距?》)。
因此调整参数即可(参考 texdoc verbatim
, sec 2.2 The interfaces)
\parskip=0pt\topsep=0pt\partopsep=0pt
|
完整代码:
\documentclass{article} \usepackage{verbatim,xcolor}
\makeatletter \newwrite\example@out \newlength\savefboxrule \newlength\savefboxsep \edef\example@name{\jobname-example.aux} \newenvironment{example} {\begingroup\@bsphack \immediate\openout\example@out=\example@name \let\do\@makeother\dospecials\catcode`\^^M\active \def\verbatim@processline{\immediate\write\example@out{\the\verbatim@line}} \verbatim@start} {\immediate\closeout\example@out\@esphack\endgroup \trivlist\item\relax \setlength{\savefboxrule}{\fboxrule} \setlength{\savefboxsep}{\fboxsep} \setlength{\fboxsep}{0.015\textwidth} \setlength{\fboxrule}{0.4pt} \fcolorbox[gray]{0}{0.95}{% \begin{minipage}[c]{0.5\textwidth} \setlength{\fboxrule}{\savefboxrule} \setlength{\fboxsep}{\savefboxsep} \parskip=0pt\topsep=0pt\partopsep=0pt \small \texttt{\mypreamble} \verbatiminput{\example@name} \texttt{\char`\\end\char`\{document\char`\}} \end{minipage} } \hfill \fbox{% \begin{minipage}[c]{0.4\textwidth} \setlength{\fboxrule}{\savefboxrule} \setlength{\fboxsep}{\savefboxsep} \setlength{\parskip}{1ex plus 0.4ex minus 0.2ex} \normalsize\input{\example@name} \end{minipage} } \endtrivlist } \makeatother \def\mypreamble{% \char`\\documentclass\char`\{article\char`\}\\ \char`\\begin\char`\{document\char`\} } \begin{document} \begin{example} \begin{equation}\label{eq:1} E = mc^2 \end{equation} The equation~(\ref{eq:1}) is a famous mass energy equation. \end{example} \end{document}
|
效果为
稍微高级一点的方法
在初级方法中,我们看到,我们需要手动输入导言区,且非常繁琐。
因此可以仿照输出、导入 \jobname-example.aux
的方法,写一个环境用来导入导言区代码。
我们看到定义 example
环境的代码
\newenvironment{example} {\begingroup\@bsphack \immediate\openout\example@out=\example@name \let\do\@makeother\dospecials\catcode`\^^M\active \def\verbatim@processline{\immediate\write\example@out{\the\verbatim@line}} \verbatim@start} {\immediate\closeout\example@out\@esphack\endgroup
|
看得出来,这部分的功能是将环境内的代码写到 \example@name
文件中,因此仿写即可。
仿写部分为
\newwrite\pre@out \edef\pre@name{\jobname-pre.aux} \newenvironment{pre} {\begingroup\@bsphack \immediate\openout\pre@out=\pre@name \let\do\@makeother\dospecials\catcode`\^^M\active \def\verbatim@processline{\immediate\write\pre@out{\the\verbatim@line}} \verbatim@start} {\immediate\closeout\pre@out\@esphack\endgroup}
|
这部分的功能为写一个名为 \jobname-pre.aux
的文件,内容为 pre
环境内的代码。
然后我们只需要在适当的位置导入文件即可。
完整代码:
\documentclass{article} \usepackage{verbatim,xcolor}
\makeatletter \newwrite\example@out \newwrite\pre@out \newlength\savefboxrule \newlength\savefboxsep \edef\example@name{\jobname-example.aux} \edef\pre@name{\jobname-pre.aux} \newenvironment{pre} {\begingroup\@bsphack \immediate\openout\pre@out=\pre@name \let\do\@makeother\dospecials\catcode`\^^M\active \def\verbatim@processline{\immediate\write\pre@out{\the\verbatim@line}} \verbatim@start} {\immediate\closeout\pre@out\@esphack\endgroup} \newenvironment{example} {\begingroup\@bsphack \immediate\openout\example@out=\example@name \let\do\@makeother\dospecials\catcode`\^^M\active \def\verbatim@processline{\immediate\write\example@out{\the\verbatim@line}} \verbatim@start} {\immediate\closeout\example@out\@esphack\endgroup \trivlist\item\relax \setlength{\savefboxrule}{\fboxrule} \setlength{\savefboxsep}{\fboxsep} \setlength{\fboxsep}{0.015\textwidth} \setlength{\fboxrule}{0.4pt} \fcolorbox[gray]{0}{0.95}{% \begin{minipage}[c]{0.5\textwidth} \setlength{\fboxrule}{\savefboxrule} \setlength{\fboxsep}{\savefboxsep} \parskip=0pt\topsep=0pt\partopsep=0pt \small \verbatiminput{\pre@name} \verbatiminput{\example@name} \texttt{\char`\\end\char`\{document\char`\}} \end{minipage} } \hfill \fbox{% \begin{minipage}[c]{0.4\textwidth} \setlength{\fboxrule}{\savefboxrule} \setlength{\fboxsep}{\savefboxsep} \setlength{\parskip}{1ex plus 0.4ex minus 0.2ex} \normalsize\input{\example@name} \end{minipage} } \endtrivlist } \makeatother \begin{document} \begin{pre} \documentclass{article} \begin{document} \end{pre} \begin{example} \begin{equation}\label{eq:1} E = mc^2 \end{equation} The equation~(\ref{eq:1}) is a famous mass energy equation. \end{example} \end{document}
|
高级方法
我们知道,不能在 example 环境中写导言区是因为这个环境本质上是在「执行」这一段代码,那么我们转化思路,不在主文件中执行即可,即在「外部」执行。
必备知识
\write18{shell_command}
:\write18
会在工作目录下,向命令行输入一段代码;
\immediate
:要求现在将代码发送到操作系统中执行。
用这两个命令,就可以在「将代码输出到外部文件」后执行命令行编译。
实现代码如下:
\documentclass{ctexart} \usepackage{verbatim, graphicx, xcolor} \newcounter{myexample} \setcounter{myexample}{1} \makeatletter \newwrite\example@out \newlength\savefboxrule \newlength\savefboxsep \edef\example@name{\jobname-example\themyexample.tex} \newenvironment{hexample} {\begingroup\@bsphack \immediate\openout\example@out=\jobname-example\themyexample.tex \let\do\@makeother\dospecials\catcode`\^^M\active \def\verbatim@processline{\immediate\write\example@out{\the\verbatim@line}} \verbatim@start} {\immediate\closeout\example@out\@esphack\endgroup \immediate\write18{latexmk -C \jobname-example\themyexample.tex && latexmk -xelatex \jobname-example\themyexample.tex && pdfcrop \jobname-example\themyexample.pdf \jobname-example\themyexample.pdf} \trivlist\item\relax \setlength{\savefboxrule}{\fboxrule} \setlength{\savefboxsep}{\fboxsep} \setlength{\fboxsep}{0.015\textwidth} \setlength{\fboxrule}{0.4pt} \fcolorbox[gray]{0}{0.95}{% \begin{minipage}[c]{0.45\textwidth} \setlength{\fboxrule}{\savefboxrule} \setlength{\fboxsep}{\savefboxsep} \small\verbatiminput{\jobname-example\themyexample.tex} \end{minipage} } \hfill \fbox{% \begin{minipage}[c]{0.45\textwidth} \setlength{\fboxrule}{\savefboxrule} \setlength{\fboxsep}{\savefboxsep} \includegraphics {\jobname-example\themyexample.pdf} \end{minipage} } \endtrivlist\addtocounter{myexample}{1} } \newenvironment{vexample} {\begingroup\@bsphack \immediate\openout\example@out=\jobname-example\themyexample.tex \let\do\@makeother\dospecials\catcode`\^^M\active \def\verbatim@processline{\immediate\write\example@out{\the\verbatim@line}} \verbatim@start} {\immediate\closeout\example@out\@esphack\endgroup \immediate\write18{latexmk -C \jobname-example\themyexample.tex && latexmk -xelatex \jobname-example\themyexample.tex && pdfcrop \jobname-example\themyexample.pdf \jobname-example\themyexample.pdf} \trivlist\item\relax \setlength{\savefboxrule}{\fboxrule} \setlength{\savefboxsep}{\fboxsep} \setlength{\fboxsep}{0.015\textwidth} \setlength{\fboxrule}{0.4pt} \fcolorbox[gray]{0}{0.95}{% \begin{minipage}[c]{\textwidth} \setlength{\fboxrule}{\savefboxrule} \setlength{\fboxsep}{\savefboxsep} \small\verbatiminput{\jobname-example\themyexample.tex} \end{minipage} } \\ \fbox{% \begin{minipage}[c]{\textwidth} \setlength{\fboxrule}{\savefboxrule} \setlength{\fboxsep}{\savefboxsep} \centering\includegraphics {\jobname-example\themyexample.pdf} \end{minipage} } \endtrivlist\addtocounter{myexample}{1} } \makeatother \usepackage[a4paper,margin=2cm]{geometry} \begin{document} \begin{hexample} \documentclass{article} \pagestyle{empty} \usepackage{amsmath, unicode-math} \begin{document} $\alpha, \symbfit{\alpha}$ \end{document} \end{hexample} \begin{vexample} \documentclass{article} \pagestyle{empty} \usepackage{graphicx} \begin{document} \includegraphics[width=0.5\textwidth]{example-image.pdf} \end{document} \end{vexample} \end{document}
|
注意:example 环境内的代码需要加上 \pagestyle{empty}
,否则 pdfcrop
不会裁剪到合适的尺寸。
编译方式:xelatex --shell-escape
。