if not modules then modules = { } end modules ['spac-pas'] = { version = 1.001, comment = "companion to spac-pas.mkxl", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files" } local rawget, tonumber = rawget, tonumber local report = logs.reporter("break quality") local integer_value = tokens.values.integer local currentfile = luatex.currentfile local toobad = 20 local tracing = false local details = false -- builders.passnames = utilities.storage.mark(builders.passnames or { }) -- local passnames = builders.passnames -- local nofidentifiers = #passnames -- -- storage.register("builders/passnames", passnames, "builders.passnames") local passnames = { } local nofidentifiers = 0 table.setmetatableindex(passnames,function(t,k) if type(k) == "number" and k >= 0 then return k else nofidentifiers = nofidentifiers - 1 t[k] = nofidentifiers t[nofidentifiers] = k return nofidentifiers end end) interfaces.implement { name = "parpassidentifier", public = true, usage = "value", arguments = "string", actions = function(s) return integer_value, passnames[s] end, } local function linebreak_quality_console(id,line,pass,subpass,subpasses,overfull,underfull,badness,classes) local filename = currentfile() local passname = passnames[id] if pass == 1 then if details then report("file %a, line %i, pass 1",filename,line) end elseif overfull ~= 0 then if subpass > 0 then report("file %a, line %i, pass %i, subpass %i of %i, overfull %p, classes 0x%02X, id %a",filename,line,pass,subpass,subpasses,overfull,classes,passname) else report("file %a, line %i, pass %i, classes 0x%02X, overfull %p",filename,line,pass,classes,overfull) end elseif underfull ~= 0 then if subpass > 0 then report("file %a, line %i, pass %i, subpass %i of %i, underfull %p, classes 0x%02X, id %a",filename,line,pass,subpass,subpasses,underfull,classes,passname) else report("file %a, line %i, pass %i, classes 0x%02X, underfull %p",filename,line,pass,classes,underfull) end elseif badness > toobad then if subpass > 0 then report("file %a, line %i, pass %i, subpass %i of %i, badness %s, classes 0x%02X, id %a",filename,line,pass,subpass,subpasses,badness,classes,passname) else report("file %a, line %i, classes 0x%02X, badness %i, okay",filename,line,pass,classes,badness) end else if subpass > 0 then report("file %a, line %i, pass %i, subpass %i of %i, okay, classes 0x%02X, id %a",filename,line,pass,subpass,subpasses,classes,passname) elseif details then report("file %a, line %i, okay",filename,line,pass) end end end local collected = table.setmetatableindex("table") local noffirst = 0 local nofsecond = 0 local nofthird = 0 local nofsubpasses = 0 local nofsubdone = 0 local nofoverfull = 0 local nofunderfull = 0 local nofbadness = 0 local function linebreak_quality_summary(id,line,pass,subpass,subpasses,overfull,underfull,badness,classes) if pass == 1 then -- t = { pass = 1, line = line } noffirst = noffirst + 1 else if pass == 2 then nofsecond = nofsecond + 1 else nofthird = nofthird + 1 end local o = overfull ~= 0 local u = underfull ~= 0 local b = badness > toobad local s = subpass > 0 if o then nofoverfull = nofoverfull + 1 end if u then nofunderfull = nofunderfull + 1 end if b then nofbadness = nofbadness + 1 end if s then nofsubpasses = nofsubpasses + 1 nofsubdone = nofsubdone + subpass end if o then local c = collected[currentfile()] c[#c+1] = { pass = pass, line = line, subpass = subpass, subpasses = subpasses, overfull = overfull, classes = classes, id = passnames[id], } elseif b then local c = collected[currentfile()] c[#c+1] = { pass = pass, line = line, subpass = subpass, subpasses = subpasses, badness = badness, classes = classes, id = passnames[id], } end end end logs.registerfinalactions(function() if tracing and next(collected) then logs.startfilelogging(report,"overfull lines") for filename, list in table.sortedhash(collected) do for i=1,#list do local t = list[i] local b = t.badness local o = t.overfull if b then report(" file %a, line %i, pass %i, subpass %i of %i, classes 0x%02X, badness %i", filename,t.line,t.pass,t.subpass,t.subpasses,t.classes,b) elseif o then report(" file %a, line %i, pass %i, subpass %i of %i, classes 0x%02X, overfull %p",filename,t.line,t.pass,t.subpass,t.subpasses,t.classes,o) end end end logs.stopfilelogging() end end) statistics.register("linebreak quality",function() if tracing then return string.formatters["%i first, %i second, %i third, %i subpasses, %i subruns, %i overfull, %i underfull, %i badness"]( noffirst, nofsecond, nofthird, nofsubpasses, nofsubdone, nofoverfull, nofunderfull, nofbadness ) end end) local registercallback = callback.register trackers.register("paragraphs.passes", function(v) details = false if not v then tracing = nil elseif v == "summary" then tracing = linebreak_quality_summary elseif v == "details" then details = true tracing = linebreak_quality_console else tracing = linebreak_quality_console end registercallback("linebreak_quality",tracing) end) -- -- -- -- local nuts = nodes.nuts local tonut = nodes.tonut local setprop = nuts.setprop local getprop = nuts.getprop local trace_callbacks = false trackers.register("paragraphs.passes.callbacks", function(v) trace_callbacks = v end) local actions = { } local identifiers = table.setmetatableindex(function(t,k) local v = #t + 1 local s = tostring(k) -- no number t[s] = v t[v] = s return v end) callback.register("paragraph_pass", function( head,identifier,callback, overfull,underfull,verdict,classified, threshold,badness,classes ) local action = actions[callback] if action then local head = tonut(head) local step = getprop(head,"par_pass_done") or 1 setprop(head,"par_pass_done",step+1) local result, again = action( head,rawget(identifiers,identifier) or identifier,callback,step, overfull,underfull,verdict,classified, threshold,badness,classes ) if trace_callbacks then if type(result) == "table" then report("subpass identifier %a, callback %a, %s",identifier,callback,"process with data") elseif result then report("subpass identifier %a, callback %a, %s",identifier,callback,"process") else report("subpass identifier %a, callback %a, %s",identifier,callback,"quit") end end return result, again else report("subpass identifier %a, unknown callback %a",identifier,callback) return false end end) function builders.registerpaspasscallback(identifier,action) local index = identifiers[identifier] actions[index] = action return index end interfaces.implement { name = "parpasscallback", public = true, usage = "value", arguments = "string", actions = function(s) return integer_value, identifiers[s] end, }