LuaTeX回调游乐场
欢迎加入本人建的"LuaTeX ConTeXt 学习互助"群:431714622,互助学习LuaTeX ConTeXt LaTeX相关技术,以及通过Lua、Python实现格式化文本、数据的自动排版。
本教程与luametatex-callback-playground项目配套。 使用、调整配套项目可以看到效果,更好理解。
本文主要参考ConTeXt Lua documents相关章节,原文件task-ini.lmt,官网回调函数,以及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 | ??? |
每类下还有一些小类,甚至小小类,小小小类,但用户只能用before
和after
两个小类(见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 |
|
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 |
|
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的算法。 -->