Skip to content

luatex中怎么让插入的对box内容的改动在当前页就生效 #342

@ROGERDJQ

Description

@ROGERDJQ

检查清单

  • 我已在 issues 中进行搜索(包括已关闭的问题)

操作系统

linux

TeX 发行版

live 2024 overleaf

描述问题

  1. 通过lua定义了数据结构notes,保存当前页的note---【这一步没问题】
  2. 尝试让当前页的notes写入box中,然后利用splitbox切出当前页后输出---【出现问题:写入box中的内容总是在下一页才真正写入box】

尝试了两种方案,一种是写好tex_code后luatex再sprint

             for _, idx in ipairs(pagenotes) do
                 local note = notes[idx]
                 local tex_code = "\\setbox\\notescontentbox=\\vbox{\\unvbox\\notescontentbox\\parbox{0.34\\textwidth}{\\noindent\\footnotesize\\textcolor{blue}{[" 
                                 .. note.id .. "]} " .. note.content .. "}\\par\\vspace{0.5em}}"
                 tex.sprint(tex_code)
             tex.sprint("\\relax")  
             end

另一种是在lua中先进行node拼接,拼出来vbox然后再转给tex

            local head_notes  
            local tail_notes  
    
            function delayed_process_box()
                local tmpbox = tex.box[255]
                if tmpbox and tmpbox.list then
                    local new_list = node.copy_list(tmpbox.list)
                    tex.print("Delayed processing successful")
                end
            end
    
            % for _, idx in ipairs(pagenotes) do
            %     local note = notes[idx]
                
                
            %     tex.sprint("\\setbox255=\\hbox{\\noindent\\footnotesize\\textcolor{blue}{[" .. note.id .. "]}" .. note.content .. "}")
            %     tex.sprint("\\directlua{delayed_process_box()}")
            %     local tmpbox    = tex.box[255]
            %     tex.print("Height: " ..  tmpbox.height)
            %     local new_list  = node.copy_list(tmpbox.list)
                
            %     local glue_spec = node.new("glue_spec")
            %     glue_spec.width = tex.sp("0.5em")
            %     local glue      = node.new("glue")
            %     glue.spec       = glue_spec
            %     node.insert_after(new_list, node.tail(new_list), glue)
            
            %     if not head_notes then
            %         head_notes = new_list
            %         tail_notes = node.tail(new_list)
            %     else
            %         node.insert_after(head_notes, tail_notes, new_list)
            %         tail_notes = node.tail(new_list)
            %     end
            % end
            
            % local vbox_notes = node.vpack(head_notes, 0)
            % tex.setbox("notescontentbox", vbox_notes)

最小工作示例(MWE)

\documentclass[a4paper,12pt]{article}
\usepackage[utf8]{inputenc}
\usepackage{ctex} % 中文支持
\usepackage{zref-abspage,zref-user}
\usepackage{luacode}
\usepackage{xcolor}
\usepackage{tikz}
\usepackage{fancyhdr}
\usepackage{calc}
\usepackage{etoolbox}
\usepackage{atbegshi}
\usepackage{luatexbase} 



 

% Lua代码部分
\begin{luacode*}

    notes = {}
    currentnotes = {}
  
    function get_textheight()
        return tex.dimen.textheight
    end

    
    function add_note(id, content,height)
    notes[id] = {
        id = id,
        content = content,
        printed = false,
        height =  tonumber(height) or 0
    }
    texio.write_nl("log", "Adding note "..id..", height="..height)
    end
  
\end{luacode*}

         

\newcounter{notecounter}

% 存储盒子
\newsavebox{\maincontentbox}
\newsavebox{\notecontentbox}
\setbox\notecontentbox=\vbox{}

\newsavebox{\mainforprint}
\newsavebox{\noteforprint}

% 添加注释的命令
\makeatletter
\newcommand{\sidenote}[1]{%
    \stepcounter{notecounter}%
    \textcolor{red}{\textsuperscript{[\thenotecounter]}}

    % 测量内容高度并回传
    \setbox0=\vbox{%
        \hsize=0.38\textwidth\noindent\footnotesize\textcolor{red}{[\thenotecounter]} #1\par\vspace{0.5em}%
    }%
  
    \directlua{
    local newwhat = node.new(node.id('whatsit'), node.subtype('user_defined'))
    newwhat.user_id = 112
    newwhat.type = 100
    newwhat.value = \the\value{notecounter}
    node.write(newwhat)

    add_note(
      \the\value{notecounter},          
      "\luaescapestring{#1}",            
      tex.sp("\the\dimexpr\ht0+\dp0\relax")  
    )
    }
}
 \makeatother



\newenvironment{chapterpage}[1]{%
    \noindent{\LARGE\bfseries #1}\par
    \vspace{1em}
    \hrule
    \vspace{1em}
    
    % 使用vbox而不是lrbox
    \setbox\maincontentbox=\vbox\bgroup
    \hsize=0.62\textwidth
}{%
    \egroup

    \newcounter{paginatepage}
    \setcounter{paginatepage}{1}
    \MainPaginateWithNotes
}


\newcommand{\MainPaginateWithNotes}{%
  \begingroup
  \loop
    \directlua{
        pagenotes={}
        local function traverse_notes(head,d)
            for n in node.traverse(head) do
                local t = node.type(n.id)
              
                if  n.id == node.id("whatsit") and  n.user_id == 112 then
                  % tex.print("Found sidenote node"..n.value)
                  table.insert(currentnotes, n.value)
                  table.insert(pagenotes, n.value)
                end
                if n.id == node.id("hlist") or n.id == node.id("vlist")  then
                traverse_notes(n.list,d+1)
                end
            end
        end
   
      
        local textheight_pt = get_textheight() 
 
        maincontentbox=tex.box['maincontentbox']
    
        if maincontentbox and maincontentbox.list then
            local mboxnum= token.create("maincontentbox").index
            local currentmainnum= token.create("mainforprint").index
            local mainpage =tex.splitbox(mboxnum,textheight_pt,'exactly')
            
            
            local head0 = mainpage.list 
            local vbox = node.vpack(head0)
            tex.box[currentmainnum] = vbox
            
            traverse_notes(mainpage.head,1)
            tex.print("本页notes有"..table.concat(pagenotes, "; "))

% 方案一
            for _, idx in ipairs(pagenotes) do
                local note = notes[idx]
                local tex_code = "\\setbox\\notecontentbox=\\vbox{\\unvbox\\notecontentbox\\parbox{0.34\\textwidth}{\\noindent\\footnotesize\\textcolor{blue}{[" 
                                 .. note.id .. "]} " .. note.content .. "}\\par\\vspace{0.5em}}"
                tex.sprint(tex_code)
            tex.sprint("\\relax")  
            end
% 方案2
            local head_notes  
            local tail_notes  
    
            function delayed_process_box()
                local tmpbox = tex.box[255]
                if tmpbox and tmpbox.list then
                    local new_list = node.copy_list(tmpbox.list)
                    tex.print("Delayed processing successful")
                end
            end
    
            % for _, idx in ipairs(pagenotes) do
            %     local note = notes[idx]
                
                
            %     tex.sprint("\\setbox255=\\hbox{\\noindent\\footnotesize\\textcolor{blue}{[" .. note.id .. "]}" .. note.content .. "}")
            %     tex.sprint("\\directlua{delayed_process_box()}")
            %     local tmpbox    = tex.box[255]
            %     tex.print("Height: " ..  tmpbox.height)
            %     local new_list  = node.copy_list(tmpbox.list)
                
            %     local glue_spec = node.new("glue_spec")
            %     glue_spec.width = tex.sp("0.5em")
            %     local glue      = node.new("glue")
            %     glue.spec       = glue_spec
            %     node.insert_after(new_list, node.tail(new_list), glue)
            
            %     if not head_notes then
            %         head_notes = new_list
            %         tail_notes = node.tail(new_list)
            %     else
            %         node.insert_after(head_notes, tail_notes, new_list)
            %         tail_notes = node.tail(new_list)
            %     end
            % end
            
            % local vbox_notes = node.vpack(head_notes, 0)
            % tex.setbox("notescontentbox", vbox_notes)
    %  方案2 结束


            
            
            local nboxnum= token.create("notecontentbox").index
            local currentnotenum= token.create("noteforprint").index
            % local curnotes = tex.box['notescontentbox']
            % tex.print("Height: " .. get_notescontentbox_height())
            local notepage =tex.splitbox(nboxnum,textheight_pt,'exactly')
            local head1 = notepage.list 
            local vbox1 = node.vpack(head1)
            tex.box[currentnotenum] = vbox1
            
            tex.print([[
                \noindent
                \hbox to \textwidth{%
                \vtop{%
                \vskip 0pt
                \hsize=0.38\textwidth
                \noindent
            ]])
            tex.print( [[\usebox\noteforprint]] )
            % tex.print( generate_notes_content() )
            tex.print([[
                }%
                \hfill
                \vtop{%
                \vskip 0pt
                \hsize=0.62\textwidth
                \noindent\usebox{\mainforprint}
                }%
                }
            ]])
        
        end
    }
  \ifnum\value{paginatepage}<50 % 防止死循环
    \stepcounter{paginatepage}
  \repeat
  \endgroup
}





% 页面样式
\pagestyle{fancy}
\fancyhf{}
\renewcommand{\headrulewidth}{0pt}
\fancyfoot[C]{\thepage}

\begin{document}



% 框架1:章首页
\begin{chapterpage}{第一章:引言}
    验知乎的全部功能。在使用某些功能和/或某些单项服务前,如发布内容、直播开播等,您需要注册或登录知乎账号,并按照国家相关法律法规的要求完成真实身份信息认证。\sidenote{开始。
        知乎账号的所有权归知乎所有,用户完成申}请注册流程后,获得知乎账号的使用权,且该使用权仅属于初始申请注册人,初始申请注册人应当对账号进行的所有活动和事件负法律责任。 初始申请注册人不得赠与、借用、租用、转让或售卖该账号或者以其他方式许可其他人使用该账号,非初始申请注册人不得通过受赠、承租、受让或\sidenote{者其他任何方式使用该账号。如知乎有合理理由认为账号使用者非账号初始申请注册人,为保障账号安全及账号初始申请注册人的合法权益,知乎有权立即暂停或终止向该账号提供服务。 初始申请注册人死亡的,初始申请注册人的继承人可提交死亡证明、户口本等能证明继承关系的文件,知乎核实通过后,继承人可取得该账号的部分使用权益。
        您理解并承诺,您所注册的账号不得违反国家法律法规及知乎的相关规则,您的账号名称、头像和简介等注册信息及其他个人信息中不得出现违法和不良信息,未经他人许可不得用他人名义(包}括但不限于冒用他人姓名、名称、字号、头像等或采取其他足以让人引起混淆的方式)开设账号,不得恶意注册知乎账号(包括但不限于频繁注册、批量注册账号等行为)。如果您的注册信息发生变化,您应及时更改。
    账号和密码的安全性和保密性由您负责保管,如您因\sidenote{丢失账号、遗忘密码或手机号变更等而无法登录的,应当遵照知乎提供的申诉途径和方式,及时申诉请求找回账号或密码。您理解并认可,账号找回机制仅需要识别申诉单上所填资料与系统记录资料具有一致性,而无法识别申诉人是否系账号真正有权使用者。您应妥善保管您的账号和密码。因您保管不当等自身原因或其他不可抗因素导致遭受盗号或密码丢失,您应自行承担相应责任和后果。
        您应对所有使用您账号的行为负完全责任。您同意:
        a. 您的知乎账号遭到未获授权的使用,或者发生其它任何安全问题时,您应立即通知知乎;
        b. 如果您未保管好自己的账号和密码,因此而产生的任何损失或损害,知乎不承担任何责任;c. 您要对使用账号的所有行为给您、知乎或第三方造成的损害负全责,包括您未保管好自己的账号或密码的情形;
        d. 除法律明文规定外,您不得将账号赠与、借用}、租用、转让或售卖给他人使用。
    您须对在知乎的注册信息的真实性、合法性、有效性承\sidenote{开始。}担全部责任,不得冒充他人、不得利用他人的名义发布任何信息、不得不当使用注册账号导致其他用户误认,否则知乎有权立即停止提供服务,收回账号并由您独自承担由此而产生的一切法律责任。
    如无特别说明,知乎各关联版本均使用统一的知乎账号服务,您注册的知乎账号通用于知乎和关联版本,您在知乎账号下发布的内容也会在知乎和关联版本中同步。您以\sidenote{开始。}知乎账号登录并使用关联版本相关服务的,应同时受本协议和关联版本用户协议及平台规则约束。如关联版本的用户协议及平台规则与本协议不一致的,优先适用关联版本的用户协议及平台规则。
    您理解并同意,除您登录、使用知乎外,您还可以用知乎账号登录使用我们或其他合作方提供的其他产品、服务。如您以知乎账号登录并使用该等产品、服务的,同样应受其他产品、服务实际\sidenote{开始。}提供方的用户协议及其他协议条款约束。
    为维护良好的社区秩序及氛围,我们可能会对知乎、知乎关联版本、我们提供的其他产品采取协同的管理手段。例如:如您在知乎中因违反法律法规或本协议约定的行为被采取处罚措施,您对关联版本及相关服务的使用也可能受到处罚措施的影响,反之亦然。
    根据相关法律法规要求,如您在注册后连续超过6个月未登录账号并使用,我们有权冻结或收回您的账号。如您的知乎账号被冻结或收回,您可能无法通过该账号及密码登录并使用知乎;如您的账号被收回,账号下保存的信息和使用记录将无法恢复。在冻结或收回您的账号前,我们将以适当的方式向您作出提示,如您在收到相关提示后仍未按提示进行操作,\sidenote{开始。}我们将冻结或收回账号。
    二、使用规则
    您直接或通过各类方式(如 RSS 源和站外 API 引用等)间接使用知乎服务和数据的行为,都将被视作已无条件接受本协议全部内容;若您对本协议的任何条款存在异议,请停止使用知乎所提供的全部产品及服务。 知乎中包含我们合法运营的其他单项服务,这些服务可能以单独板块形式存在。我们\sidenote{开始。}有权不时地增加、减少或改动这些特别板块的设置及服务,您可以在知乎中开启和使用上述单项服务功能。某些单项服务可能需要您同时接受就该服务特别制订的协议或规则,我们将以合理的方式提供这些协议、规则供您查阅。一旦您开始使用上述服务,则视为您理解并接受有关单项服务的相关协议、规则的约束。
    您应单独对其任何信息的发布行为承担法律责任;任何不愿被其他第三人获知的信息都不应该在知乎上发布。
    您承诺不得以任何方式利用本平台直接或间接从事违反中国法律以及社会公德的行为,知乎有权对违反上述承诺的内容予以删除。
    您不得利用本平台制作、上载、复制、发布、传播、转载或者以各种关键词/表述尝试输入或搜索如下内容:
    反



\end{chapterpage}

\end{document}
\end{document}

链接

  • TeX.SX:
  • GitHub:

其他信息

我也尝试问过AI chat, 发现关于tex的覆盖并不好,幻觉太多

附件

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions