How to align the top lines of frames?
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},
commentstyle=\color[rgb]{0.13,0.54,0.13},
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}
define after loading package showexpl
\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
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
\g@addto@macro\SX@@explpreset{,float=false}%
\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\@addtofilelist\@gobble
\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},
commentstyle=\color[rgb]{0.13,0.54,0.13},
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