lang-dis.lmt /size: 6854 b    last modification: 2023-12-21 09:44
1if not modules then modules = { } end modules ['lang-dis'] = {
2    version   = 1.001,
3    comment   = "companion to lang-ini.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 concat = table.concat
10
11local tex                = tex
12local nodes              = nodes
13
14local tasks              = nodes.tasks
15local nuts               = nodes.nuts
16
17local enableaction       = tasks.enableaction
18local setaction          = tasks.setaction
19
20local setfield           = nuts.setfield
21local getnext            = nuts.getnext
22local getprev            = nuts.getprev
23local getid              = nuts.getid
24local getattr            = nuts.getattr
25local getsubtype         = nuts.getsubtype
26local setsubtype         = nuts.setsubtype
27local getchar            = nuts.getchar
28local setchar            = nuts.setchar
29local getdiscpart        = nuts.getdiscpart
30local getdisc            = nuts.getdisc
31local setdisc            = nuts.setdisc
32local getlanguage        = nuts.getlanguage
33local getboth            = nuts.getboth
34local setlist            = nuts.setlist
35local setlink            = nuts.setlink
36local isglyph            = nuts.isglyph
37
38local copy_node          = nuts.copy
39local remove_node        = nuts.remove
40----- flushnode          = nuts.flushnode
41
42local nextdisc           = nuts.traversers.disc
43local nextglyph          = nuts.traversers.glyph
44
45local new_disc           = nuts.pool.disc
46
47local nodecodes          = nodes.nodecodes
48local disccodes          = nodes.disccodes
49
50local disc_code          = nodecodes.disc
51local glyph_code         = nodecodes.glyph
52
53local discoptioncodes    = tex.discoptioncodes
54local pre_part_code      = discoptioncodes.pre
55local post_part_code     = discoptioncodes.post
56local replace_part_code  = discoptioncodes.replace
57local always_part_code   = discoptioncodes.always
58
59local explicitdisc_code  = disccodes.explicit
60
61local a_visualize        = attributes.private("visualizediscretionary")
62local setattribute       = tex.setattribute
63
64local getlanguagedata    = languages.getdata
65local prehyphenchar      = language.prehyphenchar
66local posthyphenchar     = language.posthyphenchar
67
68local check_regular      = true
69
70local setlistcolor = nodes.tracers.colors.setlist
71
72function languages.visualizediscretionaries(head)
73    for d in nextdisc, head do
74        if getattr(d,a_visualize) then
75            local pre, post, replace = getdisc(d)
76            if pre then
77                setlistcolor(pre,"darkred")
78            end
79            if post then
80                setlistcolor(post,"darkgreen")
81            end
82            if replace then
83                setlistcolor(replace,"darkblue")
84            end
85        end
86    end
87    for g in nextglyph, head do
88        if getattr(g,a_visualize) then
89            local c = getdiscpart(g)
90            if c == pre_part_code then
91                setlistcolor(g,"darkmagenta")
92            elseif c == post_part_code then
93                setlistcolor(g,"darkcyan")
94            elseif c == replace_part_code then
95                setlistcolor(g,"darkyellow")
96            elseif c == always_part_code then
97                setlistcolor(g,"darkgray")
98            end
99        end
100    end
101    return head
102end
103
104local enabled = false
105
106function languages.showdiscretionaries(v)
107    if v == false then
108        setattribute(a_visualize,unsetvalue)
109    else -- also nil
110        if not enabled then
111            enableaction("processors","languages.visualizediscretionaries")
112            enabled = true
113        end
114        setattribute(a_visualize,1)
115    end
116end
117
118interfaces.implement {
119    name    = "showdiscretionaries",
120    actions = languages.showdiscretionaries
121}
122
123do
124
125    local toutf   = nodes.listtoutf
126    local utfchar = utf.char
127    local f_disc  = string.formatters["{%s}{%s}{%s}"]
128    local replace = lpeg.replacer( {
129        [utfchar(0x200C)] = "|",
130        [utfchar(0x200D)] = "|",
131    }, nil, true)
132
133    local function convert(list)
134        return list and replace(toutf(list)) or ""
135    end
136
137    function languages.serializediscretionary(d) -- will move to tracer
138        local pre, post, replace = getdisc(d)
139        return f_disc(convert(pre),convert(post),convert(replace))
140    end
141
142end
143
144-- --
145
146local wiped = 0
147
148local flattendiscretionaries = nuts.flattendiscretionaries -- todo in nodes
149
150-- if flattendiscretionaries then
151
152    function languages.flatten(head)
153        local h, n = flattendiscretionaries(head)
154        wiped = wiped + n
155        return h, n > 0
156    end
157
158-- else
159--
160--     local function wipe(head,delayed)
161--         local p, n = getboth(delayed)
162--         local _, _, h, _, _, t = getdisc(delayed,true)
163--         if p or n then
164--             if h then
165--                 setlink(p,h)
166--                 setlink(t,n)
167--                 setfield(delayed,"replace")
168--             else
169--                 setlink(p,n)
170--             end
171--         end
172--         if head == delayed then
173--             head = h
174--         end
175--         wiped = wiped + 1
176--         flushnode(delayed)
177--         return head
178--     end
179--
180--     function languages.flatten(head)
181--         local delayed = nil
182--         for d in nextdisc, head do
183--             if delayed then
184--                 head = wipe(head,delayed)
185--             end
186--             delayed = d
187--         end
188--         if delayed then
189--             return wipe(head,delayed), true
190--         else
191--             return head, false
192--         end
193--     end
194--
195-- end
196
197function languages.nofflattened()
198    return wiped -- handy for testing
199end
200
201-- experiment: for now not in not in export mode!
202
203local flatten = languages.flatten
204
205nodes.handlers.flattenline = flatten
206
207function nodes.handlers.flatten(head,where)
208    if head and (where == "box" or where == "adjustedhbox") then
209        return flatten(head)
210    end
211    return head
212end
213
214directives.register("hyphenator.flatten",function(v)
215    -- use with care
216    setaction("processors","nodes.handlers.flatten",v)
217    setaction("contributers","nodes.handlers.flattenline",v)
218end)
219
220-- moved here:
221
222function languages.explicithyphen(template)
223    local pre, post
224    local disc = new_disc()
225    if template then
226        local langdata = getlanguagedata(getlanguage(template))
227        local instance = langdata and langdata.instance
228        if instance then
229            local prechr  = prehyphenchar(instance)
230            local postchr = posthyphenchar(instance)
231            if prechr >= 0 then
232                pre = copy_node(template)
233                setchar(pre,prechr)
234            end
235            if postchr >= 0 then
236                post = copy_node(template)
237                setchar(post,postchr)
238            end
239        end
240    end
241    setdisc(disc,pre,post,nil,explicitdisc_code,tex.exhyphenpenalty)
242    return disc
243end
244