
Estoy tratando de encontrar una manera de tener una macro en la que demuestre el resultado de un comando y luego muestro el comando mediante un lstinline
comando. He leído que necesito escapar de los caracteres especiales (como {
y }
) y ahora me pregunto si hay alguna manera de hacerlo automáticamente. No estoy seguro de si esto es posible.
Idealmente, el \commandExample{\qty{1.2}{\meter}}
comando produciríaOutput: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}
Respuesta1
Absorbería el argumento palabra por palabra y lo utilizaría \tl_rescan:nn
para componerlo.
\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}
Respuesta2
Generalmenteel código proporcionado por egreges preferible a mi código.
Pero el mecanismo mathescape, que se habilitará a través de \mathescape=true
inside \lstset
y que permite escapar al modo matemático dentro del argumento de \lstinline
anidando cosas entre $...$
, se rompe cuando se aplica \lstinline
directamente al argumento de tipo v.
Con mathescape habilitado, el comando \lstinline{$x^2+y^2=2^2$}
obtiene muchos mensajes de error de patrón ! Undefined control sequence. \lst@arg ->$x
en caso de que $x^2+y^2=2^2$
se haya tokenizado como un argumento de tipo v.
Entonces, si en el escenario de la vida real no necesita la función mathescape, recomiendo usar el código de egreg.
Si en el escenario de la vida real necesita la función mathescape, modifique la respuesta de egreg para que \commandExample
lea y tokenice su argumento bajo el régimen de código de categoría apropiado o pruebe un enfoque en el que \scantokens
o también \tl_rescan:nn
se aplique a los tokens pasados .\lstinline
Un problema menor es: con distribuciones LaTeX menos recientes, su código no proporciona ninguna definición para \unit
y \meter
. Entonces, en el siguiente ejemplo, se utilizan los comandos \si
y en su lugar.\metre
Un problema es: una peculiaridad de \lstinline
es que el argumento de \lstinline
normalmente no puede anidarse entre {
y }
si él mismo también contiene {
. En este caso, el argumento debe estar anidado entre un carácter que no aparece dentro del argumento. Entonces \lstinline{\unit{\meter}}
no funcionaría, pero necesitarías hacer algo como \lstinline|\unit{\meter}|
. (Otro truco, que se hace en la respuesta de egreg, es tener el argumento de \lstinline
tokenizado en textual-catcode-régime para que en cualquier caso no contenga {
la categoría 1 o }
la categoría 2. Pero v
-type-category-code-régime se rompe algunas características de \lstinline
—al menos la característica mathescape.)
Otro problema es que TeX espera que el argumento de \lstinline
sea tokenizado bajo un régimen de código de categoría diferente. Por lo tanto, \lstinline
cambia temporalmente el régimen de código de categoría para tomar los tokens que pertenecen a su argumento del flujo de tokens. \lstinline
se basa en que TeX necesita leer del archivo de entrada .tex y tokenizar los tokens que pertenecen al argumento bajo el régimen de código de categoría modificado para que puedan ser tomados del flujo de tokens. Por lo tanto, \lstinline
solo funciona en el nivel de usuario/nivel superior. \lstinline
no funciona cuando los argumentos se pasan después de tokenizarlos bajo un régimen de código de categoría sin cambios, como sería el caso, por ejemplo, cuando se realizan llamadas a \lstinline
en los textos de definición de otras macros que toman argumentos bajo un régimen de código de categoría sin cambios y los pasan a \lstinline
.
Este problema se puede evitar hasta cierto punto haciendo que la macro \commandExample
cambie el régimen del código de categoría antes de tomar los argumentos y luego pasarlos a \lstinline
, anidados en \scantokens{...%}
.
Pero aquí surge otro problema: ni LaTeX 2ε ni expl3 ni xparse proporcionan un tipo de argumento textual que le permita conservar y transmitir el delimitador textual.
Por lo tanto, en el siguiente ejemplo se proporciona el comando \UDcollectverbarg
que cambia al régimen de catcode textual y toma el argumento sin y anidado entre el delimitador textual para que estas cosas puedan transmitirse correctamente para su posterior procesamiento.
\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}