1
- local M = {}
2
-
3
1
local C = {}
4
2
5
3
--- Predefined comparator, defaulting to name
27
25
--- @param a Node
28
26
--- @param b Node
29
27
--- @return boolean | nil
30
- local function folders_or_files_first (a , b )
31
- if not (M . config . sort . folders_first or M . config . sort .files_first ) then
28
+ local function folders_or_files_first (a , b , cfg )
29
+ if not (cfg . folders_first or cfg .files_first ) then
32
30
return
33
31
end
34
32
35
33
if not a .nodes and b .nodes then
36
34
-- file <> folder
37
- return M . config . sort .files_first
35
+ return cfg .files_first
38
36
elseif a .nodes and not b .nodes then
39
37
-- folder <> file
40
- return not M . config . sort .files_first
38
+ return not cfg .files_first
41
39
end
42
40
end
43
41
@@ -95,67 +93,17 @@ local function split_merge(t, first, last, comparator)
95
93
merge (t , first , mid , last , comparator )
96
94
end
97
95
98
- --- Perform a merge sort using sorter option.
99
- --- @param t table nodes
100
- function M .sort (t )
101
- if C .user then
102
- local t_user = {}
103
- local origin_index = {}
104
-
105
- for _ , n in ipairs (t ) do
106
- table.insert (t_user , {
107
- absolute_path = n .absolute_path ,
108
- executable = n .executable ,
109
- extension = n .extension ,
110
- filetype = vim .filetype .match { filename = n .name },
111
- link_to = n .link_to ,
112
- name = n .name ,
113
- type = n .type ,
114
- })
115
- table.insert (origin_index , n )
116
- end
117
-
118
- local predefined = C .user (t_user )
119
- if predefined then
120
- split_merge (t , 1 , # t , get_comparator (predefined ))
121
- return
122
- end
123
-
124
- -- do merge sort for prevent memory exceed
125
- local user_index = {}
126
- for i , v in ipairs (t_user ) do
127
- if type (v .absolute_path ) == " string" and user_index [v .absolute_path ] == nil then
128
- user_index [v .absolute_path ] = i
129
- end
130
- end
131
-
132
- -- if missing value found, then using origin_index
133
- local mini_comparator = function (a , b )
134
- local a_index = user_index [a .absolute_path ] or origin_index [a .absolute_path ]
135
- local b_index = user_index [b .absolute_path ] or origin_index [b .absolute_path ]
136
-
137
- if type (a_index ) == " number" and type (b_index ) == " number" then
138
- return a_index <= b_index
139
- end
140
- return (a_index or 0 ) <= (b_index or 0 )
141
- end
142
-
143
- split_merge (t , 1 , # t , mini_comparator ) -- sort by user order
144
- else
145
- split_merge (t , 1 , # t , get_comparator (M .config .sort .sorter ))
146
- end
147
- end
148
96
149
97
--- @param a Node
150
98
--- @param b Node
151
99
--- @param ignorecase boolean | nil
152
100
--- @return boolean
153
- local function node_comparator_name_ignorecase_or_not (a , b , ignorecase )
101
+ local function node_comparator_name_ignorecase_or_not (a , b , ignorecase , cfg )
154
102
if not (a and b ) then
155
103
return true
156
104
end
157
105
158
- local early_return = folders_or_files_first (a , b )
106
+ local early_return = folders_or_files_first (a , b , cfg )
159
107
if early_return ~= nil then
160
108
return early_return
161
109
end
@@ -167,15 +115,16 @@ local function node_comparator_name_ignorecase_or_not(a, b, ignorecase)
167
115
end
168
116
end
169
117
170
- function C .case_sensitive (a , b )
171
- return node_comparator_name_ignorecase_or_not (a , b , false )
118
+
119
+ function C .case_sensitive (a , b , cfg )
120
+ return node_comparator_name_ignorecase_or_not (a , b , false , cfg )
172
121
end
173
122
174
- function C .name (a , b )
175
- return node_comparator_name_ignorecase_or_not (a , b , true )
123
+ function C .name (a , b , cfg )
124
+ return node_comparator_name_ignorecase_or_not (a , b , true , cfg )
176
125
end
177
126
178
- function C .modification_time (a , b )
127
+ function C .modification_time (a , b , cfg )
179
128
if not (a and b ) then
180
129
return true
181
130
end
@@ -199,13 +148,13 @@ function C.modification_time(a, b)
199
148
return last_modified_b <= last_modified_a
200
149
end
201
150
202
- function C .suffix (a , b )
151
+ function C .suffix (a , b , cfg )
203
152
if not (a and b ) then
204
153
return true
205
154
end
206
155
207
156
-- directories go first
208
- local early_return = folders_or_files_first (a , b )
157
+ local early_return = folders_or_files_first (a , b , cfg )
209
158
if early_return ~= nil then
210
159
return early_return
211
160
elseif a .nodes and b .nodes then
@@ -248,7 +197,7 @@ function C.suffix(a, b)
248
197
return a_suffix :lower () < b_suffix :lower ()
249
198
end
250
199
251
- function C .extension (a , b )
200
+ function C .extension (a , b , cfg )
252
201
if not (a and b ) then
253
202
return true
254
203
end
@@ -273,12 +222,12 @@ function C.extension(a, b)
273
222
return a_ext < b_ext
274
223
end
275
224
276
- function C .filetype (a , b )
225
+ function C .filetype (a , b , cfg )
277
226
local a_ft = vim .filetype .match { filename = a .name }
278
227
local b_ft = vim .filetype .match { filename = b .name }
279
228
280
229
-- directories first
281
- local early_return = folders_or_files_first (a , b )
230
+ local early_return = folders_or_files_first (a , b , cfg )
282
231
if early_return ~= nil then
283
232
return early_return
284
233
end
@@ -298,13 +247,77 @@ function C.filetype(a, b)
298
247
return a_ft < b_ft
299
248
end
300
249
301
- function M .setup (opts )
302
- M .config = {}
303
- M .config .sort = opts .sort
304
250
305
- if type (M .config .sort .sorter ) == " function" then
306
- C .user = M .config .sort .sorter
251
+ --- @class Sorter
252
+ local Sorter = {}
253
+
254
+ function Sorter :new (opts )
255
+ local o = {} -- create object if user does not provide one
256
+ setmetatable (o , self )
257
+ self .__index = self
258
+ o .config = opts .sort
259
+
260
+ if type (o .config .sorter ) == " function" then
261
+ o .user = o .config .sorter
262
+ end
263
+ return o
264
+ end
265
+
266
+ function Sorter :get_comparator (sorter )
267
+ return function (a , b )
268
+ return (C [sorter ] or C .name )(a , b , self .config )
269
+ end
270
+ end
271
+
272
+ --- Perform a merge sort using sorter option.
273
+ --- @param t table nodes
274
+ function Sorter :sort (t )
275
+ if self .user then
276
+ local t_user = {}
277
+ local origin_index = {}
278
+
279
+ for _ , n in ipairs (t ) do
280
+ table.insert (t_user , {
281
+ absolute_path = n .absolute_path ,
282
+ executable = n .executable ,
283
+ extension = n .extension ,
284
+ filetype = vim .filetype .match { filename = n .name },
285
+ link_to = n .link_to ,
286
+ name = n .name ,
287
+ type = n .type ,
288
+ })
289
+ table.insert (origin_index , n )
290
+ end
291
+
292
+ local predefined = self .user (t_user )
293
+ if predefined then
294
+ split_merge (t , 1 , # t , self :get_comparator (predefined ))
295
+ return
296
+ end
297
+
298
+ -- do merge sort for prevent memory exceed
299
+ local user_index = {}
300
+ for i , v in ipairs (t_user ) do
301
+ if type (v .absolute_path ) == " string" and user_index [v .absolute_path ] == nil then
302
+ user_index [v .absolute_path ] = i
303
+ end
304
+ end
305
+
306
+ -- if missing value found, then using origin_index
307
+ local mini_comparator = function (a , b )
308
+ local a_index = user_index [a .absolute_path ] or origin_index [a .absolute_path ]
309
+ local b_index = user_index [b .absolute_path ] or origin_index [b .absolute_path ]
310
+
311
+ if type (a_index ) == " number" and type (b_index ) == " number" then
312
+ return a_index <= b_index
313
+ end
314
+ return (a_index or 0 ) <= (b_index or 0 )
315
+ end
316
+
317
+ split_merge (t , 1 , # t , mini_comparator ) -- sort by user order
318
+ else
319
+ split_merge (t , 1 , # t , self :get_comparator (self .config .sorter ))
307
320
end
308
321
end
309
322
310
- return M
323
+ return Sorter
0 commit comments