Sorter type safety

This commit is contained in:
Alexander Courtis 2024-11-09 13:37:43 +11:00
parent 30f1aa3bd7
commit bb0e0ec277

View File

@ -7,12 +7,8 @@ local DirectoryNode = require("nvim-tree.node.directory")
---@alias SorterUser fun(nodes: Node[]): SorterType? ---@alias SorterUser fun(nodes: Node[]): SorterType?
---@class (exact) Sorter: Class ---@class (exact) Sorter: Class
---@field private sorter SorterType|SorterUser ---@field private explorer Explorer
---@field private folders_first boolean
---@field private files_first boolean
---@field private comparators table<SorterType, SorterComparator>
local Sorter = Class:extend() local Sorter = Class:extend()
Sorter.comparators = {}
---@class Sorter ---@class Sorter
---@overload fun(args: SorterArgs): Sorter ---@overload fun(args: SorterArgs): Sorter
@ -23,9 +19,7 @@ Sorter.comparators = {}
---@protected ---@protected
---@param args SorterArgs ---@param args SorterArgs
function Sorter:new(args) function Sorter:new(args)
self.sorter = args.explorer.opts.sort.sorter self.explorer = args.explorer
self.folders_first = args.explorer.opts.sort.folders_first
self.files_first = args.explorer.opts.sort.files_first
end end
---Create a shallow copy of a portion of a list. ---Create a shallow copy of a portion of a list.
@ -42,20 +36,20 @@ local function tbl_slice(t, first, last)
return slice return slice
end end
---Evaluate `sort.folders_first` and `sort.files_first` ---Evaluate folders_first and sort.files_first returning nil when no order is necessary
---@private ---@private
---@type SorterComparator ---@type SorterComparator
function Sorter:folders_or_files_first(a, b) function Sorter:folders_or_files_first(a, b)
if not (self.folders_first or self.files_first) then if not (self.explorer.opts.sort.folders_first or self.explorer.opts.sort.files_first) then
return nil return nil
end end
if not a:is(DirectoryNode) and b:is(DirectoryNode) then if not a:is(DirectoryNode) and b:is(DirectoryNode) then
-- file <> folder -- file <> folder
return self.files_first return self.explorer.opts.sort.files_first
elseif a:is(DirectoryNode) and not b:is(DirectoryNode) then elseif a:is(DirectoryNode) and not b:is(DirectoryNode) then
-- folder <> file -- folder <> file
return not self.files_first return not self.explorer.opts.sort.files_first
end end
return nil return nil
@ -120,9 +114,9 @@ end
---Perform a merge sort using sorter option. ---Perform a merge sort using sorter option.
---@param t Node[] ---@param t Node[]
function Sorter:sort(t) function Sorter:sort(t)
if self.comparators[self.sorter] then if self[self.explorer.opts.sort.sorter] then
self:split_merge(t, 1, #t, self.comparators[self.sorter]) self:split_merge(t, 1, #t, self[self.explorer.opts.sort.sorter])
elseif type(self.sorter) == "function" then elseif type(self.explorer.opts.sort.sorter) == "function" then
local t_user = {} local t_user = {}
local origin_index = {} local origin_index = {}
@ -140,9 +134,9 @@ function Sorter:sort(t)
end end
-- user may return a SorterType -- user may return a SorterType
local ret = self.sorter(t_user) local ret = self.explorer.opts.sort.sorter(t_user)
if self.comparators[ret] then if self[ret] then
self:split_merge(t, 1, #t, self.comparators[ret]) self:split_merge(t, 1, #t, self[ret])
return return
end end
@ -193,19 +187,19 @@ end
---@private ---@private
---@type SorterComparator ---@type SorterComparator
function Sorter.comparators:case_sensitive(a, b) function Sorter:case_sensitive(a, b)
return self:name_case(a, b, false) return self:name_case(a, b, false)
end end
---@private ---@private
---@type SorterComparator ---@type SorterComparator
function Sorter.comparators:name(a, b) function Sorter:name(a, b)
return self:name_case(a, b, true) return self:name_case(a, b, true)
end end
---@private ---@private
---@type SorterComparator ---@type SorterComparator
function Sorter.comparators:modification_time(a, b) function Sorter:modification_time(a, b)
if not (a and b) then if not (a and b) then
return true return true
end end
@ -231,7 +225,7 @@ end
---@private ---@private
---@type SorterComparator ---@type SorterComparator
function Sorter.comparators:suffix(a, b) function Sorter:suffix(a, b)
if not (a and b) then if not (a and b) then
return true return true
end end
@ -241,7 +235,7 @@ function Sorter.comparators:suffix(a, b)
if early_return ~= nil then if early_return ~= nil then
return early_return return early_return
elseif a.nodes and b.nodes then elseif a.nodes and b.nodes then
return self.comparators:name(a, b) return self:name(a, b)
end end
-- dotfiles go second -- dotfiles go second
@ -250,7 +244,7 @@ function Sorter.comparators:suffix(a, b)
elseif a.name:sub(1, 1) ~= "." and b.name:sub(1, 1) == "." then elseif a.name:sub(1, 1) ~= "." and b.name:sub(1, 1) == "." then
return false return false
elseif a.name:sub(1, 1) == "." and b.name:sub(1, 1) == "." then elseif a.name:sub(1, 1) == "." and b.name:sub(1, 1) == "." then
return self.comparators:name(a, b) return self:name(a, b)
end end
-- unsuffixed go third -- unsuffixed go third
@ -262,7 +256,7 @@ function Sorter.comparators:suffix(a, b)
elseif a_suffix_ndx and not b_suffix_ndx then elseif a_suffix_ndx and not b_suffix_ndx then
return false return false
elseif not (a_suffix_ndx and b_suffix_ndx) then elseif not (a_suffix_ndx and b_suffix_ndx) then
return self.comparators:name(a, b) return self:name(a, b)
end end
-- finally, compare by suffixes -- finally, compare by suffixes
@ -274,7 +268,7 @@ function Sorter.comparators:suffix(a, b)
elseif not a_suffix and b_suffix then elseif not a_suffix and b_suffix then
return false return false
elseif a_suffix:lower() == b_suffix:lower() then elseif a_suffix:lower() == b_suffix:lower() then
return self.comparators:name(a, b) return self:name(a, b)
end end
return a_suffix:lower() < b_suffix:lower() return a_suffix:lower() < b_suffix:lower()
@ -282,7 +276,7 @@ end
---@private ---@private
---@type SorterComparator ---@type SorterComparator
function Sorter.comparators:extension(a, b) function Sorter:extension(a, b)
if not (a and b) then if not (a and b) then
return true return true
end end
@ -301,7 +295,7 @@ function Sorter.comparators:extension(a, b)
local a_ext = (a.extension or ""):lower() local a_ext = (a.extension or ""):lower()
local b_ext = (b.extension or ""):lower() local b_ext = (b.extension or ""):lower()
if a_ext == b_ext then if a_ext == b_ext then
return self.comparators:name(a, b) return self:name(a, b)
end end
return a_ext < b_ext return a_ext < b_ext
@ -309,7 +303,7 @@ end
---@private ---@private
---@type SorterComparator ---@type SorterComparator
function Sorter.comparators:filetype(a, b) function Sorter:filetype(a, b)
local a_ft = vim.filetype.match({ filename = a.name }) local a_ft = vim.filetype.match({ filename = a.name })
local b_ft = vim.filetype.match({ filename = b.name }) local b_ft = vim.filetype.match({ filename = b.name })
@ -328,7 +322,7 @@ function Sorter.comparators:filetype(a, b)
-- same filetype or both nil, sort by name -- same filetype or both nil, sort by name
if a_ft == b_ft then if a_ft == b_ft then
return self.comparators:name(a, b) return self:name(a, b)
end end
return a_ft < b_ft return a_ft < b_ft