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