1if not modules then modules = { } end modules ['strc-syn'] = {
2 version = 1.001,
3 comment = "companion to str-syn.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 = next, type
10local sortedkeys = table.sortedkeys
11
12local context = context
13local implement = interfaces.implement
14
15local allocate = utilities.storage.allocate
16
17local sorters = sorters
18
19local structures = structures
20local synonyms = structures.synonyms
21local tags = structures.tags
22
23local collected = allocate()
24local tobesaved = allocate()
25
26local firstofsplit = sorters.firstofsplit
27local strip = sorters.strip
28local splitter = sorters.splitters.utf
29
30synonyms.collected = collected
31synonyms.tobesaved = tobesaved
32
33local progressions = { }
34
35local c_realpageno <const> = tex.iscount("realpageno")
36
37local texgetcount = tex.getcount
38
39local v_all <const> = interfaces.variables.all
40local v_current <const> = interfaces.variables.current
41
42local function initializer()
43 collected = synonyms.collected
44 tobesaved = synonyms.tobesaved
45end
46
47local function finalizer()
48 for entry, data in next, tobesaved do
49 data.hash = nil
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 end
67end
68
69job.register('structures.synonyms.collected', tobesaved, initializer, finalizer)
70
71
72
73table.setmetatableindex(tobesaved,function(t,k)
74 local v = {
75 metadata = {
76 language = 'en',
77 sorted = false,
78 class = v
79 },
80 entries = {
81 },
82 hash = {
83 }
84 }
85 t[k] = v
86 return v
87end)
88
89function synonyms.define(class,kind)
90 local data = tobesaved[class]
91 data.metadata.kind = kind
92end
93
94function synonyms.register(class,kind,spec)
95 local data = tobesaved[class]
96 local hash = data.hash
97 local definition = spec.definition
98 local tag = definition.tag or ""
99 data.metadata.kind = kind
100 if not hash[tag] then
101 local entries = data.entries
102 entries[#entries+1] = spec
103 hash[tag] = spec
104 end
105end
106
107function synonyms.registerused(class,tag)
108 local data = tobesaved[class]
109 local okay = data.hash[tag]
110 if okay then
111 local definition = okay.definition
112 definition.used = true
113 definition.list = true
114 end
115end
116
117function synonyms.registershown(class,tag)
118 local data = tobesaved[class]
119 local okay = data.hash[tag]
120 if okay then
121 local definition = okay.definition
122 definition.shown = true
123 definition.list = true
124 end
125end
126
127function synonyms.isused(class,tag)
128 local data = tobesaved[class]
129 local okay = data.hash[tag]
130 return okay and okay.definition.used or false
131end
132
133function synonyms.isshown(class,tag)
134 local data = tobesaved[class]
135 local okay = data.hash[tag]
136 return okay and okay.definition.shown or false
137end
138
139local function resetused(class)
140 for tag, data in next, tobesaved[class].hash do
141 data.definition.used = nil
142 end
143end
144
145local function resetshown(class)
146 for tag, data in next, tobesaved[class].hash do
147 data.definition.shown = nil
148 end
149end
150
151local function resetlist(class)
152 for tag, data in next, tobesaved[class].hash do
153 data.definition.list = nil
154 end
155end
156
157local function resetall(class)
158 for tag, data in next, tobesaved[class].hash do
159 local definition = data.definition
160 definition.used = nil
161 definition.shown = nil
162 definition.list = nil
163 end
164end
165
166synonyms.resetused = resetused
167synonyms.resetshown = resetshown
168synonyms.resetlist = resetlist
169synonyms.resetall = resetall
170
171function synonyms.reset(class,what)
172 if what == "progress" then
173 progressions = { }
174 elseif what == "used" then
175 resetused(class)
176 elseif what == "shown" then
177 resetshown(class)
178 elseif what == "list" then
179 resetlist(class)
180 else
181 resetall(class)
182 end
183end
184
185function synonyms.synonym(class,tag)
186 local data = tobesaved[class]
187 local okay = data.hash[tag]
188 if okay then
189 local definition = okay.definition
190 definition.used = true
191 definition.list = true
192 context(definition.synonym)
193 end
194 if progressions[tag] == nil then
195 progressions[tag] = false
196 end
197end
198
199function synonyms.meaning(class,tag)
200 local data = tobesaved[class]
201 local okay = data.hash[tag]
202 if okay then
203 local definition = okay.definition
204 definition.shown = true
205 definition.list = true
206 context(definition.meaning)
207 end
208end
209
210function synonyms.pages(class,tag)
211 local data = tobesaved[class]
212 local okay = data.hash[tag]
213 if okay then
214 local definition = okay.definition
215 local pages = definition.pages
216 if pages and next(pages) then
217 context("%,t",sortedkeys(pages))
218 end
219 end
220end
221
222local ctx_latelua = context.latelua
223
224local function enhance(data)
225 data.pages[texgetcount(c_realpageno)] = true
226end
227
228function synonyms.enhance(class,tag)
229 local data = tobesaved[class]
230 local okay = data.hash[tag]
231 if okay then
232 local definition = okay.definition
233 local pages = definition.pages
234 if not pages then
235 pages = { }
236 definition.pages = pages
237 end
238 ctx_latelua { action = enhance, pages = pages }
239 end
240end
241
242synonyms.compare = sorters.comparers.basic
243
244function synonyms.filter(data,options)
245 local result = { }
246 local entries = data.entries
247 local criterium = options and options.criterium
248 if criterium == v_all then
249 for i=1,#entries do
250 result[i] = entries[i]
251 end
252 else
253 for i=1,#entries do
254 local entry = entries[i]
255 local definition = entry.definition
256 if definition.list then
257 local tag = definition.tag
258 local done = progressions[tag]
259 if done == false then
260 result[#result+1] = entry
261 progressions[tag] = true
262 end
263 end
264 end
265 if criterium == v_current then
266 progressions = { }
267 end
268 end
269 data.result = result
270end
271
272function synonyms.prepare(data)
273 local result = data.result
274 if result then
275 for i=1, #result do
276 local entry = result[i]
277 local definition = entry.definition
278 if definition then
279 local srt = definition.sortkey or ""
280 local tag = definition.tag or ""
281 local key = (srt ~= "" and srt) or (tag ~= "" and tag) or definition.synonym
282 if key then
283 entry.split = splitter(strip(key))
284 end
285 end
286 end
287 end
288end
289
290function synonyms.sort(data,options)
291 sorters.sort(data.result,synonyms.compare)
292 data.metadata.sorted = true
293end
294
295function synonyms.finalize(data,options)
296 local result = data.result
297 local split = { }
298 local nofsplit = 0
299 local lasttag = nil
300 local lasttag = nil
301 local nofdone = 0
302 for k=1,#result do
303 local entry = result[k]
304 local first, tag = firstofsplit(entry)
305 if tag ~= lasttag then
306
307
308
309 done = { }
310 nofdone = 0
311 nofsplit = nofsplit + 1
312 lasttag = tag
313 split[nofsplit] = { tag = tag, data = done }
314 end
315 nofdone = nofdone + 1
316 done[nofdone] = entry
317 end
318 data.result = split
319end
320
321
322
323
324local ctx_synonymentry = context.synonymentry
325
326function synonyms.flush(data,options)
327 local result = data.result
328 for i=1,#result do
329 local sublist = result[i]
330 local data = sublist.data
331 for d=1,#data do
332 local entry = data[d].definition
333 ctx_synonymentry(d,entry.tag,entry.synonym,entry.meaning or "")
334 end
335 end
336 data.result = nil
337 data.metadata.sorted = false
338end
339
340function synonyms.analyzed(class,options)
341 local data = collected[class]
342 if data and data.entries then
343 options = options or { }
344 sorters.setlanguage(options.language,options.method)
345 synonyms.filter(data,options)
346 synonyms.prepare(data,options)
347 synonyms.sort(data,options)
348 synonyms.finalize(data,options)
349 data.metadata.sorted = true
350 end
351 return data and data.metadata.sorted and data.result and next(data.result)
352end
353
354function synonyms.process(class,options)
355 if synonyms.analyzed(class,options) then
356 synonyms.flush(collected[class],options)
357 end
358end
359
360
361
362implement { name = "registerusedsynonym", actions = synonyms.registerused, arguments = "2 strings" }
363implement { name = "registershownsynonym", actions = synonyms.registershown, arguments = "2 strings" }
364implement { name = "synonymmeaning", actions = synonyms.meaning, arguments = "2 arguments" }
365implement { name = "synonymname", actions = synonyms.synonym, arguments = "2 arguments" }
366implement { name = "synonympages", actions = synonyms.pages, arguments = "2 arguments" }
367implement { name = "enhancesynonym", actions = synonyms.enhance, arguments = "2 arguments" }
368
369
370
371implement { name = "resetsynonyms", actions = synonyms.reset, arguments = "2 strings" }
372
373implement {
374 name = "doifelsesynonymused",
375 actions = { synonyms.isused, commands.doifelse },
376 arguments = "2 arguments",
377}
378
379implement {
380 name = "doifelsesynonymshown",
381 actions = { synonyms.isshown, commands.doifelse },
382 arguments = "2 arguments",
383}
384
385implement {
386 name = "registersynonym",
387 actions = synonyms.register,
388 arguments = {
389 "string",
390 "string",
391 {
392 { "metadata", {
393 { "catcodes", "integer" },
394 { "coding" },
395 { "xmlroot" }
396 }
397 },
398 {
399 "definition", {
400 { "tag" },
401 { "synonym" },
402 { "meaning" },
403 { "sortkey" },
404 { "used", "boolean" }
405 }
406 }
407 }
408 }
409}
410
411implement {
412 name = "processsynonyms",
413 actions = synonyms.process,
414 arguments = {
415 "string",
416 {
417 { "criterium" },
418 { "language" },
419 { "method" }
420 }
421 }
422}
423 |