summaryrefslogtreecommitdiff
path: root/macros/luatex/generic/minim/minim-callbacks.lua
diff options
context:
space:
mode:
Diffstat (limited to 'macros/luatex/generic/minim/minim-callbacks.lua')
-rw-r--r--macros/luatex/generic/minim/minim-callbacks.lua265
1 files changed, 265 insertions, 0 deletions
diff --git a/macros/luatex/generic/minim/minim-callbacks.lua b/macros/luatex/generic/minim/minim-callbacks.lua
new file mode 100644
index 0000000000..3ac075dc01
--- /dev/null
+++ b/macros/luatex/generic/minim/minim-callbacks.lua
@@ -0,0 +1,265 @@
+
+local M = {}
+
+local function log(msg, ...)
+ texio.write_nl('log', string.format(msg, ...))
+end
+
+-- 1 capturing the callback mechanism
+
+-- if ltluatex is loaded, we must get callback.register back
+if luatexbase ~= nil then
+ local luatex_base = luatexbase
+ luatexbase.uninstall ()
+ luatexbase = luatex_base
+end
+
+local primitives = { }
+M.primitives = primitives
+primitives.register = callback.register
+primitives.find = callback.find
+primitives.list = callback.list
+
+local own_callbacks = {}
+local callback_lists = {}
+local callback_stacks = {}
+
+-- 1 finding callbacks
+
+function M.find (name)
+ local f = own_callbacks[name]
+ if f == nil then
+ return primitives.find(name)
+ else
+ return f
+ end
+end
+
+function M.list (name)
+ local t = {}
+ for n,f in pairs(callback_lists) do
+ if f then
+ t[n] = #f
+ else
+ t[n] = false
+ end
+ end
+ for n,f in pairs(own_callbacks) do
+ if f then
+ t[n] = t[n] or true
+ else
+ t[n] = t[n] or false
+ end
+ end
+ for n,f in pairs(primitives.list()) do
+ if f then
+ t[n] = t[n] or true
+ else
+ t[n] = t[n] or false
+ end
+ end
+ return t
+end
+
+-- 1 registering callbacks
+
+local function register_simple (cb,f)
+ -- prefer user-defined callbacks over built-in
+ local x = own_callbacks[cb]
+ if x == nil then
+ return primitives.register (cb, f)
+ else
+ -- default to false because nil would delete the callback itself
+ own_callbacks[cb] = f or false
+ return -1
+ end
+end
+
+-- will be redefined later
+local function announce_callback(cb, f) end
+
+function M.register (cb, f)
+ announce_callback(cb, f)
+ local list = callback_lists[cb]
+ local stack = callback_stacks[cb]
+ if stack then
+ if f == nil then -- pop
+ local p = stack[#stack]
+ stack[#stack] = nil
+ return register_simple (cb,p)
+ else -- push
+ stack[#stack+1] = M.find (cb)
+ return register_simple (cb,f)
+ end
+ elseif list ~= nil then
+ list[#list+1] = f
+ return -2
+ else
+ return register_simple (cb,f)
+ end
+end
+
+
+-- 1 lists of callback functions
+
+local function call_list_node (lst)
+ return function (head, ...)
+ local list = callback_lists[lst]
+ for _,f in ipairs(list) do
+ local newhead = f(head,...)
+ if node.is_node(newhead) then
+ head = newhead
+ elseif newhead == false then
+ return false
+ end
+ end
+ return head
+ end
+end
+
+local function call_list_data (lst)
+ return function (str)
+ local list = callback_lists[lst]
+ for _,f in ipairs(list) do
+ str = f(str) or str
+ end
+ return str
+ end
+end
+
+local function call_list_simple (lst)
+ return function (...)
+ local list = callback_lists[lst]
+ for _,f in ipairs(list) do
+ f(...)
+ end
+ end
+end
+
+-- 1 creating and calling callbacks
+
+local function register_list (lst, fn)
+ M.register (lst, fn(lst))
+ callback_lists[lst] = {}
+end
+
+local function stack_callback (cb)
+ callback_stacks[cb] = {}
+end
+
+function M.new_callback (name, prop)
+ own_callbacks[name] = false -- false means empty here
+ if prop == 'stack' then
+ stack_callback (name)
+ elseif prop == 'node' then
+ register_list (name, call_list_node)
+ elseif prop == 'simple' then
+ register_list (name, call_list_simple)
+ elseif prop == 'data' then
+ register_list (name, call_list_data)
+ end
+end
+
+function M.call_callback (name, ...)
+ local f = own_callbacks[name]
+ if f then
+ return f (...)
+ else
+ return false
+ end
+end
+
+-- 1 initialisation
+
+-- save all registered callbacks
+local saved = {}
+for n,s in pairs(primitives.list()) do
+ if s then
+ log('save callback: %s', n)
+ saved[n] = callback.find(n)
+ end
+end
+
+-- replace the primitive registering
+callback.register = M.register
+callback.find = M.find
+callback.list = M.list
+
+-- string processing callbacks
+register_list ('process_input_buffer', call_list_data)
+register_list ('process_output_buffer', call_list_data)
+register_list ('process_jobname', call_list_data)
+
+-- node list processing callbacks
+register_list ('pre_linebreak_filter', call_list_node)
+register_list ('post_linebreak_filter', call_list_node)
+--register_list ('append_to_vlist_filter', call_list_node) -- TODO this breaks something
+register_list ('hpack_filter', call_list_node)
+register_list ('vpack_filter', call_list_node)
+register_list ('pre_output_filter', call_list_node)
+
+-- mlist_to_mlist and mlist_to_mlist
+M.new_callback ('mlist_to_mlist', 'node')
+M.new_callback ('mlist_to_hlist', 'stack')
+M.register ('mlist_to_hlist', node.mlist_to_hlist )
+primitives.register ('mlist_to_hlist', function (head, ...)
+ local newhead = M.call_callback ('mlist_to_mlist', head, ...)
+ if newhead ~= true then
+ head = newhead or head
+ end
+ newhead = M.call_callback ('mlist_to_hlist', head, ...)
+ return newhead
+end)
+
+-- simple listable callbacks
+register_list ('contribute_filter', call_list_simple)
+register_list ('pre_dump', call_list_simple)
+register_list ('wrapup_run', call_list_simple)
+register_list ('finish_pdffile', call_list_simple)
+register_list ('finish_pdfpage', call_list_simple)
+register_list ('insert_local_par', call_list_simple)
+
+register_list ('ligaturing', call_list_simple)
+register_list ('kerning', call_list_simple)
+
+-- stack callbacks
+stack_callback ('hpack_quality')
+stack_callback ('vpack_quality')
+stack_callback ('hyphenate')
+stack_callback ('linebreak_filter')
+stack_callback ('buildpage_filter')
+stack_callback ('build_page_insert')
+
+-- process_rule
+M.new_callback ('process_rule', 'simple')
+primitives.register ('process_rule', function (rule, ...)
+ local p = own_callbacks[rule.index]
+ if p then
+ p (rule, ...)
+ else
+ M.call_callback ('process_rule')
+ end
+end)
+
+-- restore all registered callbacks
+for n,f in pairs(saved) do
+ log('restore callback: %s', n)
+ M.register (n,f)
+end
+saved = nil
+
+
+local function announce_callback(cb, f)
+ if f then
+ log('callback added: %s', cb)
+ else
+ log('callback removed: %s', cb)
+ end
+end
+
+
+--
+
+return M
+
+