summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/sauerj/parcolumns.dtx
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/contrib/sauerj/parcolumns.dtx
Initial commit
Diffstat (limited to 'macros/latex/contrib/sauerj/parcolumns.dtx')
-rw-r--r--macros/latex/contrib/sauerj/parcolumns.dtx1090
1 files changed, 1090 insertions, 0 deletions
diff --git a/macros/latex/contrib/sauerj/parcolumns.dtx b/macros/latex/contrib/sauerj/parcolumns.dtx
new file mode 100644
index 0000000000..f898e43aae
--- /dev/null
+++ b/macros/latex/contrib/sauerj/parcolumns.dtx
@@ -0,0 +1,1090 @@
+% \iffalse meta-comment
+% Line endings: UNIX
+% Tab size: 4
+%
+% Copyright 2004 Jonathan Sauer
+%
+% This work may be distributed and/or modified under the
+% conditions of the LaTeX Project Public License, either version 1.3
+% of this license or (at your option) any later version.
+% The latest version of this license is in
+%
+% http://www.latex-project.org/lppl.txt
+%
+% and version 1.3 or later is part of all distributions of LaTeX
+% version 2003/12/01 or later.
+%
+% This work has the LPPL maintenance status "maintained".
+%
+% The Current Maintainer of this work is Jonathan Sauer
+% (<jonathan.sauer@gmx.de>).
+%
+% This work consists of the files parcolumns.dtx and parcolumns.ins
+% and the derived file parcolumns.sty.
+%
+% \fi
+%
+% \iffalse
+%
+%<*driver>
+\documentclass{ltxdoc}
+\usepackage{parcolumns}
+\EnableCrossrefs
+\CodelineIndex
+\RecordChanges
+% Modification of verbatim for tabs in listings
+\makeatletter
+{\catcode`\ =\active%
+\catcode`\^^I=\active%
+\gdef\@vobeyspaces{%
+\catcode`\ \active\let \@xobeysp%
+\catcode`\^^I\active\def^^I{~~}%
+}}%
+\makeatother
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+%
+%<package>\NeedsTeXFormat{LaTeX2e}
+%<package>\ProvidesPackage{parcolumns}
+%<package> [2004/11/25 v1.2 Typeset multiple parallel columns]
+%<package>\RequirePackage{processkv}[2004/08/05]
+%
+% \fi
+%
+% \CheckSum{368}
+% \CharacterTable
+% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
+% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
+% Digits \0\1\2\3\4\5\6\7\8\9
+% Exclamation \! Double quote \" Hash (number) \#
+% Dollar \$ Percent \% Ampersand \&
+% Acute accent \' Left paren \( Right paren \)
+% Asterisk \* Plus \+ Comma \,
+% Minus \- Point \. Solidus \/
+% Colon \: Semicolon \; Less than \<
+% Equals \= Greater than \> Question mark \?
+% Commercial at \@ Left bracket \[ Backslash \\
+% Right bracket \] Circumflex \^ Underscore \_
+% Grave accent \` Left brace \{ Vertical bar \|
+% Right brace \} Tilde \~}
+%
+% \DoNotIndex{\@clubpenalty,\@doendpe,\@ehc,\@ifundefined,\@M,\@ne}
+% \DoNotIndex{\@one,\@nobreakfalse,\@plus,\@tempa,\@tempb,\@tempboxa}
+% \DoNotIndex{\@tempcnta,\@tempdima,\@tempdimb,\@tempdimc}
+% \DoNotIndex{\@tempswafalse,\@testopt,\advance,\afterassignment}
+% \DoNotIndex{\box,\brokenpenalty,\clubpenalty,\count@,\csname}
+% \DoNotIndex{\def,\define@key,\displaywidowpenalty,\divide,\dp,\edef}
+% \DoNotIndex{\else,\endcsname,\endgraf,\everypar,\expandafter}
+% \DoNotIndex{\fi,\global,\hbadness,\hb@xt@,\hfill,\hsize,\hskip}
+% \DoNotIndex{\if@tempswa,\ifnum,\ifvoid,\ifx,\interlinepenalty}
+% \DoNotIndex{\lastbox,\leavevmode,\let,\linewidth,\long,\loop}
+% \DoNotIndex{\m@ne,\multiply,\newbox,\newcommand,\newcount}
+% \DoNotIndex{\newdimen,\newenvironment,\newif,\newtoks}
+% \DoNotIndex{\number,\PackageError,\PackageInfo,\processkeyvalues}
+% \DoNotIndex{\relax,\repeat,\setbox,\setkeys,\space,\spaceskip}
+% \DoNotIndex{\splittopsep,\splittopskip,\strut,\strutbox,\the}
+% \DoNotIndex{\toks@,\tolerance,\unvbox,\vbadness,\vbox,\vfuzz}
+% \DoNotIndex{\vrule,\vsplit,\widowpenalty,\z@,\z@skip,\\}
+%
+% \GetFileInfo{\jobname.sty}
+%
+% \title{The \textsf{parcolumns} package\thanks{This document
+% corresponds to \textsf{\filename}~\fileversion, dated \filedate.}}
+%
+% \author{Jonathan Sauer \\ \texttt{jonathan.sauer@gmx.de}}
+%
+% \date{\filedate}
+%
+% \maketitle
+%
+% \begin{abstract}
+% This file describes the \textsf{parcolumns} package that provides an
+% environment for typesetting text in two or more columns columns in
+% parallel.
+%
+% \end{abstract}
+%
+% \tableofcontents
+%
+% \section{Introduction}
+%
+% Sometimes it is necessary to typeset text in two or more columns in
+% parallel, i.e. when typesetting a text in its original language and
+% in its translation(s). This package provides the \verb|parcolumns|
+% environment for typesetting text in several columns, where the text
+% of all columns is aligned vertically.
+%
+% Text in the |parcolums| environment is typeset in chunks, where the
+% chunks of one row are aligned vertically. A chunk consists of one or
+% more paragraphs of text, including \TeX\ macros.
+%
+%
+% \section{Usage}\label{sec:Usage}
+%
+% \DescribeEnv{parcolumns} Usage: |parcolumns| \oarg{options}
+% \marg{number of colums}.
+%
+% Inside the |parcolumns| environment text can be typeset in two or
+% more columns in parallel via the |\parchunk| macro. Normal text can
+% also be included.
+%
+% The \verb|parcolumns| environment takes an optional parameter that
+% specifies the options for the environment using the \textsf{keyval}
+% and \textsf{processkv} packages. The following options exist:
+%
+% \begin{description}
+% \item[\emph{colwidths}] Sets the widths of the columns. The
+% widths are specified as key-values,
+% \meta{columnnumber}=\meta{width}.
+% Columns start at `1'. Note that in
+% order to be ignored by the
+% \textsf{keyval} package, the complete
+% value has to be surrounded by braces,
+% i.e. `|colwidths={1=2cm,3=5cm,4=2cm}|'
+% to set the first column to a width of
+% 2~cm, the third to 5~cm and the fourth
+% to 2~cm. (the second column is
+% calculated)
+%
+% Columns not set this way will be
+% distributed evenly across the remaining
+% horizontal space of the page.
+%
+% \item[distance] Sets the distance between two columns.
+% If omitted set to \verb|2em|.
+%
+% \item[rulebetween] (Flag)\footnote{Meaning that if you
+% just say \texttt{rulebetween}, you set the
+% flag, as well as when you say
+% \texttt{rulebetween=true}. Saying
+% \texttt{rulebetween=false} clears the flag,
+% even though this does not make much sense,
+% as it is the default.}
+% Typeset a vertical bar between two
+% columns.
+%
+% |false| if omitted.
+%
+% \item[nofirstindent] (Flag) Suppress the indentation of the first
+% paragraph in the environment.
+%
+% |false| if omitted.
+%
+% \item[sloppy] (Flag) Typeset text in the columns in a
+% more sloppy way, preventing overfull
+% hboxes at the cost of larger
+% interword spacing.
+%
+% |false| if omitted.
+%
+% \item[sloppyspaces] (Flag) Makes spaces in the columns
+% stretchable, preventing overfull
+% hboxes at the cost of even larger
+% interword spacing that |sloppy|.
+%
+% |false| if omitted.
+%
+% \end{description}
+%
+%
+% \DescribeMacro{\colchunk} Usage: |\colchunk| \oarg{column}
+% \marg{chunk}.
+%
+% The macro |\colchunk| sets a chunk of text for the next column. You
+% don't have to set chunks for all columns; the colums not set remain
+% empty. However, the columns are filled from left to right, so if a
+% column inbetween should remain empty, you must say |\colchunk{}| or
+% specify the column to set using the optional parameter (columns
+% start at 1): |\colchunk[2]{|\ldots|}| sets the text of the second
+% column. Following calls to |\colchunk| without optional parameter
+% fill the third, fourth et cetera column.
+%
+% After a call to |\colplacechunks|, the column number is reset to
+% one.
+%
+%
+%
+% \DescribeMacro{\colplacechunks} Usage: |\colplacechunks|.
+%
+% The macro |\colplacechunks| places the chunks added with |\colchunk|
+% on the page. If there are no chunks to place, it does nothing.
+%
+%
+%
+% \section{Examples}
+%
+% Two columns, option |rulebetween=true| (which is the same as
+% just saying |rulebetween|):
+%
+% \addvspace{\baselineskip}
+% \begin{parcolumns}[rulebetween=true]{2}
+% \colchunk{Erwarten Sie von mir, dass ich rede? -- Nein, Mister
+% Bond, ich erwarte von Ihnen, dass Sie sterben!}
+%
+% \colchunk{Do you expect me to talk? -- No, Mister Bond, I expect you
+% to die!}
+%
+% \colplacechunks
+%
+% \colchunk{Erwarten Sie von mir, dass ich rede? -- Nein, Mister
+% Bond, ich erwarte von Ihnen, dass Sie sterben!}
+%
+% \colchunk{Do you expect me to talk? -- No, Mister Bond, I expect you
+% to die!}
+%
+% \colplacechunks
+%
+% \end{parcolumns}
+% \addvspace{\baselineskip}
+% As the german text is slightly longer, let's make the left column
+% alittle bit larger using |colwidths={1=.55\linewidth}|:
+%
+% \addvspace{\baselineskip}
+% \begin{parcolumns}[rulebetween=true,colwidths={1=.55\linewidth}]{2}
+% \colchunk{Erwarten Sie von mir, dass ich rede? -- Nein, Mister
+% Bond, ich erwarte von Ihnen, dass Sie sterben!}
+%
+% \colchunk{Do you expect me to talk? -- No, Mister Bond, I expect you
+% to die!}
+%
+% \colplacechunks
+%
+% \colchunk{Erwarten Sie von mir, dass ich rede? -- Nein, Mister
+% Bond, ich erwarte von Ihnen, dass Sie sterben!}
+%
+% \colchunk{Do you expect me to talk? -- No, Mister Bond, I expect you
+% to die!}
+%
+% \colplacechunks
+%
+% \end{parcolumns}
+% \addvspace{\baselineskip}
+% Three columns, option |nofirstindent=true|:
+%
+% \addvspace{\baselineskip}
+% \begin{parcolumns}[nofirstindent]{3}
+% \colchunk{This is just a short english text, just long enough to fill
+% a few lines.}
+%
+% \colchunk{Dies ist nur ein kurzer deutscher Text, gerade lang genug,
+% um ein paar Zeilen zu fuellen.}
+%
+% \colchunk{This is another short english text, as my french is not
+% that good anymore.}
+%
+% \colplacechunks
+%
+% \end{parcolumns}
+% \addvspace{\baselineskip}
+% There was an overfull |\hbox| in the previous text. Let's
+% try that again with the option |sloppy|:
+%
+% \addvspace{\baselineskip}
+% \begin{parcolumns}[nofirstindent,sloppy]{3}
+% \colchunk{This is just a short english text, just long enough to fill
+% a few lines.}
+%
+% \colchunk{Dies ist nur ein kurzer deutscher Text, gerade lang genug,
+% um ein paar Zeilen zu fuellen.}
+%
+% \colchunk{This is another short english text, as my french is not
+% that good anymore.}
+%
+% \colplacechunks
+%
+% \end{parcolumns}
+% \addvspace{\baselineskip}
+% No overfull hbox this time, but the spacing in the first column
+% is not optimal. You just have to pick what's better. Or you could
+% try the interword spacing provided by the \textsf{soul} package.
+%
+% \addvspace{\baselineskip}\noindent Maybe we do not want to fill the
+% first column, but do not want to type |\colchunk{}| either. Then we
+% can say |\colchunk[2]| to directly start with the second column
+% (note that we are using the option |sloppy|, too):
+%
+% \addvspace{\baselineskip}
+% \begin{parcolumns}[nofirstindent,sloppy]{3}
+% \colchunk[2]{This is just a short english text, just long enough to fill
+% a few lines.}
+%
+% \colchunk{Dies ist nur ein kurzer deutscher Text, gerade lang genug,
+% um ein paar Zeilen zu fuellen.}
+%
+% \colplacechunks
+%
+% \end{parcolumns}
+% \addvspace{\baselineskip}
+% Note that \texttt{parcolumns} does not insert vertical space
+% before or after the environment! In these examples, the space has
+% manually been added with |\addvspace|.
+%
+%
+%
+% \section{Notes}\label{sec:Notes}
+%
+% \begin{itemize}
+% \item The columns will always fill the complete width of the
+% page by stretching or shrinking the space between the columns.
+% That means that if the total width of all columns is set
+% to about half the page width, the space between the columns
+% will take up the rest, ignoring whatever was set with the
+% key |distance|.\footnote{The key \texttt{distance} is only
+% used for calculating the width of the columns and is ignored
+% afterwards.}
+%
+% \item Footnotes are not set in columns.
+%
+% \item \textsf{parcolumns} does not work very well with displayed
+% formula. The best way to typeset a |displaymath| et.al.
+% environment is to include it in separate |\colchunk|
+% commands, i.e. (assuming two columns and the same formula
+% in both):
+%
+% \begin{verbatim}
+% ... some text placed using \colchunk ...
+% \colchunk{ % Left column
+% \begin{displaymath}
+% x^2 + y^2 = z^2
+% \end{displaymath}
+% }
+% \colchunk{ % Right column
+% \begin{displaymath}
+% x^2 + y^2 = z^2
+% \end{displaymath}
+% }
+% \colplacechunks
+% ... some more text placed using \colchunk ...
+% \end{verbatim}
+%
+% \end{itemize}
+%
+%
+%
+% \StopEventually{}
+%
+% \section{Implementation}
+%
+% \subsection{Allocation}
+%
+% The current column (starting with one):
+%
+% \begin{macrocode}
+\newcount\pc@columnctr
+% \end{macrocode}
+%
+% The total number of columns in the current |parcolums| environment.
+%
+% \begin{macrocode}
+\newcount\pc@columncount
+% \end{macrocode}
+%
+% Place a vertical rule between two columns?
+%
+% \begin{macrocode}
+\newif\ifpc@rulebetween
+% \end{macrocode}
+%
+% Stores |\everypar| for use in |\parparagraphs|.
+%
+% \begin{macrocode}
+\newtoks\pc@everypar
+% \end{macrocode}
+%
+% Note that additional allocations are performed later on-demand in
+% |\pc@alloccolumns|.
+%
+%
+%
+% \subsection{\textsf{keyvalue} keys}
+%
+% \begin{macro}{\pc@boolkey}
+%
+% Sets an \verb|if|-condition in \marg{\#1} to the value passed as
+% \marg{\#2}. If \verb|#2| is \verb|false|, set \verb|if#1| to
+% \verb|false|, else (any other value) to \verb|true|.
+%
+% Usage: |\pc@boolkey| \marg{ifcondition} \marg{value}
+%
+% \begin{macrocode}
+\def\pc@boolkey#1#2{%
+ \edef\@tempa{#2}%
+ \edef\@tempb{false}%
+ \ifx\@tempa\@tempb%
+ \csname #1false\endcsname%
+ \else%
+ \csname #1true\endcsname%
+ \fi%
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% Define the keys for the options of |parcolumns|.
+%
+% \begin{macrocode}
+\define@key{parcolumns}{distance}{%
+ \@tempdimc#1\relax%
+}
+\define@key{parcolumns}{rulebetween}[true]{%
+ \pc@boolkey{pc@rulebetween}{#1}%
+}
+\define@key{parcolumns}{nofirstindent}[true]{%
+ \pc@boolkey{@tempswa}{#1}%
+% \end{macrocode}
+%
+% If the indentation of the first line of the first paragraph should
+% be suppressed, change |\pc@everypar| accordingly. The token register
+% is reset after the placing of the first row of chunks in
+% |\colplacechunks|.
+%
+% What exactly are we doing? First we assign box 0 the contents of
+% |\lastbox|. At the beginning of a paragraph |\lastbox| contains
+% the glue inserted for the indentation of the first line. By
+% assigning this box to box 0, we remove the indentation. We do
+% this in a group as not to change the contents of box 0.
+%
+% Afterwards we set |\everypar| to nothing. This is necessary because
+% we only want to suppress the indentation for the first paragraph of
+% the |parcolumns| environment, not every paragraph. We set
+% |\everypar| and not |\pc@everypar| to nothing, because
+% |\pc@everypar| is only a temporary storage that will be assigned to
+% |\everypar| when used.
+%
+% \begin{macrocode}
+ \if@tempswa\pc@everypar{{\setbox\z@\lastbox}\everypar{}}\fi%
+}
+\define@key{parcolumns}{sloppy}[true]{%
+ \pc@boolkey{@tempswa}{#1}%
+% \end{macrocode}
+%
+% If sloppy typesetting is asked for, we set |\hbadness| and
+% |\tolerance| to 10000, so that \TeX\ breaks lines whenever possible,
+% even if this means high interword spacing.
+%
+% \begin{macrocode}
+ \if@tempswa%
+ \hbadness\@M%
+ \tolerance\@M%
+ \fi%
+}
+\define@key{parcolumns}{sloppyspaces}[true]{%
+ \pc@boolkey{@tempswa}{#1}%
+% \end{macrocode}
+%
+% If sloppy spaces are asked for, we make the space stretchable:
+%
+% \begin{macrocode}
+ \if@tempswa%
+ \spaceskip.3333em\@plus1em %
+ \fi%
+}
+% \end{macrocode}
+%
+%
+% We save the key-value-list containing widths of the columns in
+% |\toks@| for later use in |\pc@setcolumnwidths|.
+%
+% \begin{macrocode}
+\define@key{parcolumns}{colwidths}{%
+ \toks@{#1}%
+}
+% \end{macrocode}
+%
+%
+% \subsection{Main environments and macros}
+%
+% \begin{environment}{parcolumns}
+%
+% Environment for a number of columns of text set in parallel (see
+% section \ref{sec:Usage} on page \pageref{sec:Usage} for the possible
+% options)
+%
+% Usage: |\begin{parcolumns}| \oarg{options} \marg{number of columns}
+% \ldots\ |\end{parcolums}|
+%
+% \begin{macrocode}
+\newenvironment{parcolumns}[2][]{%
+ \pc@rulebetweenfalse%
+% \end{macrocode}
+%
+% |\if@tempswa| is |true|, if the indentation of the first line
+% should be suppressed, otherwise |false|. Default is |false|:
+%
+% \begin{macrocode}
+ \@tempswafalse%
+% \end{macrocode}
+%
+% |\@tempdimc| contains the space between two columns. Default
+% is |2em|:
+%
+% \begin{macrocode}
+ \@tempdimc2em\relax%
+% \end{macrocode}
+%
+% We set the options:
+%
+% \begin{macrocode}
+ \toks@{}%
+ \setkeys{parcolumns}{#1}%
+% \end{macrocode}
+%
+% We store the total number of columns and reset the counter for
+% the current column:
+%
+% \begin{macrocode}
+ \pc@columncount#2 %
+ \pc@columnctr\z@%
+% \end{macrocode}
+%
+% We allocate the columns and set their widths:
+%
+% \begin{macrocode}
+ \pc@alloccolumns%
+ \pc@setcolumnwidths%
+% \end{macrocode}
+%
+% We switch to vertical mode:
+%
+% \begin{macrocode}
+ \endgraf%
+% \end{macrocode}
+%
+% As we are changing |\everypar|, we need to make sure that the most
+% important flag is reset, which normally happens in the |\everypar|
+% of a |\section|-command: |\if@nobreak|. (otherwise the next section
+% is typeset directly after the text of the previous section instead
+% of leaving some space)\footnote{I discovered this the hard way,
+% spending one or two hours wondering why the spacing between two
+% sections was much too small.}
+%
+% \begin{macrocode}
+ \@nobreakfalse%
+% \end{macrocode}
+%
+% We reset |\everypar|, as it is of no use for us and can only screw
+% up things badly:
+%
+% \begin{macrocode}
+ \global\everypar{}%
+}{%
+% \end{macrocode}
+%
+% At the end of the |parcolumns|-environment \ldots\ just in case, we
+% place the last chunks, if not already done so:
+%
+% \begin{macrocode}
+ \colplacechunks%
+ \endgraf%
+% \end{macrocode}
+%
+% We reset |\clubpenalty| globally to its normal value (the |\global|
+% makes sure that if |\everypar| should have reset |\clubpenalty|, it
+% is reset now).
+%
+% \begin{macrocode}
+ \global\clubpenalty\@clubpenalty%
+% \end{macrocode}
+%
+% We suppress the indentation of the next paragraph immediately
+% following the environment:
+%
+% \begin{macrocode}
+ \@doendpe%
+}
+% \end{macrocode}
+% \end{environment}
+%
+%
+% \begin{macro}{\colchunk}
+%
+% Sets the text for the next chunk of the next column.
+%
+% Usage: |\colchunk| \oarg{column} \marg{chunk}. (note that the |{|
+% and |}| are \emph{not} optional, even if the chunk consists of only
+% one token!)
+%
+% We need two macros for handling the optional parameter
+% \meta{column}, |\colchunk| and |\colchunk@|. First we define
+% |\colchunk|:
+%
+% \changes{1.1}{2004/08/22}{Optional parameter added.}
+%
+% \begin{macrocode}
+\newcommand{\colchunk}{\@testopt\colchunk@{}}%
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\colchunk@}
+%
+% What are we doing now? By suffixing the last (optional) parameter by
+% |#|, we tell \TeX\ that the last parameter of |\colchunk| is to be
+% delimited by a right brace |{|, or \TeX\ will complain with a more
+% comprehensible message that without the |#|: `Use of |\colchunk|
+% doesn't match its definition.' instead of `Missing |{| inserted.'
+%
+% \changes{1.0.1}{2004/08/10}{Parameter added.}
+% \changes{1.1}{2004/08/22}{Optional parameter added.}
+%
+% \begin{macrocode}
+\long\def\colchunk@[#1]#{%
+% \end{macrocode}
+%
+% We check if the optional parameter is not empty. Then we use it as
+% the column number, otherwise we simply pick the next column:
+%
+% \begin{macrocode}
+ \ifx\\#1\\%
+ \advance\pc@columnctr\@ne%
+ \else%
+ \pc@columnctr#1\relax%
+ \fi%
+% \end{macrocode}
+%
+% If we try to add a column past the last one, we display an error
+% message:
+%
+% \begin{macrocode}
+ \ifnum\pc@columnctr>\pc@columncount%
+ \PackageError{parcolumns}{The column \number\pc@columnctr\space%
+ is too large}{Only \number\pc@columncount\space columns are%
+ \space allowed.}
+% \end{macrocode}
+%
+% As we cannot simply skip the chunk (we could gobble what follows
+% after the macro, but this would require a lot of jumping, and just
+% for handling a small mistake \ldots), we simply set the last column:
+%
+% \changes{1.0.1}{2004/08/10}{Error handling somewhat improved.}
+%
+% \begin{macrocode}
+ \pc@columnctr\pc@columncount%
+ \fi%
+% \end{macrocode}
+%
+% We zero the |\clubpenalty| that could have been changed, i.e. by
+% |\everypar| of a |\section|-command: |\section| changes the
+% clubpenalty to prevent a break between the first two lines of the
+% paragraph following immediately after the section; as we split off
+% line after line when typesetting the two columns, this would make
+% splitting of a single line impossible (|\vsplit| uses the same logic
+% as page-breaking), thus resulting in a lot of overfull vboxes and
+% weird spacing inbetween, as \emph{two} lines would be split off.
+%
+% We do this every time we add chunks just in case some macro in the
+% chunks has changed |\clubpenalty|. Note that we cannot prevent a
+% macro in the text of the chunk to change the
+% |\clubpenalty|.\footnote{Well we could, by redefining the
+% clubpenalty to be a macro that simply throws its parameter away, and
+% using some tricks to make this macro behave like a register,
+% therefore completely ignoring any change of the clubpenalty.} But if
+% it is changed, at least it will not stay changed (though the typeset
+% columns will still look bad).
+%
+% \changes{1.0.1}{2004/08/09}{clubpenalty is always reset before
+% adding chunks}
+%
+% \begin{macrocode}
+ \clubpenalty\z@%
+% \end{macrocode}
+%
+% The same goes for the other penalties \TeX\ will insert between two
+% lines, as we absolutely, positively \emph{must} be able to break
+% between any two lines:\footnote{C.f. chapter 14 of the \TeX book}
+%
+% \changes{1.2}{2004/11/25}{other penalties added}
+%
+% \begin{macrocode}
+ \interlinepenalty\z@%
+ \displaywidowpenalty\z@%
+ \widowpenalty\z@%
+ \brokenpenalty\z@%
+% \end{macrocode}
+%
+% We set |\everypar| to our self-defined |\pc@everypar| to suppress
+% the indentation of the first paragraph if so desired:
+%
+% \begin{macrocode}
+ \everypar\expandafter{\the\pc@everypar}%
+% \end{macrocode}
+%
+% After the next assignment, insert the width of the column:
+%
+% \begin{macrocode}
+ \afterassignment\pc@setcolumnwidth%
+% \end{macrocode}
+%
+% We typeset the chunk's text into the box |\pc@column@|\meta{column
+% counter}. The text of the chunk follows the macro, meaning that the
+% last line looks like this: |\vbox{|\meta{chunk text}|}|.
+%
+% But what about the width of the box? |\hsize| must be set in the
+% vbox in order to make it the correct width! We achieve this using
+% the |\afterassignment| above: After the assignment of the chunk's
+% text to the box, we are inside the box, therefore the contents of
+% |\pc@setcolumnwidth| is inserted at the very beginning of the vbox,
+% setting the correct width.
+%
+% Why don't we simply make |\colchunk| take one parameter that
+% contains the text of the chunk? Because in that case, macros that
+% change catcodes like |\verb| would be prohibited, which would
+% restrict this package somewhat. Also it would be slower and would
+% use more memory.
+%
+% \begin{macrocode}
+ \expandafter\setbox\csname pc@column@\number\pc@columnctr\endcsname%
+ \vbox%
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\colplacechunks}
+%
+% Places all chunks set with |\colchunk|.
+%
+% \begin{macrocode}
+\newcommand{\colplacechunks}{%
+% \end{macrocode}
+%
+% If there are any chunks to place:
+%
+% \begin{macrocode}
+ \ifnum\pc@columnctr>\z@%
+% \end{macrocode}
+%
+% We place them:
+%
+% \begin{macrocode}
+ \pc@placeboxes%
+% \end{macrocode}
+%
+% We reset the column counter:
+%
+% \begin{macrocode}
+ \pc@columnctr\z@%
+% \end{macrocode}
+%
+% We clear |\pc@everypar|, because we only want to suppress the
+% indentation of the first paragraph of each column at the very top of
+% the |parcolumns| environment, not of the first paragraph of every
+% call to |\colchunk|.
+%
+% \begin{macrocode}
+ \pc@everypar{}%
+ \fi%
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+%
+% \subsection{Internal environments and macros}
+%
+% \begin{macro}{\pc@placeboxes}
+%
+% Places the prepared boxes (containing the chunks) on the page.
+%
+% \begin{macrocode}
+\def\pc@placeboxes{%
+% \end{macrocode}
+%
+% We assume we don't have to perform another line (|\@tempa| contains
+% what we have to to after we are finished with this macro). The
+% assignment is global because later on when changing |\@tempa| we are
+% in a group:
+%
+% \begin{macrocode}
+ \global\let\@tempa\relax%
+ \count@\z@%
+% \end{macrocode}
+%
+% We create a hbox. Inside a hbox, vboxes are put horizontally
+% next to each other and are aligned on their baseline:
+%
+% \begin{macrocode}
+ \hb@xt@\linewidth{%
+% \end{macrocode}
+%
+% Before doing any work, we change a few parameters:
+%
+% \changes{1.2}{2004/11/22}{moved parameter changes from begin of
+% environment}
+%
+% We prevent warnings of overfull and underfull vboxes as they can
+% happen, but we do not really care (happens when we |\vsplit| the top
+% off the chunks, this is okay):
+%
+% \changes{1.2}{2004/11/22}{vfuzz increased to prevent warnings with
+% math}
+%
+% \changes{1.2}{2004/11/22}{vbadness set}
+%
+% \begin{macrocode}
+ \vfuzz30ex %
+ \vbadness\@M%
+% \end{macrocode}
+%
+% We prevent vertical glue to be insert when |vsplit|ting a vbox
+% (otherwise it screws up the spacing).
+%
+% \begin{macrocode}
+ \splittopskip\z@skip%
+% \end{macrocode}
+%
+% Now we loop over all the prepared boxes. We can use |\loop| here as
+% we are in a group (begun by |\hbox|). Otherwise we would have to
+% open a group manually or loop manually, as to not screw up a |\loop|
+% outside the macro:
+%
+% \begin{macrocode}
+ \loop\ifnum\count@<\pc@columncount%
+ \advance\count@\@ne%
+% \end{macrocode}
+%
+% If the box |\pc@column@|\meta{counter} is empty, we simply insert a
+% hskip the width of the box (saved in
+% |\pc@column@width@|\meta{counter}):
+%
+% \begin{macrocode}
+ \expandafter\ifvoid\csname pc@column@\number\count@%
+ \endcsname%
+ \hskip\csname pc@column@width@\number\count@\endcsname%
+ \else%
+% \end{macrocode}
+%
+% Otherwise we |\vsplit| the first line of the box (at the same time
+% removing it from |\pc@column@|\meta{counter}) and save it in
+% |\@tempboxa|. Then, we strip this resulting box of its enclosing
+% vbox and put it into another vbox, which we put into the hbox begun
+% a few lines ago.
+%
+% Why is this so complicated? To ensure that proper vertical glue is
+% inserted (otherwise the spacing between the lines would be wrong).
+%
+% \begin{macrocode}
+ \expandafter\setbox\expandafter\@tempboxa\expandafter%
+ \vsplit\csname pc@column@\number\count@\endcsname%
+ to \dp\strutbox%
+ \vbox{\unvbox\@tempboxa}%
+ \fi%
+% \end{macrocode}
+%
+% If the remaining box is not empty, we have to perform at least
+% another line:
+%
+% \begin{macrocode}
+ \expandafter\ifvoid\csname pc@column@\number\count@%
+ \endcsname\else%
+ \global\let\@tempa\pc@placeboxes%
+ \fi%
+% \end{macrocode}
+%
+% If this is not the last column, we put a strut into the hbox to
+% ensure propery vertical spacing:
+%
+% \begin{macrocode}
+ \ifnum\count@<\pc@columncount%
+ \strut%
+% \end{macrocode}
+%
+% If a vertical line should be placed between two columns, we insert
+% it now, centering it between two |\hfill|s. Otherwise, we simply
+% insert a |\hfill| that stretches as much as possible, pushing the
+% right column to the right margin. (see also section \ref{sec:Notes}
+% on page \pageref{sec:Notes})
+%
+% \begin{macrocode}
+ \hfill%
+ \ifpc@rulebetween%
+ \vrule%
+ \hfill%
+ \fi%
+ \fi%
+ \repeat%
+ }%
+% \end{macrocode}
+%
+% If necessary, we perform another line:
+%
+% \begin{macrocode}
+ \@tempa%
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\pc@alloccolumns}
+%
+% Allocates a number of |\box|es, named |\pc@column@1|, |\pc@column@2|
+% et cetera, if not already allocated.
+%
+% Also allocates a number of |\dimen|s, named |\pc@column@width@1| et
+% cetera.
+%
+% If the |\box|es and |\dimen|s are already allocated, they are
+% cleared (|\box|es) or set to zero (|\dimen|s).
+%
+% \begin{macrocode}
+\def\pc@alloccolumns{%
+ \count@\z@%
+ \loop\ifnum\count@<\pc@columncount%
+ \advance\count@\@ne%
+ \@ifundefined{pc@column@\number\count@}{%
+ \expandafter\newbox\csname pc@column@\number\count@%
+ \endcsname%
+ \expandafter\newdimen\csname pc@column@width@\number%
+ \count@\endcsname%
+ }{%
+ \setbox0\box\csname pc@column@\number\count@\endcsname%
+ \csname pc@column@width@\number\count@\endcsname\z@%
+ }%
+ \repeat%
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\pc@setcolumnwidths}
+%
+% Sets the widths of all columns. The defined widths have been
+% temporarily stored in |\toks@|. |\@tempdimc| contains the space
+% between two columns.
+%
+% \begin{macrocode}
+\def\pc@setcolumnwidths{%
+ \expandafter\processkeyvalues\expandafter{\the\toks@}%
+ \pc@setsinglecolwidth%
+% \end{macrocode}
+%
+% |\@tempdima| will contain the total width of all columns that have a
+% known width (read: have had their width set via the parameter
+% |colwidths|)
+%
+% \begin{macrocode}
+ \@tempdima\z@%
+% \end{macrocode}
+%
+% |\@tempcnta| will contain the count of columns that an unknown width
+% (read: have had their width \emph{not} set via the parameter
+% |colwidths|, thus now having a width of zero points, as the widths
+% of all columns have been reset in |\pc@alloccolumns|):
+%
+% \begin{macrocode}
+ \@tempcnta\z@%
+% \end{macrocode}
+%
+% We calculate the total width of all columns known. We count how many
+% columns have an unknown width:
+%
+% \begin{macrocode}
+ \count@\z@%
+ \loop\ifnum\count@<\pc@columncount%
+ \advance\count@\@ne%
+ \@tempdimb\csname pc@column@width@\number\count@\endcsname%
+ \advance\@tempdima\@tempdimb%
+ \ifnum\@tempdimb=\z@%
+ \advance\@tempcnta\@ne%
+ \else%
+ \PackageInfo{parcolumns}{Width of column \number\count@%
+ \space set to \the\@tempdimb}
+ \fi%
+ \repeat%
+% \end{macrocode}
+%
+% If at least one column has an unknown width:
+%
+% \begin{macrocode}
+ \ifnum\@tempcnta>\z@%
+% \end{macrocode}
+%
+% |\@tempdimc| contains the distance between columns. We calculate the
+% space left for the columns with an unknown width.
+%
+% |\@tempdimb| will contain the sum of the space between all the
+% columns \ldots
+%
+% \begin{macrocode}
+ \@tempdimb\@tempdimc%
+ \multiply\@tempdimb\pc@columncount%
+ \advance\@tempdimb-\@tempdimc%
+% \end{macrocode}
+%
+% \ldots\ plus the sum of the width of all columns with a known width:
+%
+% \begin{macrocode}
+ \advance\@tempdimb\@tempdima%
+% \end{macrocode}
+%
+% |\@tempdima| will contain the space for each column with an unknown
+% width:
+%
+% \begin{macrocode}
+ \@tempdima\linewidth%
+ \advance\@tempdima-\@tempdimb%
+ \divide\@tempdima\@tempcnta%
+% \end{macrocode}
+%
+% We set the widths of the colums with an unknown width:
+%
+% \begin{macrocode}
+ \count@\z@%
+ \loop\ifnum\count@<\pc@columncount%
+ \advance\count@\@ne%
+ \ifnum\csname pc@column@width@\number\count@\endcsname=\z@%
+ \csname pc@column@width@\number\count@\endcsname\@tempdima%
+ \PackageInfo{parcolumns}{Width of column \number\count@%
+ \space calculated as \the\@tempdima}
+ \fi%
+ \repeat%
+ \fi%
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\pc@setsinglecolwidth}
+%
+% Usage: |\pc@setsinglecolwidth| \marg{column} \marg{width}.
+%
+% Sets the width of the column \meta{column} to the width
+% \meta{width}. Displays an error message if the column is not valid.
+%
+% \begin{macrocode}
+\def\pc@setsinglecolwidth#1#2{%
+ \@ifundefined{pc@column@width@\number#1}{
+ \PackageError{parcolumns}{`#1' is not a valid column number!}%
+ {\@ehc}%
+ }{%
+ \csname pc@column@width@\number#1\endcsname=#2\relax%
+ }%
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\pc@setcolumnwidth}
+%
+% Sets |\hsize| to the width of a column (stored in
+% |\pc@column@width@|\meta{pc@columnctr}) and enters horizonal mode.
+%
+% \changes{1.2}{2004/11/22}{linewidth set, too}
+%
+% \begin{macrocode}
+\def\pc@setcolumnwidth{%
+ \hsize\csname pc@column@width@\number\pc@columnctr\endcsname%
+ \linewidth\hsize%
+ \leavevmode%
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \Finale
+% \PrintChanges
+% \PrintIndex
+\endinput \ No newline at end of file