![Optex 中的边注自动垂直跳过](https://linux22.com/image/466324/Optex%20%E4%B8%AD%E7%9A%84%E8%BE%B9%E6%B3%A8%E8%87%AA%E5%8A%A8%E5%9E%82%E7%9B%B4%E8%B7%B3%E8%BF%87.png)
下图显示了以下代码的第二页的结果:
\fontfam[Myriad]
\margins/2 a4 (2,6,2,2)cm
\mnotesize=4.5cm
\newcount\notenum
%\fixmnotes\right
\def\note#1{\global\advance\notenum by 1
\fnmark{\the\notenum}%
\mnote{\fnmark{\the\notenum}\kern.3em #1}%
}
\def\fnmark#1{\leavevmode\raise.7ex\hbox{\setfontsize{mag.6}\setff{+lnum}\setff{-onum}\currvar #1}}
%and use:
%
%Text\fnmark{69} text.
%
%If you want to use this in footnotes, try to define:
\def\_printfnotemark{\fnmark{\_fnotenum}}
\onum\rm
ASDF1234567890\note{asdf}
ASDF\note{asdf} And this note will be above the next one \mnoteskip -\baselineskip\note{asdf}
\mnoteskip =-\baselineskip
ASDF\note{asdf}
\lipsum[1]\note{asdf}
\vfill \eject
ASDF1234567890\note{This is a very long note to check out if we’re going to need more space below.}
ASDF \mnoteskip-2\baselineskip \note{asdf} And this note will be above the next one. \mnoteskip-3\baselineskip \note{asdf}\mnoteskip-4\baselineskip\note{asdf}
ASDF\mnoteskip-5\baselineskip \note{asdf}
\lipsum[1]\note{asdf}
\bye
\mnoteskip
令人担心的是,当有多个音符或长音符时,我们必须手动调整垂直间距。有没有办法根据前一个音符的间距来设置这个间距?
答案1
如果我们在发货时使用 Lua 添加旁注,我们就可以确保不会发生任何冲突。使用这种机制,我们只需要一次传递,并且不需要写入任何.aux
文件.ref
。
sidenote-test.tex
\fontfam[lm]
\margins/2 letter (1,3,2,2)in
\parindent=0pt
\parskip=1ex
\addto\_begoutput{%
\ifodd\pageno%
\sidenote_side\right%
\else%
\sidenote_side\left%
\fi%
}
\load[sidenote]
\lorem[1.]\sidenote{\lorem[1.]}
\lorem[2.]\sidenote{\lorem[2.]}
\def\_par{\let\_par=\par}
\lorem[3]\sidenote{\lorem[3.]}
\lorem[4.]\sidenote{\lorem[4.]}
\lorem[5.]\sidenote{\lorem[5.]}
\lorem[6.]\sidenote{\lorem[6.]}
\lorem[7.]\sidenote{\lorem[7.]}
\vfill\eject
\sidenote_number=199
\def\sidenote_makemark{%
\leavevmode%
\raise 0.7ex%
\hbox{\typosize[8/8]\romannumeral\sidenote_number}%
}
\def\sidenote_makeleft#1{%
\hsize=2in\relax%
\leftskip=0pt plus 1fill\relax%
\rightskip=1in\relax%
\it%
\sidenote_makemark%
#1%
\vskip 1cm\relax%
}
\lorem[1.]\sidenote{\lorem[1.]}
\lorem[2.]\sidenote{\lorem[2.]}
\def\_par{\let\_par=\par}
\lorem[3]\sidenote{\lorem[3.]}
\lorem[4.]\sidenote{\lorem[4.]}
\lorem[5.]\sidenote{\lorem[5.]}
\lorem[6.]\sidenote{\lorem[6.]}
\lorem[7.]\sidenote{\lorem[7.]}
\bye
sidenote.opm
%% Initialize namespace
\_namespace{sidenote}
%% Initialize some variables
\_newcount\sidenote_number
\_newbox\.left
\_newbox\.right
%% We just want a unique attribute number, but to get at the number
%% itself, we need this hack.
\_newattribute\.attr__
\_chardef\.attr=\_attributealloc
%% Load the Lua module
\_directlua{require "sidenote"}
%% Add some redefinable styling commands
%% Make the sidenote mark in the text.
%% out --> Something to be typeset in the current paragraph
%% (will be placed in an \hbox)
%% (redefine this if you want a different style)
\_newpublic\_def\sidenote_makemark{%
\_unskip$^{\_the\sidenote_number}$%
}
%% Make the sidenote variant for the left margin.
%% #1 --> The text of the sidenote
%% out --> The contents of the sidenote (will be placed in a \vbox)
%% (redefine this if you want a different style)
\_newpublic\_def\sidenote_makeleft#1{%
\_hsize=2in\_relax%% Width of the sidenote
\_leftskip=0pt plus 1fill\_relax%% Ragged left
\_rightskip=1em\_relax%% 1em separation from the paragraphs
\sidenote_makemark%% Print the sidenote number
#1%% Sidenote text
\_vskip 1ex\_relax%% Make sure succesive sidenotes are 1ex apart
}
%% Make the sidenote variant for the left margin.
%% #1 --> The text of the sidenote
%% out --> The contents of the sidenote (will be placed in a \vbox)
%% (redefine this if you want a different style)
\_newpublic\_def\sidenote_makeright#1{%
\_hsize=2in\_relax%% Width of the sidenote
\_rightskip=0pt plus 1fill\_relax%% Ragged right
\_leftskip=1em\_relax%% 1em separation from the paragraphs
\sidenote_makemark%% Print the sidenote number
#1%% Sidenote text
\_vskip 1ex\_relax%% Make sure succesive sidenotes are 1ex apart
}
%% Define the sidenote command
%% #1 --> The text of the sidenote
%% out --> Typesets the sidenote number with \sidenote_makemark,
%% and records the sidenote text to be included at shipout.
\_newpublic\_def\sidenote#1{%
\_incr\sidenote_number%% Increment the sidenote number
\_setbox\.left=\_vbox{%% Save the left sidenote contents
\sidenote_makeleft{#1}%
}%
\_setbox\.right=\_vbox{%% Save the right sidenote contents
\sidenote_makeright{#1}%
}%
%
%% Make the sidenote mark and mark it with an attribute so we can
%% find it from Lua
\_hbox attr \.attr=\sidenote_number {\sidenote_makemark}%
%
\.savenote%% Run the Lua function
}
%% Set the page side
\_newcount\.side
%% Sets the side to typeset the sidenotes on
%% #1 --> ``\left'' or ``\right''
%% out --> (nothing)
\_newpublic\_def\sidenote_side#1{%
\ifx#1\_left%
\_global\.side=0%
\else%
\_global\.side=1%
\fi%
}
%% Set the default sidenote side
\sidenote_side\left
%% Switch sides automatically for each page
% \addto\_begoutput{%
% \ifodd\pageno%
% \sidenote_side\right%
% \else%
% \sidenote_side\left%
% \fi%
% }
\_endnamespace
sidenote.lua
-- Initialize some constants
local glue_id = node.id("glue")
local hlist_id = node.id("hlist")
local vlist_id = node.id("vlist")
local attribute = token.create("_sidenote_attr").mode
local LEFT = 0
-- Make an \hss now so that we can copy and reuse it later
local hss = node.new("glue")
hss.stretch = 1
hss.stretch_order = 1
hss.shrink = 1
hss.shrink_order = 1
-- Store the sidenote contents
local lefts = {}
local rights = {}
-- Save the sidenote contents in Lua so we can access them later
define_lua_command(
"_sidenote_savenote",
function()
local number = tex.count.sidenote_number
lefts[number] = node.copy_list(tex.box._sidenote_left)
rights[number] = node.copy_list(tex.box._sidenote_right)
end
)
-- Typeset the sidenote contents
callback.add_to_callback("pre_shipout_filter", function(head)
-- Should we place the sidenotes on the left or on the right?
local side = tex.count._sidenote_side
-- The minimum height to place the sidenote at
local min_height = 0
local max_height = (tex.voffset or 0) + tex.vsize
-- Recursively traverse the page
local function recurse(n, height, parent)
for m in node.traverse(n) do
-- Set the height of the current node
local self_height = 0
if m.id == glue_id and parent.id == vlist_id then
-- Glue is only vertical if it's in a \vbox
self_height = node.effective_glue(m, parent)
elseif (m.height or m.depth) and parent.id == vlist_id then
self_height = (m.height or 0) + (m.depth or 0)
end
-- A node's "shift" attribute is vertical only if the parent is
-- an \hbox. This corresponds to the primitive \raise.
local vshift = 0
if m.shift and
(parent.id == hlist_id or
not node.is_node(parent))
then
vshift = m.shift
end
-- Set the current height
height = height + self_height
-- The number of this node's corresponding sidenote
local attr = node.get_attribute(m, attribute)
-- We've found a sidenote node
if attr then
-- Get the sidenote contents
local note
if side == LEFT then
note = lefts[attr]
else
note = rights[attr]
end
local note_height = note.height + note.depth
if min_height + note_height > max_height then
texio.write_nl(
"Warning: sidenote " .. attr .. " is too tall!!!\n"
)
end
-- Zero out the note's height
note.height = 0
note.depth = 0
-- Add any necessary vertical space to prevent collisions
local offset = math.max(min_height - height, 0)
local vskip = node.new("glue")
vskip.width = offset
note.list = node.insert_before(note.list, note.list, vskip)
local hss = node.copy(hss)
-- Create a zero-width \hbox to hold the sidenote
local box
if side == LEFT then
hss.next = note
box = node.hpack(hss, 0, "exactly")
lefts[attr] = nil
node.free(rights[attr])
rights[attr] = nil
else
local offset = node.new("glue")
offset.width = parent.width
offset.next = note
note.next = hss
box = node.hpack(offset, 0, "exactly")
rights[attr] = nil
node.free(lefts[attr])
lefts[attr] = nil
end
-- Inject the \hbox into the page
parent.prev.next = box
box.next = parent
node.slide(parent.prev)
-- Update the minimum height
min_height = height + note_height + offset
-- Not a sidenote, so we need to recurse
elseif m.list then
recurse(
m.list,
height - self_height + vshift,
m
)
end
end
end
-- Start at the root of the page
recurse(head.list, tex.voffset or 0, {})
return true
end, "sidenote")