Comando robusto che non si espande come argomento \ input

Nov 03 2020

Potrei davvero usare un po 'di aiuto: utilizzo LaTeX casualmente da diversi anni, ma raramente ho dovuto immergermi nei dettagli o nei problemi e non riesco a capirlo.

Problema

Sto lavorando con un .clsfile fornito dalla mia organizzazione che ha una linea (forse) problematica. Definisce una macro che memorizza la seconda cifra della dimensione in punti immessa e quindi la utilizza per inserire un .clofile. Un MWE abbinato è il seguente:

\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}

Ho anche creato un .texfile MWE da compilare:

\documentclass[11pt]{mwe}

\begin{document}
    
\end{document}

Tuttavia, quando lo compilo usando latexmk -synctex=1 -interaction=nonstopmode -file-line-error -pdf -outdir=%OUTDIR% %DOC%(all'interno di VSCode usando LaTeX Workshop), ottengo questo file di registro con un messaggio che dice

`File `[email protected]' not found`

Il registro dice:

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: 

Potenziale soluzione

Ecco il punto: se cambio il .clsfile in modo che @ptsizesia definito tramite \newcommande \renewcommandanziché tramite \newrobustcmde \renewrobustcmd, il .texfile MWE sopra funziona perfettamente, generando un PDF vuoto (di due pagine).

Qualcuno potrebbe a) spiegare perché questo sta accadendo (per quanto ne so, questo .clsfile funziona bene per altre persone nella mia organizzazione), eb) quale sarebbe l'approccio migliore per questo problema? Grazie in anticipo!

Risposte

4 PhelypeOleinik Nov 04 2020 at 19:49

La differenza nel comportamento può essere vista in questo codice di esempio:

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

che era solito inserire size11.clo, ma dalla versione LaTeX 2020-10-01 non lo è più, ma si sbaglia con:

! 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:

Questo è stato un cambiamento deliberato nel meccanismo di analisi del nome file di LaTeX. È stato sostituito da un parser più robusto che non espande le macro protette (insieme a molte altre chicche). Il comportamento del nuovo parser è quella corretta per quanto riguarda le macro robusti: questi non possono lavorare in contesti di espansione-solo perché si romperà un modo o nell'altro ( che si possono trovare tonnellate di esempi di quel giro ), in modo da non li in espansione è la cosa ragionevole fare.

Il file di classe nella tua organizzazione utilizza in modo improprio comandi robusti per memorizzare alcuni dati (ciò che di solito chiamiamo "elenco di token"). Dati del genere per lo più devono sempre essere disponibili per altre macro, quindi devono espandersi, quindi non possono essere robusti / protetti. La cosa giusta da fare, se puoi modificare il file di classe, è sostituirlo \(re)newrobustcmdcon \(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}

Per la cronaca, il messaggio di errore

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

sembra così perché il parser del nome file funziona con \escapechar=-1, quindi \@ptsizeviene colpito con \stringe diventa @ptsize.

2 UlrichDiez Dec 05 2020 at 02:00

Se per qualche oscuro motivo si deve insistere sulla memorizzazione di dati che dovrebbero essere recuperabili in robuste macro, allora puoi attivare tu stesso l'espansione e il posizionamento nell'ordine corretto dei token, usando alcuni \expandafter/ \romannumeral/ scambio di argomenti: inganno:

file 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%
}

Sul mio sistema compilando un file test.tex:

\documentclass{mwe}
\stop

restituisce questo output della 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 questo file 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)

Alle tue domande:

a) spiegare perché sta accadendo (per quanto ne so, questo file .cls funziona bene per altre persone nella mia organizzazione)

Sono state introdotte modifiche significative al kernel LaTeX 2ε. Una delle modifiche più recenti è che all'interno dell'argomento delle \input{...}macro robuste non vengono espanse.

Questi cambiamenti sono buoni e fastidiosi allo stesso tempo: sono buoni perché con molte cose il modo in cui funzionano ora mi sembra più rigoroso. Sono fastidiosi perché devo guardare di nuovo il codice e abituarmi. ;-)

Probabilmente le altre persone nella tua organizzazione non usano una delle versioni più recenti del kernel LaTeX 2ε e quindi le modifiche introdotte con le versioni più recenti del kernel LaTeX 2ε non influenzano il modo in cui le cose funzionano sulle loro macchine .

b) quale sarebbe l'approccio delle migliori pratiche per questo problema?

Non so se queste siano "best practice", ma dal momento che ci sono stati così tanti cambiamenti negli ultimi due anni, ho smesso di fare affidamento sulle macro LaTeX 2ε-kernel per funzionare nel modo in cui ero abituato da oltre due decenni. ;-)

Soprattutto non mi affido più al codice mantenuto da altri che eseguono l'espansione nello stesso modo in cui ha fatto due giorni fa e quindi spesso ho il mio codice che fa tutto il lavoro di espansione prima che le cose vengano consegnate come argomenti alle macro di altre persone.

Non lo faccio perché sarei scontento dei cambiamenti e delle innovazioni.

Lo faccio per rendere il mio codice compatibile con il maggior numero possibile di versioni di LaTeX 2ε.