答案1
这是我的解决方案:
关于实施的一些一般性评论:
- 目前所有内容都是底部对齐的。一些定位魔法可能会让边注靠近脚注标记(尤其是当它们很稀疏时),但可能只能在第二次运行中实现。当存在冲突时,获得美观的位置将需要大量工作。
- 这主要基于
\footins
。我从 TeXbook 附录 D 中的多列脚注技巧开始。 - 我必须单独插入页边注,这样在计算分页符位置时它们就会被忽略。脚注是放在页边还是放在页脚中是在执行时决定的
\footnotetext
。 - 感谢 David Carlisle 向我指出了一种方法,可以恢复在分页符处被拆分的脚注并将其放回页边距。参见问题我可以获得“当前页面”或“最近贡献”中的内容吗?。
- 我将使用浮点数等标准内容对实现进行更多测试,修复问题,但除此之外,我宣布此操作已完成。问题中要求的基本技术已提供。除非有人真正使用它并希望添加一些功能或修复故障,否则我不会尝试任何花哨的东西,包括边距脚注的垂直定位。
编辑:代码
以下内容应放入文件中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
}%
然后测试:
\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}
请注意,这有点粗糙,但如果没有清晰的应用视角和一些很好的“真实”示例,就很难进行重大测试。
该columns
选项设置列数在页脚中。
通过提供选项fixorder=false
,奇数页上的脚注重新排序功能将被关闭。由于页面上的第一个脚注总是进入页边距,因此在奇数页上,页边距在左侧,数字顺序与页脚组合看起来很奇怪。因此,通常(默认fixorder=true
),所有脚注都会在奇数页上重新排序,以便第一个脚注从页脚开始。
享受!
更新
最近编辑:
- 增加了对 的支持
oneside
。 - 测试了冲突
afterpage
并修复了一些问题。 - 测试了与之的冲突
\marginpar
(当然根本不起作用)并\marginpar
暂时禁用。如果我实现了边距脚注的垂直定位,我可能会将其添加\marginpar
为非编号注释。
答案2
免责声明:我对输出例程一无所知。这只是一个非常不完整的第一步,代码很乱。我们的想法是将边注和正文内容收集到两个垂直框中,检查每一段是否已达到页面区域(通过除以 100pt 转换为尺寸,以保持在 TeX 的最大尺寸范围内)。如果是,则输出一个包含两部分的水平框:左列只有注释(\vsplit
至\vsize
),右列包含所有正文(因此我们假设正文适合,换句话说,至少有 1/3 的注释,不检查这一点),然后并排放置两列注释。
而且,那是纯 TeX。好吧,我其实并不怎么使用纯 TeX。
\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
答案3
这完全让我想起了上次但丁莱比锡会议提出的“排版塔木德”挑战。在塔木德中,原文位于中心,周围是(洋葱状)学者对文本的评论文本。