Optex 中的边注自动垂直跳过

Optex 中的边注自动垂直跳过

下图显示了以下代码的第二页的结果:

在此处输入图片描述

\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")

示例输出第 1 页

示例输出第 2 页

相关内容