2

I am writing custom package, and attempting to use aux file for some two-pass typesetting. The punch line is that my package renders some blocks of text which all need to have width equal to the width of the biggest one. My current approach is:

  • Get initial width from aux file (0pt if not present)
  • Calculate max(initial width, width of each block)
  • Typeset
  • Write max width to aux file

This mostly works, with one problem: the max width written to the aux file can never decrease this way, so if the longest block is removed from the document, the typesetting still keeps using its width until I delete the aux file.

It seems to me like the correct solution to this problem is to ignore the width in the aux file if the aux file is older than the tex file; that way, every time the tex file changes, I'll start over with initial width of 0pt. What's the best way to do that?

MWE

\RequirePackage{filecontents}
\begin{filecontents*}{mwe.sty}
\RequirePackage{calc}

\ProcessOptions\relax

\newlength{\maxwidth}
\newlength{\itemwidth}
\gdef\initmaxwidth{0pt}

\newcommand{\updatewidth}[1]{\settowidth{\itemwidth}{#1}\setlength{\maxwidth}{\maxof{\maxwidth}{\itemwidth}}\global\maxwidth=\maxwidth}

\newcommand{\mycmd}[1]{\updatewidth{#1}#1}

\AtBeginDocument{%
    \setlength{\maxwidth}{\initmaxwidth}
}

\AtEndDocument{%
    \immediate\write\@auxout{%
        \gdef\string\initmaxwidth{\the\maxwidth}%
    }
}

\endinput
\end{filecontents*}


\documentclass{article}
\usepackage{mwe}
\begin{document}

\mycmd{M}
\mycmd{I}

Max width is \the\maxwidth .

\end{document}

To repro with this MWE, you have to first latex this file twice (you'll get max width of ~9pt), then change the \mycmd{M} to \mycmd{}, and re-latex the file — notice that max width doesn't decrease.

5
  • 1
    It will probably be tomorrow before I can type up the details, but I would think you could define separate \maxwidthfromaux, \maxwidthsofar, and \maxwidth. Once you get to the end, compare \maxwidthfromaux to \maxwidthsofar.
    – Teepeemm
    Commented Feb 19, 2020 at 23:20
  • 1
    You should calculate the real maximum, without using the value in the aux file, each time the document is processed and then save the current maximum to the aux file as you are currently doing. If the maximum changes then you will need to LaTeX the file twice in order to use the new maximum value. That is, replace step two with "Calculate max(width of each block)".
    – user30471
    Commented Feb 20, 2020 at 0:09
  • This is exactly why longtable uses the aux file, and prior to version 4 had the problem that you describe. Longtable 4 uses an idea of David Kastrup's to overcome this, it records which chunk was used to record the widest entry and does not use the saved version on that chunk, so the code does eventually stabilise just using the current values Commented Feb 20, 2020 at 12:58
  • @DavidCarlisle (Assuming I understand what you mean) wouldn't that only work if the widest chunk is available to BenArtin at the time that he is typesetting the first chunk?
    – Teepeemm
    Commented Feb 20, 2020 at 17:14
  • I agree with the advice from @Andrew which I will paraphrase as a. only write information to the aux file that can be derived from the tex file but b. typeset using information from the tex file + information loaded from the aux file. This ensures that the process is convergent and that stale information is not perpetuated by the aux file. In my particular case, that means that I am now writing the actual width of every block into the aux file, which is then loaded AtDocumentStart and used at that time to calculate the max width, which is then used for typesetting (but never written out).
    – Iris Artin
    Commented Feb 21, 2020 at 0:07

1 Answer 1

0

You mostly already have the pieces, just add one more variable (I'll use \maxwiidthsofar) to track the width as if you didn't know what the aux file told you. When you get to the end, compare that to what the aux file told you and react accordingly.

\documentclass{article}
\RequirePackage{calc}

\newlength{\maxwidth}
\newlength{\maxwidthsofar} % added
\newlength{\itemwidth}
\def\initmaxwidth{0pt}

\newcommand{\updatewidth}[1]{%
 \settowidth{\itemwidth}{#1}%
 \setlength{\maxwidth}{\maxof{\maxwidth}{\itemwidth}}%
 \setlength{\maxwidthsofar}{\maxof{\maxwidthsofar}{\itemwidth}}% added
 \global\maxwidth=\maxwidth%
}

\newcommand{\mycmd}[1]{\updatewidth{#1}#1}

\AtBeginDocument{%
    \setlength{\maxwidth}{\initmaxwidth}
}

\makeatletter
\AtEndDocument{%
    \immediate\write\@auxout{%
        \gdef\string\initmaxwidth{\the\maxwidthsofar}% adjusted
    }
    \ifdim\maxwidthsofar=\initmaxwidth
        \else
            \typeout{^^JMax width changed. Rerun.^^J}
    \fi
}
\makeatother

\begin{document}

\mycmd{M}
\mycmd{I}

Max width is \the\maxwidth .

\end{document}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .