我想制作一个显示数字和相应代码的文档,并希望减少重复。下面的 MWE。我认为在新命令中列出列表有些奇怪。
\documentclass{article}
\usepackage{graphicx}
\usepackage{listings}
\usepackage{mwe}
\newcommand{\figMe}[3]{
\begin{figure}
#3
\caption{#2. See Listing~\ref{lst#1} for code.}
\label{fig#1}
\end{figure}
\begin{lstlisting}[caption={#2. See Figure~\ref{fig#1}.},label={lst#1}]
#3
\end{lstlisting}
}
\begin{document}
\figMe{ex1}{Example drawing}{
\includegraphics{example-image-a}
}
\end{document}
谢谢您的回答。这就是我最终所做的,使用外部文件...
\newcommand{\figMeToo}[3]{
\begin{figure}
\input{#3}
\caption{#2 See Listing~\ref{lst#1} for code.}
\label{fig#1}
\end{figure}%\FloatBarrier
\lstinputlisting[frame=tb,caption={#2 See Figure~\ref{fig#1}.},label={lst#1},captionpos=b,language={[latex]TeX}]{#3}%\FloatBarrier
}
答案1
我以前为自己写过一些代码(我的一份文档),这些代码允许我根据需要将输入和输出分离。本答案中的代码重用了大部分代码,但这些定义中可能有一些死键对你不起作用,因为我是为自己的输出创建的。
我删除了一些键,但我可能忽略了其中一个。 、gappend
和no-append
键after
都是有用的,但您必须用它们自己构建一些东西(我创建它们是gappend
为了能够存储一些代码,稍后将其添加到另一个环境的输出中,但由于您的代码只有 1:1 的对应关系,我想这对您来说没什么用)。
此实现enverb
将忽略第一个n其主体每行的字符,其中n是匹配前的空格数\end
(所以这里是\end{figMe}
)加上为键指定的数字more-ignore
(本例中为 2 - 这是我在文档中个人使用的缩进量)。我自己的文档不使用空格,<Tab>
只使用空格,我不知道制表符与此配合得如何(假设它应该可以工作,但尚未经过广泛测试)。
这些是许多行实现(好吧,这是一个包草稿,所以就假装\makeatletter
和之间的所有内容\makeatother
都隐藏在后面\usepackage{enverb}
),我用于输出的代码实际上只有 26 行代码:
\NewDocumentEnvironment{figMe}{mm}
{\enverb} % enverb will collet an additional o-arg for its own options
{%
\enverbUnexpandedOutput
{\begin{figure}}% pre-contents
{% post-contents
\caption
{%
#2. See Listing~\ref{lst#1} for code.%
\label{fig#1}%
}%
\end{figure}%
}%
\enverbExpandedOutput
{% pre-contents
% we don't want to expand the begin part
\unexpanded
{%
\begin{lstlisting}
[caption={#2. See Figure~\ref{fig#1}.},label={lst#1}]%
}%
}
% verbatim output in lstlistings needs to see the \end as a string without
% a trailing space
{\string\end{lstlisting}}% post-contents
}
整个文档及enverb
代码:
\documentclass{article}
\usepackage{graphicx}
\usepackage{listings}
\usepackage{mwe}
\usepackage{expkv-def}
\makeatletter
\ExplSyntaxOn
\cs_new_eq:NN \enverb@count \tl_count:n
\cs_set:Npx \enverb@othercr { \char_generate:nn {13} {12} }
\ExplSyntaxOff
%% key setup
\ekvdefinekeys{enverb}
{
boolTF auto-ignore = \enverb@ifautoignore
,initial auto-ignore
,protected code ignore = \let\enverb@ifautoignore\@secondoftwo
,also eint ignore = \enverb@ignore
,eint more-ignore = \enverb@moreignore
,initial more-ignore = 2
,long store bol = \enverb@bol@content
,long store eol = \enverb@eol@content
,einitial eol = \enverb@othercr
,data gappend = \enverb@append
,code no-append = \let\enverb@append\@secondoftwo
,store after = \enverb@after
}
\protected\long\ekvsetdef\enverbsetup{enverb}
%% auxiliary error function
\newcommand\enverb@error[1]
{%
\GenericError
{(enverb)\@spaces\@spaces\@spaces\@spaces\@spaces}%
{Environment enverb error: #1}%
{Just use it correctly!}%
{Read the sources.}%
}
%% setup for weird category code regime
\begingroup
\lccode`\~=`\^^M
\catcode`\:=13
\lccode`\:=`\ % <- space
\catcode`\;=13
\lccode`\;=`\^^I % <- tab
\lowercase{\endgroup
%% code for spaces and CR
\def\enverb@body@space{}%
\def\enverb@body@tab{}%
\def\enverb@body@newline#1~%
{\enverb@ifnotend{#1}{\enverb@bol\unexpanded{#1}\enverb@eol~}}%
%% activate the category code regime of the body
\protected\def\enverb@body@setup
{%
\let\enverb@collected@body\@empty
\let\do\@makeother\dospecials
\catcode`\^^M=13 \let~\enverb@body@newline
\catcode`\ =13 \let:\enverb@body@space
\catcode`\^^I=13 \let;\enverb@body@tab
\let\enverb@bol\relax
\let\enverb@eol\relax
}
%% check for optional argument
\newcommand\enverb@search@oarg@a
{%
\ifx:\next
\ifenverb@firsteol
\else
\enverb@body@add{:}%
\fi
\let\next\enverb@search@oarg@b
\else
\ifx~\next
\ifenverb@firsteol
\enverb@firsteolfalse
\else
\enverb@body@add{~}%
\fi
\let\next\enverb@search@oarg@b
\else
\ifx[\next\@gobble]%
\let\next\enverb@oarg
\else
\ifenverb@firsteol
\let\next\enverb@body@after@begin
\else
\let\next\enverb@body
\fi
\fi
\fi
\fi
\next
}
%% start body collection
\newcommand\enverb@body
{\edef\enverb@collected@body{\iffalse}\fi\expandafter~\enverb@collected@body}
%% check the line after an oarg
\def\enverb@body@after@oarg#1~%
{\enverb@ensure@blank{#1}{closing bracket}\enverb@body}
%% check the line after the \begin statement
\def\enverb@body@after@begin#1~%
{\enverb@ensure@blank{#1}{\string\begin}\enverb@body}
}
%% quick check for empty line
\newcommand\enverb@ensure@blank[2]
{%
\expandafter\enverb@ifempty\expanded{{#1}}{}%
{%
\expanded{%
\noexpand\enverb@error
{%
Line after #2 not empty.\noexpand\MessageBreak
Contains: \detokenize\expandafter{\romannumeral`\^^@#1}%
}%
}%
}%
}
%% quick check for empty argument
\newcommand\enverb@ifempty[1]
{%
\enverb@ifempty@\enverb@ifempty@A#1\enverb@ifempty@B.\enverb@ifempty@true
\enverb@ifempty@A\enverb@ifempty@B
}
\def\enverb@ifempty@#1\enverb@ifempty@A\enverb@ifempty@B#2#3{#3}
\def\enverb@ifempty@true\enverb@ifempty@A\enverb@ifempty@B#1#2{#1}
\newcommand\enverb@gadd[2]{\xdef#1{\unexpanded\expandafter{#1#2}}}
\newcommand\enverb@body@add[1]
{%
\edef\enverb@collected@body
{\unexpanded\expandafter{\enverb@collected@body#1}}%
}
% start of environment `enverb'
\newcommand\enverb
{%
\begingroup
\def\tmp{enverb}%
\expandafter
\endgroup
\expandafter\enverb@ifnotend@setup@perhaps\expanded
{{\string{\@currenvir\string}}}%
\begingroup
\enverb@body@setup
\enverb@firsteoltrue
\let\enverb@collected@oarg\@empty
\enverb@search@oarg
}
\newif\ifenverb@firsteol
\newcommand\enverb@search@oarg{\futurelet\next\enverb@search@oarg@a}
\newcommand\enverb@search@oarg@b{\expandafter\enverb@search@oarg\@gobble}
\newcommand\enverb@oarg{\endgroup\enverb@oarg@}
\NewDocumentCommand\enverb@oarg@{O{}}
{%
\edef\enverb@collected@oarg{\unexpanded{#1}}%
\begingroup
\enverb@body@setup
\enverb@body@after@oarg
}
\def\enverb@ifnotend#1%
{%
\def\enverb@ifnotend##1%
{%
\enverb@ifnotend@
##1\enverb@mark\enverb@ifnotend@maybe
#1\enverb@mark\@thirdofthree
\enverb@stop
}%
\def\enverb@ifnotend@##1#1##2\enverb@mark##3##4\enverb@stop{##3{##1}{##2}}%
}
\expandafter\enverb@ifnotend\expanded{{\expandafter\@gobble\string\\end}}
\newcommand\enverb@ifnotend@maybe[2]
{\expandafter\enverb@ifnotend@perhaps\expandafter{\romannumeral`\^^@#2}{#1}}
\newcommand\enverb@ifnotend@setup@perhaps[1]
{%
\def\enverb@ifnotend@perhaps##1%
{%
\enverb@ifnotend@perhaps@\enverb@mark##1\enverb@mark\enverb@ifnotend@end
\enverb@mark#1\enverb@mark\@thirdofthree
\enverb@stop
}%
\def\enverb@ifnotend@perhaps@
##1\enverb@mark#1##2\enverb@mark##3##4\enverb@stop
{##3{##2}}%
}
\providecommand\@thirdofthree[3]{#3}
\newcommand\enverb@ifnotend@end[3]
{%
\iffalse{\fi}%
\enverb@ensure@blank{#1}{\string\end}%
\expanded
{%
\endgroup
\enverbsetup
{\unexpanded\expandafter{\enverb@collected@oarg}}%
\noexpand\enverb@final
{\unexpanded\expandafter{\enverb@collected@body}}%
}%
{#2}%
\expandafter\end\expandafter{\@currenvir}%
}
\long\def\enverb@final#1#2%
{%
\enverb@ifautoignore
{\enverb@setup@ignore{\enverb@count{#2}+\enverb@moreignore}}%
{\enverb@setup@ignore\enverb@ignore}%
\edef\enverb@line##1\enverb@eol
{%
\noexpand\detokenize{##1}%
\noexpand\unexpanded{\unexpanded\expandafter{\enverb@eol@content}}%
}%
\edef\enverb@collected@body{#1}%
\expanded
{\unexpanded{\enverb@append\enverb@gadd\@gobble}\expandafter}%
\expandafter{\enverb@collected@body}%
}
\providecommand\@firstofnine[9]{#1}
\newcommand\enverb@setup@ignore[1]
{\expandafter\enverb@setup@ignore@\the\numexpr#1\relax;\enverb@line}
\def\enverb@setup@ignore@#1;#2%
{%
\ifnum#1>9
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
{\expandafter\enverb@setup@ignore@\the\numexpr#1-8;{\@firstofnine{#2}}}%
{%
\let\enverb@bol@gobble\@empty % just so that renewcommand doesn't go nuts
\expanded
{%
\unexpanded{\renewcommand\enverb@bol@gobble}\ifnum#1>\z@[#1]\fi
{\unexpanded{#2}}%
\unexpanded{\def\enverb@bol##1\enverb@eol}%
{%
\noexpand\unexpanded
{\unexpanded\expandafter{\enverb@bol@content}}%
\unexpanded{\expandafter\enverb@ifempty\expanded}{{##1}}%
{\noexpand\enverb@line}%
{\noexpand\enverb@bol@gobble}%
##1\unexpanded{\enverb@eol}%
}%
}%
}%
}
% the output routine if you'd use only an `enverb` environment, empty for you
\let\endenverb\@empty
\NewDocumentCommand\enverbExpandedOutput{O{} +m +m}
{%
\begingroup
\everyeof{\noexpand}%
#1\relax
\expandafter
\endgroup
\scantokens\expanded
{{%
#2\enverb@othercr
\enverb@collected@body
#3\enverb@othercr
}}%
}
\NewDocumentCommand\enverbUnexpandedOutput{O{} +m +m}
{%
\begingroup
\everyeof{\noexpand}%
\newlinechar=\endlinechar
#1\relax
\expandafter
\endgroup
\scantokens\expanded
{{%
\unexpanded{#2}%
\enverb@collected@body
\unexpanded{#3}%
}}%
}
\makeatother
\NewDocumentEnvironment{figMe}{mm}
{\enverb} % enverb will collet an additional o-arg for its own options
{%
\enverbUnexpandedOutput
{\begin{figure}}
{%
\caption
{%
#2. See Listing~\ref{lst#1} for code.%
\label{fig#1}%
}%
\end{figure}%
}%
\enverbExpandedOutput
{%
% we don't want to expand the begin part
\unexpanded
{%
\begin{lstlisting}%
[caption={#2. See Figure~\ref{fig#1}.},label={lst#1}]%
}%
}
% verbatim output in lstlistings needs to see the \end as a string without
% a trailing space
{\string\end{lstlisting}}%
}
\begin{document}
\begin{figMe}{ex1}{Example drawing}
\includegraphics{example-image-a}
\end{figMe}
\end{document}
输出:
答案2
您还可以使用 Ulrich Diez 的DefineVerbatimToScantokens
宏(可以在一些答案中找到,例如https://tex.stackexchange.com/a/626166/250119) 如下:
\documentclass{article}
\usepackage{graphicx}
\usepackage{listings}
\usepackage{mwe}
%=== Code of \DefineVerbatimToScantokens ========================
% With older LaTeX-releases uncomment the following line:
%\usepackage{xparse}
\NewDocumentCommand\DefineVerbatimToScantokens{mm}{%
\begingroup
\catcode`\^^I=12\relax
\InnerDefineVerbatimToScantokens{#1}{#2}%
}%
\begingroup
\makeatletter
\def\InnerDefineVerbatimToScantokens#1#2{%
\endgroup
\NewDocumentCommand\InnerDefineVerbatimToScantokens{mm+v}{%
\endgroup\ReplaceHashloop{##3}{##1}{##2}%
}%
\newcommand\ReplaceHashloop[3]{%
\ifcat$\detokenize\expandafter{\Hashcheck##1#1}$%
\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{%
\NewDocumentCommand{##2}{##3}{%
\begingroup\newlinechar=\endlinechar
\scantokens{\endgroup##1#2}%
}%
}{%
\expandafter\ReplaceHashloop\expandafter{\Hashreplace##1}{##2}{##3}%
}%
}%
\@ifdefinable\Hashcheck{\long\def\Hashcheck##1#1{}}%
\@ifdefinable\Hashreplace{\long\def\Hashreplace##1#1{##1####}}%
}%
\catcode`\%=12\relax
\catcode`\#=12\relax
\InnerDefineVerbatimToScantokens{#}{%}%
%=== End of code of \DefineVerbatimToScantokens =================
\DefineVerbatimToScantokens{\figMe}{m m +v}{
\begin{figure}
#3
\caption{#2. See Listing~\ref{lst#1} for code.}
\label{fig#1}
\end{figure}
\begin{lstlisting}[caption={#2. See Figure~\ref{fig#1}.},label={lst#1}]
#3
\end{lstlisting}
}
\begin{document}
\figMe{ex1}{Example drawing}{\includegraphics{example-image-a}}
\end{document}
尽管使用{...}
它来界定逐字环境有点脆弱,但我认为注释必须是{}
-brace-balanced。