The solutions
align
First of all, the final solution I wound up going with (essentially due to David Carlisle) for the align
environment is as follows.
\apptocmd{\place@tag}{%
\if1\shift@tag\row@%
\PackageWarning{custom}{Equation number (\theequation ) has been displaced}%
\fi
}{}{}
equation
For the equation environment, I wound up going with the following solution (explanation below).
\tikzcdset{ampersand replacement=\&} % This makes it so that "\&", not "&", is treated as the column separator in tikzcd environments. (We do this so that it these environments can be passed as arguments (via "\BODY") to our redefinition of the equation environment.) (See https://tex.stackexchange.com/questions/15093/.)
\let\@ldtikzcd\tikzcd % So that we don't have to manually write "\&", we update the "tikzcd" environment so that it automatically replaces the "&"s with "\&"s.
\let\@ldtikzcd\tikzcd
\let\@ldendtikzcd\endtikzcd
\RenewEnviron{tikzcd}[1][]{%
\xpatchcmd*{\BODY}{&}{\&}{}{}% For compatibility with tikz. (Also see \tikzcdset{ampersand replacement=\&} above.)
\@ldtikzcd[#1]%
\BODY%
\@ldendtikzcd%
}
\newbox\tempb@x
\newdimen\stest
\newdimen\smin
\newdimen\smax
\def\find#1#2#3{% Used for \getstretch and \getshrink below. (From https://tex.stackexchange.com/questions/191140/measure-total-glue-in-a-box)
\let\@ldhbadness\hbadness% Need to temporarily redefine \hbadness and \hfuzz so don't get a ridiculously number of warnings as we test for stretchability/shrinkability.
\hbadness=1000000%
\let\@ldhfuzz\hfuzz%
\hfuzz=\maxdimen%
\smin = -\maxdimen
\smax = \maxdimen
\loop
\stest = \smin
\advance \stest by \smax
\divide \stest by 2 % now \stest=(\smin+\smax)/2 truncated to 0
\ifdim \stest = \smax
\advance \stest by -1sp % ensure that \smin<=\stest<\smax.
\fi
\setbox 0 = \hbox spread #2 1sp {%
\unhcopy\tempb@x
\hskip 0pt #3-\stest
}%
\ifnum \badness > 100 % (shrink/stretch in \tempb@x) <= \stest
\smax = \stest
\else
\smin = \stest
\advance \smin by 1sp
% since ">\stest" implies ">=\stest+1sp"
\fi
% In both cases, the interval [\smin,\smax] becomes smaller.
\ifdim\smin<\smax
\repeat
\ifdim\smin>\smax\BOOM\fi% cannot happen, I think
\hfuzz=\@ldhfuzz%
\hbadness=\@ldhbadness%
}
\def\getstretch#1{% Returns the amount of stretchable glue in the \smin register.
\setbox\tempb@x\hbox{#1}%
\find{stretch}{}{plus}%
}
\def\getshrink#1{% Returns the amount of shrinkable glue in the \smin register.
\setbox\tempb@x\hbox{#1}%
\find{shrink}{-}{minus}%
}
% Modifies "equation" environment to test if equation number has been displaced.
\ifdef{\mathindent}{}{\newlength{\mathindent}}% In case \mathindent hasn't been defined, define it. (Will be used in redefinition of equation environment.)
% Modifies "equation" environment to test if equation number has been displaced.
\newlength{\widthofequ@tion}
\newlength{\widthofnumber}
\newlength{\tempshrink@bility}
\newlength{\halfqu@d}
\def\initializelengthsdispl@ced{%
\setlength{\halfqu@d}{\widthof{$\displaystyle \hspace{.5em}$}}%
\getshrink{\ensuremath{\BODY}}% Stores shrink in \smin.
\setlength{\tempshrink@bility}{\smin}%
\setlength{\widthofequ@tion}{\widthof{\ensuremath{\displaystyle\BODY}}}%
\setlength{\widthofnumber}{\widthof{\ensuremath{(\displaystyle\theequation )}}}%
}
\def\istagdispl@ced{% The Lua code expands to 1 if the equation number will be moved, and 0 otherwise.
\directlua{% See pg. 188 of the TeXBook for the notation and algorithm.
w0 = \strip@pt\widthofequ@tion;%
e = \strip@pt\widthofnumber;%
halfquad = \strip@pt\halfqu@d;%
q = e+halfquad;% Knuth says that this should be a quad, not a half quad, but that doesn't seem to work (half a quad seems to work perfectly though).
z = \strip@pt\displaywidth;%
shrinkability = \strip@pt\tempshrink@bility;%.
%
if w0-shrinkability+q > z then
tex.print("1");
else
tex.print("0");
end
}%
}
\def\settagdispl@ced{%
\initializelengthsdispl@ced%
\edef\tagdispl@ced{\istagdispl@ced}%
}
\let\@ldequation\equation
\let\@ldendequation\endequation
\RenewEnviron{equation}{%
\@ldequation% Start equation environment.
%
\BODY% Display actual equation.
% Don't want to "label" twice, so we disable labeling here (will be "label"ed below when defining \@tempequationlength, and need the label to appear there because we want it to be measured when it comes to the legnth).
\let\@ldlabel\label%
\renewcommand{\label}[1]{}%
\let\@ldfootnote\footnote% Similarly for footnotes.
\renewcommand{\footnote}[1]{}%
% Actually test if the equation number has been displaced, and if so, give a warning.
\settagdispl@ced%
\if1\tagdispl@ced%
\PackageWarning{custom}{Equation number (\theequation ) has been displaced}%
\getshrink{\hspace{\mathindent}}%
\hspace{\smin}% Sometimes there are cases where the equation number should be displaced, but instead the equation has been shifted into the left margin. If this should be the case, we add the extra space to actually displace the equation number in order to avoid confusion.
\fi%
% Restore \footnote and \label commands.
\let\footnote\@ldfootnote%
\let\label\@ldlabel%
%
\@ldendequation% Close equation environment.
}
This was actually my second solution to the problem of obtaining similar behavior for the equation
environment as David found for the align
environment.
For both my first and second attempt, the basic idea was to measure the width of the equation and the equation number, and compare the sum of those widths with the \displaywidth
. Naively, the first time around, this is all I took into account, and I found experimentally that comparing instead with .95572663\displaywidth
produced better results. This worked okay, but if the font or margins were changed, or even just for certain equations, this produced the wrong result (the effective coefficient here only worked perfectly using the settings I first tested with). There were two reasons for this. (Incidentally, I figured this out by looking at TeX's algorithm for displaying equations as explained on pg. 188 of The TeXbook.)
The obvious thing I forgot to consider was the space between the equation and equation number---Knuth says this is one quad, but it only worked perfectly if I used half a quad instead of a quad. The not-as-obvious thing I forgot to consider was the shrinkability of the equation. TeX first tries to display the equation at it's natural width, and if that were to displace the equation number, it tries to shrink the equation enough to get the equation number to fit. Only if there is not enough shrinkability does TeX displace the equation number. Thus, what I really wanted to compare was
\widthof{EQUATION}+\widthof{NUMBER}+.5em-\shrinkability{EQUATION}
width \displaywidth
.
To compute the shrinkability, I used the solution to this question. Ultimately, we make use of the macro \getshrink
(defined above) which takes in one argument, puts it in an \hbox
, and stores the shrinkability of that \hbox
in the dimension register \smin
.
Unfortunately, however, things were still not quite as simple as computing the length above, comparing it with \displaywidth
, and then issuing a warning if necessary.
First of all, using \BODY
to actually display the equation and \BODY
to measure the size of the equation results in TeX complaining about double labeling, so I had to manually disable \label
for the one that did the measuring. Similarly for footnotes that might appear in equations.
The third 'hack' needed was to account for equations which contained commutative diagrams. Evidently, tikz
changes the catcode of &
to an active character, which doesn't play nice with being passed to other macros. So I had to tell tikzcd
not to do that (and instead use \&
for that purpose); then I "patched" the tikzcd
environment to automatically replace every &
with a \&
.
Comments
As written, this requires LuaLaTeX. I'm confident you can accomplish the same with just pdfLaTeX, but in this I found writing Lua code for the main part of the algorithm was easier.
I highly doubt something like this is a final solution to things. In my single document alone I ran into two obstacles I needed to fix, so I would imagine that this current solution would break in other scenarios I didn't myself test.
Furthermore, I'm not particularly experienced with this sort of thing, and so there are probably ways my solution can be improved. If you see any such way, I would be happy to hear it.
The complete minimal working example
The final MWE is given below (together with the output and relevant lines from the .log file).
Log:
Package custom Warning: Equation number (2) has been displaced on input line 151.
Package custom Warning: Equation number (3) has been displaced on input line 157.
Overfull \hbox (5.49112pt too wide) in paragraph at lines 157--157
Package custom Warning: Equation number (123456790) has been displaced on input line 164.
Package custom Warning: Equation number (123456791) has been displaced on input line 164.
Overfull \hbox (92.71948pt too wide) in paragraph at lines 164--164
Package custom Warning: Equation number (123456792) has been displaced on input line 170.
Overfull \hbox (33.8307pt too wide) in paragraph at lines 170--170
Output:

Code:
\makeatletter
\documentclass{article}
\usepackage{etoolbox}
\usepackage{regexpatch}
\usepackage{xparse}
\usepackage{calc}
\usepackage{environ}
\usepackage[paperwidth=5in,left=.9375in,right=.9375in]{geometry}
\usepackage{mathtools}
\usepackage{tikz}
\usetikzlibrary{cd}
\tikzcdset{ampersand replacement=\&} % This makes it so that "\&", not "&", is treated as the column separator in tikzcd environments. (We do this so that it these environments can be passed as arguments (via "\BODY") to our redefinition of the equation environment.) (See https://tex.stackexchange.com/questions/15093/.)
\let\@ldtikzcd\tikzcd % So that we don't have to manually write "\&", we update the "tikzcd" environment so that it automatically replaces the "&"s with "\&"s.
\let\@ldtikzcd\tikzcd
\let\@ldendtikzcd\endtikzcd
\RenewEnviron{tikzcd}[1][]{%
\xpatchcmd*{\BODY}{&}{\&}{}{}% For compatibility with tikz. (Also see \tikzcdset{ampersand replacement=\&} above.)
\@ldtikzcd[#1]%
\BODY%
\@ldendtikzcd%
}
\newbox\tempb@x
\newdimen\stest
\newdimen\smin
\newdimen\smax
\def\find#1#2#3{% Used for \getstretch and \getshrink below. (From https://tex.stackexchange.com/questions/191140/measure-total-glue-in-a-box)
\let\@ldhbadness\hbadness% Need to temporarily redefine \hbadness and \hfuzz so don't get a ridiculously number of warnings as we test for stretchability/shrinkability.
\hbadness=1000000%
\let\@ldhfuzz\hfuzz%
\hfuzz=\maxdimen%
\smin = -\maxdimen
\smax = \maxdimen
\loop
\stest = \smin
\advance \stest by \smax
\divide \stest by 2 % now \stest=(\smin+\smax)/2 truncated to 0
\ifdim \stest = \smax
\advance \stest by -1sp % ensure that \smin<=\stest<\smax.
\fi
\setbox 0 = \hbox spread #2 1sp {%
\unhcopy\tempb@x
\hskip 0pt #3-\stest
}%
\ifnum \badness > 100 % (shrink/stretch in \tempb@x) <= \stest
\smax = \stest
\else
\smin = \stest
\advance \smin by 1sp
% since ">\stest" implies ">=\stest+1sp"
\fi
% In both cases, the interval [\smin,\smax] becomes smaller.
\ifdim\smin<\smax
\repeat
\ifdim\smin>\smax\BOOM\fi% cannot happen, I think
\hfuzz=\@ldhfuzz%
\hbadness=\@ldhbadness%
}
\def\getstretch#1{% Returns the amount of stretchable glue in the \smin register.
\setbox\tempb@x\hbox{#1}%
\find{stretch}{}{plus}%
}
\def\getshrink#1{% Returns the amount of shrinkable glue in the \smin register.
\setbox\tempb@x\hbox{#1}%
\find{shrink}{-}{minus}%
}
% Modifies "equation" environment to test if equation number has been displaced.
\ifdef{\mathindent}{}{\newlength{\mathindent}}% In case \mathindent hasn't been defined, define it. (Will be used in redefinition of equation environment.)
% Modifies "equation" environment to test if equation number has been displaced.
\newlength{\widthofequ@tion}
\newlength{\widthofnumber}
\newlength{\tempshrink@bility}
\newlength{\halfqu@d}
\def\initializelengthsdispl@ced{%
\setlength{\halfqu@d}{\widthof{$\displaystyle \hspace{.5em}$}}%
\getshrink{\ensuremath{\BODY}}% Stores shrink in \smin.
\setlength{\tempshrink@bility}{\smin}%
\setlength{\widthofequ@tion}{\widthof{\ensuremath{\displaystyle\BODY}}}%
\setlength{\widthofnumber}{\widthof{\ensuremath{(\displaystyle\theequation )}}}%
}
\def\istagdispl@ced{% The Lua code expands to 1 if the equation number will be moved, and 0 otherwise.
\directlua{% See pg. 188 of the TeXBook for the notation and algorithm.
w0 = \strip@pt\widthofequ@tion;%
e = \strip@pt\widthofnumber;%
halfquad = \strip@pt\halfqu@d;%
q = e+halfquad;% Knuth says that this should be a quad, not a half quad, but that doesn't seem to work (half a quad seems to work perfectly though).
z = \strip@pt\displaywidth;%
shrinkability = \strip@pt\tempshrink@bility;%.
%
if w0-shrinkability+q > z then
tex.print("1");
else
tex.print("0");
end
}%
}
\def\settagdispl@ced{%
\initializelengthsdispl@ced%
\edef\tagdispl@ced{\istagdispl@ced}%
}
\let\@ldequation\equation
\let\@ldendequation\endequation
\RenewEnviron{equation}{%
\@ldequation% Start equation environment.
%
\BODY% Display actual equation
% Don't want to "label" twice, so we disable labeling here (will be "label"ed below when defining \@tempequationlength, and need the label to appear there because we want it to be measured when it comes to the legnth).
\let\@ldlabel\label%
\renewcommand{\label}[1]{}%
\let\@ldfootnote\footnote% Similarly for footnotes.
\renewcommand{\footnote}[1]{}%
% Actually test if the equation number has been displaced, and if so, give a warning.
\settagdispl@ced%
\if1\tagdispl@ced%
\PackageWarning{custom}{Equation number (\theequation ) has been displaced}%
\getshrink{\hspace{\mathindent}}%
\hspace{\smin}% Sometimes there are cases where the equation number should be displaced, but instead the equation has been shifted into the left margin. If this should be the case, we add the extra space to actually displace the equation number in order to avoid confusion.
\fi%
% Restore \footnote and \label commands.
\let\footnote\@ldfootnote%
\let\label\@ldlabel%
%
\@ldendequation% Close equation environment.
}
% Something simliar as above but for "align" environments and related. (See https://tex.stackexchange.com/questions/384222/.)
\apptocmd{\place@tag}{%
\if1\shift@tag\row@%
\PackageWarning{custom}{Equation number (\theequation ) has been displaced}%
\fi
}{}{}
\begin{document}
\begin{equation}
\begin{split}
z & =a+b+c+d+e+f+g+h+i+j+k \\
& +l+m+n+o+p+q+r+s+t+u+v % Does not throw a warning
\end{split}
\end{equation}
\begin{equation}
\begin{split}
z & =a+b+c+d+e+f+g+h+i+j+k+l \\
& +m+n+o+p+q+r+s+t+u+v % Should throw a warning
\end{split}
\end{equation}
\begin{equation}
\begin{split}
z & =a+b+c+d+e+f+g+h+i+j+k+l+m\\&+n+o+p+q+r+s+t+u+v+w % Overfull hbox
\end{split}
\end{equation}
\setcounter{equation}{123456789}
aaa
\begin{flalign}
a+b+c+d&=111+222+333+444+555\\
aaaaaaa+bbbbbbb+cccccc+dddd+eeee&=b
\end{flalign}
bbb
\begin{flalign}
a+b+c+d&=111+222+333+444+5555\\
aaaaaaa+bbbbbbb+cccccc&=b
\end{flalign}
\end{document}
\makeatother
equation
environment that @JPi helpfully added will fix things for your fleqn situation as well.