1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
|
if not modules then modules = { } end modules ['publ-sor'] = {
version = 1.001,
comment = "this module part of publication support",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
}
-- if needed we can optimize this one: chekc if it's detail or something else
-- and use direct access, but in practice it's fast enough
local type = type
local concat = table.concat
local formatters = string.formatters
local compare = sorters.comparers.basic -- (a,b)
local sort = table.sort
local toarray = utilities.parsers.settings_to_array
local utfchar = utf.char
local publications = publications
local writers = publications.writers
local variables = interfaces.variables
local v_short = variables.short
local v_default = variables.default
local v_reference = variables.reference
local v_dataset = variables.dataset
local report = logs.reporter("publications","sorters")
local trace_sorters trackers.register("publications.sorters",function(v) trace_sorters = v end)
-- authors(s) | year | journal | title | pages
local template = [[
local type, tostring = type, tostring
local writers = publications.writers
local datasets = publications.datasets
local getter = publications.getfaster -- (current,data,details,field,categories,types)
local strip = sorters.strip
local splitter = sorters.splitters.utf
local function newsplitter(splitter)
return table.setmetatableindex({},function(t,k) -- could be done in the sorter but seldom that many shared
local v = splitter(k,true) -- in other cases
t[k] = v
return v
end)
end
return function(dataset,list,method) -- indexer
local current = datasets[dataset]
local luadata = current.luadata
local details = current.details
local specification = publications.currentspecification
local categories = specification.categories
local types = specification.types
local splitted = newsplitter(splitter) -- saves mem
local snippets = { } -- saves mem
local result = { }
%helpers%
for i=1,#list do
-- either { tag, tag, ... } or { { tag, index }, { tag, index } }
local li = list[i]
local tag = type(li) == "string" and li or li[1]
local index = tostring(i)
local entry = luadata[tag]
if entry then
local detail = details[tag]
result[i] = {
index = i,
split = {
%getters%
},
}
else
result[i] = {
index = i,
split = {
%unknowns%
},
}
end
end
return result
end
]]
local f_getter = formatters["splitted[strip(getter(current,entry,detail,%q,categories,types) or %q)], -- %s"]
local f_writer = formatters["splitted[strip(writer_%s(getter(current,entry,detail,%q,categories,types) or %q,snippets))], -- %s"]
local f_helper = formatters["local writer_%s = writers[%q] -- %s: %s"]
local f_value = formatters["splitted[%q], -- %s"]
local s_index = "splitted[index], -- the order in the list, always added"
-- there is no need to cache this in specification
local sharedmethods = { }
publications.sortmethods = sharedmethods
local function sortsequence(dataset,list,sorttype)
if not list or #list == 0 then
return
end
local specification = publications.currentspecification
local types = specification.types
local sortmethods = specification.sortmethods
local method = sortmethods and sortmethods[sorttype] or sharedmethods[sorttype]
local sequence = method and method.sequence
local s_default = "<before end>"
local s_unknown = "<at the end>"
local c_default = utfchar(0xFFFE)
local c_unknown = utfchar(0xFFFF)
if not sequence and type(sorttype) == "string" then
local list = toarray(sorttype)
if #list > 0 then
local indexdone = false
sequence = { }
for i=1,#list do
local entry = toarray(list[i])
local field = entry[1]
local default = entry[2]
local unknown = entry[3] or default
sequence[i] = {
field = field,
default = default == s_default and c_default or default or c_default,
unknown = unknown == s_unknown and c_unknown or unknown or c_unknown,
}
if field == "index" then
indexdone = true
end
end
if not indexdone then
sequence[#sequence+1] = {
field = "index",
default = 0,
unknown = 0,
}
end
end
if trace_sorters then
report("creating sequence from method %a",sorttype)
end
end
if sequence then
local getters = { }
local unknowns = { }
local helpers = { }
if trace_sorters then
report("initializing method %a",sorttype)
end
for i=1,#sequence do
local step = sequence[i]
local field = step.field or "?"
local default = step.default or c_default
local unknown = step.unknown or c_unknown
local fldtype = types[field]
local fldwriter = step.writer or fldtype
local writer = fldwriter and writers[fldwriter]
if trace_sorters then
report("% 3i : field %a, type %a, default %a, unknown %a",i,field,fldtype,
default == c_default and s_default or default,
unknown == c_unknown and s_unknown or unknown
)
end
if writer then
local h = #helpers + 1
getters[i] = f_writer(h,field,default,field)
helpers[h] = f_helper(h,fldwriter,field,fldtype)
else
getters[i] = f_getter(field,default,field)
end
unknowns[i] = f_value(unknown,field)
end
unknowns[#unknowns+1] = s_index
getters [#getters +1] = s_index
local code = utilities.templates.replace(template, {
helpers = concat(helpers, "\n"),
getters = concat(getters, "\n"),
unknowns = concat(unknowns,"\n"),
})
-- print(code)
local action, error = loadstring(code)
if type(action) == "function" then
action = action()
else
report("error when compiling sort method %a: %s",sorttype,error or "unknown")
end
if type(action) == "function" then
local valid = action(dataset,list,method)
if valid and #valid > 0 then
sorters.sort(valid,compare)
return valid
else
report("error when applying sort method %a",sorttype)
end
else
report("error in sort method %a",sorttype)
end
else
report("invalid sort method %a",sorttype)
end
end
-- index : order in dataset
-- order : order of citations
-- short : alphabetic + suffix
-- reference : order in list
-- default : automatic sorter
-- authoryear : sort order list
-- tag | listindex | 0 | u | u.btxint | data.index
local sorters = {
[v_short] = function(dataset,rendering,list) -- should we store it
local shorts = rendering.shorts
local function compare(a,b)
local aa = a and a[1]
local bb = b and b[1]
if aa and bb then
aa, bb = shorts[aa], shorts[bb]
return aa and bb and aa < bb
else
return a[1] < b[1]
end
end
sort(list,compare)
end,
[v_reference] = function(dataset,rendering,list) -- tag
local function compare(a,b)
return a[1] < b[1]
end
sort(list,compare)
end,
[v_dataset] = function(dataset,rendering,list) -- dataset index
local function compare(a,b)
local aa = a and a[6]
local bb = b and b[6]
if aa and bb then
return aa < bb
else
return a[1] < b[1]
end
end
sort(list,compare)
end,
[v_default] = function(dataset,rendering,list,sorttype)
if sorttype == "" or sorttype == v_default then -- listorder
local function compare(a,b)
return a[2] < b[2]
end
sort(list,compare)
else
local valid = sortsequence(dataset,list,sorttype) -- field order
if valid and #valid > 0 then
-- hm, we have a complication here because a sortsequence doesn't know if there's a field
-- so there is no real catch possible here .., anyway, we add a index as last entry when no
-- one is set so that should be good enough (needs testing)
for i=1,#valid do
local v = valid[i]
valid[i] = list[v.index]
end
return valid
end
end
end
}
table.setmetatableindex(sorters,function(t,k) return t[v_default] end)
publications.lists.sorters = sorters
|