跳转至

LuaTeX回调游乐场

欢迎加入本人建的"LuaTeX ConTeXt 学习互助"群:431714622,互助学习LuaTeX ConTeXt LaTeX相关技术,以及通过Lua、Python实现格式化文本、数据的自动排版。

本教程与luametatex-callback-playground项目配套。 使用、调整配套项目可以看到效果,更好理解。

本文主要参考ConTeXt Lua documents相关章节,官网回调函数,以及tex.stackexchange.com上的一些问答。

回调简介#

回调函数(callback)是LuaTeX(后继者叫LuaMetaTeX,简称LMTX)开放给用户的Lua编程钩子,我们可以编写自己的回调函数,挂载到需要的钩子上,以控制各种底层的处理过程。

回调函数分类:

  • 发现文件
  • 读文件
  • 数据处理
  • 结点处理
  • 信息报告
  • 杂项

有两类回调,一类与现有功能混合,另一类替代现有功能。后一种应该与内建功能类似,以免输出结果不能再进一步处理。

CONTEXT回调函数被包裹在一个保护层中,一方面有一些额外功能(通常通过宏使用),另一方面用户可以通过钩子加入自己的处理。 本文主要讨论与结点列表相关的一大类回调钩子,少量兼及其他。

回调动作 Actions#

几乎所有LUATEX回调都能在CONTEXT(CLD)中使用,但有些尽管enabled,但已经冻结(用户不能挂载)。详见ConTeXt Lua documents, 14.2 Actions列表。

最终所有的回调都会被使用,所以不要依赖“未定义的回调不被保护”。有些回调只有在某些功能被启用时才会被设置。与file handling, font definition and housekeeping相关的回调已经冻结,因为它们都涉及TEX目录结构。

与 node list相关的回调函数仅开放这些(使用callback等价的category钩子):

category callback arguments return value usage
processors pre_linebreak_filter head, ... head, done 每个段落分行之前回调
hpack_filter 在水平盒子/行盒子构造前回调
finalizers post_linebreak_filter head, ... head, done 在段落分行后回调
shipouts no callback yet head head, done 应用到即将送出的盒子(或xform)
mvlbuilders buildpage_filter done 有材料添加到主垂直列表后回调
vboxbuilders vpack_filter head, ... head, done 有材料添加到垂直盒子后回调
math mlist_to_hlist head, ... head, done 数学列表构造后、转为水平盒子列表前回调
pagebuilders ??? head, ... head, done ???

每类下还有一些小类,甚至小小类,小小小类,但用户只能用beforeafter两个小类(见14.3 Tasks)。

回调任务 Tasks#

在某些时候,过多的嵌套任务会带来性能上的损失。在运行结束后,MKIV会报告一些统计数据和时间,这些可以让你了解到在LUA中花费了多少时间。

processors#

  • before
    • unset
  • normalizers
    • languages.transliteration.handler
    • builders.kernel.collapsing
    • typesetters.periodkerns.handler
    • languages.replacements.handler
    • typesetters.wrappers.handler
    • typesetters.characters.handler
    • fonts.collections.process
    • fonts.checkers.missing
    • userdata.processmystuff 用户钩子??
  • characters
    • scripts.autofontfeature.handler
    • scripts.splitters.handler
    • typesetters.cleaners.handler
    • typesetters.directions.handler
    • typesetters.cases.handler
    • typesetters.breakpoints.handler
    • scripts.injectors.handler
  • words
    • languages.words.check
    • languages.hyphenators.handler
    • typesetters.initials.handler
    • typesetters.firstlines.handler
  • fonts
    • builders.paragraphs.solutions.splitters.split
    • nodes.handlers.characters
    • nodes.injections.handler
    • typesetters.fontkerns.handler
    • nodes.handlers.protectglyphs
    • builders.kernel.ligaturing
    • builders.kernel.kerning
    • nodes.handlers.show
    • nodes.handlers.stripping
    • nodes.handlers.flatten
    • fonts.goodies.colorschemes.coloring
  • lists
    • typesetters.rubies.check
    • typesetters.characteralign.handler
    • typesetters.spacings.handler
    • typesetters.kerns.handler
    • typesetters.digits.handler
    • typesetters.italics.handler
    • languages.visualizediscretionaries
  • after
    • typesetters.marksuspects
    • userdata.processmystuff 用户钩子

processors针对每个段落应用回调;有hbox嵌套的段落则从第一个内套的最后一层开始,比如我\hbox{你}\hbox{他\hbox{它}},依次是“你、它、他、我”所在的层。

  • "processors", "before",这时只加了par vmodepar和左右parfill skip
  • "processors", "after",这时还有脚本scrp-cjk.lua之hanzi加入了字间的glue userskip、标点前后的penalty userpenalty,可用于断行

finalizers#

  • before
    • unset
  • normalizers
    • unset
  • fonts
    • builders.paragraphs.solutions.splitters.optimize
  • lists
    • nodes.handlers.showhyphenation
    • nodes.handlers.visualizehyphenation
    • typesetters.margins.localhandler
    • builders.paragraphs.keeptogether
    • builders.paragraphs.tag
    • nodes.linefillers.handler
  • after
    • unset

Shipouts#

  • before
    • unset
  • normalizers
    • nodes.handlers.cleanuppage
    • typesetters.showsuspects
    • typesetters.margins.finalhandler
    • builders.paragraphs.expansion.trace
    • typesetters.alignments.handler
    • nodes.references.handler
    • nodes.destinations.handler
    • nodes.rules.handler
    • nodes.shifts.handler
    • structures.tags.handler
    • nodes.handlers.accessibility
    • nodes.handlers.backgrounds
    • typesetters.rubies.attach
    • nodes.tracers.directions
  • finishers
    • nodes.visualizers.handler
    • attributes.colors.handler
    • attributes.transparencies.handler
    • attributes.colorintents.handler
    • attributes.negatives.handler
    • attributes.effects.handler
    • attributes.alternates.handler
    • attributes.viewerlayers.handler
  • after
    • unset
  • wrapup
    • nodes.handlers.export
    • luatex.synctex.collect

mvlbuilders#

  • before
    • unset
  • normalizers
    • streams.collect
    • nodes.handlers.backgroundspage
    • typesetters.margins.globalhandler
    • nodes.handlers.migrate
    • builders.vspacing.pagehandler
    • builders.profiling.pagehandler
    • typesetters.checkers.handler
  • after
    • unset

vboxbuilders#

  • before
    • unset
  • normalizers
    • nodes.handlers.backgroundsvbox
    • builders.vspacing.vboxhandler
    • preliminary, uncorrected version -- July 25, 2021
    • typesetters.checkers.handler
  • after
    • unset

未来会增加更多parbuilder任务。这里有一些子任务取决于当前的排版环境,可以用于语言相关的特定处理。 parbuilders和pagebuilder任务都是非官方的,还不适合用户使用。

math#

  • before
    • unset
  • normalizers
    • noads.handlers.showtree
    • noads.handlers.unscript
    • noads.handlers.unstack
    • noads.handlers.variants
    • noads.handlers.relocate
    • noads.handlers.families
    • noads.handlers.render
    • noads.handlers.collapse
    • noads.handlers.fixscripts
    • noads.handlers.domains
    • noads.handlers.autofences
    • noads.handlers.resize
    • noads.handlers.alternates
    • noads.handlers.tags
    • noads.handlers.italics
    • noads.handlers.kernpairs
    • noads.handlers.classes
  • builders
    • builders.kernel.mlisttohlist
    • typesetters.directions.processmath
    • noads.handlers.makeup
    • noads.handlers.align
  • finalizers
    • noads.handlers.export
  • after
    • unset

挂载结点任务#

实际挂载nodes.tasks.appendaction()的任务列表见ConTeXt Lua documents, 14.3 Tasks

新建任务列表,挂载、激活、暂停、删除任务:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
nodes.tasks.new("mytasks",{ "one", "two" })
nodes.tasks.appendaction ("mytask","one","bla.alpha")
nodes.tasks.appendaction ("mytask","one","bla.beta")
nodes.tasks.appendaction ("mytask","one","bla.whatever","bla.alpha")
nodes.tasks.prependaction("mytask","two","bla.gamma")
nodes.tasks.prependaction("mytask","two","bla.delta")
nodes.tasks.removeaction("mytask","one","bla.whatever") -- 移除,动作大
nodes.tasks.enableaction ("mytask","bla.whatever") -- 无小类,请保证名称的唯一性
nodes.tasks.disableaction("mytask","bla.whatever") -- 无小类,请保证名称的唯一性
nodes.tasks.enablegroup ("mytask","one") -- 组/小类操作
nodes.tasks.disablegroup("mytask","one")
nodes.tasks.actions("mytask",2) -- 返回函数及其两个(head之外的)额外参数

LuaTeX用:

  • id = callback.register( callback_name, func)
  • id = callback.register( callback_name, nil) -- 清除回调
  • id = callback.register( callback_name, false) -- 阻止默认行为以获得速度,但可能造成混乱
  • info = callback.list() -- 列表
  • f = callback.find(callback_name) -- 是否激活
  • if callback.known("foo") then ... end -- 钩子是否可用

清除回调,回到系统默认行为:callback.register(nil)

阻止回调(包括系统默认行为): callback.register(false)

注册会覆盖前一次注册的回调。

LuaLaTeX中用:

  • luatexbase.add_to_callback("post_linebreak_filter",my_filter,"a fancy new filter")
  • luatexbase.remove_from_callback("post_linebreak_filter","a fancy new filter")

LuaTeX结点列表相关回调#

投稿过滤器 contribute_filter#

当LuaTEX向结点列表中增加内容时回调。

页面构建过滤器 buildpage_filter#

每次LuaTEX准备好向主垂直列表(main vertical list,即页面主体)转移材料时回调。你可以使用本回调做一些特定的页面构建阶段的操作,比如拼版(imposition)或栏间协调(column balancing)。

构建页时插入 build_page_insert#

当页面构建器(pagebuilder)增加一个插入(insert)时回调。这个机制没有太多可操控的地方,但本回调可以在最后时刻、在插入前操控加空(spacing);有时很方便,比如有多个插入附加在一个行(row)后。

断行前过滤器 pre_linebreak_filter#

在LuaTEXT添加\type{\parfillskip}(段后空)后和开始把结点列表转换为一栈\type{\hboxes}前回调。

断行过滤器 linebreak_filter#

本回调替代LuaTEX的断行算法。

加入vlist的过滤器 append_to_vlist_filter#

LuaTEXT每次向vlist添加一个盒子时回调。

断行后过滤器 post_linebreak_filter#

在LuaTEX把结点列表转换为一栈\type{\hboxes}后回调。

字模处理 glyph_run#

LuaMetaTeX新增。当TEX正常处理合字和字间时回调。在LuaTEX中,你可以使用hpack_filter和per_linebreak_filter回调来完成(每个回调传递不同的参数)。当没有字模时,这个回调不会触发(在LuaTEX中,这个优化是由一个变量控制的)。

hpack过滤器 hpack_filter#

当TEX准备开始把水平材料(horizontal mode material)装盒(boxing)时回调。会忽略数学项目和线条盒子(line boxes)。

vpack过滤器 vpack_filter#

当TEX准备开始把垂直材料(vertical mode material)装盒(boxing)时回调。会忽略数学特排(Math displays)。

与hpack_filter相似。除了回调时机不同,还有一个匹配TEX的\type{\maxdepth}设置的变量。

hpack质量 hpack_quality#

用于截取打包hlist(类似段落构造时)产生的溢出(overfull)信息。

1
2
3
function(<string> incident, <number> detail, <node> head, <number> first, <number> last)
    return <node> whatever
end

incident(事件)指overfull, underfull, loose, tight其中之一

vpack质量 vpack_quality#

用于截取打包vlist(类似页面构造时)产生的溢出(overfull)信息。

处理界尺 process_rule#

实验中。 用于小类为4(user)的界尺。

输出前过滤器 pre_output_filter#

当TEX准备开始把box 255(页面盒子)装盒给\type{\output}时回调。

断词 hyphenate#

合字 ligaturing#

一定不要破坏节点列表。例如,头部通常是一个剧部par节点,而尾部是一个胶结点。弄得太乱会使LuaTEX进入慌乱模式。

加字间 kerning#

一定不要破坏节点列表。例如,头部通常是一个剧部par节点,而尾部是一个胶结点。弄得太乱会使LuaTEX进入慌乱模式。

插入段落 insert_par#

每个段落由一个剧本par结点开始,par结点有标记方向等功能。

mlist转hlist mlist_to_hlist#

本回调会替换mlist(数学列表)转hlist的算法。 -->

评论