diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index be998c6de51..9dc36cada63 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -191,7 +191,6 @@ Subsequent calls to setup will replace the previous configuration. number = false, relativenumber = false, signcolumn = "yes", - -- @deprecated mappings = { custom_only = false, list = { @@ -426,9 +425,25 @@ if the tree was previously open. *nvim-tree.sort_by* Changes how files within the same directory are sorted. -Can be one of 'name', 'case_sensitive', 'modification_time' or 'extension'. - Type: `string`, Default: `"name"` - +Can be one of `name`, `case_sensitive`, `modification_time`, `extension` or a +function. + Type: `string` | `function(nodes)`, Default: `"name"` + + Function is passed a table of nodes to be sorted, each node containing: + - `absolute_path`: `string` + - `executable`: `boolean` + - `extension`: `string` + - `link_to`: `string` + - `name`: `string` + - `type`: `"directory"` | `"file"` | `"link"` + + Example: sort by name length: > + local sort_by = function(nodes) + table.sort(nodes, function(a, b) + return #a.name < #b.name + end) + end +< *nvim-tree.hijack_unnamed_buffer_when_opening* Opens in place of the unnamed buffer if it's empty. Type: `boolean`, Default: `false` diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index a1a81b5a94f..0af27560180 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -640,6 +640,7 @@ local FIELD_OVERRIDE_TYPECHECK = { height = { string = true, ["function"] = true, number = true }, remove_keymaps = { boolean = true, table = true }, on_attach = { ["function"] = true, string = true }, + sort_by = { ["function"] = true, string = true }, } local function validate_options(conf) diff --git a/lua/nvim-tree/explorer/sorters.lua b/lua/nvim-tree/explorer/sorters.lua index 4168a931c95..be0d7fcfbd1 100644 --- a/lua/nvim-tree/explorer/sorters.lua +++ b/lua/nvim-tree/explorer/sorters.lua @@ -66,13 +66,52 @@ end ---@param t any[] ---@param comparator function|nil function M.merge_sort(t, comparator) - if not comparator then - comparator = function(left, right) - return left < right + if type(M.sort_by) == "function" then + local t_user = {} + local origin_index = {} + + for _, n in ipairs(t) do + table.insert(t_user, { + absolute_path = n.absolute_path, + executable = n.executable, + extension = n.extension, + link_to = n.link_to, + name = n.name, + type = n.type, + }) + table.insert(origin_index, n) end - end - split_merge(t, 1, #t, comparator) + M.sort_by(t_user) + + -- do merge sort for prevent memory exceed + local user_index = {} + for i, v in ipairs(t_user) do + if type(v.absolute_path) == "string" and user_index[v.absolute_path] == nil then + user_index[v.absolute_path] = i + end + end + + -- if missing value found, then using origin_index + local mini_comparator = function(a, b) + local a_index = user_index[a.absolute_path] or origin_index[a.absolute_path] + local b_index = user_index[b.absolute_path] or origin_index[b.absolute_path] + + if type(a_index) == "number" and type(b_index) == "number" then + return a_index <= b_index + end + return (a_index or 0) <= (b_index or 0) + end + + split_merge(t, 1, #t, mini_comparator) -- sort by user order + else + if not comparator then + comparator = function(left, right) + return left < right + end + end + split_merge(t, 1, #t, comparator) + end end local function node_comparator_name_ignorecase_or_not(a, b, ignorecase) @@ -150,7 +189,9 @@ end function M.setup(opts) M.sort_by = opts.sort_by - if M.sort_by == "modification_time" then + if M.sort_by and type(M.sort_by) == "function" then + M.node_comparator = M.sort_by + elseif M.sort_by == "modification_time" then M.node_comparator = M.node_comparator_modification_time elseif M.sort_by == "case_sensitive" then M.node_comparator = M.node_comparator_name_case_sensisive