# Low-level command for controlling left superscript spacing

This question has led to a new package: leftindex

It is a well-known problem that there seems to be no automatic way of getting nice spacing for left indices, particularly left superscripts. The most standard choice of command seems to be \prescript from mathtools, but superscripts suffer from the same problem as with other options:

\documentclass{article}

\usepackage{mathtools}

\begin{document}

$\prescript{a}{b}{f}, \qquad \prescript{a}{b}{\int}$

\end{document}


What I would like is a low-level, manual solution to this problem: A command

\manualprescript{<height>}{<superscript indentation>}{<subscript indentation>}
{<superscript>}{<subscript>}{<symbol>}


where I can manually specify the height and the indentation of the indices. This could be either using TeX dimensions (e.g. .3em) or as tokens to be plugged into \vphantom and \hphantom. Either solution will be fine by me (or both, if you have the time). I could probably come up with some (very) bad solution to this myself using boxes and \phantom’s, which is why I am asking in here in order to obtain the right solution. (If possible, I would prefer a solution in LaTeX3 syntax since this is usually more readable and future-proof).

• \documentclass{article} \usepackage{mathtools} \begin{document} $\prescript{\rlap{a}}{b}{\int}$ \end{document} ? Aug 6 '20 at 17:26
• @Zarko, well, then if the upper index is too long, it will just run into the integral. And it does not allow me to manually control the spacing the way I want to. Aug 6 '20 at 17:30

You can do it automatically.

\documentclass{article}
\usepackage{amsmath,mathtools,xparse}

\makeatletter
\NewDocumentCommand{\preint}{e{^_}}{\mathpalette\pre@int{{#1}{#2}}\!\int}
\newcommand{\pre@int}[2]{\pre@@int#1#2}
\newcommand{\pre@@int}[3]{%
\sbox0{$#1\int\sb{xxxxxx}$}%
\sbox2{$#1{\int}\sb{xxxxxx}$}%
\setlength{\dimen4}{\dimexpr\wd2-\wd0\relax}%
% compute the spacing
\settowidth{\dimen0}{$\m@th#1^{\IfValueT{#2}{#2}}$}%
\settowidth{\dimen2}{$\m@th#1_{\IfValueT{#3}{#3}}$}%
\ifdim\dimen0>\dimen2 \kern\dimen0\else\kern\dimen2\fi
% print the scripts
\mathop{}\!%
{\mbox{$#1\vphantom{\int}$}}
^{\mathmakebox[0pt][l]{\mathmakebox[\dimen4][r]{\IfValueT{#2}{#2}\mspace{-1mu}}}}
_{\mathmakebox[0pt][r]{\IfValueT{#3}{#3}}}
}
\makeatother

\begin{document}

$x\preint_a^b f(x)\,dx + \preint_a^{b+c+d} f(x)\,dx$
\begin{center}
$x\preint_a^b$
\end{center}

\end{document}


• Thanks for the solution! But how can one adjust it so that it does not just fit \int, but arbitrary symbols? I suspect that one will have to specify some dimensions (or degrees of slanting) manually, since the symbols f, M, and \Gamma have different slanting and therefore require different spacing. Can one turn this solution into a general, low-level command like I suggested in the original post? Aug 7 '20 at 7:31
• @Gaussler The integral is quite special. A general command? I’m afraid it’ very hard, if not impossible, because it depends on the shape of the symbol. Aug 7 '20 at 8:21
• But that’s why I wanted a very low-level command as specified in the original post, where I can specify all those dimensions manually. One could add another factor: The slanting factor of the symbol. For \Gamma, this slanting factor is 0, and for f, it’s probably about 0.2, i.e. you have to indent by about 0.2 times the height of the symbol. (This requires more thorough testing, but the important thing is to get a manual, low-level command that allows you to plug in all this information and get a result.) Aug 7 '20 at 8:28
• @Gaussler The ideas are there: the vertical dimensions can be emulated; add an argument for a horizontal displacement for both subscript and superscript, instead of computing it like I did for the integral. Then compensate the space in a similar way. Aug 7 '20 at 8:34
• Yes, you are right. I will adjust it myself, even though I probably cannot do it on an egreg level. xD Thanks for the answer! :-) Aug 7 '20 at 8:37

This solution is now available as a package: leftindex

I tried adjusting egreg’s answer to the general case. It is not built specifically for \int and therefore does not produce quite as perfect an output for that particular symbol. The benefit is that it provides relatively nice results in the general case. I provide the command

\leftindex^{<left superscript>}_{<left subscript>} {<symbol>}


This will indent the left superscript with the same value as the negative indentation of the right subscript. Sometimes, this yields wrong results. Therefore, the command takes two additional, optional arguments:

\leftindex[<slanting phantom>][<height phantom>]
^{<left superscript>}_{<left subscript>} {<symbol>}


This one will instead calculate the left superscript indentation using the <slanting phantom>. If provided, it will calculate the height based on the <height phantom>.

There is also another, underlying command

\manualleftindex
{<height phantom>}
{<slanting phantom>}
{<subscript>}
{<superscript>}


which is mainly intended for use in other commands (or packages).

\documentclass{article}

\usepackage{expl3,mathtools,kpfonts}

\ExplSyntaxOn

\RequirePackage{xparse,mathtools}
\ProvidesExplPackage{leftindex}{2020/08/24}{0.1alpha}{}

\DeclareDocumentCommand\manualleftindex { mmmm }
{
% #1 = height phantom
% #2 = slanting phantom
% #3 = left superscript
% #4 = left subscript
\mathpalette \__leftindex_auxiliary_mathpalette_command:nn { {#1}{#2}{#3}{#4} }
}

\ExplSyntaxOff

\DeclareDocumentCommand\leftindex { o o E{^_}{{}{}} m }
{
% #1 = slanting phantom
% #2 = height phantom
% #3 = left superscript
% #4 = left subscript
% #5 = symbol
\IfValueTF {#1}
{
\IfValueTF{#2}
{
\manualleftindex { #2 } { #1 } { #3 } { #4 }
}
{
\manualleftindex { #5 } { #1 } { #3 } { #4 }
}
}
{
\manualleftindex { #5 } { #5 } { #3 } { #4 }
}
#5
}

\ExplSyntaxOn

\cs_new_protected:Npn\leftindex_kern_horizontal:n#1
{
\kern #1 \relax
}

\cs_new_protected:Npn\leftindex_set_mathsurround_to_zero:
{
% This is equivalent to "\m@th"
\dim_set:Nn \mathsurround { 0pt }
}

\cs_new_protected:Npn\__leftindex_auxiliary_mathpalette_command:nn#1#2
{
\__leftindex_auxiliary:nnnnn { #1 } #2
}

\dim_new:N\l__leftindex_phantom_height_dim

\box_new:N \l__leftindex_slanting_phantom_with_subscript_box
\dim_new:N \l__leftindex_slanting_phantom_with_subscript_dim

\box_new:N \l__leftindex_slanting_phantom_with_subscript_without_indentation_box
\dim_new:N \l__leftindex_slanting_phantom_with_subscript_without_indentation_dim

\dim_new:N \l__leftindex_indentation_of_slanting_phantom_subscript

\box_new:N \l__leftindex_superscript_temp_box
\dim_new:N \l__leftindex_width_of_superscript_dim

\box_new:N \l__leftindex_subscript_temp_box
\dim_new:N \l__leftindex_width_of_subscript_dim

\cs_new_protected:Npn\__leftindex_auxiliary:nnnnn#1#2#3#4#5
{
\group_begin:
\hbox_set:Nn \l__leftindex_slanting_phantom_with_subscript_box
{ $#1 #3 \sb{xxxxxx}$ }
\dim_set:Nn \l__leftindex_slanting_phantom_with_subscript_dim
{ \box_wd:N \l__leftindex_slanting_phantom_with_subscript_box }
\hbox_set:Nn \l__leftindex_slanting_phantom_with_subscript_without_indentation_box
{ $#1 \hbox:n {$ #1 #3 $} \sb{xxxxxx}$ }
\dim_set:Nn \l__leftindex_slanting_phantom_with_subscript_without_indentation_dim
{ \box_wd:N \l__leftindex_slanting_phantom_with_subscript_without_indentation_box }
\dim_set:Nn \l__leftindex_indentation_of_slanting_phantom_subscript
{
\l__leftindex_slanting_phantom_with_subscript_without_indentation_dim
-
\l__leftindex_slanting_phantom_with_subscript_dim
}
\tl_if_blank:nTF { #4 }
{
\dim_zero:N \l__leftindex_width_of_superscript_dim
}
{
\hbox_set:Nn \l__leftindex_superscript_temp_box
{
$\leftindex_set_mathsurround_to_zero: #1 \sp { #4 }$
}
\dim_set:Nn \l__leftindex_width_of_superscript_dim
{
\box_wd:N \l__leftindex_superscript_temp_box
-
\l__leftindex_indentation_of_slanting_phantom_subscript
}
}
\tl_if_blank:nTF { #5 }
{
\dim_zero:N \l__leftindex_width_of_subscript_dim
}
{
\hbox_set:Nn \l__leftindex_subscript_temp_box
{
$\leftindex_set_mathsurround_to_zero: #1 \sb { #5 }$
}
\dim_set:Nn \l__leftindex_width_of_subscript_dim
{
\box_wd:N \l__leftindex_subscript_temp_box
}
}
\leftindex_kern_horizontal:n
{
\dim_max:nn
{ \l__leftindex_width_of_superscript_dim }
{ \l__leftindex_width_of_subscript_dim }
}
\mathop{}
\mathopen{ \vphantom { #2 } }
\tl_if_blank:nF { #4 }
{
\sp {
\mathmakebox[0pt][l]{
\mathmakebox[ \l__leftindex_indentation_of_slanting_phantom_subscript ][r]{ #4 }
}
}
}
\tl_if_blank:nF { #5 }
{
\sb {
\mathmakebox[0pt][r]{ #5 }
}
}
\group_end:
}

\ExplSyntaxOff

\begin{document}

$x \leftindex^{a+b}_{c+d} {\int} f(x)\, dx$

$\leftindex^{1}_{0} {f}^u_v \neq \leftindex^{pq}_{0} {H}^u_v$

$\leftindex^{a}_{b} {\Gamma}^c_d \neq \leftindex[]^{a}_{b} {\Gamma}^c_d$

\end{document}


• @egreg Any comments? :-) Aug 23 '20 at 11:59
• The kerning is appropriate for the integral, definitely not for Gamma. Aug 23 '20 at 14:17
• @egreg I don’t quite follow. Is the second solution, \manualleftindex{\Gamma}{}{a}{b}, not appropriate for \Gamma? On the surface, it looks good to me. Aug 23 '20 at 14:29
• Yes, the right-hand side is good, which I can't say about the left-hand side. Aug 23 '20 at 14:37
• @egreg No, of course not. ;-) That’s why I have the manual version, to show the difference. :-). Any other comments? I did things mostly as you did, but some things are different, e.g. I include a \mathopen, taking inspiration from mathtools. So I replace {\mbox{$#1\vphantom{\int}$}} by simply \mathopen{\vphantom{#2}}. Are there any issues with this or with other of the changes I made? Any comments will be greatly appreciated. ;-) (I will use this in a package, so I want to make 100 % sure there are no issues before I do. :-) ) Aug 23 '20 at 14:42