# How do I create parallel columns that automatically adjust line spacing

Let's say I have some text that I have in multiple languages and want to display in parallel, as shown below. This text might span multiple pages.

How can I make it so that the line height on the shorter texts is automatically adjusted to make it take up the same amount of space as the longest text, as shown above?

EDIT: Here's an example using Malipivo's approach which is close to what I want except that it does not deal with page-breaking for text that spans multiple pages. The text wrapping is also a bit ugly, but I can probably manage to finagle around that issue.

• Please try to make your question clear and simple by giving a minimal working example (MWE): you'll stand a greater chance of getting help. Hints like I do (not) like multicol or It need (not) to deal with page-breaking are also helpful. – Symbol 1 Mar 17 '15 at 2:52
• Maybe you can get some inspiration in the solution given by egreg in tex.stackexchange.com/questions/147545/…, and perhaps this might be also of help tex.stackexchange.com/questions/128615/… – summer Mar 17 '15 at 5:40
• In a vertical group you could use \baselineskip=12pt plus 1fill. – Malipivo Mar 17 '15 at 9:44
• @Symbol1 I did mention multiple pages in the question, but I guess it wasn't obvious, so I've emphasized it now. I don't care especially what library is used (multicol, parcolumns, etc.) as long as it works. – Peter Olson Mar 17 '15 at 18:11
• paracol and eledpar are both used for this purpose. – John Kormylo Mar 18 '15 at 21:05

My solution introduces the \langs{text1}{text2}{text3} macro with desired output. The implementation calculates the coefficients for all three columns and uses \vsplit with these coefficients if the text spans multiple pages.

Of course, my solution is in plain TeX but if you need to use it in another formats, I believe that this will be no problem.

\newdimen\colhsize
\newcount\tmpnum \newdimen\tmpdim
\newdimen\pagesize \newdimen \maxht \newdimen\coef
\newif\ifrepeat

{\lccode\?=\p \lccode\!=\t  \lowercase{\gdef\ignorept#1?!{#1}}}

\def\langs#1#2#3{\setbox1=\vbox{\setbaselines #1}\setbox0=\vsplit1 to0pt
\setbox2=\vbox{\setbaselines #2}\setbox0=\vsplit2 to0pt
\setbox3=\vbox{\setbaselines #3}\setbox0=\vsplit3 to0pt \printlangs
}
\def\setbaselines{\penalty0
}
\def\printlangs{\par \repeattrue
\loop \maxht=\ht1
\ifdim\maxht<\ht2 \maxht=\ht2 \fi  \ifdim\maxht<\ht3 \maxht=\ht3 \fi
\pagesize=\pagegoal
\ifdim\pagesize=\maxdimen \pagesize=\vsize
\ifdim\maxht>\pagesize
\tmpnum=\maxht \divide\tmpnum by256
\splitlang1 \splitlang2 \splitlang3
\putlangboxes\pagesize{11}{12}{13}\vfil\break
\else \putlangboxes\maxht123 \repeatfalse \fi
\ifrepeat \repeat
}
\def\splitlang#1 {\coef=\ht#1 \divide\coef by\tmpnum \multiply\coef by256
\tmpdim=\pagesize
\setbox 1#1=\vsplit #1 to \expandafter\ignorept\the\coef \tmpdim
}
\def\putlangboxes#1#2#3#4{\hbox{\vbox to#1{\unvbox#2}\kern2em
\vbox to#1{\unvbox#3}\kern2em \vbox to#1{\unvbox#4}}}

%%% The test:

\def\text{Rr eiewb ei s sd fuz dhg fg zd jd ffj  xds c sg xv fxdz xvv zhx cdfg.}
\def\textA{\text\par\text\text\par\text}
\def\textB{\text\text\text\par\text\text\par\text\text}
\def\textC{\text\text\par\text\text\text}

This text is before language columns. \text\text

\langs{Language one: \textA\textA\textA\textA\textA\textA\textA\textA}
{Language two: \textB\textB\textB\textB\textB\textB\textB\textB}
{Language three: \textC\textC\textC\textC\textC\textC\textC\textC}

This text follows. \text\text

\bye


Explanation of implementation details. The text1 is set to box1 as \vbox with \baselineskip=\baselineskip plus\vsize. This makes potential stretching of \baselineskip. The text2 is set to box2 and text3 to box3 similarly. The first element of all boxes are \penalty0. The first \vsplit to all three boxes is applied at this \penalty0 in order to set the \splittopskip above the first line in all boxes. This ensures that the first line will be at the same position in all three boxes when we will do \vbox to something{\unvbox1} etc.

The \printlangs macro measures the space on the page \pagesize and does the loop of splitting texts. The \maxht is maximal height of the boxes. If \maxht>\pagesize then we need to split the boxes and repeat the loop. Else we need to print the boxes and end the loop. The macro \splitlang does the \vsplit of the given box to the given size \pagesize multiplied by coeeficient \ht-of current box over \maxht. The result of the splitting is stored from box1 to box11, from box2 to box12, from box3 to box13. The macro \putlangboxes prints \hbox{\vbox{}\vbox{}\vbox{}}, i.e the three columns and does reboxing all given boxes to the size given in #1.

Edid: I have had a bug in the \setbaselines: \advance\baselineskip by 0pt plus\vsize. The \vsize value was incremented per each line and as the result the value was overfull at line 49 and next lines have had negative plus value. Solution: I write plus1em. This value will never overfull. Another solution: write plus1fil.

Maybe I dont understand it correctly but one suggestion is the following MWE. I compiled via pdflatex.

\documentclass{scrreprt}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}

% http://uucode.com/blog/2010/12/06/multi-page-tables-with-inter-row-page-breaks/
\usepackage{lipsum}
\usepackage{cals}
\usepackage[latin]{babel}
\showboxdepth=100

\makeatletter
\let\oldDispatch=\cals@row@dispatch
\newbox\rowBefore
\newbox\rowAfter
\newbox\decorationCopy
\newdimen\splitHeight

\def\cals@row@dispatch{%
\cals@ifbreak\iftrue % detect that a break is required
\ifdim \splitHeight>50pt % break inrow only if at least 100pt left
\advance\splitHeight -5pt % avoid pagebreak due to overflows
%
% Split the current row on two: before and after the break
%
\setbox\rowBefore=\hbox{}
\setbox\rowAfter=\hbox{}
\def\next{%
\setbox0=\lastbox
\ifvoid0
\def\next{\global\setbox\rowBefore=\box\rowBefore
\global\setbox\rowAfter=\box\rowAfter }%
\else
\setbox2=\vsplit0 to\splitHeight
\setbox\rowBefore=\hbox{\box2 \unhbox\rowBefore}%
\setbox\rowAfter=\hbox{\box0 \unhbox\rowAfter}%
\fi
\next}
\setbox0=\hbox{\unhbox\cals@current@row \next}
%
% Decoration backup, typeset the first row,
% restore context, typeset the second at the end of macro
%
\setbox\decorationCopy=\copy\cals@current@cs
\setbox\cals@current@row=\box\rowBefore
\ht\cals@current@cs=\ht\cals@current@row
\oldDispatch
\cals@issue@break
\setbox\cals@current@row=\box\rowAfter
\cals@reheight@cells\cals@current@row
\setbox\cals@current@cs=\box\decorationCopy
\ht\cals@current@cs=\ht\cals@current@row
\let\cals@current@context=b
\fi
\fi
\oldDispatch}
\makeatother

\makeatletter
\def\cals@rs@width{0pt}
\def\cals@cs@width{0pt}
\def\cals@rs@color{red}
\makeatother

\begin{document}

\begin{calstable}
\colwidths{{150pt}{150pt}{150pt}}
% \mdseries \erow}
\brow \cell{\lipsum[ 1]}\cell{\lipsum[ 2]}\cell{\lipsum[ 3]} \erow
\brow \cell{\lipsum[16]}\cell{\lipsum[17]}\cell{\lipsum[18]} \erow
\end{calstable}

\end{document}


The most part is used from http://uucode.com/blog/2010/12/06/multi-page-tables-with-inter-row-page-breaks/

I have reset the linewidth to zero in order to prevent black lines. Also I have removed the header, so pagebreaks can go along cells. You have to input your text in one cell of each column.

Best regards

Peter Ebelserger

• This seems to work fine for making the parallel cells that go over a page break, but as far as I can tell, the line height is not adjusted to make the text in parallel cells take up the same vertical space. (See picture example in question to see what I mean) – Peter Olson Mar 19 '15 at 20:53
• Now I understand. But my example solves another problem. ;) – Peter Ebelsberger Mar 19 '15 at 21:02