|
1 | 1 | local C = {} |
2 | 2 |
|
| 3 | +---@class Sorter |
| 4 | +local Sorter = {} |
| 5 | + |
| 6 | +function Sorter:new(opts) |
| 7 | + local o = {} -- create object if user does not provide one |
| 8 | + setmetatable(o, self) |
| 9 | + self.__index = self |
| 10 | + o.config = vim.deepcopy(opts.sort) |
| 11 | + |
| 12 | + if type(o.config.sorter) == "function" then |
| 13 | + o.user = o.config.sorter |
| 14 | + end |
| 15 | + return o |
| 16 | +end |
| 17 | + |
| 18 | +--- Predefined comparator, defaulting to name |
| 19 | +---@param sorter string as per options |
| 20 | +---@return function |
| 21 | +function Sorter:get_comparator(sorter) |
| 22 | + return function(a, b) |
| 23 | + return (C[sorter] or C.name)(a, b, self.config) |
| 24 | + end |
| 25 | +end |
| 26 | + |
3 | 27 | ---Create a shallow copy of a portion of a list. |
4 | 28 | ---@param t table |
5 | 29 | ---@param first integer First index, inclusive |
@@ -86,6 +110,57 @@ local function split_merge(t, first, last, comparator) |
86 | 110 | merge(t, first, mid, last, comparator) |
87 | 111 | end |
88 | 112 |
|
| 113 | +---Perform a merge sort using sorter option. |
| 114 | +---@param t table nodes |
| 115 | +function Sorter:sort(t) |
| 116 | + if self.user then |
| 117 | + local t_user = {} |
| 118 | + local origin_index = {} |
| 119 | + |
| 120 | + for _, n in ipairs(t) do |
| 121 | + table.insert(t_user, { |
| 122 | + absolute_path = n.absolute_path, |
| 123 | + executable = n.executable, |
| 124 | + extension = n.extension, |
| 125 | + filetype = vim.filetype.match { filename = n.name }, |
| 126 | + link_to = n.link_to, |
| 127 | + name = n.name, |
| 128 | + type = n.type, |
| 129 | + }) |
| 130 | + table.insert(origin_index, n) |
| 131 | + end |
| 132 | + |
| 133 | + local predefined = self.user(t_user) |
| 134 | + if predefined then |
| 135 | + split_merge(t, 1, #t, self:get_comparator(predefined)) |
| 136 | + return |
| 137 | + end |
| 138 | + |
| 139 | + -- do merge sort for prevent memory exceed |
| 140 | + local user_index = {} |
| 141 | + for i, v in ipairs(t_user) do |
| 142 | + if type(v.absolute_path) == "string" and user_index[v.absolute_path] == nil then |
| 143 | + user_index[v.absolute_path] = i |
| 144 | + end |
| 145 | + end |
| 146 | + |
| 147 | + -- if missing value found, then using origin_index |
| 148 | + local mini_comparator = function(a, b) |
| 149 | + local a_index = user_index[a.absolute_path] or origin_index[a.absolute_path] |
| 150 | + local b_index = user_index[b.absolute_path] or origin_index[b.absolute_path] |
| 151 | + |
| 152 | + if type(a_index) == "number" and type(b_index) == "number" then |
| 153 | + return a_index <= b_index |
| 154 | + end |
| 155 | + return (a_index or 0) <= (b_index or 0) |
| 156 | + end |
| 157 | + |
| 158 | + split_merge(t, 1, #t, mini_comparator) -- sort by user order |
| 159 | + else |
| 160 | + split_merge(t, 1, #t, self:get_comparator(self.config.sorter)) |
| 161 | + end |
| 162 | +end |
| 163 | + |
89 | 164 | ---@param a Node |
90 | 165 | ---@param b Node |
91 | 166 | ---@param ignorecase boolean|nil |
@@ -238,79 +313,4 @@ function C.filetype(a, b, cfg) |
238 | 313 | return a_ft < b_ft |
239 | 314 | end |
240 | 315 |
|
241 | | ----@class Sorter |
242 | | -local Sorter = {} |
243 | | - |
244 | | -function Sorter:new(opts) |
245 | | - local o = {} -- create object if user does not provide one |
246 | | - setmetatable(o, self) |
247 | | - self.__index = self |
248 | | - o.config = opts.sort |
249 | | - |
250 | | - if type(o.config.sorter) == "function" then |
251 | | - o.user = o.config.sorter |
252 | | - end |
253 | | - return o |
254 | | -end |
255 | | - |
256 | | ---- Predefined comparator, defaulting to name |
257 | | ----@param sorter string as per options |
258 | | ----@return function |
259 | | -function Sorter:get_comparator(sorter) |
260 | | - return function(a, b) |
261 | | - return (C[sorter] or C.name)(a, b, self.config) |
262 | | - end |
263 | | -end |
264 | | - |
265 | | ----Perform a merge sort using sorter option. |
266 | | ----@param t table nodes |
267 | | -function Sorter:sort(t) |
268 | | - if self.user then |
269 | | - local t_user = {} |
270 | | - local origin_index = {} |
271 | | - |
272 | | - for _, n in ipairs(t) do |
273 | | - table.insert(t_user, { |
274 | | - absolute_path = n.absolute_path, |
275 | | - executable = n.executable, |
276 | | - extension = n.extension, |
277 | | - filetype = vim.filetype.match { filename = n.name }, |
278 | | - link_to = n.link_to, |
279 | | - name = n.name, |
280 | | - type = n.type, |
281 | | - }) |
282 | | - table.insert(origin_index, n) |
283 | | - end |
284 | | - |
285 | | - local predefined = self.user(t_user) |
286 | | - if predefined then |
287 | | - split_merge(t, 1, #t, self:get_comparator(predefined)) |
288 | | - return |
289 | | - end |
290 | | - |
291 | | - -- do merge sort for prevent memory exceed |
292 | | - local user_index = {} |
293 | | - for i, v in ipairs(t_user) do |
294 | | - if type(v.absolute_path) == "string" and user_index[v.absolute_path] == nil then |
295 | | - user_index[v.absolute_path] = i |
296 | | - end |
297 | | - end |
298 | | - |
299 | | - -- if missing value found, then using origin_index |
300 | | - local mini_comparator = function(a, b) |
301 | | - local a_index = user_index[a.absolute_path] or origin_index[a.absolute_path] |
302 | | - local b_index = user_index[b.absolute_path] or origin_index[b.absolute_path] |
303 | | - |
304 | | - if type(a_index) == "number" and type(b_index) == "number" then |
305 | | - return a_index <= b_index |
306 | | - end |
307 | | - return (a_index or 0) <= (b_index or 0) |
308 | | - end |
309 | | - |
310 | | - split_merge(t, 1, #t, mini_comparator) -- sort by user order |
311 | | - else |
312 | | - split_merge(t, 1, #t, self:get_comparator(self.config.sorter)) |
313 | | - end |
314 | | -end |
315 | | - |
316 | 316 | return Sorter |
0 commit comments