if not modules then modules = { } end modules ['luat-cbk'] = { version = 1.001, comment = "companion to luat-lib.mkiv", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files" } local insert, remove, concat = table.insert, table.remove, table.concat local find, format = string.find, string.format local type, next = type, next local round = math.round local sortedhash, sortedkeys, tohash = table.sortedhash, table.sortedkeys, table.tohash -- Callbacks are the real asset of LuaTeX. They permit you to hook your own code -- into the TeX engine. Here we implement a few handy auxiliary functions. Watch -- out, there are diferences between LuateX and LuaMetaTeX. -- By now most callbacks are frozen and most provide a way to plug in your own code. -- For instance all node list handlers provide before/after namespaces and the file -- handling code can be extended by adding schemes and if needed I can add more -- hooks. So there is no real need to overload a core callback function. The ability -- to overload by a user (push/pop etc) has been removed. You can find the oveload -- code in version before 2025-06-01. callbacks = callbacks or { } local callbacks = callbacks local trace_callbacks = false trackers.register("system.callbacks", function(v) trace_callbacks = v end) local trace_checking = false trackers.register("memory.checking", function(v) trace_checking = v end) local report_system = logs.reporter("system") local report_callbacks = logs.reporter("system","callbacks") local report_memory = logs.reporter("system","memory") local register_callback = callback.register local find_callback = callback.find local list_callbacks = callback.list local set_callback_state = callback.setstate local get_callback_state = callback.getstate local set_callback_options = callback.setoptions local get_callback_index = callback.getindex local comments = { } local list = callbacks.list local options = callback.getoptionvalues() local states = callback.getstatevalues() options = table.swapped(options,options) states = table.swapped(states,states) callbacks.optioncodes = options callbacks.statecodes = states local disabled_code = states.disabled local frozen_code = states.frozen local trace_code = options.trace callback.setoptions(options.direct) trackers.register("callbacks.calls",function(v) set_callback_options(trace_code,v and true or false) end) local delayed = false do if environment.initex then delayed = { "buildpage", } for i=1,#delayed do set_callback_state(delayed[i],disabled_code & frozen_code) end delayed = tohash(delayed) end end -- temporary, not public, needed in driv-ini and lua-run callbacks.functions = { } local function state(name) local f = find_callback(name) if f == false then return "disabled" elseif f then return "enabled" else return "undefined" end end function callbacks.known(name) return list[name] end function callbacks.report() local usage = list_callbacks() for name, _ in sortedhash(list) do local com = comments[name] local sta = state(name) local use = usage[name] and "+" or "-" local fro = frozen[name] and " (frozen)" or "" if com and com ~= "" and com ~= name then report_callbacks("%-9s : %s : %-22s -> %s%s",sta,use,name,com,fro) else report_callbacks("%-9s : %s : %-22s%s", sta,use,name, fro) end end end function callbacks.freeze(name) if find(name,"*",1,true) then local pattern = name for name, _ in next, list do if find(name,pattern) then set_callback_state(name,frozen_code) end end else set_callback_state(name,frozen_code) end end -- For now we also support the old interface. local function register(specification,action,freeze) if type(specification) ~= "table" then specification = { name = specification, action = action, frozen = freeze and true or false, comment = type(freeze) == "string" and freeze or nil, } end local name = specification.name if type(name) ~= "string" or name == "" then report_callbacks("bad callback registration") return end if delayed and delayed[name] then return nil end local comment = specification.comment if type(comment) ~= "string" then comment = name end -- local index = register_callback(name,specification.action or false) if index then if specification.disable or specification.disabled then set_callback_state(index,disabled_code) end if specification.freeze or specification.frozen then set_callback_state(index,frozen_code) end end return index end callbacks.register = register function callback.register(name,action) -- original return register { name = name, action = action } end function callbacks.optimizer(name) local index = get_callback_index(name) if index then return index, function() set_callback_state(index) end, function() set_callback_state(index,disabled_code) end end end -- For old times sake: function callbacks.push() end function callbacks.pop () end -- This will move to a module (but then i need to adapt a few manuals and -- modules. local getstates do local states, keys -- delayed local function getstates(i) if not states then states = callback.getstatevalues() keys = table.sortedkeys(states) end local state = get_callback_state(i) local result = { } if state and state ~= 0 then for i=1,#keys do local k = keys[i] if (state & k) == k then result[#result+1] = states[i] end end end return result end end commands = commands or { } function commands.showcallbacks() local NC, NR = context.NC, context.NR context.starttabulate { "|lT|lT|" } for name, _ in sortedhash(list) do NC() context(name) NC() context("% t",getstates(name)) NC() NR() end context.stoptabulate() end