我问自己如何才能轻松地编写以完全相同的方式经常使用的长命令/短语。
例如:我怎样才能编写以下内容:
\begin{mdframed}\begin{lstlisting}[style=mystyle]
bla bla bla
\end{lstlisting}\end{mdframed}
简而言之:
\mycommand{
bla bla bla
}
编辑: 根据要求,我将在下面添加对我的原始问题的更新:
这是缺失的样式定义:
\lstdefinestyle{mystyle}{
language = C,
basicstyle=\footnotesize\ttfamily,
keywordstyle = {\color{DarkGreen}\bfseries},
morekeywords = {Send,Receive},
mathescape=true,
columns=fullflexible,
prebreak=\raisebox{0ex}[0ex][0ex]{\ensuremath{\rhookswarrow}},
breakindent=0
}
因此,正如您所看到的,我还希望在里面有 mathescape 选项,以便执行如下操作:
\mycommand{
bla bla bla $1+2=3$
}
哪一个应该不是结果转化为文本"$1+2=3$"
,但转化1+2=3
为数学解释。
答案1
我不建议将mdframed
–lstlisting
变成带有参数的命令,而不是适当的环境。
首先,换行符不能保留在参数版本中。
我还建议使用tcolorbox
而不是mdframed
,因为它可以更好地与 集成listings
。无论如何,你可以这样做
\documentclass{article}
\usepackage{listings,mdframed}
\lstnewenvironment{mylisting}
{\mdframed\lstset{}}
{\endmdframed}
\begin{document}
\begin{mylisting}
bla bla bla
\end{mylisting}
\end{document}
请注意辅助命令\mdframed
和\endmdframed
,否则\lstnewenvironment
声明会产生根本不起作用的东西。我删除了,style=mystyle
因为我不知道样式是如何定义的。在的参数中添加您需要的所有必要选项\lstset
。
具有风格的扩展版本
\documentclass{article}
\usepackage{listings,mdframed}
\usepackage[svgnames]{xcolor}
\lstdefinestyle{tmstyle}{
language = C,
basicstyle=\footnotesize\ttfamily,
keywordstyle = {\color{DarkGreen}\bfseries},
morekeywords = {Send,Receive},
mathescape=true,
columns=fullflexible,
prebreak=\raisebox{0ex}[0ex][0ex]{\ensuremath{\rhookswarrow}},
breakindent=0,
}
\lstnewenvironment{mylisting}
{\mdframed\lstset{style=tmstyle}}
{\endmdframed}
\begin{document}
\begin{mylisting}
Send bla bla bla $1+2=3$
\end{mylisting}
\end{document}
答案2
随着即将于 10 月发布的 LaTeX 内核的推出,您可以添加“钩子”来实现这一点。例如
\documentclass{article}
\usepackage{listings}
\usepackage{mdframed}
\AddToHook{env/lstlisting/before}{\begin{mdframed}}
\AddToHook{env/lstlisting/after}{\end{mdframed}}
\begin{document}
\begin{lstlisting}
bla bla bla
\end{lstlisting}
\end{document}
(您需要运行例如pdflatex-dev
现在才能使其工作:它使用内核的预发布版本。)
答案3
一般来说,你可以做这样的事情:
\newcommand{\mycommand}[1]{
\begin{environment}
#1
\end{environment}
}
但是,lstlisting
环境依赖于改变类别代码来工作,因此当参数扩展时,类别代码将不会是它们所需要的。
幸运的是,这个问题是可以预见的。相反,您需要使用命令,\lstnewenvironment
以便可以执行如下操作:
\lstnewenvironment{mylisting}
{\begin{mdframed}\lstset{style=mystyle}}
{\end{mdframed}}
然后使用它
\begin{mylisting}
bla bla bla
\end{mylisting}
答案4
只要\mycommand
仅在文档级别使用,而不是来自其他宏的参数中,不是来自其他宏的定义文本中,不是来自标记寄存器中,不是作为移动参数的一部分,您就可以让 LaTeX 将内容读取为逐字参数并将它们传递给\scantokens
。
但是我不推荐这样做,因为这样缩进要显示的代码肯定不会更容易:
\documentclass{article}
\usepackage{xparse}
\usepackage{listings}
\usepackage{mdframed}
\lstdefinestyle{mystyle}{%
language = C,
basicstyle=\footnotesize\ttfamily,
keywordstyle = {\color{DarkGreen}\bfseries},
morekeywords = {Send,Receive},
mathescape=true,
columns=fullflexible,
prebreak=\raisebox{0ex}[0ex][0ex]{\ensuremath{\rhookswarrow}},
breakindent=0
}
\newcommand\mycommand{%
\begingroup
\catcode`\^^I=12 %
\newlinechar=\endlinechar
\MyReadVerbatimArgument
}%
\begingroup
\NewDocumentCommand\MyReadVerbatimArgument{+v +v}{%
\endgroup
\NewDocumentCommand\MyReadVerbatimArgument{+v}{%
\scantokens{\endgroup#1##1#2}%
}%
}%
\MyReadVerbatimArgument|\begin{mdframed}
\begin{lstlisting}[style=mystyle]
||
\end{lstlisting}
\end{mdframed}
%|
\begin{document}
\mycommand{bla bla bla
bla bla bla
bla bla bla}
\end{document}
如果您愿意,可以扩展此功能以从整个逐字参数中删除前导结束符(如果存在)以及从整个逐字参数中删除尾随结束符(如果存在)。
这边走
\mycommand{
bla bla bla
bla bla bla
This line is not indented.
bla bla bla
bla bla bla
}
和
\mycommand{ bla bla bla
bla bla bla
This line is not indented.
bla bla bla
bla bla bla
}
和
\mycommand{
bla bla bla
bla bla bla
This line is not indented.
bla bla bla
bla bla bla}
和
\mycommand{ bla bla bla
bla bla bla
This line is not indented.
bla bla bla
bla bla bla}
都会产生相同的输出。
删除前导/尾随行尾字符(即^^M
类别代码 12(其他)的前导/尾随字符 = 类别代码 12(其他)的前导/尾随返回字符)的技巧与从宏参数中删除前导/尾随空格标记的技巧相同。
使用辅助宏时,不要使用空格标记作为参数分隔符,而是使用类别代码 12(其他)的显式返回字符标记。
后者(删除前导/尾随空格)在 Michael Downes 的“Around the Bend”TeX 挑战集的第 15 个练习中进行了讨论。
可以在以下位置找到由 Peter Wilson 编写的 pdf 文件,其中包含“Around the Bend”系列 TeX 挑战的所有挑战 / 练习和所有解决方案 / 答案:
http://mirrors.ctan.org/info/challenges/AroBend/AroundTheBend.pdf
挑战/练习的原文可以在以下位置找到:
http://mirrors.ctan.org/info/challenges/aro-bend/exercise.015
提交的解决方案/答案的讨论原文可以在以下位置找到:
http://mirrors.ctan.org/info/challenges/aro-bend/answer.015
\documentclass{article}
\usepackage{xparse}
\usepackage{listings}
\usepackage{mdframed}
%%/////////////////////////////////////////////////////////////////////////////
%% Begin of code for \UDRemoveLeadingNTrailingEndl
%%/////////////////////////////////////////////////////////////////////////////
\makeatletter
%%=============================================================================
%% Check whether argument is empty:
%%=============================================================================
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is empty>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is not empty>}%
\newcommand\UD@CheckWhetherNull[1]{%
\romannumeral0\if\relax\detokenize{#1}\relax
\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{\@firstoftwo{\expandafter}{} \@firstoftwo}%
{\@firstoftwo{\expandafter}{} \@secondoftwo}%
}%
%%=============================================================================
%% Exchange arguments
%%=============================================================================
\newcommand\UDExchange[2]{#2#1}%
\begingroup
% Dummy-definition, will be overridden. Is used only to get ^^M of
% category code 12(other) as #1 into subsequent definition-texts:
\NewDocumentCommand\UD@CheckWhetherLeadingEndl{+m}{%
\endgroup
%%===========================================================================
%% Check whether_verbatimized_ argument starts with a endline-character
%%===========================================================================
%% \UD@CheckWhetherLeadingEndl{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case <argument
%% which is to be checked>'s 1st token is a
%% endline-charactern>}%
%% {<Tokens to be delivered in case <argument
%% which is to be checked>'s 1st token is not
%% a endline-character>}%
\newcommand\UD@CheckWhetherLeadingEndl[1]{%
\UD@@CheckWhetherLeadingEndl\UD@SelDom##1\UD@SelDom#1\UD@@SelDom
}%
\@ifdefinable\UD@@CheckWhetherLeadingEndl{%
\long\def\UD@@CheckWhetherLeadingEndl##1\UD@SelDom#1##2\UD@@SelDom{%
\UD@CheckWhetherNull{##2}{\@secondoftwo}{\@firstoftwo}%
}%
}%
%%===========================================================================
%% Remove one leading endline-character from _verbatimized_ argument
%%===========================================================================
\@ifdefinable\UD@@TrimLeadingEndl{\long\def\UD@@TrimLeadingEndl#1{}}%
%%===========================================================================
%% Check whether _verbatimized_ argument ends with a endline-character
%%===========================================================================
%% \UD@CheckWhetherTrailingEndl{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case <argument
%% which is to be checked>'s last token is a
%% endline-charactern>}%
%% {<Tokens to be delivered in case <argument
%% which is to be checked>'s last token is not
%% a endline-character>}%
\newcommand\UD@CheckWhetherTrailingEndl[1]{%
\UD@@CheckWhetherTrailingEndl##1\UD@SelDom#1\UD@SelDom\UD@@SelDom
}%
\@ifdefinable\UD@@CheckWhetherTrailingEndl{%
\long\def\UD@@CheckWhetherTrailingEndl##1#1\UD@SelDom##2\UD@@SelDom{%
\UD@CheckWhetherNull{##2}{\@secondoftwo}{\@firstoftwo}%
}%
}%
%%===========================================================================
%% Remove one trailing endline-character from _verbatimized_ argument
%%===========================================================================
\newcommand\UD@TrimTrailingEndl[1]{\UD@@TrimTrailingEndl##1\UD@SelDom}%
\@ifdefinable\UD@@TrimTrailingEndl{%
\long\def\UD@@TrimTrailingEndl##1#1\UD@SelDom{##1}%
}%
%%===========================================================================
%% Remove one leading and one trailing endline-character from _verbatimized_
%% argument if present. Due to \romannumeral0-expansion the result is
%% delivered in 2 expansion-steps:
%%===========================================================================
\newcommand\UDRemoveLeadingNTrailingEndl[1]{%
\romannumeral0%
\UD@CheckWhetherLeadingEndl{##1}{%
\UD@CheckWhetherTrailingEndl{##1}{%
\UDExchange{ }{%
\expandafter\expandafter\expandafter\expandafter
\expandafter\expandafter\expandafter
}%
\expandafter\UD@TrimTrailingEndl\expandafter{\UD@@TrimLeadingEndl##1}%
}{%
\UDExchange{ }{\expandafter}%
\UD@@TrimLeadingEndl##1%
}%
}{%
\UD@CheckWhetherTrailingEndl{##1}{%
\UDExchange{ }{\expandafter\expandafter\expandafter}%
\UD@TrimTrailingEndl{##1}%
}{ ##1}%
}%
}%
}%
%%-----------------------------------------------------------------------------
%% Now let's change the catcode of ^^M and then call the dummy-definition
%% of \UD@CheckWhetherLeadingEndl so that it can fetch the catcode-12-^^M,
%% close the group, override itself and define all those macros where that
%% catcode-12-^^M is needed:
\catcode`\^^M=12 %
\UD@CheckWhetherLeadingEndl{^^M}%
\makeatother
%%/////////////////////////////////////////////////////////////////////////////
%% End of code for \UDRemoveLeadingNTrailingEndl
%%/////////////////////////////////////////////////////////////////////////////
\lstdefinestyle{mystyle}{
language = C,
basicstyle=\footnotesize\ttfamily,
keywordstyle = {\color{DarkGreen}\bfseries},
morekeywords = {Send,Receive},
mathescape=true,
columns=fullflexible,
prebreak=\raisebox{0ex}[0ex][0ex]{\ensuremath{\rhookswarrow}},
breakindent=0
}
\newcommand\mycommand{%
\begingroup
\catcode`\^^I=12 %
\newlinechar=\endlinechar
\MyReadVerbatimArgument
}%
\begingroup
\NewDocumentCommand\MyReadVerbatimArgument{+v +v}{%
\endgroup
\NewDocumentCommand\MyReadVerbatimArgument{+v}{%
\scantokens\expandafter{\romannumeral0%
\expandafter\expandafter\expandafter\UDExchange
\expandafter\expandafter\expandafter{%
\UDRemoveLeadingNTrailingEndl{##1}%
}{ \endgroup#1}#2}%
}%
}%
\MyReadVerbatimArgument|\begin{mdframed}
\begin{lstlisting}[style=mystyle]
||
\end{lstlisting}
\end{mdframed}
%|
\begin{document}
\mycommand{
bla bla bla
bla bla bla
This line is not indented.
bla bla bla
bla bla bla
}
\mycommand{ bla bla bla
bla bla bla
This line is not indented.
bla bla bla
bla bla bla
}
\mycommand{
bla bla bla
bla bla bla
This line is not indented.
bla bla bla
bla bla bla}
\mycommand{ bla bla bla
bla bla bla
This line is not indented.
bla bla bla
bla bla bla}
\end{document}
关于 TeX 工作方式的细微差别的一些评论:
在任何情况下,TeX 读取和标记输入的机制都会丢弃 .tex 输入行末尾的所有空格字符,然后添加一个字符,该字符在 TeX 引擎的内部字符编码方案中的编码点号(对于传统引擎,为 ASCII;对于基于 XeTeX/LuaTeX 的引擎,为 UTF-8/Unicode;ASCII 可以被视为 Unicode 的严格子集)等于整数参数的值,\endlinechar
然后才开始标记该行。通常,\endlinechar
-parameter 的值为 13,表示返回字符,在 TeX 的^^
-notation 中也可以访问为。(M 是拉丁字母中的第^^M
13 个字母。)
这意味着包含空格字符(ASCII 32(dec)/Unicode 32(dec))的 .tex 输入行在任何情况下都将被视为空行。
这也意味着,如果 .tex 输入行以空格字符结尾(ASCII 32(dec)/Unicode 32(dec)),这些空格字符将被丢弃。
您可以通过将以空格字符序列结尾的文本行放入环境来测试这一点verbatim*
。