refactor(#2829): multi instance nvim-tree.explorer.sorters (#2835)

* refactor: multi instance nvim-tree.explorer.sorters

* fix: linter errors

* fix: style

* fix: according to code review

* chore: removed comment

* fix: missing cfg params in sorters

* tidy following rebase

* tidy following rebase

---------

Co-authored-by: Alexander Courtis <alex@courtis.org>
This commit is contained in:
Mateusz Russak 2024-07-27 05:54:40 +02:00 committed by GitHub
parent 908478a0e0
commit 82ba116bbd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 53 additions and 48 deletions

View File

@ -2,7 +2,6 @@ local utils = require "nvim-tree.utils"
local builders = require "nvim-tree.explorer.node-builders"
local explorer_node = require "nvim-tree.explorer.node"
local git = require "nvim-tree.git"
local sorters = require "nvim-tree.explorer.sorters"
local live_filter = require "nvim-tree.live-filter"
local log = require "nvim-tree.log"
@ -82,7 +81,7 @@ function M.explore(node, status, parent)
return ns
end
sorters.sort(node.nodes)
parent.sorters:sort(node.nodes)
live_filter.apply_filter(node)
log.profile_end(profile)

View File

@ -4,6 +4,7 @@ local watch = require "nvim-tree.explorer.watch"
local explorer_node = require "nvim-tree.explorer.node"
local Filters = require "nvim-tree.explorer.filters"
local Marks = require "nvim-tree.marks"
local Sorters = require "nvim-tree.explorer.sorters"
local M = {}
@ -40,6 +41,7 @@ function Explorer.new(path)
nodes = {},
open = true,
marks = Marks:new(),
sorters = Sorters:new(M.config),
}, Explorer)
explorer.watcher = watch.create_watcher(explorer)
explorer.filters = Filters:new(M.config, explorer)
@ -76,7 +78,6 @@ function M.setup(opts)
M.config = opts
require("nvim-tree.explorer.node").setup(opts)
require("nvim-tree.explorer.explore").setup(opts)
require("nvim-tree.explorer.sorters").setup(opts)
require("nvim-tree.explorer.reload").setup(opts)
require("nvim-tree.explorer.watch").setup(opts)
end

View File

@ -1,7 +1,6 @@
local utils = require "nvim-tree.utils"
local builders = require "nvim-tree.explorer.node-builders"
local explorer_node = require "nvim-tree.explorer.node"
local sorters = require "nvim-tree.explorer.sorters"
local live_filter = require "nvim-tree.live-filter"
local git = require "nvim-tree.git"
local log = require "nvim-tree.log"
@ -165,7 +164,7 @@ function M.reload(node, git_status)
return ns
end
sorters.sort(node.nodes)
explorer.sorters:sort(node.nodes)
live_filter.apply_filter(node)
log.profile_end(profile)
return node.nodes

View File

@ -1,12 +1,27 @@
local M = {}
local C = {}
---@class Sorter
local Sorter = {}
function Sorter:new(opts)
local o = {}
setmetatable(o, self)
self.__index = self
o.config = vim.deepcopy(opts.sort)
if type(o.config.sorter) == "function" then
o.user = o.config.sorter
end
return o
end
--- Predefined comparator, defaulting to name
---@param sorter string as per options
---@return function
local function get_comparator(sorter)
return C[sorter] or C.name
function Sorter:get_comparator(sorter)
return function(a, b)
return (C[sorter] or C.name)(a, b, self.config)
end
end
---Create a shallow copy of a portion of a list.
@ -27,17 +42,17 @@ end
---@param a Node
---@param b Node
---@return boolean|nil
local function folders_or_files_first(a, b)
if not (M.config.sort.folders_first or M.config.sort.files_first) then
local function folders_or_files_first(a, b, cfg)
if not (cfg.folders_first or cfg.files_first) then
return
end
if not a.nodes and b.nodes then
-- file <> folder
return M.config.sort.files_first
return cfg.files_first
elseif a.nodes and not b.nodes then
-- folder <> file
return not M.config.sort.files_first
return not cfg.files_first
end
end
@ -97,8 +112,8 @@ end
---Perform a merge sort using sorter option.
---@param t table nodes
function M.sort(t)
if C.user then
function Sorter:sort(t)
if self.user then
local t_user = {}
local origin_index = {}
@ -115,9 +130,9 @@ function M.sort(t)
table.insert(origin_index, n)
end
local predefined = C.user(t_user)
local predefined = self.user(t_user)
if predefined then
split_merge(t, 1, #t, get_comparator(predefined))
split_merge(t, 1, #t, self:get_comparator(predefined))
return
end
@ -142,7 +157,7 @@ function M.sort(t)
split_merge(t, 1, #t, mini_comparator) -- sort by user order
else
split_merge(t, 1, #t, get_comparator(M.config.sort.sorter))
split_merge(t, 1, #t, self:get_comparator(self.config.sorter))
end
end
@ -150,12 +165,12 @@ end
---@param b Node
---@param ignorecase boolean|nil
---@return boolean
local function node_comparator_name_ignorecase_or_not(a, b, ignorecase)
local function node_comparator_name_ignorecase_or_not(a, b, ignorecase, cfg)
if not (a and b) then
return true
end
local early_return = folders_or_files_first(a, b)
local early_return = folders_or_files_first(a, b, cfg)
if early_return ~= nil then
return early_return
end
@ -167,20 +182,20 @@ local function node_comparator_name_ignorecase_or_not(a, b, ignorecase)
end
end
function C.case_sensitive(a, b)
return node_comparator_name_ignorecase_or_not(a, b, false)
function C.case_sensitive(a, b, cfg)
return node_comparator_name_ignorecase_or_not(a, b, false, cfg)
end
function C.name(a, b)
return node_comparator_name_ignorecase_or_not(a, b, true)
function C.name(a, b, cfg)
return node_comparator_name_ignorecase_or_not(a, b, true, cfg)
end
function C.modification_time(a, b)
function C.modification_time(a, b, cfg)
if not (a and b) then
return true
end
local early_return = folders_or_files_first(a, b)
local early_return = folders_or_files_first(a, b, cfg)
if early_return ~= nil then
return early_return
end
@ -199,17 +214,17 @@ function C.modification_time(a, b)
return last_modified_b <= last_modified_a
end
function C.suffix(a, b)
function C.suffix(a, b, cfg)
if not (a and b) then
return true
end
-- directories go first
local early_return = folders_or_files_first(a, b)
local early_return = folders_or_files_first(a, b, cfg)
if early_return ~= nil then
return early_return
elseif a.nodes and b.nodes then
return C.name(a, b)
return C.name(a, b, cfg)
end
-- dotfiles go second
@ -218,7 +233,7 @@ function C.suffix(a, b)
elseif a.name:sub(1, 1) ~= "." and b.name:sub(1, 1) == "." then
return false
elseif a.name:sub(1, 1) == "." and b.name:sub(1, 1) == "." then
return C.name(a, b)
return C.name(a, b, cfg)
end
-- unsuffixed go third
@ -230,7 +245,7 @@ function C.suffix(a, b)
elseif a_suffix_ndx and not b_suffix_ndx then
return false
elseif not (a_suffix_ndx and b_suffix_ndx) then
return C.name(a, b)
return C.name(a, b, cfg)
end
-- finally, compare by suffixes
@ -242,18 +257,18 @@ function C.suffix(a, b)
elseif not a_suffix and b_suffix then
return false
elseif a_suffix:lower() == b_suffix:lower() then
return C.name(a, b)
return C.name(a, b, cfg)
end
return a_suffix:lower() < b_suffix:lower()
end
function C.extension(a, b)
function C.extension(a, b, cfg)
if not (a and b) then
return true
end
local early_return = folders_or_files_first(a, b)
local early_return = folders_or_files_first(a, b, cfg)
if early_return ~= nil then
return early_return
end
@ -267,18 +282,18 @@ function C.extension(a, b)
local a_ext = (a.extension or ""):lower()
local b_ext = (b.extension or ""):lower()
if a_ext == b_ext then
return C.name(a, b)
return C.name(a, b, cfg)
end
return a_ext < b_ext
end
function C.filetype(a, b)
function C.filetype(a, b, cfg)
local a_ft = vim.filetype.match { filename = a.name }
local b_ft = vim.filetype.match { filename = b.name }
-- directories first
local early_return = folders_or_files_first(a, b)
local early_return = folders_or_files_first(a, b, cfg)
if early_return ~= nil then
return early_return
end
@ -292,19 +307,10 @@ function C.filetype(a, b)
-- same filetype or both nil, sort by name
if a_ft == b_ft then
return C.name(a, b)
return C.name(a, b, cfg)
end
return a_ft < b_ft
end
function M.setup(opts)
M.config = {}
M.config.sort = opts.sort
if type(M.config.sort.sorter) == "function" then
C.user = M.config.sort.sorter
end
end
return M
return Sorter