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