Опасный \if@ в преамбуле dtx

Опасный \if@ в преамбуле dtx

Почему следующий код .dtxне компилируется, а эквивалентный .texфайл компилируется? (Вы должны назвать файл error.dtx, это то, что \DocInputвключено.)

DTX:

% \iffalse meta-comment
%<*driver>
\documentclass{ltxdoc}
\input pgfutil-common
\makeatletter
\def\myitem#1{%
  \pgfutil@in@{,}{#1}%
  \ifpgfutil@in@
    \myitem@#1\@end
  \else
    \myitem@#1,\@end
  \fi
}
\def\myitem@#1,#2\@end{\item\texttt{#1}\quad\marginpar{\small\it#2}}
\makeatother
\begin{document}
  \DocInput{error.dtx}
\end{document}
%</driver>
% \fi
% \begin{description}
%   \myitem{align,key} This is documentation for key \emph{align}.
% \end{description}
% \endinput

Латекс:

\documentclass{ltxdoc}
\input pgfutil-common
\makeatletter
\def\myitem#1{%
  \pgfutil@in@{,}{#1}%
  \ifpgfutil@in@
    \myitem@#1\@end
  \else
    \myitem@#1,\@end
  \fi
}
\def\myitem@#1,#2\@end{\item\texttt{#1}\quad\marginpar{\small\it#2}}
\makeatother
\begin{document}
  \begin{description}
    \myitem{align,key} This is documentation for key \emph{align}.
  \end{description}
\end{document}

решение1

Диагноз, из-за которого это происходит, \elseправильный. Альтернативный подход к решению этой проблемы — поместить новый код в часть Docstrip 'document'. Для этого необходимо преобразовать символы комментариев в определении в^^A

% \iffalse meta-comment
%<*driver>
\documentclass{ltxdoc}
\input pgfutil-common %
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%\makeatletter
%\def\myitem#1{^^A
%  \pgfutil@in@{,}{#1}^^A
%  \ifpgfutil@in@
%    \myitem@#1\@end
%  \else
%    \myitem@#1,\@end
%  \fi
%}
%\def\myitem@#1,#2\@end{\item\texttt{#1}\quad\marginpar{\small\it#2}}
%\makeatother
% \show\myitem
% \begin{description}
%   \myitem{align,key} This is documentation for key \emph{align}.
% \end{description}
% \endinput

решение2

Когда документ обрабатывается во второй раз (вводится \DocInput), TeX находит \iffalseв верхней части файла. Предполагается, что это \iffalseбудет соответствовать \fiследующему за комментарием знаку, тем самым пропуская преамбулу. Но этого не происходит. Он застревает \elseв определении \myitem.

Обычно \ifpgfutil@in@его безопасно использовать во вложенных условных операторах. Так почему же это происходит?

Ответ в том, что TeX не находит «no» \ifpgfutil@in@при втором проходе, так как catcode — @это другой, а не буква — \makeatletterбыл пропущен тем самым \iffalse, который застрял на \ifpgfutil@in@«s» \else...

Быстрое и грубое решение — предоставить комментарий \if, который будет виден только TeX при втором проходе:

% \iffalse meta-comment
%<*driver>
\documentclass{ltxdoc}
\input pgfutil-common
\makeatletter
\def\myitem#1{%
  \pgfutil@in@{,}{#1}%
  \ifpgfutil@in@          %\if
    \myitem@#1\@end
  \else
    \myitem@#1,\@end
  \fi
}
\def\myitem@#1,#2\@end{\item\texttt{#1}\quad\marginpar{\small\it#2}}
\makeatother
\begin{document}
  \DocInput{error.dtx}
\end{document}
%</driver>
% \fi
% \begin{description}
%   \myitem{align,key} This is documentation for key \emph{align}.
% \end{description}
% \endinput

Или, может быть, даже лучше, поместить весь потенциально опасный код в отдельный файл...

Связанный контент