1if not modules then modules = { } end modules ['typo-dig'] = {
2 version = 1.001,
3 optimize = true,
4 comment = "companion to typo-dig.mkiv",
5 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
6 copyright = "PRAGMA ADE / ConTeXt Development Team",
7 license = "see context related readme files"
8}
9
10
11
12
13local next, type, tonumber = next, type, tonumber
14local format, insert = string.format, table.insert
15local round, div = math.round, math.div
16
17local trace_digits = false trackers.register("typesetters.digits", function(v) trace_digits = v end)
18
19local report_digits = logs.reporter("typesetting","digits")
20
21local nodes, node = nodes, node
22
23local nuts = nodes.nuts
24
25local getnext = nuts.getnext
26local getprev = nuts.getprev
27local getid = nuts.getid
28local getwidth = nuts.getwidth
29local isglyph = nuts.isglyph
30local getattr = nuts.getattr
31
32local setlink = nuts.setlink
33local setnext = nuts.setnext
34local setprev = nuts.setprev
35
36local hpacknode = nuts.hpack
37local insertnodebefore = nuts.insertbefore
38local insertnodeafter = nuts.insertafter
39local findattribute = nuts.findattribute
40local unsetattributes = nuts.unsetattributes
41
42local texsetattribute = tex.setattribute
43
44local unsetvalue <const> = attributes.unsetvalue
45
46local glyph_code <const> = nodes.nodecodes.glyph
47
48local nodepool = nuts.pool
49local enableaction = nodes.tasks.enableaction
50
51local new_glue = nodepool.glue
52
53local fonthashes = fonts.hashes
54local chardata = fonthashes.characters
55
56local v_reset <const> = interfaces.variables.reset
57
58local charbase = characters.data
59local getdigitwidth = fonts.helpers.getdigitwidth
60
61typesetters = typesetters or { }
62local typesetters = typesetters
63
64typesetters.digits = typesetters.digits or { }
65local digits = typesetters.digits
66
67digits.actions = { }
68local actions = digits.actions
69
70local a_digits <const> = attributes.private("digits")
71
72
73
74
75function nodes.aligned(head,start,stop,width,how)
76 if how == "flushright" or how == "middle" then
77 head, start = insertnodebefore(head,start,new_glue(0,65536,65536))
78 end
79 if how == "flushleft" or how == "middle" then
80 head, stop = insertnodeafter(head,stop,new_glue(0,65536,65536))
81 end
82 local prv = getprev(start)
83 local nxt = getnext(stop)
84 setprev(start)
85 setnext(stop)
86 local packed = hpacknode(start,width,"exactly")
87 if prv then
88 setlink(prv,packed)
89 end
90 if nxt then
91 setlink(packed,nxt)
92 end
93 if getprev(packed) then
94 return head, packed
95 else
96 return packed, packed
97 end
98end
99
100actions[1] = function(head,start,attr)
101 local char, font = isglyph(start)
102 local unic = chardata[font][char].unicode or char
103 if charbase[unic].category == "nd" then
104 local oldwidth = getwidth(start)
105 local newwidth = getdigitwidth(font)
106 if newwidth ~= oldwidth then
107 if trace_digits then
108 report_digits("digit trigger %a, instance %a, char %C, unicode %U, delta %s",
109 attr%100,div(attr,100),char,unic,newwidth-oldwidth)
110 end
111 head, start = nodes.aligned(head,start,start,newwidth,"middle")
112 return head, start
113 end
114 end
115 return head, start
116end
117
118function digits.handler(head)
119 local _, start = findattribute(head, a_digits)
120 if start then
121 local current = head
122 while current do
123 if getid(current) == glyph_code then
124 local attr = getattr(current,a_digits)
125 if attr and attr > 0 then
126 local action = actions[attr%100]
127 if action then
128 head, current = action(head,current,attr)
129 elseif trace_digits then
130 report_digits("unknown digit trigger %a",attr)
131 end
132 done = true
133 end
134 end
135 if current then
136 current = getnext(current)
137 end
138 end
139 if done then
140 unsetattributes(a_digits, head)
141 end
142 end
143 return head
144end
145
146local m, enabled = 0, false
147
148function digits.set(n)
149 if n == v_reset then
150 n = unsetvalue
151 else
152 n = tonumber(n)
153 if n then
154 if not enabled then
155 enableaction("processors","typesetters.digits.handler")
156 if trace_digits then
157 report_digits("enabling digit handler")
158 end
159 enabled = true
160 end
161 if m == 100 then
162 m = 1
163 else
164 m = m + 1
165 end
166 n = m * 100 + n
167 else
168 n = unsetvalue
169 end
170 end
171 texsetattribute(a_digits,n)
172end
173
174
175
176interfaces.implement {
177 name = "setdigitsmanipulation",
178 actions = digits.set,
179 arguments = "string"
180}
181 |