spac-brk.lmt /size: 7178 b    last modification: 2024-01-16 10:22
1if not modules then modules = { } end modules ['spac-brk'] = {
2    version   = 1.001,
3    comment   = "companion to spac-brk.mkiv",
4    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5    copyright = "PRAGMA ADE / ConTeXt Development Team",
6    license   = "see context related readme files"
7}
8
9local next, type, tonumber, tostring = next, type, tonumber, tostring
10
11local settings_to_array  = utilities.parsers.settings_to_array
12local settings_to_hash   = utilities.parsers.settings_to_hash
13
14local nuts               = nodes.nuts
15local tonut              = nodes.tonut
16
17local newrule            = nuts.pool.virtualrule
18local insertbefore       = nuts.insertbefore
19local insertafter        = nuts.insertafter
20local hpack_string       = nuts.typesetters.tohpack
21local getwidth           = nuts.getwidth
22local getid              = nuts.getid
23local getprev            = nuts.getprev
24local getnext            = nuts.getnext
25local setwhd             = nuts.setwhd
26local getlist            = nuts.getlist
27local setoffsets         = nuts.setoffsets
28
29local setcolor           = nodes.tracers.colors.set
30local settransparency    = nodes.tracers.transparencies.set
31
32local texgetnest         = tex.getnest
33local texgetcount        = tex.getcount
34
35local nodecodes          = nodes.nodecodes
36
37local penalty_code       = nodecodes.penalty
38local glue_code          = nodecodes.glue
39local disc_code          = nodecodes.disc
40local kern_code          = nodecodes.kern
41local math_code          = nodecodes.math
42
43local breakcodes         = tex.breakcodes
44
45local registercallback   = callback.register
46
47local c_tracinglousiness = tex.iscount("tracinglousiness")
48
49local alignments       = { }
50typesetters.alignments = alignments
51
52typesetters              = typesetters or { }
53local breakpoints        = typesetters.breakpoints or { }
54typesetters.breakpoints  = breakpoints
55
56local width      =      65536 / 2
57local height     =  9 * 65536
58local depth      =  3 * 65536
59local xoffset    =  1 * 65536
60local yoffset    = -3 * 65536
61
62local serial     = false
63local usedfont   = false
64local nestlevel  = false
65local overload   = false
66local order      = 0
67
68local report     = logs.reporter("linebreaks")
69
70local actions = {
71    [breakcodes.initialize] = function()
72        if texgetnest("ptr") == nestlevel then
73            usedfont = nodes.visualizers.getusedfont()
74            serial   = false
75            order    = order + 1
76        end
77    end,
78    [breakcodes.start] = function(pass)
79        if texgetnest("ptr") == nestlevel then
80            if pass == 2 then
81                serial = { }
82            end
83        end
84    end,
85    [breakcodes.report] = function(pass,currentserial,previousserial,line,kind,class,demerits,breakpoint,short,glue)
86        if serial and breakpoint and texgetnest("ptr") == nestlevel then
87            local s = {
88                serial     = currentserial,
89                demerits   = demerits,
90                breakpoint = breakpoint,
91            }
92            serial[currentserial] = s
93            local found = overload and overload[currentserial]
94            if found then
95                report("pass %i, overloading serial %i.%i demerits from %i to %i",2,order,currentserial,demerits,found)
96                return found
97            end
98        end
99        return demerits
100    end,
101    [breakcodes.collect] = function()
102        if serial and texgetnest("ptr") == nestlevel and texgetcount(c_tracinglousiness) >= 1 then
103            for currentserial=1,#serial do
104                local data       = serial[currentserial]
105                local breakpoint = data.breakpoint
106                local current    = tonut(breakpoint)
107                while current do
108                    local id = getid(current)
109                    if id == penalty_code or id == glue_code or id == kern_code or id == math_code then
110                        current = getprev(current)
111                    else
112                        break
113                    end
114                end
115                if current then
116                    local rule   = newrule(width,height,depth,currentserial)
117                    data.rule    = rule
118                    insertafter(current,current,rule)
119                end
120            end
121        end
122    end,
123    [breakcodes.wrapup] = function()
124        if serial and texgetnest("ptr") == nestlevel then
125            local n     = #serial
126            local trace = texgetcount(c_tracinglousiness)
127            if trace >= 2 then
128                report("%i demerits in set %i",n,order)
129            end
130            for currentserial=1,n do
131                local data = serial[currentserial]
132                local demerits = data.demerits
133                if trace >= 1 then
134                    local rule = data.rule
135                    if rule then
136                        local tag  = tostring(order).."."..tostring(currentserial)
137                        local text = hpack_string(tag,usedfont)
138                        local size = getwidth(text)
139                        setwhd(text,0,0,0)
140                        setoffsets(text,-size-xoffset,yoffset)
141                        insertafter(rule,rule,text)
142                    end
143                end
144                serial[currentserial] = demerits
145                if trace >= 2 then
146                    report("% 4i : %8i",currentserial,demerits)
147                end
148            end
149            overload = false
150            registercallback("show_break")
151        end
152    end,
153}
154
155local function action(what,...)
156    local action = actions[what]
157    if action then
158        return action(...)
159    end
160end
161
162local function show(str)
163    nestlevel = texgetnest("ptr")
164    if str and str ~= "" then
165        if type(str) == "table" then
166            overload = str
167        else
168            overload = settings_to_hash(str)
169            for k, v in next, overload do
170                overload[tonumber(k)] = tonumber(v) or -1
171            end
172        end
173    else
174        overload = false
175    end
176    registercallback("show_break", action)
177end
178
179local function last()
180    return serial or { }
181end
182
183typesetters.breakpoints.show = show
184typesetters.breakpoints.last = last
185
186-- interface
187
188local context     = context
189local scaninteger = tokens.scanners.integer
190
191local function feedback()
192    local l = last()
193    local n = #l
194    if n > 0 then
195        local t = { n }
196        local m = 1
197        for i=1,#l do
198            m = m + 1 ; t[m] = i
199            m = m + 1 ; t[m] = l[i]
200        end
201        context("% t",t)
202    end
203end
204
205interfaces.implement {
206    name      = "lousiness",
207    public    = true,
208    protected = true,
209    usage     = "value",
210    actions   = function(what)
211        if what == "value" then
212            feedback()
213        else
214            local n = scaninteger()
215            local t = { }
216            for i=1,n do
217                t[scaninteger()] = scaninteger()
218            end
219            show(t)
220        end
221    end,
222}
223
224interfaces.implement {
225    name      = "silliness",
226    public    = true,
227    protected = true,
228    usage     = "value",
229    actions   = function(what)
230        if what == "value" then
231            feedback()
232        else
233            show { [scaninteger()] = 0 }
234        end
235    end,
236}
237