
コマンドの出力を示し、コマンドを介してコマンドを表示するマクロを作成する方法を見つけようとしていますlstinline
。特殊文字 (やなど{
)をエスケープする必要があると読んだのです}
が、それを自動的に行う方法があるかどうか疑問に思っています。これが可能かどうかはわかりません。
理想的には、この\commandExample{\qty{1.2}{\meter}}
コマンドはOutput:1.2 m - Code:\qty{1.2}{\meter}
MWE:
\documentclass{report}
\usepackage{graphicx}
\usepackage{xcolor}
\usepackage{siunitx}
\usepackage{listings}
\definecolor{lightgrey}{rgb}{0.9,0.9,0.9}
\definecolor{darkgreen}{rgb}{0,0.6,0}
\lstset{language=[LaTeX]TeX,
caption = {Missing Caption}
,label = {lst:missingLabel}
,basicstyle = \footnotesize\ttfamily %\footnotesize % \small\ttfamily
,frame = shadowbox%
,numbers = left%
,breaklines = true%
,keywordstyle = \color{darkgreen}%
,commentstyle = \color{red}%
,tabsize = 2%
,backgroundcolor = \color{lightgrey}%
%,texcsstyle = {*\bf\color{blue}}%
%,otherkeywords = $, \{, \}, \[, \]%
,morekeywords = {includegraphics }%
,moretexcs = {graphicspath}%
}
\NewDocumentCommand{\commandExample}{m}{%
Output:#1 - Code:\lstinline{#1}}
\begin{document}
\commandExample{begin}.
\unit{\meter}
%\commandExample{\unit{\meter}} % This line causes it to crash
\end{document}
答え1
私はその議論をそのまま吸収し、\tl_rescan:nn
それをタイプセットするために使用します。
\documentclass{report}
\usepackage{graphicx}
\usepackage{xcolor}
\usepackage{siunitx}
\usepackage{listings}
\definecolor{lightgrey}{rgb}{0.9,0.9,0.9}
\definecolor{darkgreen}{rgb}{0,0.6,0}
\lstset{language=[LaTeX]TeX,
caption = {Missing Caption}
,label = {lst:missingLabel}
,basicstyle = \footnotesize\ttfamily
,frame = shadowbox
,numbers = left
,breaklines = true
,keywordstyle = \color{darkgreen}
,commentstyle = \color{red}
,tabsize = 2
,backgroundcolor = \color{lightgrey}
,texcsstyle = {*\bfseries\color{blue}}
%,otherkeywords = {$, \{, \}, \[, \]}
,morekeywords = {includegraphics,unit}
,moretexcs = {graphicspath}%
}
\ExplSyntaxOn
\NewDocumentCommand{\commandExample}{v}
{
Output:~\tl_rescan:nn {} {#1} ~ - ~ Code:~\lstinline{#1}
}
\ExplSyntaxOff
\begin{document}
\commandExample{\unit{\meter}}
\commandExample{\textit{word}}
\end{document}
答え2
一般的にegregが提供したコード私のコードよりも優先されます。
\mathescape=true
しかし、内を介して有効になり、の間にものをネストすることで\lstset
の引数内で数式モードにエスケープできるようにするmathescape メカニズムは、 v-type 引数に直接適用すると壊れます。\lstinline
$...$
\lstinline
mathescape を有効にすると、コマンドは、v-type-argument としてトークン化された場合に、\lstinline{$x^2+y^2=2^2$}
パターンのエラー メッセージを多数取得します。! Undefined control sequence. \lst@arg ->$x
$x^2+y^2=2^2$
したがって、実際のシナリオで mathescape 機能が必要ない場合は、egreg のコードを使用することをお勧めします。
実際のシナリオで mathescape 機能が必要な場合は、egreg の回答を変更して、\commandExample
適切なカテゴリ コード体制の下で引数を読み取ってトークン化するようにするか、渡されるトークンにも\scantokens
または が適用されるアプローチを試してください。\tl_rescan:nn
\lstinline
小さな問題としては、最近の LaTeX ディストリビューションでは、コードに と の定義が提供されていないことです\unit
。\meter
そのため、以下の例では、代わりに コマンド\si
と\metre
が使用されています。
1 つの問題は次のとおりです。 の特殊性は、\lstinline
の引数は、それ自体も を含む場合、通常と\lstinline
の間にネストできないことです。 この場合、引数は、引数内に出現しない文字の間にネストする必要があります。 したがって、 は機能せず、 のようにする必要があります。 (egreg の回答で行われている別のトリックは、 の引数をverbatim-catcode-régime でトークン化して、カテゴリ 1 またはカテゴリ 2 が含まれないようにすることです。 ただし、 -type-category-code-régime は、 のいくつかの機能(少なくとも mathescape 機能) を破壊します。){
}
{
\lstinline{\unit{\meter}}
\lstinline|\unit{\meter}|
\lstinline
{
}
v
\lstinline
もう 1 つの問題は、TeX では の引数が\lstinline
異なるカテゴリ コード レジームでトークン化されることが想定されていることです。したがって、は\lstinline
、その引数に属するトークンをトークン ストリームから取得するために、カテゴリ コード レジームを一時的に変更します。\lstinline
は、TeX が .tex 入力ファイルから読み取り、変更されたカテゴリ コード レジームで引数に属するトークンをトークン化して、トークン ストリームから取得できるようにする必要があることに依存しています。したがって、 は\lstinline
ユーザー レベル/トップレベルでのみ機能します。\lstinline
は、引数が変更されていないカテゴリ コード レジームでトークン化された後に渡される場合には機能しません。たとえば、変更されていない\lstinline
カテゴリ コード レジームで引数を取得して に渡す他のマクロの定義テキストに への呼び出しを配置する場合などです\lstinline
。
\commandExample
この問題は、引数を取得する前にマクロ自体でカテゴリ コード レジームを変更し、それを に\lstinline
ネストされたに渡すことで、ある程度回避できます\scantokens{...%}
。
しかし、これによってさらに別の問題が発生します。LaTeX 2ε も expl3 も xparse も、逐語的区切り文字を保存して渡すことができる逐語的引数型を提供していません。
したがって、以下の例では\UDcollectverbarg
、逐語的な catcode régime に切り替えて、逐語的な区切り文字なしの引数と区切り文字の間にネストされた引数の両方を取得し、これらが適切に渡されてさらに処理できるようにするコマンドが提供されています。
\makeatletter
%%======================Code for \UDcollectverbarg=============================
%% \UDcollectverbarg{<mandatory 1>}{<mandatory 2>}|<verbatim arg>|
%%
%% reads <verbatim arg> under verbatim-catcode-regime and delivers:
%%
%% <mandatory 1>{<mandatory 2>{<verbatim arg>}{|<verbatim arg>|}}
%%
%% Instead of verbatim-delimiter | the <verbatim arg> can be nested in braces.
%% You cannot use percent or spaces or horizontal tab as verbatim-delimiter.
%%
%% You can use <mandatory 1> for nesting calls to \UDcollectverbarg.
%% <mandatory 2> gets the <verbatim arg> twice: Once without verbatim-delimiters/braces,
%% once surrounded by verbatim-delimiters/braces.
%% Reason: When you feed it to \scantokens you don't need the verbatim-delimiters.
%% When you use it for writing to temporary files and reading back,
%% you need them.
%%=============================================================================
%% Check whether argument is empty:
%%=============================================================================
\@ifdefinable\UD@stopromannumeral{\chardef\UD@stopromannumeral=`\^^00}%
%%
%% \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>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\UD@CheckWhetherNull[1]{%
\romannumeral\expandafter\@secondoftwo\string{\expandafter
\@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
\@secondoftwo\string}\expandafter\UD@stopromannumeral\@secondoftwo}{%
\expandafter\UD@stopromannumeral\@firstoftwo}%
}%
%%=============================================================================
\newcommand\UDcollectverbarg[2]{%
\begingroup
\let\do\@makeother % <- this and the next line switch to
\dospecials % verbatim-category-code-régime.
\catcode`\{=1 % <- give opening curly brace the usual catcode so a
% curly-brace-balanced argument can be gathered in
% case of the first thing of the verbatimized-argument
% being a curly opening brace.
\catcode`\ =10 % <- give space and horizontal tab the usual catcode so \UD@collectverbarg
\catcode`\^^I=10 % cannot catch a space or a horizontal tab as its 4th undelimited argument.
% (Its 4th undelimited argument denotes the verbatim-
% syntax-delimiter in case of not gathering a
% curly-brace-nested argument.)
\catcode`\%=14 % <- make percent comment.
\kernel@ifnextchar\bgroup
{% seems a curly-brace-nested argument is to be caught:
\catcode`\}=2 % <- give closing curly brace the usual catcode also.
\UD@collectverbarg{#1}{#2}{}%
}{% seems an argument with verbatim-syntax-delimiter is to be caught:
\do\{% <- give opening curly brace the verbatim-catcode again.
\UD@collectverbarg{#1}{#2}%
}%
}%
\newcommand\UD@collectverbarg[3]{%
\do\ % <- Now that \UD@collectverbarg has the delimiter or
\do\^^I% emptiness in its 4th arg, give space and horizontal tab
% the verbatim-catcode again.
\do\^^M% <- Give the carriage-return-character the verbatim-catcode.
\do\%% <- Give the percent-character the verbatim-catcode.
\long\def\@tempb##1#3{%
\def\@tempb{##1}%
\UD@CheckWhetherNull{#3}{%
\def\@tempc{{##1}}%
}{%
\def\@tempc{#3##1#3}%
}%
\@onelevel@sanitize\@tempb % <- Turn characters into their "12/other"-pendants.
% This may be important with things like the
% inputenc-package which may make characters
% active/which give them catcode 13(active).
\@onelevel@sanitize\@tempc
\expandafter\expandafter\expandafter\UD@@collectverbarg% <- this "spits out the result.
\expandafter\expandafter\expandafter{%
\expandafter\@tempb\expandafter}%
\expandafter{\@tempc}{#1}{#2}%
}%
\@tempb
}%
\newcommand\UD@@collectverbarg[4]{%
\endgroup
#3{#4{#1}{#2}}%
}%
%%================= End of code for \UDcollectverbarg =========================
\makeatother
%%
\documentclass{report}
\usepackage{graphicx}
\usepackage{xcolor}
\usepackage{siunitx}
\usepackage{listings}
\definecolor{lightgrey}{rgb}{0.9,0.9,0.9}
\definecolor{darkgreen}{rgb}{0,0.6,0}
\lstset{language=[LaTeX]TeX,
% !!! Let's enable the mathescape-feature to test if it works:
mathescape=true,
%
caption = {Missing Caption}
,label = {lst:missingLabel}
,basicstyle = \footnotesize\ttfamily %\footnotesize % \small\ttfamily
,frame = shadowbox%
,numbers = left%
,breaklines = true%
,keywordstyle = \color{darkgreen}%
,commentstyle = \color{red}%
,tabsize = 2%
,backgroundcolor = \color{lightgrey}%
%,texcsstyle = {*\bf\color{blue}}%
%,otherkeywords = $, \{, \}, \[, \]%
,morekeywords = {includegraphics }%
,moretexcs = {graphicspath}%
}
\makeatletter
\NewDocumentCommand{\commandExample}{}{%
\UDcollectverbarg{\@firstofone}{\@commandExample}%
}%
\begingroup
\catcode`\X=14 %
\catcode`\%=12 X
\csname @firstofone\endcsname{X
\endgroup
\NewDocumentCommand{\@commandExample}{mm}{X
\scantokens{Output: #1 - Code: \lstinline#2%}X
}X
}%
\makeatother
\begin{document}
\verb:\commandExample{begin}: yields:
\commandExample{begin}
\medskip\hrule\medskip
\noindent Both with \verb|\lstinline| and thus with this variant of \verb|\commandExample| you can't have
\verb|{| within arguments that are nested between \verb|{...}|. Use some verbatim-delimiter instead:
\medskip
\verb:\commandExample|\si{\metre}|: yields:
\commandExample|\si{\metre}|
\medskip\hrule\medskip
\noindent \verb|mathescape|-thingies in the code seem to work, too:
\medskip
\verb:\commandExample|$x^2+y^2=z^2$|: yields:
\commandExample|$x^2+y^2=z^2$|
\medskip\hrule\medskip
\verb:\commandExample{$x^2+y^2=z^2$}: yields:
\commandExample{$x^2+y^2=z^2$}
\end{document}