1if not modules then modules = { } end modules ['typo-sus'] = {
2 version = 1.001,
3 comment = "companion to typo-sus.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 = next
10
11local punctuation = {
12 po = true,
13}
14
15local openquote = {
16 ps = true,
17 pi = true,
18}
19
20local closequote = {
21 pe = true,
22 pf = true,
23}
24
25local weird = {
26 lm = true,
27 no = true,
28}
29
30local categories = characters.categories
31
32local nodecodes = nodes.nodecodes
33
34local glyph_code = nodecodes.glyph
35local kern_code = nodecodes.kern
36local penalty_code = nodecodes.penalty
37local glue_code = nodecodes.glue
38local math_code = nodecodes.math
39local hlist_code = nodecodes.hlist
40local vlist_code = nodecodes.vlist
41
42local nuts = nodes.nuts
43
44local nextnode = nuts.traversers.node
45
46local getid = nuts.getid
47local getprev = nuts.getprev
48local getnext = nuts.getnext
49local getattr = nuts.getattr
50local getfont = nuts.getfont
51local getlist = nuts.getlist
52local getkern = nuts.getkern
53local getpenalty = nuts.getpenalty
54local getwidth = nuts.getwidth
55local getwhd = nuts.getwhd
56local isglyph = nuts.isglyph
57
58local setattr = nuts.setattr
59local setlist = nuts.setlist
60
61local setcolor = nodes.tracers.colors.set
62local insertbefore = nuts.insertbefore
63local insertafter = nuts.insertafter
64local endofmath = nuts.endofmath
65
66local nodepool = nuts.pool
67
68local new_rule = nodepool.rule
69local new_kern = nodepool.kern
70local new_hlist = nodepool.hlist
71
72
73local a_characters = attributes.private("characters")
74local a_suspecting = attributes.private('suspecting')
75local a_suspect = attributes.private('suspect')
76local texsetattribute = tex.setattribute
77local unsetvalue = attributes.unsetvalue
78local enabled = false
79
80local enableaction = nodes.tasks.enableaction
81
82local threshold = 65536 / 4
83
84local function special(n)
85 if n then
86 local id = getid(n)
87 if id == kern_code then
88 return getkern(n) < threshold
89 elseif id == penalty_code then
90 return true
91 elseif id == glue_code then
92 return getwidth(n) < threshold
93 elseif id == hlist_code then
94 return getwidth(n) < threshold
95 end
96 else
97 return false
98 end
99end
100
101local function goback(current)
102 local prev = getprev(current)
103 while prev and special(prev) do
104 prev = getprev(prev)
105 end
106 if prev then
107 return prev, getid(prev)
108 end
109end
110
111local function goforward(current)
112 local next = getnext(current)
113 while next and special(next) do
114 next = getnext(next)
115 end
116 if next then
117 return next, getid(next)
118 end
119end
120
121
122
123local function mark(head,current,id,color)
124 if id == glue_code then
125
126
127 local width = getwidth(current)
128 local rule = new_rule(width)
129 local kern = new_kern(-width)
130 head = insertbefore(head,current,rule)
131 head = insertbefore(head,current,kern)
132 setcolor(rule,color)
133
134
135
136
137
138
139
140 else
141 local width, height, depth = getwhd(current)
142 local extra = fonts.hashes.xheights[getfont(current)] / 2
143 local rule = new_rule(width,height+extra,depth+extra)
144 local hlist = new_hlist(rule)
145 head = insertbefore(head,current,hlist)
146 setcolor(rule,color)
147 setcolor(current,"white")
148 end
149 return head, current
150end
151
152
153
154
155
156local colors = {
157 "darkred",
158 "darkgreen",
159 "darkblue",
160 "darkcyan",
161 "darkmagenta",
162 "darkyellow",
163 "darkgray",
164 "orange",
165}
166
167local found = 0
168
169function typesetters.marksuspects(head)
170 local current = head
171 local lastdone = nil
172 while current do
173 if getattr(current,a_suspecting) then
174 local char, id = isglyph(current)
175 if char then
176 local code = categories[char]
177 local done = false
178 if punctuation[code] then
179 local prev, pid = goback(current)
180 if prev and pid == glue_code then
181 done = 3
182 elseif prev and pid == math_code then
183 done = 3
184 else
185 local next, nid = goforward(current)
186 if next and nid ~= glue_code then
187 done = 3
188 end
189 end
190 elseif openquote[code] then
191 local next, nid = goforward(current)
192 if next and nid == glue_code then
193 done = 1
194 end
195 elseif closequote[code] then
196 local prev, pid = goback(current)
197 if prev and pid == glue_code then
198 done = 1
199 end
200 elseif weird[code] then
201 done = 2
202 else
203 local prev, pid = goback(current)
204 if prev then
205 if pid == math_code then
206 done = 7
207 elseif pid == glyph_code and getfont(current) ~= getfont(prev) then
208 if lastdone ~= prev then
209 done = 2
210 end
211 end
212 end
213 if not done then
214 local next, nid = goforward(current)
215 if next then
216 if nid == math_code then
217 done = 7
218 elseif nid == glyph_code and getfont(current) ~= getfont(next) then
219 if lastdone ~= prev then
220 done = 2
221 end
222 end
223 end
224 end
225 end
226 if done then
227 setattr(current,a_suspect,done)
228 lastdone = current
229 found = found + 1
230 end
231 current = getnext(current)
232 elseif id == math_code then
233 current = getnext(endofmath(current))
234 elseif id == glue_code then
235 local a = getattr(current,a_characters)
236 if a then
237 local prev = getprev(current)
238 local prid = prev and getid(prev)
239 local done = false
240 if prid == penalty_code and getpenalty(prev) == 10000 then
241 done = 8
242 else
243 done = 5
244 end
245 if done then
246 setattr(current,a_suspect,done)
247
248 found = found + 1
249 end
250 end
251 current = getnext(current)
252 else
253 current = getnext(current)
254 end
255 else
256 current = getnext(current)
257 end
258 end
259 return head
260end
261
262local function showsuspects(head)
263
264 for current, id, subtype in nextnode, head do
265 if id == glyph_code then
266 local a = getattr(current,a_suspect)
267 if a then
268 head, current = mark(head,current,id,colors[a])
269 end
270 elseif id == glue_code then
271 local a = getattr(current,a_suspect)
272 if a then
273 head, current = mark(head,current,id,colors[a])
274 end
275 elseif id == math_code then
276 current = endofmath(current)
277 elseif id == hlist_code or id == vlist_code then
278 local list = getlist(current)
279 if list then
280 local l = showsuspects(list)
281 if l ~= list then
282 setlist(current,l)
283 end
284 end
285 end
286 end
287 return head
288end
289
290function typesetters.showsuspects(head)
291 if found > 0 then
292 return showsuspects(head)
293 else
294 return head
295 end
296end
297
298
299
300trackers.register("typesetters.suspects",function(v)
301 texsetattribute(a_suspecting,v and 1 or unsetvalue)
302 if v and not enabled then
303 enableaction("processors","typesetters.marksuspects")
304 enableaction("shipouts", "typesetters.showsuspects")
305 enabled = true
306 end
307end)
308
309 |