Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

In this document, from page 12 and following, the notes from the marginpar are overflowing in the footer of each page.

overflowing notes

How can this be achieved in LaTeX?

ConTeXT/LuaTeX based solutions are welcome, too!

share|improve this question
1  
sadly, the cited file throws the message "File does not begin with %PDF-." from adobe reader, and i'm unable to look past the first page. (trying to read with current adobe reader plugin to current firefox on windows xp.) –  barbara beeton Sep 10 '11 at 15:36
    
@barbara: I've downloaded it several times without a problem... and acroread 9 opens it well on Ubuntu Natty. –  ℝaphink Sep 10 '11 at 16:33
5  
@JosephWright and latex3 folks: am I right in thinking this would make a great testcase and usecase for latex3's coffins or galleys, or whichever the right module is these days? :) This seems like an interesting page description challenge: "The textblock is 0.66\pagewidth * 0.75\pageheight. The marginpar area consists of three coffins, of width 0.33\pagewidth and heights \textheight and 0.25\textheight, and the text flows between them." This is the sort of layout that usually made me give up on latex and switch to InDesign or a desktop publishing program... I hope latex can do it soon too! –  Ben Lerner Sep 15 '11 at 18:19
1  
@Ben. At present, this is well beyond the areas we've examined. 'coffins' are about box alignment, but not reflowing text. I suspect that may come up in the output routine, but even there you have to remember that TeX's model for a page is not really suited to reflowing. Of course, the ConTeXt people may well have a Lua-based solution: I will try to find out. –  Joseph Wright Sep 15 '11 at 20:02
2  
@Ben Lerner Your suggestion is a variant of multicolumn layouts. This particular layout's main feature is that all notes fit on the same page as the main text (no note is carried over to the next page). This way it can be solved easier by measuring the marginpar boxes, if they exceed overflow to third box, measure again and reduce the textheight. Only complication would be when a note is on the last paragraph or so. When the page textheight is reduced the boxes will change size again and you will need to iterate. I agree though that a general solution is more desirable. Pray for LaTeX3! –  Yiannis Lazarides Sep 15 '11 at 21:42

3 Answers 3

up vote 41 down vote accepted
+400

Here's my solution:

marginfootnote example

marginfootnote 2column

Some general remarks on the implementation:

  1. At the moment everything is bottom-aligned. Some positioning magic might be possible to get the margin notes near their footnote marks (especially when they are sparse), but probably only in a second run. It will be a lot of work to get good-looking positions when there are conflicts.
  2. This is mainly based on \footins. I started from the multicol footnote trick from Appendix D of the TeXbook.
  3. I had to make a separate insert for the margin notes, so that they are ignored for calculating the page break position. Whether a footnote is put in the margin or in the foot is decided while executing \footnotetext.
  4. Thanks to David Carlisle for pointing me to a means for recovering footnotes which were split off at page break and putting them back in the margin. See question Can I get at stuff in “current page” or “recent contributions”?.
  5. I'll test the implementation a bit more with standard stuff like floats, fixing issues, but apart from that, I declare this finished. The basic technique requested in the question has been provided. Unless someone has a real use for this and wants some features added or glitches fixed, I won't attempt anything fancy, including the vertical positioning of margin footnotes.

EDIT: The code

The following should be put into a file marginfootnotes.sty:

\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{marginfootnotes}[2012/04/03 EXPERIMENTAL package for
putting footnotes into the margin, overflowing into the footer]

\RequirePackage{kvoptions}

\RequirePackage{etoolbox}

% We need this package to do some output / insert recovery magic. 

\RequirePackage{afterpage}

% Number of columns in footer.

\DeclareStringOption[2]{columns}

% Should we reorder footnotes on odd pages?

\DeclareBoolOption[true]{fixorder}

\ProcessKeyvalOptions*

% Need a fresh insert for the marginfoornotes.

\newinsert\marginfootnotes@ofn
\skip\marginfootnotes@ofn=\z@
\count\marginfootnotes@ofn=\z@
\dimen\marginfootnotes@ofn=\textheight

% Measure how much material already is in the margin.

\newdimen\marginht@ofn

% We rebuild page geometry such that there are <columns>+1 columns
% (including marginpar) of width \marginparwidth, separated by
% \marginparsep, and \textwidth covers <columns>-1 of them. 

\@tempdima\marginparwidth
\marginparwidth
\dimexpr
  (\textwidth+\marginparwidth+2\marginparsep)%
  /\numexpr\marginfootnotes@columns+\@ne\relax%
  -\marginparsep
\relax
\textwidth\dimexpr\marginfootnotes@columns\marginparwidth+\numexpr\marginfootnotes@columns-\@ne\relax\marginparsep\relax

\advance\evensidemargin\dimexpr\marginparwidth-\@tempdima\relax

% As there are <columns> columns of footnotes now, we need to adjust
% the magnification factor.

\count\footins=\numexpr1000/\marginfootnotes@columns\relax

% Redefinition of \@footnotetext. Measure whether footnote still fits
% in the margin, otherwise insert as footnote.

\long\def\@footnotetext#1%
{%
  \setbox\@tempboxa=\vbox{\typesetfootnote@ofn{#1}}%
  \ifdim\dimexpr\marginht@ofn+\ht\@tempboxa+\dp\@tempboxa\relax>\textheight
    \insert\footins{\typesetfootnote@ofn{#1}}%
   \else
    \insert\marginfootnotes@ofn{\typesetfootnote@ofn{#1}}%
    \global\advance\marginht@ofn\dimexpr\ht\@tempboxa+\dp\@tempboxa\relax
  \fi
}%

\newcommand\typesetfootnote@ofn[1]
{%
  \reset@font\footnotesize
  \interlinepenalty\interfootnotelinepenalty
  \splittopskip\footnotesep
  \splitmaxdepth \dp\strutbox \floatingpenalty \@MM
  \hsize\marginparwidth \@parboxrestore
  \protected@edef\@currentlabel{%
    \csname p@footnote\endcsname\@thefnmark
  }%
  \color@begingroup
  \@makefntext{%
    \rule\z@\footnotesep\ignorespaces#1\@finalstrut\strutbox}%
  \color@endgroup
}

% We hook into the output routine, replacing the "simple" output of
% \footins by our more complicated scheme.

\patchcmd\@makecol
{%
   \ifvoid\footins
     \setbox\@outputbox \box\@cclv
   \else
     \setbox\@outputbox \vbox {%
       \boxmaxdepth \@maxdepth
       \unvbox \@cclv
       \vskip \skip\footins
       \color@begingroup
         \normalcolor
         \footnoterule
         \unvbox \footins
       \color@endgroup
       }%
   \fi
}{\output@footins}{}{}

% If \footins is void, we still need to output the margin
% box. Otherwise we call the macro for balancing footnote columns.

\newcommand\output@footins
{%
   \ifvoid\footins
     \setbox\@outputbox \vbox {%
       \boxmaxdepth \@maxdepth
       \unvbox \@cclv
       \hbox
       {%
         \if@twoside
           \ifodd\c@page
             \hskip\textwidth\hskip\marginparsep
            \else 
             \hskip-\marginparwidth\hskip-\marginparsep
           \fi
          \else
           \hskip\textwidth\hskip\marginparsep
         \fi
         \smash{\box\marginfootnotes@ofn}%
       }%
     }%
   \else
     \setbox\@outputbox \vbox {%
       \boxmaxdepth \@maxdepth
       \unvbox \@cclv
       \vskip \skip\footins
       \color@begingroup
         \normalcolor
         \footnoterule
         \balancecolumns@ofn
       \color@endgroup
       }%
   \fi
   \global\marginht@ofn\z@
}

% The following is roughly based on the example from appendix D of the
% TeXbook, plus outputting the margin column.

\newcount\k
\newcount\lines@ofn
\newbox\footnotetextbox@ofn
\def\balancecolumns@ofn
{%
  \setbox\footnotetextbox@ofn=\box\footins
  \k=\marginfootnotes@columns
  \hbox to\dimexpr\k\marginparwidth+\marginparwidth+\k\marginparsep\relax
  {%
    \footnotesize
    \lines@ofn
    \numexpr
      \dimexpr\ht\footnotetextbox@ofn+\dp\footnotetextbox@ofn\relax
      /\baselineskip
      /\marginfootnotes@columns
    \relax
    \splittopskip\dimexpr\baselineskip-\dp\strutbox\relax
    \vbadness\maxdimen
    \vfuzz\maxdimen
    \splitmaxdepth \dp\strutbox
    \if@twoside
      \ifodd\c@page
        \ifmarginfootnotes@fixorder
          \setbox\footnotetextbox@ofn=\vbox{\unvbox\marginfootnotes@ofn\unvbox\footnotetextbox@ofn}%
        \fi
       \else
        \hskip-\marginparwidth\hskip-\marginparsep
        \setbox\@tempboxa=\box\marginfootnotes@ofn
        \output@tempboxa
        \hskip\marginparsep
      \fi
     \else
      \ifmarginfootnotes@fixorder
        \setbox\footnotetextbox@ofn=\vbox{\unvbox\marginfootnotes@ofn\unvbox\footnotetextbox@ofn}%
      \fi
    \fi
    \dosplits
    \if@twoside
      \ifodd\c@page
        \ifmarginfootnotes@fixorder
          \setbox\@tempboxa=\box\footnotetextbox@ofn
         \else
          \setbox\@tempboxa=\box\marginfootnotes@ofn
        \fi
        \output@tempboxa
      \fi
     \else
      \ifmarginfootnotes@fixorder
        \setbox\@tempboxa=\box\footnotetextbox@ofn
       \else
        \setbox\@tempboxa=\box\marginfootnotes@ofn
      \fi
      \output@tempboxa
    \fi
  }%
}

\newcommand\output@tempboxa
{%
  \@tempcnta
  \numexpr
    \dimexpr\ht\@tempboxa+\dp\@tempboxa\relax
    /\baselineskip
  \relax
  \smash{\vsplit\@tempboxa to \@tempcnta\baselineskip}%
}

\def\dosplits{\ifnum\k>\@ne \splitoff\hskip\marginparsep
\global\advance\k-1\dosplits\fi}
\def\splitoff
{%
  \vsplit\footnotetextbox@ofn to \lines@ofn\baselineskip
}

% Thanks to David Carlisle for pointing me to this easy solution how
% to recover \footins material which was split off by a page break
% and move it into the margin. afterpage code is used and patched
% to avoid conflicts.

\newtoks\output@ofn

\output@ofn{%
  \the\AP@output
  \ifnum\outputpenalty>-\@Mi
    \aftergroup\fixfootins@ofn
  \fi
}%

\global\output{\the\output@ofn}%

\newcommand\fixfootins@ofn
{%
  \AP@savetop
  \addboxcontents\AP@partial
  \ifvoid\AP@footins\else
    \movefootins@ofn
  \fi
  \AP@noindent
}

\newcommand\movefootins@ofn
{%
  \global\advance\marginht@ofn\dimexpr\ht\AP@footins+\dp\AP@footins\relax
  \insert\marginfootnotes@ofn{\unvbox\AP@footins}%
}

\patchcmd\AP@@
{\insert\footins{\unvbox\AP@footins}}
{\movefootins@ofn}{}{}    

\patchcmd\AP@@
{\AP@noindent}
{\AP@noindent\global\output{\the\output@ofn}}{}{}

% Disable \marginpar because it would conflict with margin footnotes.

\renewcommand\marginpar[2][]
{%
  \PackageError{marginfootnotes}
  {\string\marginpar\space disabled}\@eha
}%

Then test with:

\documentclass[a4paper,twoside]{article}

\usepackage[columns=3]{marginfootnotes}

\usepackage[expansion=alltext]{microtype}

\usepackage{lipsum}

\newcommand\fnlipsum[1]
{%
  \begingroup
    \let\par\empty
    \edef\@temp{\csname lipsum@\romannumeral#1\endcsname}%
    \@temp\footnote{\@temp}%
  \endgroup
  \par
}

\usepackage[latin]{babel}

\showboxdepth\maxdimen
\showboxbreadth\maxdimen

\begin{document}

\fnlipsum{1}
\fnlipsum{2}
\fnlipsum{3}
\afterpage{\noindent\fbox{\parbox{\dimexpr\textwidth-2\fboxsep-2\fboxrule\relax}{\lipsum[1]}}}
\fnlipsum{4}
\fnlipsum{5}
\fnlipsum{6}
\fnlipsum{7}
\fnlipsum{8}
\fnlipsum{9}
\fnlipsum{10}
\fnlipsum{11}
\fnlipsum{12}
\fnlipsum{13}
\end{document}

Note that this is a bit rough, but without a clear application perspective and some nice "real" examples it is hard to do significant testing.

The columns option sets the number of columns in the footer.

By giving the option fixorder=false, reordering of footnotes on odd pages is turned off. As the first footnotes on a page always go into the margin, on odd pages where the margin is to the left, the numerical order combined with the footer looks strange. So normally (default fixorder=true), all the footnotes are reordered on odd pages such that the first footnotes start in the footer.

Enjoy!

Update

Recent edits:

  1. Added support for oneside.
  2. Tested for conflicts with afterpage and fixed some issues.
  3. Tested for conflicts with \marginpar (which of course doesn't work at all) and disabled \marginpar for the time being. If I ever implement the vertical positioning of margin footnotes, I might add \marginpar back in as a non-numbered note.
share|improve this answer
    
I'd be interested in using this, but the initial goal was mostly that I saw this and thought, "Surely, there must be a way to do that with TeX, right?" :-) –  ℝaphink Apr 6 '12 at 6:22
    
Great job by the way! –  ℝaphink Apr 6 '12 at 6:22
1  
@wasteofspace Could you be a bit more specific in which way flowfram is relevant for this? Please post an answer to achieve the results above with flowfram. –  Stephan Lehmke Apr 6 '12 at 10:57
1  
Definitely a great answer to the question. I'm happy to give you the bounty, and looking forward to seeing the package on CTAN :-) –  ℝaphink Apr 7 '12 at 11:43
1  
Reconsidering it I also think, a general warning is the best, because it came in my mind, that there are some other packages, too, which put something into the margins (e. g. sidenotes, a command and an environment in pdfcomment, according to marginfix doc in memoir is a command \sidebar – surely there are more), but you can’t catch all cases. –  Speravir Apr 8 '12 at 13:31

Disclaimer: I don't know anything about output routines. This is just meant to be a very partial first step, and the code is a mess. The idea is to collect the margin notes and the body content in two vertical boxes, check at every paragraph whether we've reached the area of the page (converted to a dimension by dividing it by 100pt, to remain within TeX's max dimension). If so, shipout a horizontal box with two parts: a left column with only notes, (\vsplit to \vsize), and a right column with all the body text (hence we assume that this body text fits, in other words that there are at least 1/3 of notes, no check for that), then two columns of notes side by side.

Also, that's plain TeX. Well, I'm not really using much of plain, even.

\catcode`@=11
\newbox\marg@m@galley % contains all marginpars
\newbox\marg@b@galley % contains all of the body text
\newbox\marg@void@box % empty box.
\newdimen\marg@m@area % marginpar surface area
\newdimen\marg@b@area % body surface area
\newdimen\marg@t@area % m+b surface area
\newdimen\marg@p@area % page surface area
\newdimen\marg@m@prevdepth \global\marg@m@prevdepth=-1000pt
\newdimen\marg@b@prevdepth \global\marg@b@prevdepth=-1000pt
\newdimen\marg@notes@space % space between body and bottom notes.
\marg@notes@space=15pt

\def\marg@leavevmode{\begingroup\everypar={}\unhbox\marg@void@box\endgroup}
\def\marg@strip@pt{\expandafter\marg@rem@pt\the}
\begingroup\catcode`P=12\catcode`T=12
  \lowercase{\endgroup\def\marg@rem@pt#1PT{#1}}

\def\marg@set@to@area#1#2{%
  #1=.01\dp#2\relax
  \advance#1by .01\ht#2\relax
  #1=\marg@strip@pt#1\wd#2\relax}
\def\marg@conditionally@output{%
  \marg@set@to@area\marg@m@area\marg@m@galley
  \marg@set@to@area\marg@b@area\marg@b@galley
  \marg@t@area\marg@m@area
  \advance\marg@t@area by \marg@b@area
  \marg@p@area=.0095\hsize
  \marg@p@area=\marg@strip@pt\marg@p@area\vsize
  \ifdim\marg@t@area>\marg@p@area
    \marg@output
  \fi}

\def\marg@output{%
  \shipout\hbox to \hsize{%
    \vbox to \vsize{\ifdim\ht\marg@m@galley>\vsize
      \vsplit\marg@m@galley to \vsize\else\unvbox\marg@m@galley\fi\vfill}%
    \hfill
    \vbox to \vsize{%
      \hsize\wd\marg@b@galley
      \dimen@\vsize
      \advance\dimen@ by -\ht\marg@b@galley
      \advance\dimen@ by -\dp\marg@b@galley
      \unvbox\marg@b@galley
      \vskip\marg@notes@space
      \hbox to \hsize {\vbox{\vsplit\marg@m@galley to \dimen@}%
        \hfil\vbox{\vsplit\marg@m@galley to \dimen@}}%
      \vfill
    }%
  }%
}

\def\marg@m@start{%
  \setbox\marg@m@galley=\vbox\bgroup
    \hsize=.30\hsize
    \unvbox\marg@m@galley
    \prevdepth=\marg@m@prevdepth
    \let\@par\par
    \def\par{\marg@m@stop\par\marg@m@start}}
\def\marg@m@stop{%
    \@par
    \global\marg@m@prevdepth=\prevdepth
  \egroup
  \marg@conditionally@output}

\def\marg@b@start{%
  \setbox\marg@b@galley=\vbox\bgroup
    \hsize=.65\hsize
    \unvbox\marg@b@galley
    \prevdepth=\marg@b@prevdepth
    \let\@par\par
    \def\par{\marg@b@stop\par\marg@b@start}}
\def\marg@b@stop{%
    \@par
    \global\marg@b@prevdepth=\prevdepth
  \egroup
  \marg@conditionally@output}

\long\def\marginpar#1{%
  \marg@b@stop
  \marg@m@start
  #1%
  \marg@m@stop
  \marg@b@start
}

\def\lipsum@i{Lorem ipsum dolor sit amet, consectetuer
  adipiscing elit. Ut purus elit, vestibulum ut, placerat ac,
  adipiscing vitae, felis. Curabitur dictum gravida mauris. Nam arcu
  libero, nonummy eget, consectetuer id, vulputate a, magna. Donec
  vehicula augue eu neque. Pellentesque habitant morbi tristique
  senectus et netus et malesuada fames ac turpis egestas. Mauris ut
  leo. Cras viverra metus rhoncus sem. Nulla et lectus vestibulum urna
  fringilla ultrices.  Phasellus eu tellus sit amet tortor gravida
  placerat. Integer sapien est, iaculis in, pretium quis, viverra ac,
  nunc. Praesent eget sem vel leo ultrices bibendum. Aenean faucibus.
  Morbi dolor nulla, malesuada eu, pulvinar at, mollis ac, nulla.
  Curabitur auctor semper nulla. Donec varius orci eget risus. Duis
  nibh mi, congue eu, accumsan eleifend, sagittis quis, diam. Duis
  eget orci sit amet orci dignissim rutrum.\par}

\emergencystretch=.15\hsize

\marg@b@start
  \lipsum@i
  \lipsum@i
  \marginpar{\lipsum@i\lipsum@i}
  \lipsum@i
  \marginpar{\lipsum@i\lipsum@i}
  \lipsum@i
\marg@b@stop
\marg@output

\bye
share|improve this answer
    
Very interesting! What is the point of changing the catcode for P and T? –  ℝaphink Oct 5 '11 at 9:39
2  
@Raphink See the definition of \strip@pt in the LaTeX kernel. The result of \the\len (where \len is a dimension register, is a decimal number followed by the two characters pt of category 12. In order to strip them it's customary to define a macro with a delimited argument (the delimiter is exactly pt of category 12). –  egreg Oct 5 '11 at 11:55
    
Thanks @egreg. In my case it's used to get a decimal number for TeX to do the multiplication of two dimensions. Where it becomes a mess is that I'm starting with .01 times the first dimension to avoid overflowing TeX's dimensions when doing the product. So very rough computations, but that seems to work in very trivial cases. Of course, the correct way would be to think a little bit and only compare the relevant heights. –  Bruno Le Floch Oct 5 '11 at 12:15

This totally reminds me of the "Typesetting the talmud" challenges presented at the last Dante meeting in Leipzig. In the Talmud the original text version is in the center, around are (onion-like) the texts of scholars commenting on the text.

Talmud example

share|improve this answer
1  
This is not an answer to the OP's question -- but a comment can't include pictures (nice example BTW). Perhaps consider to make your "answer" community wiki. Another option would be to include the material at the end of the original question (with a note "EDIT by Uwe Ziegenhagen"). –  lockstep Apr 7 '12 at 10:28
1  
Uwe, @lockstep: You still can have a link to the image in a comment. –  Martin Scharrer Apr 7 '12 at 12:48
7  
Perhaps it could be made to a real answer by adding some value, like a link to the Talmud project, where one could get further information on this topic. –  Stefan Kottwitz Apr 9 '12 at 9:22

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.