How to align the top lines of frames?

I want to align the top lines of the left and right frames. How to do it?

\documentclass[12pt]{book}
\usepackage[a4paper,margin=25mm,showframe=true]{geometry}
\usepackage{xcolor}

\usepackage{accsupp}
\newcommand*{\noaccsupp}[1]{\BeginAccSupp{ActualText={}}#1\EndAccSupp{}}

\usepackage{showexpl}

\lstset
{
language={[LaTeX]TeX},
alsolanguage={PSTricks},
numbers=left,
numbersep=1em,
numberstyle=\tiny\color{red}\noaccsupp,
frame=single,
framesep=\fboxsep,
framerule=\fboxrule,
rulecolor=\color{red},
xleftmargin=\dimexpr\fboxsep+\fboxrule\relax,
xrightmargin=\dimexpr\fboxsep+\fboxrule\relax,
breaklines=true,
basicstyle=\small\tt,
keywordstyle=\color{blue},
%identifierstyle=\color{magenta},
backgroundcolor=\color{yellow!10},
tabsize=2,
columns=flexible,
explpreset={pos=r},
morekeywords={
graphicspath,
includegraphics,
},
}

\begin{document}
\LTXexample
How to align the top lines of frames?\\
How to align the top lines of frames?
\endLTXexample
How to align the top lines of frames?
\LTXexample
How to align the top lines of frames?\\
How to align the top lines of frames?
\endLTXexample
\end{document}

Note: accsupp only works when this input file is compiled with either xelatex or pdflatex. Compiling it with latex followed by dvips and ps2pdf will not produce a PDF output that allows us not to copy the line numbers.

-
I think rather than messing with showexpl I would just use listings, a tabular environment, minipages and then you should be able to put the stuff in \saveboxes to measure the heights and put them where they belong. No easy way to do such a simple thing as vertical alignment in LaTeX, it's quite sad. I'm sorry I don't have the time for a proper answer right now :/ –  Christian Jun 22 '12 at 17:34

I'll try to explain where the problem is located, and a possible workaround. Be warned, the workaround is very ugly!

The problem is located at different places in the code of showexpl and listings packages (listings is used by showexpl).

The way the package works is the following: it outputs the code into a intermediate file, then it uses listings package to input the code and typeset it nicely formatted, with listings options (in your case, with a red frame around). Finally it stores the result of "executing" that code through TeX into a temporal box, and outputs that box too, side to side with the one created by listings.

The problem is thus how to align the box created by listings (framed in red) and the one created by latex (framed in black in your example).

The package showexpl uses parbox to create both boxes, so apparently it would be enough to insert [t] at the appropiate places, to have "top aligned" parboxes. So the first guess is to add the following in your preamble (after including showexpl package):

\makeatletter
\renewcommand\SX@CodeArea[2]{%
\parbox[t]{#1}{#2}
\rlap{\parbox[t]{#1}{\SX@attachfile}}}
\renewcommand\SX@ResultArea[2]{%
\SX@justification%
\parbox[t]{#1}{#2}%
}
\makeatother

However, this alone won't work. Now the two parboxes are "top" aligned, but "top" alignment only means "move the baseline of the parbox to the baseline of the first line of the parbox".

The problem is that the left box (red frame) and the right box (black frame) have a different concept of what the "first line" is. We have to insert an empty first line ("null box" or \hbox{}) at the beginning of both parboxes, so that they align properly.

In order to insert a \hbox{} at the beginning of the left box, we have to make listings to insert that command before it renders the listing. This can be done using listings basicstyle option: basicstyle=\small\tt\hbox{}, (yucks!)

In order to insert a \hbox{} at the beginning of the right box, we have to modify the code in showexpl which builds that box (called \SX@ResBox). Unfortunately that code is deeply buried inside a macro definition (\SX@put@code@result), so we have to rewrite the complete macro (63 lines of code!) in order to change only two lines inside it.

So the final, complete, code is:

\documentclass[12pt]{book}
\usepackage[a4paper,margin=25mm,showframe=true]{geometry}
\usepackage{xcolor}

\usepackage{accsupp}
\newcommand*{\noaccsupp}[1]{\BeginAccSupp{ActualText={}}#1\EndAccSupp{}}

\usepackage{showexpl}
\makeatletter

% Add [t] to the parbox
\renewcommand\SX@CodeArea[2]{%
\parbox[t]{#1}{#2}
\rlap{\parbox[t]{#1}{\SX@attachfile}}}

% Add [t] to the parbox
\renewcommand\SX@ResultArea[2]{%
\SX@justification%
\parbox[t]{#1}{#2}%
}

% Add \hbox{} at the creation of \SX@ResBox, look up the comment
\renewcommand*\SX@put@code@result{%
\begingroup
\expandafter\lstset\expandafter{\SX@explpreset}%
\let\lst@float=\relax\let\SX@float=\relax
\expandafter\lstset\expandafter{\SX@@explpreset}%
\ifx\lst@float\relax\else
\let\SX@float=\lst@float\let\lst@float=\relax
\edef\@tempa{\noexpand\lst@beginfloat{lstlisting}[\SX@float]}%
\expandafter\@tempa
\fi
\ifx\lst@caption\@empty
\lstset{nolol=true}%
\fi
\if@SX@wide\def\SX@overhang{\marginparwidth+\marginparsep}\fi
\trivlist\item\relax
\stepcounter{ltxexample}\label{\SX@IDENT}%
\SX@defaultWD\SX@width{\SX@width}%
\ifdim\SX@width<\z@
\@tempswatrue
\def\@tempa{t}%
\ifx\@tempa\SX@pos\@tempswafalse\fi
\def\@tempa{b}%
\ifx\@tempa\SX@pos\@tempswafalse\fi
\setlength\@tempdima{\linewidth+\SX@overhang}%
\if@tempswa\@tempdima=.5\@tempdima\fi%
\edef\SX@width{\the\@tempdima}%
\fi
\ifx\SX@rframe\@empty
\long\def\SX@frame##1{##1}%
\else
\let\SX@frame\fbox
\setlength\@tempdima{\SX@width-2\fboxsep-2\fboxrule}%
\edef\SX@width{\the\@tempdima}%
\fi
\isSX@odd{\def\@tempa{l}}{\def\@tempa{r}}%
\makebox[\linewidth][\@tempa]{%
\parbox{\linewidth+\SX@overhang}{%
\let\lst@ifdisplaystyle=\iftrue
\SX@KillAboveCaptionskip\lst@MakeCaption{t}%
\lst@belowskip=\z@
\let\SX@MakeCaption\lst@MakeCaption
\let\lst@MakeCaption\@gobble
\setbox\SX@ResBox\vtop{\hbox{}\hbox{%    <---- HERE, modified line
\SX@frame{%
\@nameuse{\if@SX@varwidth varwidth\else minipage\fi}%
\SX@width\relax\SX@resultInput%
\@nameuse{end\if@SX@varwidth varwidth\else minipage\fi}}}}% <-- Also here, to close a brace
\edef\SX@width{\the\wd\SX@ResBox}%
\@ifundefined{SX@put@\SX@pos}%
{\@latex@error{Parameter `\SX@pos' undefined}\@ehd}%
{\@nameuse{SX@put@\SX@pos}%
{\SX@width}{\box\SX@ResBox}{\SX@codeInput}}%
\let\lst@MakeCaption\SX@MakeCaption
\lst@MakeCaption{b}\SX@KillBelowCaptionskip
}%
}%
\endtrivlist
\ifx\SX@float\relax\else\expandafter\lst@endfloat\fi
\gdef\SX@@explpreset{}%
\endgroup
}
\makeatother

\lstset
{
language={[LaTeX]TeX},
alsolanguage={PSTricks},
numbers=left,
numbersep=1em,
numberstyle=\tiny\color{red}\noaccsupp,
frame=single,
framesep=\fboxsep,
framerule=\fboxrule,
rulecolor=\color{red},
xleftmargin=\dimexpr\fboxsep+\fboxrule\relax,
xrightmargin=\dimexpr\fboxsep+\fboxrule\relax,
breaklines=true,
basicstyle=\small\tt\hbox{},  % <--- Add \hbox{} here too
keywordstyle=\color{blue},
%identifierstyle=\color{magenta},
backgroundcolor=\color{yellow!10},
tabsize=2,
columns=flexible,
explpreset={pos=r},
morekeywords={
graphicspath,
includegraphics,
},
}

\begin{document}
\LTXexample
How to align the top lines of frames?\\
How to align the top lines of frames?
\endLTXexample
How to align the top lines of frames?
\LTXexample
How to align the top lines of frames?\\
How to align the top lines of frames?
\endLTXexample
\end{document}

Which works as desired

-

A "simple" workaround using TikZ:

\documentclass[12pt]{book}
\usepackage[a4paper,showframe=true]{geometry}
\usepackage{xcolor}
\usepackage{tikz}
\usepackage{accsupp}
\newcommand*{\noaccsupp}[1]{\BeginAccSupp{ActualText={}}#1\EndAccSupp{}}
\usepackage{showexpl}

\makeatletter
\renewcommand*\SX@put@r[3]{%
\setlength\@tempdimc{\linewidth-#1-\SX@hsep}%
\begin{tikzpicture}[baseline={(expl.north)}]
\node[draw=red,anchor=base west,line width=1pt,inner sep=1pt,fill=yellow!10]
(expl){\SX@CodeArea{\@tempdimc}{#3}};
\end{tikzpicture}%
\hfill%
\tikz[baseline={(expl.north)}]\node[inner sep=0pt]%
(expl){\SX@ResultArea{#1}{#2}};
}
\makeatother

\lstset
{
language={[LaTeX]TeX},
alsolanguage={PSTricks},
numbers=left,
numbersep=1em,
numberstyle=\tiny\color{red}\noaccsupp,
rulecolor=\color{red},
breaklines=true,
basicstyle=\small\tt,
keywordstyle=\color{blue},
%identifierstyle=\color{magenta},
tabsize=2,
columns=flexible,
explpreset={pos=r},
morekeywords={
graphicspath,
includegraphics,
},
}

\begin{document}
\begin{LTXexample}
How to align the top lines of frames?\\
How to align the top lines of frames?
\end{LTXexample}
How to align the top lines of frames?
\begin{LTXexample}
How to align the top lines of frames?\\
How to align the top lines of frames?
\end{LTXexample}
\end{document}
-
@PeterGrill The overfull \hbox is coming from my inner sep value (5pt instead of 1pt)... Look at my new version. –  Paul Gaborit Jun 23 '12 at 0:29
\begin{LTXexample}\lipsum\end{LTXexample} will produce a truncated formatted output. –  kiss my armpit Jun 23 '12 at 2:07
@Forgiver Have you try this without my patch ? It's another problem. So, it's another question... –  Paul Gaborit Jun 23 '12 at 9:52
@PolGab: yes of course. It is another problem that must be asked in a new question. But please wait for other solutions (if any). –  kiss my armpit Jun 23 '12 at 9:57
@Forgiver I think that is a limitation of showexpl package. It was designed to show "little" example... like all other similar packages. –  Paul Gaborit Jun 23 '12 at 10:02

\makeatletter
\renewcommand\SX@CodeArea[2]{%
\setlength\@tempdima{#1}%
\sbox\@tempboxa{\parbox\@tempdima{#2}}%
\@tempdima=\dp\@tempboxa\raisebox{\dimexpr -\baselineskip-\fboxsep-\fboxrule-2pt}{\usebox\@tempboxa}
\rlap{\raisebox{-\@tempdima}[0pt][0pt]{\SX@attachfile}}}
\makeatother

2pt is the interlineskip

-
If you see the output carefully (at more than 100% magnification), the top of frames are not exactly aligned. –  kiss my armpit Jun 24 '12 at 10:51
@Forgiver: maybe, but when I run your example I have only a frame on the left side, the code part. –  Herbert Jun 24 '12 at 11:45
If you compile my code (without your code snippet), it should look like the attached screen shot above. –  kiss my armpit Jun 24 '12 at 14:56
no, i get the right code without a frame ( current texlive 2011) –  Herbert Jun 24 '12 at 15:01
@Herbert Code and documentation of showexpl package are not "aligned": by default rframe=single. –  Paul Gaborit Jun 24 '12 at 15:59