% tabto.sty
%
% version 1.4  (Dec 2018)
%
% Tabbing to fixed positions in a paragraph.
%
% Copyright 2006,2009,2012,2013,2018 by 
% Donald Arseneau,   Vancouver, Canada (asnd@triumf.ca)
% Permission to use, distribute and modify this software is granted
% under the conditions of the LaTeX Project Public License, either 
% version 1.3 or (at your option) any later version.  The license is
% found at http://www.latex-project.org/lppl.txt, and is part of all 
% recent distributions of LaTeX.
%
% This work has the LPPL maintenance status `maintained' (by author).
%
% Two new text positioning commands are defined: \tabto and \tab.
% 
% \tabto{<length>}
% Tab to a position relative to the left margin in a paragraph (any
% indentation due to a list or \leftskip is part of the `margin' in
% this context). If the text on the line already goes past the desired
% position, the tab starts a new line and moves to the requested
% horizontal position.
%
% \tabto*{<length>}
% Similar to \tabto, except it will perform backspacing, and over-
% print previous text on the line whenever that text is already
% longer than the specified length (i.e., no linebreak is produced).
% Line-breaks are suppressed immediately after \tabto or \tabto*.
%
% The length register "\CurrentLineWidth" will report the width
% of the existing text on the line, and it may be used in the
% <length> argument (using calc.sty, for example). Also, there
% is "\TabPrevPos" which gives the "\CurrentLineWidth" from the
% previous tab command (the position where the tab command occurred,
% not where it went to), and can be used to return to that position
% if no line breaks have occurred in between, or directly below it,
% if there were line breaks.
%
% \tab
% Tab to the next tab-stop chosen from a list of tab positions, in
% the traditional style of typewriters.  A \tab will always move
% to the next tab stop (or the next line), even if it is already
% exactly at a tab stop. Thus, "\tab" at the beginning of a line,
% or "\tab\tab" elsewhere skips a position. A linebreak is permitted 
% immediately following a \tab, in case the ensuing text does not 
% fit well in the remaining space.
%
% If you do not want to skip positions, use "\tabto{\NextTabStop}"
% instead of "\tab".  This is particularly useful when you want to
% use \tab in some other command, but do not want to skip a column
% for the first item.
%
% The tab-stop positions are declared using either \TabPositions
% or \NumTabs:
%
% \TabPositions{<length>, <length>,...<length>}
% Declares the tab stops as a comma-separated list of positions 
% relative to the left margin. A tab-stop at 0pt is implicit, and 
% need not be listed.
%
% \NumTabs{<number>}
% Declares a list of <number> equally-spaced tabs, starting at the
% left margin and spanning \linewidth.  For example \NumTabs{2} 
% declares tab-stops at 0pt and 0.5\linewidth, the same as
% \TabPositions{0pt, 0.5\linewidth} or \TabPositions{0.5\linewidth}
%
% After these declarations, the list of tab positions is saved in
% \TabStopList, and the next tab position, relative to the current 
% position, is given by \NextTabStop.  You do not normally need
% to access them, but they are available.
%
% Problems:
%
% Tall objects after a tab stop may overlap the line above, rather
% than forcing a greater separation between lines.

\ProvidesPackage{tabto}[2018/12/28 \space v 1.4 \space 
  Another tabbing mechanism]\relax

\newdimen\CurrentLineWidth
\newdimen\TabPrevPos

\newcommand\tabto[1]{%
 \leavevmode
 \begingroup
 \def\@tempa{*}\def\@tempb{#1}%
 \ifx\@tempa\@tempb % \tab* 
   \endgroup
   \TTo@overlaptrue % ... set a flag and re-issue \tabto to get argument
   \expandafter\tabto
 \else
   \ifinner % in a \hbox, so ignore
   \else % unrestricted horizontal mode
     \null% \predisplaysize will tell the position of this box (must be box)
     \parfillskip\fill
     \everydisplay{}\everymath{}%
     \predisplaypenalty\@M \postdisplaypenalty\@M
     $$% math display so we can test \predisplaysize
      \lineskiplimit=-999pt % so we get pure \baselineskip
      \abovedisplayskip=-\baselineskip \abovedisplayshortskip=-\baselineskip
      \belowdisplayskip\z@skip \belowdisplayshortskip\z@skip
      \halign{##\cr\noalign{%
        % get the width of the line above
        \ifdim\predisplaysize=\maxdimen %\message{Mixed R and L, so say the line is full. }%
           \CurrentLineWidth\linewidth
        \else
           \ifdim\predisplaysize=-\maxdimen 
             % \message{Not in a paragraph, so call the line empty. }%
             \CurrentLineWidth\z@
           \else
             \ifnum\TTo@Direction<\z@
               \CurrentLineWidth\linewidth \advance\CurrentLineWidth\predisplaysize
             \else
               \CurrentLineWidth\predisplaysize 
             \fi
             % Correct the 2em offset
             \advance\CurrentLineWidth -2em
             \advance\CurrentLineWidth -\displayindent
             \advance\CurrentLineWidth -\leftskip
        \fi\fi
        \ifdim\CurrentLineWidth<\z@ \CurrentLineWidth\z@\fi
        % Enshrine the tab-to position; #1 might reference \CurrentLineWidth
        \setlength\@tempdimb{#1}% allow calc.sty
        %\message{*** Tab to \the\@tempdimb, previous width is \the\CurrentLineWidth. ***}%
        % Save width for possible return use
        \global\TabPrevPos\CurrentLineWidth
        % Build the action to perform
        \protected@xdef\TTo@action{%
           \vrule\@width\z@\@depth\the\prevdepth
           \ifdim\CurrentLineWidth>\@tempdimb
              \ifTTo@overlap\else
                 \protect\newline \protect\null
           \fi\fi
           \protect\nobreak
           \protect\hskip\the\@tempdimb\relax
        }%
        %\message{\string\TTo@action: \meaning \TTo@action. }%
        % get back to the baseline, regardless of its depth.
        \vskip-\prevdepth
        \prevdepth-99\p@
        \vskip\prevdepth
      }}%
      $$
     % Don't count the display as lines in the paragraph
     \count@\prevgraf \advance\count@-4 \prevgraf\count@
     \TTo@action
     %%   \penalty\@m % to allow a penalized line break
   \fi
   \endgroup
   \TTo@overlapfalse
   \ignorespaces
 \fi
}

% \tab -- to the next position
% \hskip so \tab\tab moves two positions
% Allow a (penalized but flexible) line-break right after the tab.
%
\newcommand\tab{\leavevmode\hskip2sp\tabto{\NextTabStop}%
  \nobreak\hskip\z@\@plus 30\p@\penalty4000\hskip\z@\@plus-30\p@\relax}


% Expandable macro to select the next tab position from the list

\newcommand\NextTabStop{%
  \expandafter \TTo@nexttabstop \TabStopList,\maxdimen,>%
}

\def\TTo@nexttabstop #1,{%
    \ifdim#1<\CurrentLineWidth
      \expandafter\TTo@nexttabstop
    \else
      \ifdim#1<0.9999\linewidth#1\else\z@\fi
      \expandafter\strip@prefix
    \fi
}
\def\TTo@foundtabstop#1>{}

\newcommand\TabPositions[1]{\def\TabStopList{\z@,#1}}

\newcommand\NumTabs[1]{%
   \def\TabStopList{}%
   \@tempdimb\linewidth 
   \divide\@tempdimb by#1\relax
   \advance\@tempdimb 1sp % counteract rounding-down by \divide
   \CurrentLineWidth\z@
   \@whiledim\CurrentLineWidth<\linewidth\do {%
     \edef\TabStopList{\TabStopList\the\CurrentLineWidth,}%
     \advance\CurrentLineWidth\@tempdimb
   }%
   \edef\TabStopList{\TabStopList\linewidth}%
}

% default setting of tab positions:
\TabPositions{\parindent,.5\linewidth}

\newif\ifTTo@overlap \TTo@overlapfalse

\@ifundefined{predisplaydirection}{
 \let\TTo@Direction\predisplaysize
 \let\predisplaydirection\@undefined
}{
 \let\TTo@Direction\predisplaydirection
}

