\vbox append: Insufficient line spacing between last line of first \vbox, and first line of second \vbox

Put \strut at the end of the text in the first vbox, and at the beginning of the text in the second.

That solution works. My initial explanation was wrong because I misread \unvbox as \box: The (incorrect) explanation is that each box is treated like a single huge letter when TeX stacks them in a "vertical list"; TeX does not look inside the boxes to see where the baselines of the interior text are, and makes no attempt to make them regularly spaced.

The real explanation for no baseline-skip is that's a feature of \unvbox. But \strut will still do the job.

I presume you are actually doing something that requires \vbox... Probably \parbox is better in the general case. If you are just trying to prevent page breaks, there are better solutions (including \samepage, which works pretty well, as long as you know it only applies to lines in a paragraph).

There are fancier things possible, to rebox the box contents as \vtop and \vbox to measure the heights and depths of first and last lines, and then set \prevdepth so TeX does the vertical spacing based on contents, even without struts.


As egreg explained in this answer:

At the start of a \vbox, the parameter \prevdepth is set to -1000pt and, when you do \unvbox, this value inhibits the interline glue.

In your case, \prevdepth is set to -1000pt right after \setbox\myvboxtwo=\vbox{, among others, and this causes the problem you mentioned when \myvboxtwo is \unvboxed. If you save \myvboxone's depth after it has been set and insert it as the \prevdepth value at the beginning of the assignment to \myvboxtwo, the interline glue will be correct when \myvboxtwo is \unvboxed after \myvboxone.

Note: I switched your code to use LaTeX's \newsavebox instead of TeX's \newbox. AFAIK, it does more checks. Also, during your assignment to \myvboxthree, TeX never switches to horizontal mode, therefore the \hsize setting and the \endgraf are useless.

\documentclass{article}
\usepackage[expansion=alltext,shrink=20,stretch=20]{microtype}
\usepackage{fontspec}
\usepackage{blindtext}
\setmainfont{Verdana}

\newcommand{\mytesttext}{\blindtext[1]}
\newdimen\mydim
\pagestyle{empty}

\newsavebox{\myvboxone}
\newsavebox{\myvboxtwo}
\newsavebox{\myvboxthree}

\begin{document}

\setbox\myvboxone=\vbox{{\hsize=\textwidth \mytesttext \endgraf}}
\mydim=\dp\myvboxone

\setbox\myvboxtwo=\vbox{
  \prevdepth=\mydim
  {\hsize=\textwidth \mytesttext \endgraf}
}

\setbox\myvboxthree=\vbox{
  \unvbox\myvboxone
  \unvbox\myvboxtwo
}

\box\myvboxthree

\end{document}

enter image description here

If we add a very deep box or rule in the last line of \myvboxone, like this:

\setbox\myvboxone=\vbox{
  {\hsize=\textwidth \mytesttext
   \vrule width 0.4pt depth 20pt\endgraf}}

its depth is well taken into account by the above solution (note that I don't show again the start of the first box and the end of the second one: they are the same as above):

enter image description here

April 13 edit

Replying to this comment: if I use the following modified definition of \mytesttext:

\newcommand{\mytesttext}{\blindtext[1]ee eeeeeee eee eee ee eee eee ee eee ee
  eee ee eeeeeee eee eee ee eeen}

then zoomed output where the two \vboxes join is as follows:

enter image description here

The interline looks fine to me.


When the vertical material is \unvboxed then the result does not respect baselineskip above and below such material. If we need to add something below such material then \lastbox trick can be used. This removes the last box from \unvboxed material and returns it to the vertical list again, but the \prevdepth is correctly set and next "normal" line will respect baselineskip settings. But you does not have next "normal" line, you have next \ubvboxed material. So new problem is here. This could be solved by \null (i.e. \hbox{}). The code should be:

\newbox\myvboxone
\setbox\myvboxone=\vbox{{\mytesttext \endgraf}}%
\newbox\myvboxtwo
\setbox\myvboxtwo=\vbox{{\null \mytesttext \endgraf}}%
\newbox\myvboxthree
\setbox\myvboxthree=\vbox
   {{\unvbox\myvboxone \lastbox\kern-\prevdepth \unvbox\myvboxtwo}}%

\box\myvboxthree

\bye

Note that the \myvboxone is the same as your. When it is \unvboxed then \lastbox trick is used followed by \kern-\prevdepth. Now, we are exactly at the baseline of the last line. Next \unvboxed material begins with \null which is positioned to the baseline of last line of \myvboxone. Next line has correct \baselineskip because it was calulated when \myvboxtwo was created.

Edit If you want to use \vboxes from \vsplit then the core trick is to set \splittopskip to \baselineskip, to insert first \penalty0 before the column of the text and to do first "dummy" \vsplit in this \penalty0. This inserts the correct lineskip above the first line in the column. Next \vsplits inserts correct lineskip above the rest of the column too. So you are sure that the material from \vplit behaves like as the \null is here (but it is not here:). The connection of splitted parts back together needs only the \lastbox trick now. Example:

\newbox\myvboxone
\newbox\myvboxtwo
\newbox\myvboxthree
\newbox\allcolumn

\setbox\myvboxone=\vbox{{\mytesttext \endgraf}}% begin of the text

\splittopskip=\baselineskip      % << core trick is here + \penaty0
\setbox\allcolumn=\vbox{{\penalty0 \mytesttext \endgraf}}

\setbox0=\vsplit\allcolumn to0pt % this resets \allcolun, now it starts with 
                                 % correct skip above the first line.

\setbox\myvboxtwo=\vsplit\allcolumn to3\baselineskip % three lines from \allcolumn

\setbox\myvboxthree=\vbox  % cat begin of the text with three lines from \allcolumn
   {\unvbox\myvboxone \lastbox\kern-\prevdepth \unvbox\myvboxtwo}%

\bigskip test1:\medskip  \copy\myvboxthree % testing of the result 

\setbox\myvboxtwo=\vsplit\allcolumn to4\baselineskip % next 4 lines from \allcolumn

\setbox\myvboxthree=\vbox % cat previous text with next four lines 
   {\unvbox\myvboxthree \lastbox\kern-\prevdepth \unvbox\myvboxtwo}%

\bigskip test2:\medskip  \box\myvboxthree % testing of the result

\bye