Comando robusto que não se expande como argumento \input

Comando robusto que não se expande como argumento \input

Eu realmente preciso de ajuda - tenho usado LaTeX casualmente há vários anos, mas raramente tive que me aprofundar em detalhes ou problemas, e não consigo descobrir isso.

Problema

Estou trabalhando com um .clsarquivo fornecido pela minha organização que possui uma linha (possivelmente) problemática. Ele define uma macro que armazena o segundo dígito do tamanho do ponto inserido e, em seguida, usa isso para inserir um .cloarquivo. Um MWE emparelhado é o seguinte:

\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{mwe}

\RequirePackage{etoolbox}
\newrobustcmd\@ptsize{}

\DeclareOption{10pt}{\renewrobustcmd\@ptsize{0}}
\DeclareOption{11pt}{\renewrobustcmd\@ptsize{1}}
\DeclareOption{12pt}{\renewrobustcmd\@ptsize{2}}

\ExecuteOptions{11pt}
\ProcessOptions
\input{size1\@ptsize.clo}

Também criei um .texarquivo MWE para compilar:

\documentclass[11pt]{mwe}

\begin{document}
    
\end{document}

No entanto, quando compilo isso usando latexmk -synctex=1 -interaction=nonstopmode -file-line-error -pdf -outdir=%OUTDIR% %DOC%(dentro do VSCode usando LaTeX Workshop), recebo este arquivo de log com uma mensagem dizendo

`File `[email protected]' not found`

O registro diz:

This is pdfTeX, Version 3.14159265-2.6-1.40.21 (MiKTeX 20.11) (preloaded format=pdflatex 2020.11.3)  3 NOV 2020 08:57
entering extended mode
**"path/to/mwe/mwe.tex"
("path/to/mwe/mwe.tex"
LaTeX2e <2020-10-01> patch level 2
L3 programming layer <2020-10-27> xparse <2020-03-03> ("path/to\mwe\mwe.cls" <-- In case it matters, these slashes
Document Class: mwe                                                              really do switch directions
(path\to\tex/latex/etoolbox\etoolbox.sty                                     <-- Here as well
Package: etoolbox 2020/10/05 v2.5k e-TeX tools for LaTeX (JAW)
\etb@tempcnta=\count175
)

! LaTeX Error: File `[email protected]' not found.

Type X to quit or <RETURN> to proceed,
or enter new name. (Default extension: clo)

Enter file name: 

Solução potencial

O problema é o seguinte: se eu alterar o .clsarquivo para que @ptsizeseja definido via \newcommande \renewcommandem vez de via \newrobustcmde \renewrobustcmd, o arquivo MWE acima .texfuncionará perfeitamente, gerando um PDF em branco (duas páginas).

Alguém poderia a) explicar por que isso está acontecendo (até onde eu sei, esse .clsarquivo funciona bem para outras pessoas na minha organização) eb) qual seria a abordagem de práticas recomendadas para esse problema? Agradeço antecipadamente!

Responder1

A diferença de comportamento pode ser vista neste código de exemplo:

\makeatletter
\protected\def\@ptsize{1}
\input{size1\@ptsize.clo}
\stop

que costumava inserir size11.clo, mas desde o lançamento do LaTeX 2020-10-01 isso não acontece mais, em vez disso, apresenta erros com:

! LaTeX Error: File `[email protected]' not found.

Type X to quit or <RETURN> to proceed,
or enter new name. (Default extension: clo)

Enter file name:

Esta foi uma mudança deliberada no mecanismo de análise de nomes de arquivos do LaTeX. Ele foi substituído por um analisador mais robusto que não expande macros protegidas (junto com vários outros benefícios). O comportamento do novo analisador é o correto em relação a macros robustas: estasnão podefuncionam em contextos somente de expansão porque eles irão quebrar de uma forma ou de outra (você pode encontrar toneladas de exemplos de que em volta), portanto, não expandi-los é a coisa razoável a fazer.

O arquivo de classe em sua organização faz mau uso de comandos robustos para armazenar alguns dados (o que normalmente chamamos de “lista de tokens”). Dados como esse geralmente sempre precisam estar disponíveis para outras macros, por isso precisam ser expandidos e, portanto, não podem ser robustos/protegidos. A coisa certa a fazer, se você puder editar o arquivo de classe, é substituir \(re)newrobustcmdpor \(re)newcommand:

\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{mwe}

\RequirePackage{etoolbox}
\newcommand\@ptsize{}

\DeclareOption{10pt}{\renewcommand\@ptsize{0}}
\DeclareOption{11pt}{\renewcommand\@ptsize{1}}
\DeclareOption{12pt}{\renewcommand\@ptsize{2}}

\ExecuteOptions{11pt}
\ProcessOptions
\input{size1\@ptsize.clo}

Para que conste, a mensagem de erro

! LaTeX Error: File `[email protected]' not found.

fica assim porque o analisador de nome de arquivo funciona com \escapechar=-1, então \@ptsizeé atingido \stringe se torna @ptsize.

Responder2

Se por algum motivo obscuro for insistido em armazenar dados que devem ser recuperáveis ​​em macros robustas, então você mesmo pode acionar a expansão e colocar os tokens na ordem correta, usando alguns \expandafter// \romannumeraltruques de troca de argumentos:

arquivo mwe.cls:

\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{mwe}

\RequirePackage{etoolbox}
\newrobustcmd\@ptsize{}

\DeclareOption{10pt}{\renewrobustcmd\@ptsize{0}}
\DeclareOption{11pt}{\renewrobustcmd\@ptsize{1}}
\DeclareOption{12pt}{\renewrobustcmd\@ptsize{2}}

\newcommand\exchangeargs[2]{#2#1}

\ExecuteOptions{11pt}
\ProcessOptions
% It is not relied on \input expanding and putting into correct order
% tokens of its argument.
% Instead \romannumeral-expansion brings all tokens into
% correct order before \input and \input's filename-parsing 
% come into action.
% (This way things might sustain more changes to \input's 
% filename-parsing.)
\expandafter\input\expandafter{%
  \romannumeral
  \expandafter\exchangeargs\expandafter{\@ptsize}{\z@ size1}.clo%
}

No meu sistema compilando um arquivo test.tex:

\documentclass{mwe}
\stop

produz esta saída de console:

$ pdflatex test.tex
This is pdfTeX, Version 3.14159265-2.6-1.40.21 (TeX Live 2020) (preloaded format=pdflatex)
 restricted \write18 enabled.
entering extended mode
(./test.tex
LaTeX2e <2020-10-01> patch level 2
L3 programming layer <2020-10-27> xparse <2020-03-03> (./mwe.cls
Document Class: mwe 
(/usr/local/texlive/2020/texmf-dist/tex/latex/etoolbox/etoolbox.sty)
(/usr/local/texlive/2020/texmf-dist/tex/latex/base/size11.clo)) )
No pages of output.
Transcript written on test.log.

e este arquivo test.log:

This is pdfTeX, Version 3.14159265-2.6-1.40.21 (TeX Live 2020) (preloaded format=pdflatex 2020.11.23)  4 DEC 2020 19:47
entering extended mode
 restricted \write18 enabled.
 %&-line parsing enabled.
**test.tex
(./test.tex
LaTeX2e <2020-10-01> patch level 2
L3 programming layer <2020-10-27> xparse <2020-03-03> (./mwe.cls
Document Class: mwe 
(/usr/local/texlive/2020/texmf-dist/tex/latex/etoolbox/etoolbox.sty
Package: etoolbox 2020/10/05 v2.5k e-TeX tools for LaTeX (JAW)
\etb@tempcnta=\count175
)
(/usr/local/texlive/2020/texmf-dist/tex/latex/base/size11.clo
File: size11.clo 2020/04/10 v1.4m Standard LaTeX file (size option)
)) ) 
Here is how much of TeX's memory you used:
 364 strings out of 479485
 4393 string characters out of 5871962
 273140 words of memory out of 5000000
 17462 multiletter control sequences out of 15000+600000
 535388 words of font info for 30 fonts, out of 8000000 for 9000
 1141 hyphenation exceptions out of 8191
 52i,1n,59p,208b,36s stack positions out of 5000i,500n,10000p,200000b,80000s

No pages of output.
PDF statistics:
 0 PDF objects out of 1000 (max. 8388607)
 0 named destinations out of 1000 (max. 500000)
 1 words of extra memory for PDF output out of 10000 (max. 10000000)

Para suas perguntas:

a) explicar por que isso está acontecendo (até onde eu sei, esse arquivo .cls funciona bem para outras pessoas na minha organização)

Mudanças significativas foram introduzidas no kernel 2ε do LaTeX. Uma das mudanças mais recentes é que dentro do argumento da \input{...}robustez as macros não são expandidas.

Essas mudanças são boas e irritantes ao mesmo tempo: são boas porque, com muitas coisas, a maneira como funcionam agora me parece mais rigorosa. Eles são irritantes porque tenho que olhar o código novamente e me acostumar. ;-)

Provavelmente as outras pessoas em sua organização não usam uma das versões mais recentes do kernel LaTeX 2ε e, portanto, as alterações introduzidas nas versões mais recentes do kernel LaTeX 2ε não afetam a maneira como as coisas funcionam em suas máquinas .

b) qual seria a abordagem de melhores práticas para este problema?

Não sei se essas são "melhores práticas", mas como houve tantas mudanças nos últimos dois anos, parei de depender das macros LaTeX 2ε-kernel para funcionar da maneira que estava acostumado há mais de duas décadas. ;-)

Especialmente, não confio mais no código mantido por outras pessoas que fazem a expansão da mesma maneira que fazia há dois dias e, portanto, muitas vezes tenho meu próprio código para fazer todo o trabalho de expansão antes que as coisas sejam entregues como argumentos para as macros de outras pessoas.

Não faço isso porque ficaria insatisfeito com as mudanças e inovações.

Faço isso para tornar meu próprio código compatível com o maior número possível de versões diferentes do LaTeX 2ε.

informação relacionada