Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jul 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions lua/nvim-tree/explorer/explore.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion lua/nvim-tree/explorer/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {}

Expand Down Expand Up @@ -40,6 +41,7 @@ function Explorer.new(path)
nodes = {},
open = true,
marks = Marks:new(),
sorters = Sorters:new(M.config),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That worked out rather nicely.

}, Explorer)
explorer.watcher = watch.create_watcher(explorer)
explorer.filters = Filters:new(M.config, explorer)
Expand Down Expand Up @@ -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
Expand Down
3 changes: 1 addition & 2 deletions lua/nvim-tree/explorer/reload.lua
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -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
Expand Down
92 changes: 49 additions & 43 deletions lua/nvim-tree/explorer/sorters.lua
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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

Expand Down Expand Up @@ -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 = {}

Expand All @@ -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

Expand All @@ -142,20 +157,20 @@ 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

---@param a Node
---@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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Loading