Skip to content

Commit 552b707

Browse files
committed
refactor: multi instance nvim-tree.explorer.sorters
1 parent f9ff00b commit 552b707

File tree

4 files changed

+93
-79
lines changed

4 files changed

+93
-79
lines changed

lua/nvim-tree/explorer/explore.lua

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ local utils = require "nvim-tree.utils"
22
local builders = require "nvim-tree.explorer.node-builders"
33
local explorer_node = require "nvim-tree.explorer.node"
44
local git = require "nvim-tree.git"
5-
local sorters = require "nvim-tree.explorer.sorters"
5+
local Sorters = require "nvim-tree.explorer.sorters"
66
local filters = require "nvim-tree.explorer.filters"
77
local live_filter = require "nvim-tree.live-filter"
88
local log = require "nvim-tree.log"
@@ -81,14 +81,15 @@ function M.explore(node, status)
8181
return ns
8282
end
8383

84-
sorters.sort(node.nodes)
84+
M.sorters:sort(node.nodes)
8585
live_filter.apply_filter(node)
8686

8787
log.profile_end(profile)
8888
return node.nodes
8989
end
9090

9191
function M.setup(opts)
92+
M.sorters = Sorters:new(opts)
9293
M.config = opts.renderer
9394
end
9495

lua/nvim-tree/explorer/init.lua

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ function M.setup(opts)
7171
require("nvim-tree.explorer.node").setup(opts)
7272
require("nvim-tree.explorer.explore").setup(opts)
7373
require("nvim-tree.explorer.filters").setup(opts)
74-
require("nvim-tree.explorer.sorters").setup(opts)
7574
require("nvim-tree.explorer.reload").setup(opts)
7675
require("nvim-tree.explorer.watch").setup(opts)
7776
end

lua/nvim-tree/explorer/reload.lua

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ local utils = require "nvim-tree.utils"
22
local builders = require "nvim-tree.explorer.node-builders"
33
local explorer_node = require "nvim-tree.explorer.node"
44
local filters = require "nvim-tree.explorer.filters"
5-
local sorters = require "nvim-tree.explorer.sorters"
5+
local Sorters = require "nvim-tree.explorer.sorters"
66
local live_filter = require "nvim-tree.live-filter"
77
local git = require "nvim-tree.git"
88
local log = require "nvim-tree.log"
@@ -162,7 +162,7 @@ function M.reload(node, git_status)
162162
return ns
163163
end
164164

165-
sorters.sort(node.nodes)
165+
M.sorters:sort(node.nodes)
166166
live_filter.apply_filter(node)
167167
log.profile_end(profile)
168168
return node.nodes
@@ -226,6 +226,7 @@ function M.refresh_parent_nodes_for_path(path)
226226
end
227227

228228
function M.setup(opts)
229+
M.sorters = Sorters:new(opts)
229230
M.config = opts.renderer
230231
end
231232

lua/nvim-tree/explorer/sorters.lua

Lines changed: 87 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
local M = {}
2-
31
local C = {}
42

53
--- Predefined comparator, defaulting to name
@@ -27,17 +25,17 @@ end
2725
---@param a Node
2826
---@param b Node
2927
---@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
3230
return
3331
end
3432

3533
if not a.nodes and b.nodes then
3634
-- file <> folder
37-
return M.config.sort.files_first
35+
return cfg.files_first
3836
elseif a.nodes and not b.nodes then
3937
-- folder <> file
40-
return not M.config.sort.files_first
38+
return not cfg.files_first
4139
end
4240
end
4341

@@ -95,67 +93,17 @@ local function split_merge(t, first, last, comparator)
9593
merge(t, first, mid, last, comparator)
9694
end
9795

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
14896

14997
---@param a Node
15098
---@param b Node
15199
---@param ignorecase boolean|nil
152100
---@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)
154102
if not (a and b) then
155103
return true
156104
end
157105

158-
local early_return = folders_or_files_first(a, b)
106+
local early_return = folders_or_files_first(a, b, cfg)
159107
if early_return ~= nil then
160108
return early_return
161109
end
@@ -167,15 +115,16 @@ local function node_comparator_name_ignorecase_or_not(a, b, ignorecase)
167115
end
168116
end
169117

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)
172121
end
173122

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)
176125
end
177126

178-
function C.modification_time(a, b)
127+
function C.modification_time(a, b, cfg)
179128
if not (a and b) then
180129
return true
181130
end
@@ -199,13 +148,13 @@ function C.modification_time(a, b)
199148
return last_modified_b <= last_modified_a
200149
end
201150

202-
function C.suffix(a, b)
151+
function C.suffix(a, b, cfg)
203152
if not (a and b) then
204153
return true
205154
end
206155

207156
-- directories go first
208-
local early_return = folders_or_files_first(a, b)
157+
local early_return = folders_or_files_first(a, b, cfg)
209158
if early_return ~= nil then
210159
return early_return
211160
elseif a.nodes and b.nodes then
@@ -248,7 +197,7 @@ function C.suffix(a, b)
248197
return a_suffix:lower() < b_suffix:lower()
249198
end
250199

251-
function C.extension(a, b)
200+
function C.extension(a, b, cfg)
252201
if not (a and b) then
253202
return true
254203
end
@@ -273,12 +222,12 @@ function C.extension(a, b)
273222
return a_ext < b_ext
274223
end
275224

276-
function C.filetype(a, b)
225+
function C.filetype(a, b, cfg)
277226
local a_ft = vim.filetype.match { filename = a.name }
278227
local b_ft = vim.filetype.match { filename = b.name }
279228

280229
-- directories first
281-
local early_return = folders_or_files_first(a, b)
230+
local early_return = folders_or_files_first(a, b, cfg)
282231
if early_return ~= nil then
283232
return early_return
284233
end
@@ -298,13 +247,77 @@ function C.filetype(a, b)
298247
return a_ft < b_ft
299248
end
300249

301-
function M.setup(opts)
302-
M.config = {}
303-
M.config.sort = opts.sort
304250

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))
307320
end
308321
end
309322

310-
return M
323+
return Sorter

0 commit comments

Comments
 (0)