
Eu faço programas de concertos para meus recitais de alunos usando a classe ConcProg. Há muita repetição nas músicas que são tocadas, então eu gostaria de criar uma abreviação.
Então, em vez disso
\begin{composition}{Folk Song}{}{Twinkle Twinkle Little Star}{Student Name}
\end{composition}
Algo assim.
\newcommand{\twinkle}{{Folk Song}{}{Twinkle Twinkle Little Star}}
\newcommand{\studentname}{{Student Name}}
\begin{composition}\twinkle\studentname
\end{composition}
No entanto, \newcommand parece gostar apenas de vários conjuntos de colchetes quando usados como argumentos para esse novo comando específico. Até onde eu sei, ele ignora colchetes independentes {isto é, colchetes não relacionados a argumentos para aquele \newcommand específico ou comandos colocados dentro de \newcommand}. Na instância deste ambiente personalizado, ocorre um erro.
Segue outro exemplo (que não usa um ambiente personalizado).
%standard input
\newcommand{\wbalTwo}[2] {
This is the Wikibook about LaTeX
supported by #1 and #2}
\item \wbalTwo{John Doe}{Anthea Smith}
%trying to use new command to input args. In this instance, it seems to ignore the internal braces and treats both internally-braced items as a single text string.
\newcommand{\wbalTwo}[2] {
This is the Wikibook about LaTeX
supported by #1 and #2}
\newcommand{\passargs}
Então, existe uma maneira fácil de fazer com que eles tenham a mesma saída?
Responder1
Pelo que você nos contou até agora, não é possível reproduzir o problema e, portanto, rastrear/rastrear a origem do problema está, até certo ponto, associado a suposições.
Primeiro, algumas observações gerais – espero que minhas suposições estejam corretas e que minhas observações sejam úteis:
- No momento de reunir argumentos para macros ou ambientes do fluxo de tokens, a expansão énãoprovocado.
- Caso esteja presente, (La)TeX removerá o nível mais externo de chaves que circunda uminteiroargumento ao inserir esse argumento no texto de substituição durante a expansão.
Depois de "desenterrar" a classe ConcProg no CTAN (https://ctan.org/pkg/concprog), descobri que o ambiente composition
processa quatro argumentos:
- ⟨autor⟩
- ⟨anos de nascimento (e morte)⟩
- ⟨título da composição⟩
- ⟨descrição opcional⟩
Assim com
\begin{composition}{Folk Song}{}{Twinkle Twinkle Little Star}{Student Name}
⟨whatsoever environment-body⟩
\end{composition}
- o primeiro argumento do
composition
-environment seráFolk Song
:, - o segundo argumento do
composition
-environment estará vazio, - o terceiro argumento do
composition
-ambiente seráTwinkle Twinkle Little Star
:, - o quarto argumento do
composition
-ambiente seráStudent Name
:,
enquanto com
\begin{composition}\twinkle\studentname
\end{composition}
- o primeiro argumento do
composition
-environment será\twinkle
:, - o segundo argumento do
composition
-environment será\studentname
, - o terceiro argumento do
composition
-ambiente será\end
:, - o quarto argumento do
composition
-ambiente será:composition
.
Isso ocorre porque a expansão énãoacionado quando o LaTeX reúne argumentos para macros ou ambientes.
Dependendo de como os argumentos são inseridos quando o LaTeX executa/expande as macros subjacentes ao composition
-ambiente, esta forma de buscar argumentos pode levar a todos os tipos de comportamento estranho/errôneo/problemático.
Posso oferecer uma variante customizada do composition
-environment, chamada mycomposition
, que cuida da expansão:
Na verdade, o ambiente não processa nenhum argumento. Em vez disso, ele verifica se o próximo token no corpo do ambiente é expansível ou não. Se for, a expansão ocorrerá até encontrar um token não expansível. (Esteja ciente de que chaves de abertura {
não são tokens expansíveis. ;-)) Então ele pegará um argumento. Faz isso quatro vezes para obter 4 argumentos. Então, internamente, ele passa esses quatro argumentos para a macro subjacente ao composition
ambiente:
\documentclass{ConcProg}
\makeatletter
\newcommand\UD@CheckWhetherNextExpandable[2]{%
\def\UD@reserved@a{#1}%
\def\UD@reserved@b{#2}%
\UD@@CheckWhetherNextExpandable
}%
\newcommand\UD@@CheckWhetherNextExpandable{%
\futurelet\UD@reserved@c\UD@@@CheckWhetherNextExpandable
}%
\newcommand\UD@@@CheckWhetherNextExpandable{%
\ifx\UD@reserved@c\@sptoken\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{\afterassignment\UD@@CheckWhetherNextExpandable\let\UD@reserved@c= }%
{%
\expandafter\ifx\noexpand\UD@reserved@c\UD@reserved@c
\expandafter\UD@reserved@b
\else
\expandafter\UD@reserved@a
\fi
}%
}%
\newcommand\UD@ExpandUntilFirstUnexpandableAndAddToUD@reserved@d[1]{%
\ifx\relax#1\relax\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{\expandafter\endgroup\UD@reserved@d}%
{\UD@CheckWhetherNextExpandable
{\expandafter\UD@@CheckWhetherNextExpandable}%
{\expandafter\UD@AddNextTo\expandafter{\@gobble#1}\UD@reserved@d}%
}%
}%
\newcommand\UD@AddNextTo[3]{%
% \edef..\the\toks@-route prevents halving of hashes.
\toks@\expandafter{#2{#3}}%
\edef#2{\the\toks@}%
\UD@ExpandUntilFirstUnexpandableAndAddToUD@reserved@d{#1}%
}%
\newcommand\UD@ExpandAndAccumulateKArgsAndPassTo[2]{%
\begingroup
\def\UD@reserved@d{#2}%
\expandafter\UD@ExpandUntilFirstUnexpandableAndAddToUD@reserved@d
\expandafter{\romannumeral\number\number#1 000}%
}%
\newenvironment{mycomposition}%
{\UD@ExpandAndAccumulateKArgsAndPassTo{4}{\composition}}%
{\endcomposition}%
\makeatother
\newcommand{\twinkle}{{Folk Song}{}{Twinkle Twinkle Little Star}}
\newcommand{\studentname}{{Student Name}}
\begin{document}
\begin{composition}{Folk Song}{}{Twinkle Twinkle Little Star}{Student Name}%
environment body
\end{composition}
\begin{mycomposition} \twinkle\studentname
environment body
\end{mycomposition}
\begin{mycomposition} \twinkle {Student Name}
environment body
\end{mycomposition}
\begin{mycomposition} {Folk Song}{}{Twinkle Twinkle Little Star} \studentname
environment body
\end{mycomposition}
\begin{mycomposition}{Folk Song}{}{Twinkle Twinkle Little Star}{Student Name}
environment body
\end{mycomposition}
\end{document}