1if not modules then modules = { } end modules ['publ-sor'] = {
2 version = 1.001,
3 comment = "this module part of publication support",
4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files"
7}
8
9
10
11
12local type = type
13local concat = table.concat
14local formatters = string.formatters
15local compare = sorters.comparers.basic
16local sort = table.sort
17
18local toarray = utilities.parsers.settings_to_array
19local utfchar = utf.char
20
21local publications = publications
22local writers = publications.writers
23
24local variables = interfaces.variables
25local v_short = variables.short
26local v_default = variables.default
27local v_reference = variables.reference
28local v_dataset = variables.dataset
29local v_list = variables.list
30local v_index = variables.index
31local v_cite = variables.cite
32local v_used = variables.used
33
34local report = logs.reporter("publications","sorters")
35
36local trace_sorters = false trackers.register("publications.sorters",function(v) trace_sorters = v end)
37
38
39
40local template = [[
41local type, tostring = type, tostring
42
43local writers = publications.writers
44local datasets = publications.datasets
45local getter = publications.getfaster -- (current,data,details,field,categories,types)
46local strip = sorters.strip
47local splitter = sorters.splitters.utf
48
49local function newsplitter(splitter)
50 return table.setmetatableindex({},function(t,k) -- could be done in the sorter but seldom that many shared
51 local v = splitter(k,true) -- in other cases
52 t[k] = v
53 return v
54 end)
55end
56
57return function(dataset,list,method) -- indexer
58 local current = datasets[dataset]
59 local luadata = current.luadata
60 local details = current.details
61 local specification = publications.currentspecification
62 local categories = specification.categories
63 local types = specification.types
64 local splitted = newsplitter(splitter) -- saves mem
65 local snippets = { } -- saves mem
66 local result = { }
67
68%helpers%
69
70 for i=1,#list do
71 -- either { tag, tag, ... } or { { tag, index }, { tag, index } }
72 local li = list[i]
73 local tag = type(li) == "string" and li or li[1]
74 local index = tostring(i)
75 local entry = luadata[tag]
76 if entry then
77 -- maybe optional: if entry.key then push the keygetter
78 -- in slot 1 and ignore (e.g. author)
79 local detail = details[tag]
80 result[i] = {
81 index = i,
82 split = {
83
84%getters%
85
86 },
87 }
88 else
89 result[i] = {
90 index = i,
91 split = {
92
93%unknowns%
94
95 },
96 }
97 end
98 end
99 return result
100end
101]]
102
103local f_getter = formatters["splitted[strip(getter(current,entry,detail,%q,categories,types) or %q)], -- %s"]
104local f_writer = formatters["splitted[strip(writer_%s(getter(current,entry,detail,%q,categories,types) or %q,snippets))], -- %s"]
105local f_helper = formatters["local writer_%s = writers[%q] -- %s: %s"]
106local f_value = formatters["splitted[%q], -- %s"]
107local s_index = "splitted[index], -- the order in the list, always added"
108
109
110
111local sharedmethods = { }
112publications.sortmethods = sharedmethods
113
114local function sortsequence(dataset,list,sorttype)
115
116 if not list or #list == 0 then
117 return
118 end
119
120 local specification = publications.currentspecification
121 local types = specification.types
122 local sortmethods = specification.sortmethods
123 local method = sortmethods and sortmethods[sorttype] or sharedmethods[sorttype]
124 local sequence = method and method.sequence
125
126 local s_default = "<before end>"
127 local s_unknown = "<at the end>"
128
129 local c_default = utfchar(0xFFFE)
130 local c_unknown = utfchar(0xFFFF)
131
132 if not sequence and type(sorttype) == "string" then
133 local list = toarray(sorttype)
134 if #list > 0 then
135 local indexdone = false
136 sequence = { }
137 for i=1,#list do
138 local entry = toarray(list[i])
139 local field = entry[1]
140 local default = entry[2]
141 local unknown = entry[3] or default
142 sequence[i] = {
143 field = field,
144 default = default == s_default and c_default or default or c_default,
145 unknown = unknown == s_unknown and c_unknown or unknown or c_unknown,
146 }
147 if field == "index" then
148 indexdone = true
149 end
150 end
151 if not indexdone then
152 sequence[#sequence+1] = {
153 field = "index",
154 default = 0,
155 unknown = 0,
156 }
157 end
158 end
159 if trace_sorters then
160 report("creating sequence from method %a",sorttype)
161 end
162 end
163
164 if sequence then
165
166 local getters = { }
167 local unknowns = { }
168 local helpers = { }
169
170 if trace_sorters then
171 report("initializing method %a",sorttype)
172 end
173
174 for i=1,#sequence do
175 local step = sequence[i]
176 local field = step.field or "?"
177 local default = step.default or c_default
178 local unknown = step.unknown or c_unknown
179 local fldtype = types[field]
180 local fldwriter = step.writer or fldtype
181 local writer = fldwriter and writers[fldwriter]
182
183 if trace_sorters then
184 report("% 3i : field %a, type %a, default %a, unknown %a",i,field,fldtype,
185 default == c_default and s_default or default,
186 unknown == c_unknown and s_unknown or unknown
187 )
188 end
189
190 if writer then
191 local h = #helpers + 1
192 getters[i] = f_writer(h,field,default,field)
193 helpers[h] = f_helper(h,fldwriter,field,fldtype)
194 else
195 getters[i] = f_getter(field,default,field)
196 end
197 unknowns[i] = f_value(unknown,field)
198 end
199
200 unknowns[#unknowns+1] = s_index
201 getters [#getters +1] = s_index
202
203 local code = utilities.templates.replace(template, {
204 helpers = concat(helpers, "\n"),
205 getters = concat(getters, "\n"),
206 unknowns = concat(unknowns,"\n"),
207 })
208
209
210
211 local action, error = loadstring(code)
212 if type(action) == "function" then
213 action = action()
214 else
215 report("error when compiling sort method %a: %s",sorttype,error or "unknown")
216 end
217 if type(action) == "function" then
218 local valid = action(dataset,list,method)
219 if valid and #valid > 0 then
220
221 sorters.sort(valid,compare)
222 return valid
223 else
224 report("error when applying sort method %a",sorttype)
225 end
226 else
227 report("error in sort method %a",sorttype)
228 end
229 else
230 report("invalid sort method %a",sorttype)
231 end
232
233end
234
235
236
237
238
239
240
241
242
243
244local sorters = { }
245
246sorters[v_short] = function(dataset,rendering,list)
247 local shorts = rendering.shorts
248 local function compare(a,b)
249 if a and b then
250 local taga = a[1]
251 local tagb = b[1]
252 if taga and tagb then
253 local shorta = shorts[taga]
254 local shortb = shorts[tagb]
255 if shorta and shortb then
256
257 return shorta < shortb
258 end
259
260 return taga < tagb
261 end
262
263 local indexa = a[5]
264 local indexb = b[5]
265 if indexa and indexb then
266 return indexa < indexb
267 end
268 end
269 return false
270 end
271 sort(list,compare)
272end
273
274sorters[v_dataset] = function(dataset,rendering,list)
275 local function compare(a,b)
276 if a and b then
277 local indexa = a[5]
278 local indexb = b[5]
279 if indexa and indexb then
280 return indexa < indexb
281 end
282 local taga = a[1]
283 local tagb = b[1]
284 if taga and tagb then
285 return taga < tagb
286 end
287 end
288 return false
289 end
290 sort(list,compare)
291end
292
293sorters[v_list] = function(dataset,rendering,list)
294 local function compare(a,b)
295 if a and b then
296 local lista = a[2]
297 local listb = b[2]
298 if lista and listb then
299 return lista < listb
300 end
301 local indexa = a[5]
302 local indexb = b[5]
303 if indexa and indexb then
304 return indexa < indexb
305 end
306 end
307 return false
308 end
309 sort(list,compare)
310end
311
312sorters[v_reference] = function(dataset,rendering,list)
313 local function compare(a,b)
314 if a and b then
315 local taga = a[1]
316 local tagb = b[1]
317 if taga and tagb then
318 return taga < tagb
319 end
320 local indexa = a[5]
321 local indexb = b[5]
322 if indexa and indexb then
323 return indexa < indexb
324 end
325 end
326 return false
327 end
328 sort(list,compare)
329end
330
331sorters[v_used] = function(dataset,rendering,list)
332 local function compare(a,b)
333 if a and b then
334 local referencea = a[2]
335 local referenceb = b[2]
336 if referencea and referenceb then
337 return referencea < referenceb
338 end
339 local indexa = a[5]
340 local indexb = b[5]
341 if indexa and indexb then
342 return indexa < indexb
343 end
344 end
345 return false
346 end
347 sort(list,compare)
348end
349
350sorters[v_default] = sorters[v_list]
351sorters[""] = sorters[v_list]
352sorters[v_cite] = sorters[v_list]
353sorters[v_index] = sorters[v_dataset]
354
355local function anything(dataset,rendering,list,sorttype)
356 local valid = sortsequence(dataset,list,sorttype)
357 if valid and #valid > 0 then
358
359
360
361 for i=1,#valid do
362 local v = valid[i]
363 valid[i] = list[v.index]
364 end
365 return valid
366 end
367end
368
369table.setmetatableindex(sorters,function(t,k) return anything end)
370
371publications.lists.sorters = sorters
372
373
374
375
376
377
378
379 |