14

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

enter image description here

\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},
    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}

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.

Moriambar
  • 11,466
  • 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

3 Answers3

5

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}
David Carlisle
  • 757,742
Paul Gaborit
  • 70,770
  • 10
  • 176
  • 283
4

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

enter image description here

2

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".

Not working example

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

Working result

David Carlisle
  • 757,742
JLDiaz
  • 55,732