summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/mkxl/luat-cbk.lmt
diff options
context:
space:
mode:
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.lmt287
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