diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mkxl/luat-cbk.lmt')
-rw-r--r-- | Master/texmf-dist/tex/context/base/mkxl/luat-cbk.lmt | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/context/base/mkxl/luat-cbk.lmt b/Master/texmf-dist/tex/context/base/mkxl/luat-cbk.lmt new file mode 100644 index 00000000000..744d12e279a --- /dev/null +++ b/Master/texmf-dist/tex/context/base/mkxl/luat-cbk.lmt @@ -0,0 +1,287 @@ +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 collectgarbage, type, next = collectgarbage, type, next +local round = math.round +local sortedhash, sortedkeys, tohash = table.sortedhash, table.sortedkeys, table.tohash + +--[[ldx-- +<p>Callbacks are the real asset of <l n='luatex'/>. They permit you to hook +your own code into the <l n='tex'/> engine. Here we implement a few handy +auxiliary functions.</p> +--ldx]]-- + +callbacks = callbacks or { } +local callbacks = callbacks + +--[[ldx-- +<p>When you (temporarily) want to install a callback function, and after a +while wants to revert to the original one, you can use the following two +functions. This only works for non-frozen ones.</p> +--ldx]]-- + +local trace_callbacks = false trackers.register("system.callbacks", function(v) trace_callbacks = v end) +local trace_calls = false -- only used when analyzing performance and initializations +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 register_usercall = false +local original_register = register_callback + +local frozen = { } +local stack = { } +local list = callbacks.list +local permit_overloads = false +local block_overloads = false + +--[[ldx-- +<p>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. It might be ok for quick and dirty testing but anyway you're on your own if +you permanently overload callback functions.</p> +--ldx]]-- + +-- This might become a configuration file only option when it gets abused too much. + +directives.register("system.callbacks.permitoverloads", function(v) + if block_overloads or permit_overloads then + -- once bad news, always bad news + elseif v then + permit_overloads = { } + report_system() + report_system("The callback system has been brought in an unprotected state. As a result of directly") + report_system("setting of callbacks subsystems of ConTeXt can stop working. There is no support for") + report_system("bugs resulting from this state. It's better to use the official extension mechanisms.") + report_system() + end +end) + +sandbox.initializer { + category = "functions", + action = function() + block_overloads = true + end +} + +if not list then -- otherwise counters get reset + + list = utilities.storage.allocate(list_callbacks()) + + local supported = { } + + for k in next, list do + list[k] = 0 + supported[k] = true + end + + callbacks.list = list + callbacks.supported = supported + +end + +local delayed = tohash { + "buildpage_filter", +} + +if trace_calls then + + local functions = { } + + register_callback = function(name,func) + if type(func) == "function" then + if functions[name] then + functions[name] = func + return find_callback(name) + else + functions[name] = func + local cnuf = function(...) + list[name] = list[name] + 1 + return functions[name](...) + end + return original_register(name,cnuf) + end + else + return original_register(name,func) + end + end + +end + +-- temporary, not public: + +callbacks.functions = { } + +-- till here + +local reported = { } + +local function register_usercall(what,name,func) + if list[name] then + if trace_callbacks or not reported[name] then + report_system() + report_system("disabling core code by %s user function into callback '%s' (reported only once)",what,name) + report_system() + reported[name] = true + end + permit_overloads[name] = true + return original_register(name,function(...) + if trace_callbacks then + report_callbacks("calling user function from '%s'",name) + end + return func(...) + end) + else + report_callbacks("not %s function into invalid callback '%s'",name) + return nil, format("unknown callback '%s'",name) + end +end + +local function frozen_callback(name) + report_callbacks("not %s frozen %a","registering",name) + return nil, format("callback '%s' is frozen",name) -- no formatter yet +end + +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() + for name, _ in sortedhash(list) do + local str = frozen[name] + if str then + report_callbacks("%s: %s -> %s",state(name),name,str) + else + report_callbacks("%s: %s",state(name),name) + end + end +end + +function callbacks.freeze(name,freeze) + if not permit_overloads then + freeze = type(freeze) == "string" and freeze + if find(name,"*",1,true) then + local pattern = name + for name, _ in next, list do + if find(name,pattern) then + frozen[name] = freeze or frozen[name] or "frozen" + end + end + else + frozen[name] = freeze or frozen[name] or "frozen" + end + end +end + +function callbacks.register(name,func,freeze) + if frozen[name] then + if permit_overloads then + return register_usercall("registering",name,func) + else + return frozen_callback(name) + end + elseif freeze then + frozen[name] = type(freeze) == "string" and freeze or "registered" + end + if delayed[name] and environment.initex then + return nil + end + return register_callback(name,func) +end + +function callback.register(name,func) -- original + if not frozen[name] then + return register_callback(name,func) + elseif permit_overloads then + return register_usercall("registering",name,func) + else + return frozen_callback(name) + end +end + +function callbacks.push(name,func) + if not frozen[name] or permit_overloads then + local sn = stack[name] + if not sn then + sn = { } + stack[name] = sn + end + insert(sn,find_callback(name)) + if permit_overloads then + register_usercall("pushing",name,func) + else + register_callback(name,func) + end + else + report_callbacks("not %s frozen %a","pushing",name) + end +end + +function callbacks.pop(name) + if not frozen[name] or permit_overloads then + local sn = stack[name] + if not sn or #sn == 0 then + -- some error + register_callback(name,nil) -- ! really needed + else + -- this fails: register_callback(name, remove(stack[name])) + local func = remove(sn) + register_callback(name,func) + end + end +end + +if trace_calls then + statistics.register("callback details", function() + local t = { } -- todo: pass function to register and quit at nil + for name, n in sortedhash(list) do + if n > 0 then + t[#t+1] = format("%s -> %s",name,n) + end + end + return concat(t," ") + end) +end + +statistics.register("callbacks overloaded by user", function() + if permit_overloads then + return concat(sortedkeys(permit_overloads)," ") + end +end) + +-- this will move to a module + +commands = commands or { } + +function commands.showcallbacks() + local NC, NR, verbatim = context.NC, context.NR, context.type + context.starttabulate { "|l|l|p|" } + for name, _ in sortedhash(list) do + NC() verbatim(name) NC() verbatim(state(name)) NC() context(frozen[name] or "") NC() NR() + end + context.stoptabulate() +end |